Demuxer解复用架构—FFmpeg源码分析
FFmpeg 的 Demuxer 解复用架构可以分为 3 个部分,以 MP4 为例,其他的格式也是类似的,如下:
1,avformat_open_input,确定输入格式,再调 read_header 读取头部信息
当没有在命令行使用 -f
指定输入格式的时候,init_input()
里会遍历所有的 Demuxer
,调用他们的 read_probe
函数来探测输入文件是什么格式的。
也就是说,他会调 mp4
的 mov_porbe
函数,flv
的 kux_probe
函数,等等,来探测输入格式
当确定了 输入格式(iformat
)的时候,就会把确定的 Demuxer 赋值给 s->iformat
,然后调这个 iformat
的 read_header
函数来读取头部信息。
mp4
的 iformat
是 ff_mov_demuxer
,如下:
AVInputFormat ff_mov_demuxer = {
.name = "mov,mp4,m4a,3gp,3g2,mj2",
.long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
.priv_class = &mov_class,
.priv_data_size = sizeof(MOVContext),
.extensions = "mov,mp4,m4a,3gp,3g2,mj2,psp,m4b,ism,ismv,isma,f4v",
.read_probe = mov_probe,
.read_header = mov_read_header,
.read_packet = mov_read_packet,
.read_close = mov_read_close,
.read_seek = mov_read_seek,
.flags = AVFMT_NO_BYTE_SEEK | AVFMT_SEEK_TO_PTS,
};
提醒:avformat_open_input()
读取的是头部信息,并不会去读取文件里面的编码数据。
优化技巧:由于 avformat_open_input()
会遍历所有的 Demuxer
来进行 probe
操作,所以可以通过 -f
指定格式,来提高性能。
2,avformat_find_streaminfo,对数据进行解码
avformat_find_streaminfo()
里面会调 read_frame_internal()
来读取 AVPacket
,然后进行解码,但是为什么要解码,我也不太清楚,后面补充。
注意,这里的 AVPacket
是编码的数据,也就是一个 GOP 的 IDR 帧,所以如果读出来之后丢弃,可能会导致后面花屏,所以默认情况下会调 avpriv_packet_list_put()
函数把 AVPacket
放进去 internal->packet_buffer
缓存里面。
后面的 av_read_frame()
会优先从 packet_buffer
缓存里面里面拿 AVPacket
。
提示:可以在命令行用 -nobuffer
来禁止缓存,可以降低延迟,但是可能会导致解码器刚开始输出的数据花屏。
3,av_read_frame,读取 AVPacket 编码数据
av_read_frame()
与 read_frame_internal()
的区别在于,av_read_frame
会优选从 packet_buffer
缓存里面读数据,缓存里没数据再调 read_frame_internal()
从输入文件读数据。
后面就让我们学习,解复用(Demuxer)三部曲的具体细节。