今天在测试解码一个AVI格式的视频文件时,调用解码函数:
avcodec_decode_video2(pCodecCtx, pFrame, &got_picture,packet);
在解码第一帧的时候,函数返回的是一个大于0的数,但是got_picture返回的确实0,这说明函数没有完整的解码出一帧。但是函数
也没执行失败,很大可能是被解码器缓存起来了。
1、
先看看一段问题,对于一个AVI格式视频,带有B帧。通过工具分析出如下结构:
图1
根据码率顺序,我们看到第一个GOP的大概结构是I P B P B B P B B。
一般的解码操作代码如下结构:
while(av_read_frame(pFormatCtx, packet)>=0)
{
if(packet->stream_index==videoindex)
{
ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
}
}
av_read_frame()是按照PTS顺序读取帧的,通过看图1,显然PTS的顺序不是顺序累加的,有B帧的存在,packet解码时间DTS和PTS是对应不上了。比方说当我读取到第0个P帧的时候,由于它参考了I帧,所以这个时候avcodec_decode_video2是没有能力解码此帧的。所以avcodec_decode_video2返回的是一个大于0的数,但是got_picture返回的是0。
另外,很有可能第一帧I帧是解码不出来的,因为后面的B,P帧都参考I帧,这样的话解码器就好缓存I帧,直到没有帧依赖此I帧。
2、
另外还有个现象,一个AVI格式,里面都是I帧:
图2
这种情况也会出现解码第一帧失败情况。这种情况下由于都是I帧,应该不存在参考帧问题,网上有些地方说是因为缓存处理,解码器解码时会缓存几帧提高程序的效率,防止程序在解码这一步等待太久。
对这一块感觉不是太理解,希望有明白的大神能够指点说明下。
针对这种因缓存造成的问题,解决办法还是有的。
第一种:
int skipped_frame = 0;
while(av_read_frame(ifmt_ctx,&packet) >= 0)
{
ret = avcodec_decode_video2(video_dec_ctx, vframe, &got_frame, &packet);
if (got_frame)
{
;
}
else
{
skipped_frame++;
}
}
for(int i=skipped_frame; i>0; i--)
{
ret = avcodec_decode_video2(video_dec_ctx, vframe, &got_frame, &packet);
if (got_frame)
{
;
}
}
这种就是记录缓存的帧个数,最后再解码出来。
第二种:
设置AVCodecContext中的flags,强制解码器快速输出。这样一开始就可以正常的解码第一帧。
参考文章:
http://blog.csdn.net/leixiaohua1020/article/details/19016109#
http://blog.jianchihu.net/avcodec_decode_video2-no-pic.html
http://blog.csdn.net/huyinguo/article/details/4725326
http://bbs.csdn.net/topics/390692774
上述的问题解答,如果有更好解释的欢迎大家指正。