其实最初不是为了解决这个问题而来的,是Peter兄给我的提示解决另一个问题却让我误打误撞解决了另外一个问题之后也把这个隐藏了很久的bug找到(之前总是有一些特别短的视频产生不知所措还以为是视频素材本身有问题呢),今天真是收获颇丰啊,对libav的理解更深。

一直以来我的程序架构是让读一帧av_read_frame,然后去尝试根据packet的type类型分别去decode video或者audio,然而这样总是在视频的结尾会有许多帧丢失的问题,我找过avplay代码中似乎没找到我想象中的那种读packet完毕后特殊处理的代码。

一下log是我设置将其avcodec_decode_video2函数调用前后输出的pts、dts值(注:Frame:为decode之后,测试视频为纯视频无音频的文件),从图中可以看出来,开头为了顺序正确,libav暂存了9个packet,读packet完毕后,我当然不能就直接不管了,还是要将libav暂存的那些帧取出来才行。


    综上几点我认为是在调用avcodec_decode_video2函数的时候,函数内会去发现这个packet尚不足以解码下一帧的时候就会暂存packet在内部队列中(我自己给他们取的名字,望能理解),这样问题就来了,等到整个视频文件都读取完了,剩下libav内部存的packet还有一大堆没处理,我的架构又是要求函数直接向视频索取一帧,因此就需要在读新packet完毕后还 单独调用decode video函数或者decode audio函数来取出剩余的AVFrame。

为了这些bug我破例无耻的使用了goto语句:

首先定义了类成员变量,初始化都为false:

bool            _no_packet;   //代表是否还有packet
bool _end_video_frame; //代表是否video中的队列取出完毕
bool _end_audio_frame; //代表是否audio中的队列取出完毕
AVPacket packet = {};
while(true)
{
auto auto_releaser = std::shared_ptr<AVPacket>(&packet, [](AVPacket* p) { av_free_packet(p); });
int ret = av_read_frame(_context.get(), &packet);
if ( ret != )
{
_no_packet = true;
if(!_end_video_frame)
goto loop_end_video;
if(!_end_audio_frame)
goto loop_end_audio;
if(_end_video_frame && _end_audio_frame)
return false;
}
if(packet.stream_index == vstream_index)
{
loop_end_video:
int frame_finished = true;
if(avcodec_decode_video2(_vcodec, _decoded_frame, &frame_finished, &packet) < )
{
// 。。。。do something。。。
}
if(frame_finished)
{
//。。。。do something。。。
}
else
{
if(_no_packet)
_end_video_frame = true;
}
}
else if (packet.stream_index == astream_index && (type & MEDIA_AUDIO) != )
{
loop_end_audio:
int frame_finished;
if (avcodec_decode_audio4(_acodec, _decoded_frame, &frame_finished, &packet) < )
{
// 。。。。do something。。。
}
if(frame_finished)
{
//。。。。do something。。。
}
else
{
if(_no_packet)
_end_audio_frame = true;
}
}
}

有了这些跳转,就能完美的在read_frame完之后还继续decode为我所用。希望能帮助到与我遇到了相同问题的人。

再次感谢Peter~

关于ffmpeg(libav)解码视频最后丢帧的问题的更多相关文章

  1. avcodec_decode_video2()解码视频后丢帧的问题解决

    使用libav转码视频时发现一个问题:使用下面这段代码解码视频时,视频尾巴上会丢掉几帧. while(av_read_frame(ifmt_ctx,&packet) >= 0){ ret ...

  2. 学习FFmpeg API – 解码视频

    本文转载 视频播放过程 首先简单介绍以下视频文件的相关知识.我们平时看到的视频文件有许多格式,比如 avi, mkv, rmvb, mov, mp4等等,这些被称为容器(Container), 不同的 ...

  3. ffmpeg编解码视频导致噪声增大的一种解决方法

    一.前言 ffmpeg在视音频编解码领域算是一个比较成熟的解决方案了.公司的一款视频编辑软件正是基于ffmpeg做了二次封装,并在此基础上进行音视频的编解码处理.然而,在观察编码后的视频质量时,发现图 ...

  4. 【转】学习FFmpeg API – 解码视频

    ffmpeg是编解码的利器,用了很久,以前看过dranger 的教程,非常精彩,受益颇多,是学习ffmpeg api很好的材料.可惜的是其针对的ffmpeg版本已经比较老了,而ffmpeg的更新又很快 ...

  5. 【学习ffmpeg】打开视频文件,帧分析,并bmp保存关键帧

    http://www.tuicool.com/articles/jiUzua   http://blog.csdn.net/code_future/article/details/8646717 主题 ...

  6. FFMPEG学习----解码视频

    基础概念 我们平时看到的视频文件有许多格式,比如 avi, mkv, rmvb, mov, mp4等等,这些被称为容器(Container), 不同的容器格式规定了其中音视频数据的组织方式(也包括其他 ...

  7. FFmpeg解码视频帧为jpg图片保存到本地

    FFmpeg解码视频帧为jpg图片保存到本地 - CSDN博客 https://blog.csdn.net/qq_28284547/article/details/78151635

  8. Android 音视频深入 九 FFmpeg解码视频生成yuv文件(附源码下载)

    项目地址,求star https://github.com/979451341/Audio-and-video-learning-materials/tree/master/FFmpeg(MP4%E8 ...

  9. 视频编解码---x264用于编码,ffmpeg用于解码

    项目要用到视频编解码,最近半个月都在搞,说实话真是走了很多弯路,浪费了很多时间.将自己的最终成果记录于此,期望会给其他人提供些许帮助. 参考教程: http://ffmpeg.org/trac/ffm ...

随机推荐

  1. 获取指定日期相关DATENAME和DATEPART数据

    DATENAME和DATEPART有何区别,Insus.NET写成一个函数,可以方便查询与对比: 一个是返回一个字符串,另一个是返回一个整数. SET ANSI_NULLS ON GO SET QUO ...

  2. 图像标注工具labelImg使用方法

    最近在做打标签的工作,为了与大家参考学习,总结了在windows的环境下,基于anaconda的图像标注工具labellmg的一种使用方法! 1 搭建anaconda 以前写过怎么搭建anaconda ...

  3. 转:PHP性能:序——谈ab(Apache Bench)压力测试工具

    PHP性能:序——谈ab(Apache Bench)压力测试工具 ab(Apache  Bench)是啥? ab是Apache自带的一个压力测试软件,可以通过ab命令和选项对某个URL进行压力测试.a ...

  4. CodeForces 116B【二分匹配】

    思路: 暴力..我不会呀.. YY一个二分匹配嘛,然后数组开小了.GG for an hour. #include <bits/stdc++.h> using namespace std; ...

  5. 【NOIP模拟赛】收银员(一道差分约束好题)

    /* s[]表示最优方案的序列中的前缀和,那么s[23]就是最优方案 由题意我们可以列出这样一些式子: s[i]+s[23]-s[16+i]>=a[i] (i-8<0) s[i]-s[i- ...

  6. 2017-10-5 清北刷题冲刺班p.m

    套路(拓扑排序) /* 对每个联通块单独考虑. 每个联通块是一个环套树,树边拎出来可以随意定向,记树边为 m,所以树的方案数为2^m . 对于环来说只有两种方向,顺时针和逆时针,记环边为 n,所以环的 ...

  7. JML契约式设计——第三单元学习小结

    一.前言 本单元作业都是关于JML(Java Modeling Language),JML是一种契约式设计(Design by Contract)的语言,契约式设计的主要目的是希望程序员能够在设计程序 ...

  8. docker jvm 占用高的问题定位

    定位流程 先使用一些轻便的工具查看总体情况, 如果情况糟糕, 再使用重量级的工具 jstack       查看线程数是否过多 jstat -gc -gcutil 查看gc次数和时间是否过多, 各个分 ...

  9. postgresql导出某张表的数据

    \copy 表名 to 路径 with csv 比如: \copy dataset to /home/backup/dataset.csv with csv \copy dataset to /hom ...

  10. Regionals 2014 >> Asia - Taichung 7003 - A Balance Game on Trees 树形DP + 二维费用背包

    https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_probl ...