前言
前面我们搭建好了FFmpeg的开发环境,今天我们就来小试牛刀,使用FFmpeg库对mp4文件进行解封装,提取mp4中的视频流和音频流输出到单独的输出文件中。关于FFmpeg开发环境搭建可以看我之前的文章:
所谓的分离视频和音频是我们通俗的说法,官方的说法叫解封装。与解封装对应的叫封装或复用器,也就是将多个视频流或音频流合并成一个多媒体文件就叫封装。
API及数据结构介绍
在FFmpeg中解封装的大致流程如下图所示:
ffmpeg解封装流程图
在这里需要注意的一个点是不一定能获取到你想要的流,比如你想通过获取音频流的索引,笔者开发中发现对于某些格式是无法获取成功的,此时需要遍历一下解封装上下文的流,通过流的解码器类型来进行获取,例如你想要获取音频流,则可以判断解码器的类型是否是音频解码器即可。
下面介绍一下实现分离视频和音频数据所需要使用到的主要API以及相关的数据结构。
1、libavformat
libavformat库,是FFmpeg中用于处理各种媒体容器格式的库,它描述了一个媒体文件或媒体流的构成和基本信息,它的两个主要功能就是封装和解封装,可以说它是贯穿整个FFmpeg的根。
在解封装时,我们主要用到avformat中的几个函数、和,其中和是一对搭配使用的函数,一个打开一个关闭,千万不要忘记,否则会发生内存泄漏。
2、AVPacket
AVPacket类,用于存储编码后的帧数据。它一般由解封装导出,然后传递给解码器作为输入;又或者,从编码器作为输出,然后传递给封装去进行写入。
AVPacket可以表示一个视频包或者一个音频包,内部包含了这个视频包或音频包的播放时长,播放时间戳、二进制数据等相关信息。对于音视频等二进制数据,AVPacket内部使用了引用计数的方式进行数据共享。
对于AVPacket的那个字段,我们点进去头文件可以看到每个字段都有清晰的注释解析,这里就不细说了,例如:
下面是使用FFmpeg进行解封装的主要API调用:
提取视频
在FFMpeg中一般mp4解封装提取到的H264裸流是不带start code的,也就是提取到的这种H264裸流不能使用ffplay直接播放,还好FFmpeg很贴心地给我们提供了一个过滤器,通过这个过滤器我们可以很方便地给提取到的H264加上start code,从而能让ffplay直接播放。
废话少说,直接上代码:
提取音频
对于FFmpeg中解封装的音频AAC文件来说,mp4文件解封装出来的音频不附带adts头信息的,但是笔者看到有资料说对于ts格式的话好像解封装出来又是带有adts头的(笔者这个没有验证过)。对于这些没有附带adts头信息的aac音频文件,ffplay也是无法直接播放的,因此我们在提取音频信息时需要手动加上adts头信息。
针对添加adts头信息的话我们有两种方式,一种是对对adts比较熟悉的,可以在每个音频包的前面增加7个或者9个字节即可。还有一种就是使用FFmpeg的复用器封装功能,让其自动加上adts头信息。
其中使用FFmpeg内部复用器封装的步骤如下:
1、调用 av_guess_format 让ffmpeg帮你找到一个合适的文件格式。
2、调用 avformat_new_stream 为输出文件创建一个新流。3、调用 avio_open 打开新创建的文件。4、调用 avformat_write_header 写文件头。5、调用 av_interleaved_write_frame 写文件内容。6、调用 av_write_trailer 写文件尾。7、调用 avio_close 关闭文件
后面的代码笔者两种方式都简单测试了一下,提取到的aac音频文件都可以正常播放。
下面贴一下全部代码:
代码写的比较粗,而且很多异常也没有做处理,相关资源也没有进行释放,大家将就这看下。。。
领取专属 10元无门槛券
私享最新 技术干货