FFMPEG + SDL播放视频流
SDL播放视频流程:相关函数的说明可以看SDL视频播放API由于SDL只能播放YUV和RGB格式的像素帧,所以对于MP4、mkv、avi、flv等封装格式的视频文件来说必须对其解码成YUV或RGB,才能用SDL播放,FFMPEG解码成YUVdemo/* SDL 播放视频流*/#define SDL_MAIN_HANDLED#include <iostream>#include <
·
SDL播放视频流程:
相关函数的说明可以看 SDL视频播放API
由于SDL只能播放YUV和RGB格式的像素帧,所以对于MP4、mkv、avi、flv等封装格式的视频文件来说必须对其解码成YUV或RGB,才能用SDL播放,FFMPEG解码成YUV
SDL播放视频流demo
/* SDL 播放视频流*/
#define SDL_MAIN_HANDLED
#include <iostream>
#include <cstdio>
using namespace std;
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#include <SDL.h>
}
const char* infile = "1.mp4";
int main(int argc, char** argv)
{
AVFormatContext* afc = avformat_alloc_context();
if (avformat_open_input(&afc, infile, NULL, NULL) != 0)
{
cout << "open video error " << endl;
return 0;
}
if (avformat_find_stream_info(afc, NULL) < 0)
{
cout << "find stream error" << endl;
return 0;
}
int videoflag = -1;
AVCodec* vdecodec;
AVCodecContext* vcc = NULL;
for (int i = 0; i < afc->nb_streams; ++i)
{
if (afc->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) //视频
{
videoflag = i;
vdecodec = avcodec_find_decoder(afc->streams[videoflag]->codecpar->codec_id);
vcc = avcodec_alloc_context3(vdecodec); //为解码器创建内存
avcodec_parameters_to_context(vcc, afc->streams[i]->codecpar); //初始化解码器参数
if (avcodec_open2(vcc, vdecodec, NULL) < 0)
{
cout << "open video decodec error" << endl;
return -1;
}
}
}
if (videoflag == -1)
{
cout << "video stream not find" << endl;
return -1;
}
int win_w = vcc->width;
int win_h = vcc->height;
if (SDL_Init(SDL_INIT_VIDEO))
{
printf("Could not initialize SDL - %s\n", SDL_GetError());
return -1;
}
SDL_Window* screen = SDL_CreateWindow("player", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, win_w, win_h, SDL_WINDOW_OPENGL);
if (!screen)
{
printf("SDL: could not create window - exiting:%s\n", SDL_GetError());
return -1;
}
SDL_Renderer* sdlRenderer = SDL_CreateRenderer(screen, -1, 0);
SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, win_w, win_h);
SDL_Rect sdlRect; //设置播放窗口的起始位置和大小
sdlRect.x = 0;
sdlRect.y = 0;
sdlRect.w = win_w;
sdlRect.h = win_h;
AVFrame* frame = av_frame_alloc();//视频解码后的frame
AVFrame* yuv = av_frame_alloc();
AVPacket* pkt = (AVPacket*)av_malloc(sizeof(AVPacket));
unsigned char* out_buffer = (unsigned char*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, vcc->width, vcc->height, 1));
av_image_fill_arrays(yuv->data, yuv->linesize, out_buffer, AV_PIX_FMT_YUV420P, vcc->width, vcc->height, 1); //填充yuv像素数据缓冲区,没有这步会导致sws_scale()失败
SwsContext* ssc = sws_getContext(vcc->width, vcc->height, vcc->pix_fmt,
vcc->width, vcc->height, AV_PIX_FMT_YUV420P,
SWS_BICUBIC, NULL, NULL, NULL);
int vret = 0;
int count = 0;
while (av_read_frame(afc, pkt) >= 0)
{
if (pkt->stream_index == videoflag) //视频解码
{
if ( vret = avcodec_send_packet(vcc, pkt) != 0) //向解码器发送视频数据包
{
cout << "send video packet to decodec error, code:" << vret << endl;
return -1;
}
while (vret >= 0)
{
vret = avcodec_receive_frame(vcc, frame); //接收解码后的数据帧
if (vret == 0)
{
sws_scale(ssc, frame->data, frame->linesize, 0, vcc->height, yuv->data, yuv->linesize);
cout << "sws_scale ok" << endl;
SDL_UpdateYUVTexture(sdlTexture, &sdlRect,
yuv->data[0], yuv->linesize[0],
yuv->data[1], yuv->linesize[1],
yuv->data[2], yuv->linesize[2]);
SDL_RenderClear(sdlRenderer);
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect);
SDL_RenderPresent(sdlRenderer); //播放
SDL_Delay(40); //延时40ms,相当于1s播放25帧
count++;
cout << "player one frame succeed, this is " << count << endl;
}
else if (vret == AVERROR(EAGAIN)|| vret == AVERROR_EOF) //接收到的数据无效 需要重新读入
{
cout << "receive video frame error, need again" << endl;
break;
}
else
{
cout << "avcodec_receive_frame video error code:" << vret << endl;
return -1;
}
}
}
}
//播放最后解码器中剩下的数据帧
if (vret = avcodec_send_packet(vcc, NULL) != 0)
{
cout << "send video packet to decodec error, code:" << vret << endl;
return -1;
}
while (vret >= 0)
{
vret = avcodec_receive_frame(vcc, frame);
if (vret == 0)
{
sws_scale(ssc, frame->data, frame->linesize, 0, vcc->height, yuv->data, yuv->linesize);
cout << "sws_scale ok" << endl;
SDL_UpdateYUVTexture(sdlTexture, &sdlRect,
yuv->data[0], yuv->linesize[0],
yuv->data[1], yuv->linesize[1],
yuv->data[2], yuv->linesize[2]);
SDL_RenderClear(sdlRenderer);
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect);
SDL_RenderPresent(sdlRenderer);
SDL_Delay(40);
count++;
cout << "player one frame from AVCodecContext succeed, this is " << count << endl;
}
else
{
cout << "avcodec_receive_frame video error code:" << vret << endl;
break;
}
}
cout << "player ok" << endl;
SDL_Quit();
//释放资源
av_packet_unref(pkt);
av_frame_free(&yuv);
av_frame_free(&frame);
avcodec_free_context(&vcc);
avformat_close_input(&afc);
return 0;
}
更多推荐
已为社区贡献1条内容
所有评论(0)