您的位置:首页 > 其它

FFmpeg - 视频解码过程

2012-07-02 15:58 155 查看
FFmpeg的文档做得不好,导致学会使用这个库是存在一定难度的。在对文件进行解码时,抄网上流传的例子就可以了。比如,常见的例子是这样的:

main(0

{

av_register_all();

// Open video file
if(av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL)!=0)
return -1; // Couldn't open file
// Retrieve stream information
if(av_find_stream_info(pFormatCtx)<0)
return -1; // Couldn't find stream information

pCodecCtx=&pFormatCtx->streams[videoStream]->codec;

// Find the decoder for the video stream
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==NULL)
return -1; // Codec not found

...

}


以解TS流文件为例,上述代码会把读文件、读TS包、解PMT, PAT、解PES等过程都内部做了,使用者即使不懂这些概念,也是可以写出一个解TS文件成图像的例子的。但如果输入的是一个TS流怎么办呢?--显然再用av_open_input_file()这种就行了。

对于流媒体TS,要对MPEG-2有一定了解。其步骤简述如下:

(1) 解复用,得到PAT, PMT,得到PES_pid

(2) 对PES解复用,得到其PTS和ES

(3) 把ES(图像编码数据)交给FFmpeg解码,得到图像

(4) 按PTS顺序,显示图像。如果是AVC/H264编码,其PTS顺序一般不是自然顺序。

那么,在第(3)步中,怎么使用FFmpeg来解ES呢?参考其examples,总结得到以下顺序:

////////////////////初始化 ///////////////////////////////

// 查找解码器ID
CodecID codec_id = CODEC_ID_NONE;
switch(stream_type)
{
default:
codec_id = CODEC_ID_H264;
}

// 查找解码器
m_pCodec = avcodec_find_decoder(codec_id);
if (!m_pCodec)
{
fprintf(stderr, "codec not found\n");
return -1;
}

// 打开解码器
m_pCodecContext = avcodec_alloc_context();
if (avcodec_open(m_pCodecContext, m_pCodec) < 0)
{
fprintf(stderr, "could not open codec\n");
return -1;
}

// 申请一帧的空间用于解码
m_pPicture = avcodec_alloc_frame();


//////////// 解码 /////////////////

// 解析PES得到ES
TS_PesDecoder pesdec;
pesdec.Parse(m_iDemux.Payload(), m_iDemux.PayloadSize());

// AVPacket应包含的是ES数据
AVPacket avpkt;
av_init_packet(&avpkt);
avpkt.size = pesdec.m_nEsLength;
avpkt.data = pesdec.m_pEs;

if (avpkt.size == 0) return -1 ;

// 解AVPacket,得到图像数据AVFrame
while (avpkt.size > 0)
{
int got_picture = 0;
int len = avcodec_decode_video2(m_pCodecContext, m_pPicture, &got_picture, &avpkt);
if (len < 0)
{
fprintf(stderr, "Error while decoding frame...\n");
break;
}

if (got_picture)
{
int width = m_pCodecContext->width;
int height = m_pCodecContext->height;

VideoFrame frame;
frame.nWidth = width;
frame.nHeight = height;
frame.nPts = pesdec.m_nPts / 45; // in ms

AVPicture& pic_rgb = frame.iPic;
avpicture_alloc(&pic_rgb, PIX_FMT_RGB24, width, height);

// 用swscale库把YUYV420P转成RGB24
SwsContext* img_convert_ctx = sws_getContext(width, height, PIX_FMT_YUV420P,
width, height, PIX_FMT_RGB24,
SWS_BICUBIC, NULL, NULL, NULL);

sws_scale(img_convert_ctx,
m_pPicture->data, m_pPicture->linesize,
0, height,
pic_rgb.data, pic_rgb.linesize);

sws_freeContext(img_convert_ctx);

printf("Saving a frame ....\n");
m_iMutex.Lock();
m_lstFrames.push_back(frame);
m_iMutex.Unlock();

return 1;
}

avpkt.size -= len;
avpkt.data += len;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: