【音视频处理】转封装实战,文件转直播流,FFmpeg代码示例讲解

大家好,欢迎来到停止重构的频道。

从本期起,我们正式进入音视频处理的介绍。

本期我们讨论音视频文件转封装,如将MP4转AVI、MP4转RTMP等。

内容中所提及的代码都会放在GitHub,感兴趣的小伙伴可以到GitHub下载。

我们按这样的顺序展开讨论 :

1、  视频封装的作用 

2、  转封装的工作原理

3、  转封装成视频文件 

4、  转封装成直播流 

视频封装的作用 

在前面《音视频转码工作原理》中讨论过,一个视频文件实质上是分3层的,封装、编码、基础数据

封装格式的作用,简单地说,就是对音频数据、视频数据、基础信息等数据,按一定的结构规则编排成文件

数据编排虽然对音视频数据本身不会产生影响,但是会对一些特定场景产生影响。

如视频文件一般会采用MP4、FLV等封装格式,直播流则采用RTMP、HTTP-FLV等协议。

关于MP4、FLV、HLS等视频封装格式的详细说明,可参考往期《视频格式》。

关于RTMP、HTTP-FLV、HLS等流媒体协议的详细说明,可参考往期《直播协议》。 

 

转封装的工作原理

转封装的应用场景有很多,如MP4文件转FLV文件,MP4文件转RTMP直播流, RTMP直播流转MP4文件等。

这里需要注意的是,转封装仅仅是改变文件数据的编排方式。如果需要改变分辨率、码率等设置,则需要转码才能完成。

关于转封装、转码的区别,可参考往期《音视频转码工作原理》。

转封装的工作原理很简单,就是对视频文件或视频流解封装后按新格式重新封装成视频文件或视频流。

转封装时,音频数据、视频数据不需要区别处理,这个过程是流式的,就是每次只处理一部分数据,循环往复,直到处理完成。

另外,如果是视频文件转直播流,则循环过程中需要加上时间间隔,不然会由于推流过快而导致报错。

 

转封装成视频文件

后面是具体的FFmpeg操作过程,对应的示例代码也会同步说明。

转封装成视频文件,如将MP4文件转成FLV文件,对应示例代码为remux_tofile.cpp。环境搭建完后,运行程序如图所示:

代码流程为4步。

第一步打开源文件并获取源文件信息;

第二步构造输出文件,由于转封装是不需要对音视频数据进行处理的,所以可以直接根据源文件的轨道信息构造输出文件;

第三步,处理数据,循环解封装源数据,并封装写入到输出文件,直到源数据读取完成;

第四步,关闭输入、输出文件,处理完成后需要先对输出文件写入尾信息才能关闭,不然视频文件可能会出现问题。

如果是直播流转成视频文件,那么以上代码也适用,且不需要改动,因为直播流中断或结束时 解封装的API仍然会返回小于0的结果。

如果希望提前中断直播流录制,则需要另找时机对输出文件写入尾信息。

转封装成直播流

转封装成直播流

如将MP4文件转成RTMP流,对应示例代码为remux_tostream.cpp,运行程序如图所示:

整体代码与转封装成视频文件的代码是差不多的只是这里追加了时间间隔,防止过快退流产生错误。

这里需要说明的是,解封装出来的packet数据中,含有dts解码时间戳和pts播放时间戳。

我们一般用dts作为计算时间间隔的依据,当然dts需要乘以timebase才是真正的时间 ,timebase为源视频文件对应轨道的timebase。

 

一般dts和pts是相等的,但是如果是H264的b帧等情况的话,则可能存在pts大于dts的情况,所以选用pts作为计算时间间隔依据的话,可能会让直播流卡顿。

我们的示例MP4文件是没有b帧的,所以每一个dts和pts都是相等的。

实际录播场景下,也就是视频文件转直播流场景下,视频文件也不应该存在b帧等使得dts和pts不相等的设置,因为即使程序按dts计算时间间隔,但如果某个帧的pts和dts相差太远 也会造成直播卡顿。

如果源文件无法消除b帧,那么单纯的转封装无法保证直播流的流畅,需要加入转码过程才行。但转码是需要消耗更多性能的,如果仅仅为了消除b帧而加入转码过程,则往往得不偿失。

总结

本期内容的代码已经上传Github 需要的朋友可以下载,里面有编译运行环境的搭建说明。

如果对FFmpeg环境安装感到困惑,可以参考往期视频《FFmpeg》。 当然,也可以选择我们做好的docker容器。

猜你喜欢

转载自blog.csdn.net/Daniel_Leung/article/details/132078784