关于ffmpeg(libav)解码视频最后丢帧的问题
其实最初不是为了解决这个问题而来的,是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)解码视频最后丢帧的问题的更多相关文章
- avcodec_decode_video2()解码视频后丢帧的问题解决
使用libav转码视频时发现一个问题:使用下面这段代码解码视频时,视频尾巴上会丢掉几帧. while(av_read_frame(ifmt_ctx,&packet) >= 0){ ret ...
- 学习FFmpeg API – 解码视频
本文转载 视频播放过程 首先简单介绍以下视频文件的相关知识.我们平时看到的视频文件有许多格式,比如 avi, mkv, rmvb, mov, mp4等等,这些被称为容器(Container), 不同的 ...
- ffmpeg编解码视频导致噪声增大的一种解决方法
一.前言 ffmpeg在视音频编解码领域算是一个比较成熟的解决方案了.公司的一款视频编辑软件正是基于ffmpeg做了二次封装,并在此基础上进行音视频的编解码处理.然而,在观察编码后的视频质量时,发现图 ...
- 【转】学习FFmpeg API – 解码视频
ffmpeg是编解码的利器,用了很久,以前看过dranger 的教程,非常精彩,受益颇多,是学习ffmpeg api很好的材料.可惜的是其针对的ffmpeg版本已经比较老了,而ffmpeg的更新又很快 ...
- 【学习ffmpeg】打开视频文件,帧分析,并bmp保存关键帧
http://www.tuicool.com/articles/jiUzua http://blog.csdn.net/code_future/article/details/8646717 主题 ...
- FFMPEG学习----解码视频
基础概念 我们平时看到的视频文件有许多格式,比如 avi, mkv, rmvb, mov, mp4等等,这些被称为容器(Container), 不同的容器格式规定了其中音视频数据的组织方式(也包括其他 ...
- FFmpeg解码视频帧为jpg图片保存到本地
FFmpeg解码视频帧为jpg图片保存到本地 - CSDN博客 https://blog.csdn.net/qq_28284547/article/details/78151635
- Android 音视频深入 九 FFmpeg解码视频生成yuv文件(附源码下载)
项目地址,求star https://github.com/979451341/Audio-and-video-learning-materials/tree/master/FFmpeg(MP4%E8 ...
- 视频编解码---x264用于编码,ffmpeg用于解码
项目要用到视频编解码,最近半个月都在搞,说实话真是走了很多弯路,浪费了很多时间.将自己的最终成果记录于此,期望会给其他人提供些许帮助. 参考教程: http://ffmpeg.org/trac/ffm ...
随机推荐
- .net Core命令行,Json配置
创建.netCore控制台 NuGet :Microsoft.AspNetCore.All static void Main(string[] args) { var builder = new Co ...
- 用RegularJS开发小程序 — mpregular解析
本文来自网易云社区. Mpregular 是基于 RegularJS(简称 Regular) 的小程序开发框架.开发者可以将直接用 RegularJS 开发小程序,或者将现有的 RegularJS 应 ...
- webpack@3.6.0(3)-- 优化
本篇内容 babel配置 打包调试 第三方资源引入 静态资源的集中输出 babel配置 cnpm i -D babel-core babel-loader babel-preset-es2015 // ...
- IOS 贝塞尔曲线切割圆角
写一个UIView扩展 1. .h文件 @interface UIView (Corner) - (void)setCornerWithType:(UIRectCorner)type Radius:( ...
- Sublime Text 3 多行游标
选中要修改的地方ctrl+D ,要跳过不需要修改的选中的就用ctrl+k+d 选中要修改的地方ctrl+D,选中所有要修改的 alt+f3 ctrl+A ,然后ctrl+shift+L 按住shif ...
- python模块之calendar方法详细介绍
calendar,是与日历相关的模块.calendar模块文件里定义了很多类型,主要有Calendar,TextCalendar以及HTMLCalendar类型.其中,Calendar是TextCal ...
- jquery——下载、使用
jQuery是目前使用最广泛的javascript函数库. 怎样安装? 这是下载地址:https://code.jquery.com/ minified是压缩版的 新建一个网页打开上面这个网址,ctr ...
- Abbreviation ---- hackerrank
---恢复内容开始--- https://www.hackerrank.com/contests/world-codesprint-6/challenges/abbr 给定两个串str和sub. 对于 ...
- SQL Server 脚本跟踪
1.查询 DataBasesID select db_id('regdatas') 2.获取进程ID 3.过滤定位
- Spark编程模型(下)
创建Pair RDD 什么是Pair RDD 包含键值对类型的RDD类型被称作Pair RDD: Pair RDD通常用来进行聚合计算: Pair RDD通常由普通RDD做ETL转化而来. Pytho ...