1. FFMPEG主目录下各子模块目录,略。
2. 格式或协议、编解码模块,可以plugin,有各自统一的结构类型,模块中对应的开放接口都定义在里面。其中muxer 和demuxer是不同的结构AVOutputFormat与AVInputFormat,encoder和decoder是用的AVCodec 结构,协议是URLProtocol。
3. 【然后来看ffmpeg.C】
4. 看注册过程,相关函数avcodec_register_all、avdevice_register_all、avfilter_register_all、av_register_all,再关注下几个全局静态变量avcodec_register_all(libavutils/utils.cfirst_avcodec、libavutils/utils.cfirst_hwaccel、libavcodec/parser.c av_first_parser、libavcodec/bitstream_filter.c first_bitstream_filter,avdevice_register_all(libavformat/utils.cfirst_iformat,first_oformat),avfilter_register_all(libavfilter/avfilter.cregistered_avfilters),av_register_all(avcodec_register_all()、libavformat/utils.cfirst_iformat,first_oformat、libavformat/avio.cfirst_protocol),其中各注册了哪些模块与子模块就不多说了,注册其实就是构建链表结构,比如,编解码,不是每种格式都对应有编码、解码,所以encoder和decoder是分开注册的,其他类似。
5. 下面先看看demuxer的匹配:
(这里打断顺便说下,ffmpeg中命令的解析是需要注意的,过往的篇章里有,此略)命令对应解析函数,在const OptionDef options[]可以看到,当然有些直接赋值的就不需要了,其中用到-i却没有-o,因此前者对应opt_input_file函数,后者对应的函数opt_output_file直接作为函参回调。
先看调用关系:parse_options—opt_input_file—avformat_open_input—init_input—av_probe_input_format—av_probe_input_format2—av_probe_input_format3,原型是AVInputFormat*av_probe_input_format3(AVProbeData *pd, int is_opened, int *score_ret),其中根据传进来的probe_data数据,用av_iformat_next遍历链表first_iformat,来依次调用demuxer(AVInputFormat)的read_probe接口,进行传入的文件格式与demuxer匹配,最后返回AVInputFormat*指针。
其中函数opt_input_file中,if (o->format),format对应AVInputFormat.name,接着一系列的if 略。
这边如果是输入为流媒体,是在init_input—avio_open2—ffurl_open中打开,然后协议剥去后,在av_probe_input_buffer—av_probe_input_format2……探测格式。后头还会就此探讨,按模块依次来。
6. 来看看muxer的匹配:
调用关系:opt_output_file—avformat_alloc_output_context2—av_guess_format,原型是AVOutputFormat*av_guess_format(const char *short_name, const char *filename, const char*mime_type),根据是根据传入参数的后缀名或-f格式指定的。
7. 现在看看当前encoder/decoder的匹配:
Decoder是在opt_input_file中直到avcodec_find_decoder里完成,encoder实在opt_input_file— new_video_stream —new_output_stream —choose_encoder— avcodec_find_encoder,音频有 new_audio_stream,存储在AVFormatContext.AVInputFormat. AVStream. AVCodecContext. AVCodec *codec 与 AVFormatContext. AVOutputFormat.AVStream. AVCodecContext. AVCodec *codec变量,这就到这里吧。
8. 有几个重要的结构体,或者说变量看一看:
static InputFile **input_files与static OutputFile **output_files,从上面可以看到,输入输出的struct AVInputFormat *iformat; struct AVOutputFormat *oformat;都在AVFormatContext中,对于AVFormatContext一个上下文中,不能同时有demux和mux(结构体注释中写明了:notboth at the same time),因此,他们分别初始化,并封在InputFile结构中,以前的直接是:static AVFormatContext *input_files[MAX_FILES]。
static InputStream **input_streams 与 staticOutputStream **output_streams后头探讨。
AVStream保存与数据流关联的编解码器,数据等信息。结构中,AVCodecContext *codec这个,跟(7)有关。priv_data指针干嘛的呢?随便翻看一个encoder吧,比如ff_h264_decoder. ff_h264_decode_init函数(原型是intff_h264_decode_init(AVCodecContext *avctx))中第一句:H264Context *h= avctx->priv_data,这时应该就明了了。
其他如AVInputStream、AVPacket、AVFrame等不再依次轮他们了。
9. 【这里有必要说一下,ffmpeg对于流媒体的转码,的模块接连顺序是这样的:URL(protocol)àIO(read)àDEMUX(format)à^transcode^àMUXàIO(write)àURL(协议),transcode中有decoderàscaleràencoder】
10. 【IO】IO(read)是在opt_input_file中做demuxer匹配时,filename先传入ffurl_open,如果返回AVERROR_PROTOCOL_NOT_FOUND则可能是localfile,否则网络媒体。IO(write)是在opt_output_file中打开的,avio_open2(AVIO_FLAG_WRITE)。
11. 到此,模块基本准备好了,缩放也就是swscale,现在新版本ffmpeg有了filter,以后用到再说吧,类似微软的dshow,若是都用这个开发,结构还是很好的,但依赖网络大家分享的filters得做好管理与控制。
【天下文章一大抄,其中难免有借鉴他人的,既然他人整理的思路可以,为何不借用下!转载的话,说明出处,也是可以的,好比用开源代码做产品一样。虽然国内比较乱,很多陈腐没有废除,很多“规则”尚未制定,我们还是得厚道一些。】