本系列 以 ffmpeg4.2 源码为准,下载地址:链接:百度网盘 提取码:g3k8
本系列主要分析各种 ffmpeg 命令参数 在代码里是如何实现的。a.mp4下载链接:百度网盘,提取码:nl0s 。
命令如下:ffmpeg -i a.mp4 -vn -acodec copy output.aac
FFmpeg 抽取音视频文件 中的 AAC 音频 流,与上一条命令 ffmpeg -i a.mp4 -vn -acodec copy output.mp4
相比。
只是封装格式不同,这篇文章就来讲解,如果输出文件不是 mp4,而是aac的封装格式,ffmpeg是如何处理。
命令行参数 -vn 上篇文章已经讲解过它的实现原理,就不再重复讲解了。
输出文件 output.aac 跟 output.mp4 ,格式虽然不同,但在 ffmpeg.c 这个工程里面其实并没有做任何特殊的处理,你调 ffmpeg 的api函数 avio_open2(),只要传递不同后缀的文件名,avio_open2 内部就会根据不同的文件名后缀,生成不同的 AVOutputFormat 放进去 AVFormatContext 的 oformat 字段里。
请看下图,在 avio_open2() 后面打了断点。
然后,在ffmpeg 4.2 的源码里搜索 "ADTS AAC (Advanced Audio Coding)" 字符串,可以发现 aac 的封装格式是在 libavformat 目录的 adtsenc.c 里面,如下:
libavformat/adtsenc.c 229行
AVOutputFormat ff_adts_muxer = {.name = "adts",.long_name = NULL_IF_CONFIG_SMALL("ADTS AAC (Advanced Audio Coding)"),.mime_type = "audio/aac",.extensions = "aac,adts",.priv_data_size = sizeof(ADTSContext),.audio_codec = AV_CODEC_ID_AAC,.video_codec = AV_CODEC_ID_NONE,.init = adts_init,.write_header = adts_write_header,.write_packet = adts_write_packet,.write_trailer = adts_write_trailer,.priv_class = &adts_muxer_class,.flags = AVFMT_NOTIMESTAMPS,
};
MP4 后缀的文件名,原理类似,mp4 的封装格式文件是 libavformat/movenc.c,具体自行查看。
虽然 aac 是编码层的封装格式,mp4 是容器层的格式,但是ffmpeg把他们都放到了 libavformat 下,个人觉得比较新奇。
总结:
ffmpeg 实现不同封装格式,是通过一种多态的方式实现的。不同后缀,就用不同的AVOutputFormat来实现。
在使用 avio_open2() API函数的时候,可以不管底层实现,直接传递不同后缀的文件名 即可完成不同格式的封装。
由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。如果读者有任何宝贵意见,可以加我微信 Loken1。
推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:
Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习