解密FFmpeg播放track mode控制

上一篇文章(http://my.oschina.net/u/2336532/blog/400790)我们解决了在FFmpeg下如何处理H264和AAC的扩展数据,根据解出的NALU长度恢复了H264的起始码和AAC的ADTS头,这样一般来说播放是没有问题。本篇文章来谈谈如何实现基于FFmpeg的track mode控制,也就是如何用FFmpeg提供的功能来实现基本的seek、快进、快退。好了,废话少了,下面开始基于FFmpeg的track mode之旅。

FFmpeg提供了一个seek函数,原型如下:

int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp,                   int flags);

参数说明:

s:操作上下文;

stream_index:基本流索引,表示当前的seek是针对哪个基本流,比如视频或者音频等等。

timestamp:要seek的时间点,以time_base或者AV_TIME_BASE为单位。

Flags:seek标志,可以设置为按字节,在按时间seek时取该点之前还是之后的关键帧,以及不按关键帧seek等,详细请参考FFmpeg的avformat.h说明。基于FFmpeg的所有track mode几乎都是用这个函数来直接或间接实现的。

 

  • 文件的seek功能实现

要转跳到视频100秒(100 000毫秒)处的第一个I帧(如果没有则向前找第一个):

av_seek_frame(pFormatCtx, vid_index, 100000*vid_time_scale/time_base, AVSEEK_FLAG_BACKWARD);

跳到音频80秒(80 000毫秒)处的帧(采样):

av_seek_frame(pFormatCtx, aud_index, 80000*aud_time_scale/ time_base, AVSEEK_FLAG_BACKWARD);

跳到文件开始的地方开始播放:

av_seek_frame(pFormatCtx, vid_index, 0, AVSEEK_FLAG_BACKWARD);

上面的time_scale、time_base都能通过流信息获取到,请参考前面的文章。有的文件不一定能seek成功,可以考虑在失败的情况下将AVSEEK_FLAG_BACKWARD改为AVSEEK_FLAG_ANY再次seek,不过seek到的视频帧可能不是I帧。

这个函数不管你当前在什么时间点上,都可以seek到任何合理位置。比如要实现在当前的基础上向后或向前跳转10秒,我们可以在av_read_frame函数拿到的包中含有当前时间戳的基础上增加或较少一个10000(换算成播放时间单位)再seek即可。所以这个函数可以用做进度的拖放、前进/后退一定时间、循环播放等功能。

  1. 快进快退

对于快进来说,一般解码器能实现2倍甚至再高倍速的播放,这种情况直接按照上一篇文章的基本播放流程就可以了。但对于4倍、8倍、16倍、32倍等高速播放,一般不能像传统播放那样一帧一帧的送数据,不只是解码能力问题,数据读取也可能因为带宽不够跟不上,我们只能提取其中的I帧进行播放,将B帧和P帧丢掉。下面我们就来讨论这个过程的实现流程。

快进时,通过当前数据包获得当前的时间PTS,将该PTS换算成时间再加上一小段时间,作为seek时间点向后找关键帧,此时flags可设置为AVSEEK_FLAG_FRAME。之后用av_read_frame获取到该关键帧。完成该帧解码显示后,再在该帧的PTS时间上增加一小段时间后seek,这样一直重复上述过程,流程如下图:

                  

 

快退时,通过当前数据包获得当前的时间PTS,将该PTS换算成时间再减去一小段时间,作为seek时间点向前找关键帧,此时flags可设置为AVSEEK_FLAG_BACKWARD。之后用av_read_frame获取到该关键帧。完成该帧解码显示后,再在该帧的PTS时间上减去一小段时间后seek,这样一直重复上述结果,过程如下图:

这样,我们通过以上对av_seek_frame函数的运用,即可完成文件playback的各种track mode实现,其实理解了这个函数后,你还会有很多其他办法来实现,这里只是提供了一种简单且占内存少的办法。在特定的情况下还可以先全部走一遍所有帧,并记录下全部的I帧的时间戳、帧编号、位置信息等需要的信息,然后直接从该表里面获取信息后进行seek和读取这些关键帧进行快速播放。

 

想第一时间获得更多原创文章,请关注个人微信公众平台:程序员互动联盟(coder_online),扫一扫下方二维码或者搜索微信号coder_online即可关注,里面有大量Android,Chromium,Linux,编程技巧等相关文章等着您,我们还可以在线交流。

如需转载本文,请注明出处:http://my.oschina.net/u/2336532

谢谢合作!

转载于:https://www.cnblogs.com/yistn/p/4442880.html

ffmpeg协议之接口篇之快进快退(av_seek_frame) ffmpeg协议 阅读详情

相关推荐

音视频从入门到精通——FFmpeg之av_seek_frame函数分析

timestamp: int64_t类型的时间戳,表示要跳转到的时间位置。stream_index : int类型表示要进行操作的流索引。s: AVFormatContext类型的多媒体文件句柄。flags 的值为1,2,4,8。所以,flags 应该是要通过或运算,加起来使用的。flags : 跳转方法,主要有一下几种。av_seek_frame函数分析。

mirana的专栏 2504

基于NDK、C++、FFmpeg的android视频播放器开发实战

课程包含了对流媒体(拉流)的播放,演示了播放rtmp的香港卫视,支持rtsp摄像头和http网络视频的播放,支持访问本地的视频文件,并精确显示和控制播放进度:1讲解如何编译Android平台的ffmpeg库,使其支持neon技术和硬解码,并测试性能2使用opengles的NDK shader高效播放yuv视频,不耗费cpu性能更优(GPU)3代码支持硬解码(省电不耗cpu)和多线程解码(高性能每秒解码240帧1080p)4支持网络流媒体(rtmp,rtsp,http)可直接拉流播放电视并支持rtsp摄像头访问5课程将设计模式应用到实践 - 观察者,构建者,门面,代理,适配器,单件模式

FFmpeg源码分析:av_seek_frame()与avformat_seek_file()

播放视频过程中,想要跳过中间直接看精彩片段怎么办呢?或者看到精彩片段,想回到某个位置重新观看又该怎么办呢?所以播放器得提供seek操作实现快进快退功能,FFmpeg在libavformat模块提供此功能的API,av_seek_frame()属于旧版API,而avformat_seek_file()属于新版API并且兼容旧版本。

徐福记456 2万+

FFmpeg 4.3 音视频基础到工程应用

课程介绍1课程面向音视频行业的入门者,没有太多音视频基础或者是音视频零基础的同学2课程通过概念分析、代码试验、项目实战的方式当你真正理解音视频3提供直播答疑和学员作业代码评审,提升学员的代码能力4包含视频封装、编解码(H264、 H265、 硬件加速)、像素格式转换、视频渲染5实现接入多路RTSP网络摄像头,预览多路视频并完成硬盘录像机自动录制功能   

FFmpeg 源码分析:av_seek_frame()

FFmpeg 源码分析:av_seek_frame()

ProgramNovice的博客 1483

ffmpeg av_seek_frame

转载于:https://blog.csdn.net/xujaiwei/article/details/77651562 av_seek_frame使用时需要使用四个参数 av_seek_frame(fmt_ctx, -1 , 20 * AV_TIME_BASE, AVSEEK_FLAG_ANY); 参数一: fmt_ctx为容器内容; 参数二: 流索引, stream_index 参数三...

junlon2006的博客 1312

avformat_seek_file 函数详解,av_seek_frame函数

avformat_seek_file 是 FFmpeg 中用于媒体文件精准定位的核心函数,其功能与音视频播放器的进度跳转、数据抽取等场景密切相关。

hunandede的博客 1134

播放器进度条,ffmpeg中av_seek_frame()的使用方法

av_seek_frame有两种使用方法 1.当参数stream_index为-1时,会选择一个默认流,时间戳会从以AV_TIME_BASE为单位 //seek到1.25秒 double sec = 1.25;//1.25秒 int64_t timestamp = sec * AV_TIME_BASE; av_seek_frame(pFormatCtx,-1,timestamp,AVSEEK_FL...

qq_26611129的博客 1万+

ffmpeg新手成长之路——使用av_seek_frame做seek定位

ts一般使用AVSEEK_FLAG_BYTE,mp4一般使用AVSEEK_FLAG_ANY、AVSEEK_FLAG_BACKWARD(seek到对应时间戳之前的最后一个关键帧)timestamp:定位的时间戳,单位以流的time_base为单位,并非毫秒单位的时间戳,因此如果seek,需要结合具体的流的time_base计算对应单位的时间戳。具体的值有如下几个,可以通过运算符来进行组合。stream_index:用于seek的流索引,-1为默认,一般0为视频流索引,1为音频流索引。

bolitongyue的博客 1162
上一篇: 41. First Missing Positive
下一篇: php的系统常量
weixin_34087301
博客等级 码龄11年 5069粉丝 160原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值