ffmpeg解决帧丢失问题:还有几帧数据缓存在解码器中,需要取出来

前言
       

最近在学习如何使用ffmpeg解析视频,在网上查找的办法大同小异,直接说解码函数avcodec_send_packet和avcodec_receive_frame,这两个是一起的,必须同时出现,我是通过子线程读取视频文件,不停地将读取出来的包放入videoQueue或audioQueue中,再利用SDL创建videoThread来不断从video队列里拿出packet送入解码器中,即利用avcodec_send_packet将包送入解码器中,利用avcodec_receive_frame将ffmpeg解析出来的Frame取出来,但通过进度条或直接打印解码出来的Frame->pts来看当前帧的时间,总会在最后少那么几帧,很郁闷

一、帧丢失原因
解码器内部有缓存队列,开始时会先存几帧数据,再开始输出有效Frame,所以到最后,解码器里还有几帧数据,根据视频大小不同,解码器里还剩余的packet数量也不太一样,所以到最后还有几帧没有输出,出现帧丢失现象。

二、解决方法
第一想法就是来网上搜如何解决帧丢失,但很少有,有也是没源代码,特别是ffmpeg的avcodec_send_packet和avcodec_receive_frame的帧丢失解决办法更少,于是就转向官方文档,终于找到一点头绪,如下图是在avcode.h中找到的,也是这两函数声明的头文件

上面说明出于需要或者提升性能,在最后编解码器还可能缓存了几帧数据,需要刷新编解码器,还提供了思路

1.送入空包进avcodec_send_packet
如上图官方文档提供的思路,需要送入空包进解码器,代码如下

packet->data = nullptr;
packet->size = 0;
avcodec_send_packet(pVideoCodecCtx, packet);


2.调用avcodec_receive_frame
送入空包后,再调用avcodec_receive_frame将解码出来的frame取出来,直到avcodec_receive_frame返回AVERROR_EOF才结束,代码如下

/**队列里取数据**/
        if (packet_queue_get(&pVideosState->videoQueue, packet, 0) <= 0)
        {
 
            if (pVideosState->readFinished)
            {
                /**队列里面没有数据了且读取完毕了**/
                while(1)
                {
                    packet->data = nullptr;
                    packet->size = 0;
                    avcodec_send_packet(pVideoCodecCtx, packet);
                    
                    ret = avcodec_receive_frame(pVideoCodecCtx, pFrame);
                    if(ret == AVERROR_EOF)
                        break;
                    
                    //进行你所需的一系列操作
                }
                //这个循环跳出后就全部取出解码器缓存的数据了
            }

猜你喜欢

转载自blog.csdn.net/xionglifei2014/article/details/124951833