解密FFmpeg播放track mode控制



上一篇文章(http://blog.youkuaiyun.com/yang_danny/article/details/45016593)我们解决了在FFmpeg下如何处理H264AAC的扩展数据,根据解出的NALU长度恢复了H264的起始码和AACADTS头,这样一般来说播放是没有问题。本篇文章来谈谈如何实现基于FFmpegtrack mode控制,也就是如何用FFmpeg提供的功能来实现基本的seek、快进、快退。好了,废话少了,下面开始基于FFmpegtrack 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为单位。

Flagsseek标志,可以设置为按字节,在按时间seek时取该点之前还是之后的关键帧,以及不按关键帧seek等,详细请参考FFmpegavformat.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_scaletime_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即可关注,里面有大量AndroidChromiumLinux,编程技巧等相关文章等着您,我们还可以在线交流。

如需转载本文,请注明出处:http://blog.youkuaiyun.com/yang_danny

谢谢合作!

<think>好的,我现在需要帮助用户解决如何通过FFmpeg设置或控制packetization-mode参数的问题。首先,我得理解packetization-mode是什么。根据H.264标准,packetization-mode参数用于指定如何将视频数据封装成NAL单元。常见的值有0、1和2,不同的模式对应不同的分片方式,比如模式1通常用于实现分片传输,有助于提高网络传输的容错能力。 接下来,我需要回忆FFmpeg中如何传递参数给libx264编码器。FFmpeg通常通过-x264-params选项来传递私有编码器参数,或者使用标准的-vf/-af等选项。但packetization-mode可能属于x264的特定参数,因此需要使用-x264-params来设置。 然后,我应该验证这个参数的具体传递方式。查阅相关资料或官方文档,发现packetization-mode确实可以通过设置x264的sps参数中的相应选项。因此,正确的FFmpeg命令应该包括-x264-params "sps-id=0:packetization-mode=1"这样的参数。 另外,需要确认参数格式是否正确,比如使用sps-id指定参数集ID,然后跟上packetization-mode的值。同时,用户可能需要不同的模式,比如1或2,所以示例中应该给出不同值的设置方法。 还需要提醒用户注意版本兼容性,不同版本的FFmpeg或libx264可能有不同的参数支持情况,建议使用最新版本。此外,检查生成的SPS信息是否包含正确的packetization-mode参数,可以用mediainfo工具查看编码后的文件。 最后,生成相关问题,帮助用户进一步了解相关配置,比如如何设置其他x264参数,如何验证参数生效,以及不同模式的应用场景等。</think>通过FFmpeg控制H.264的packetization-mode参数需要理解该参数与编码器参数的映射关系。具体实现方法如下: 1. **参数含义** packetization-mode参数属于H.264的序列参数集(SPS),用于控制NAL单元封装方式: - `0`:单一NAL单元模式 - `1`:分片模式(默认值) - `2`:分片与自定义NAL单元组合模式[^1] 2. **FFmpeg设置方法** 使用`-x264-params`选项传递编码器私有参数: ```bash ffmpeg -i input.mp4 -c:v libx264 -x264-params "sps-id=0:packetization-mode=1" output.mp4 ``` 其中`sps-id`指定参数集ID,多个SPS时需要分别设置 3. **验证方法** 通过以下命令查看生成的SPS信息: ```bash ffprobe -v error -show_frames -select_streams v output.mp4 | grep packetization_mode ``` 4. **注意事项** - 需要FFmpeg编译时包含libx264支持 - 不同版本的x264编码器可能对参数支持存在差异 - 某些流媒体协议(如RTP)对packetization-mode有特定要求 参考验证结果示例: $$ \text{packetization\_mode}=1 \quad (\text{HEVC规范文档T-REC-H.264-202108-I}) $$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值