Demuxer解复用架构—FFmpeg源码分析

FFmpeg 的 Demuxer 解复用架构可以分为 3 个部分,以 MP4 为例,其他的格式也是类似的,如下:

1-1

1,avformat_open_input,打开输入文件

avformat_open_input() 里面的 init_input() 主要负责探测输入文件的格式,一旦确认了输入格式,就会把确定的 Demuxer 赋值给 s->iformat,然后调这个 Demuxerread_header 接口来读取解析头部。

MP4 的 read_headers 接口是 mov_read_header(),FLV 的 read_headers 接口是 flv_read_header()

MP4 与 FLV 的 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,
};

AVInputFormat ff_flv_demuxer = {
    .name           = "flv",
    .long_name      = NULL_IF_CONFIG_SMALL("FLV (Flash Video)"),
    .priv_data_size = sizeof(FLVContext),
    .read_probe     = flv_probe,
    .read_header    = flv_read_header,
    .read_packet    = flv_read_packet,
    .read_seek      = flv_read_seek,
    .read_close     = flv_read_close,
    .extensions     = "flv",
    .priv_class     = &flv_class,
};

提示:avformat_open_input() 读取的是头部信息,并不会去读取文件里面的编码数据。


2,avformat_find_streaminfo,提取各个流的信息

avformat_find_stream_info 这个名字其实非常恰当的,它做的任何事情,都是为了 find(找到),stream(流),info(信息)。

avformat_find_stream_info() 里面有可能会对编码数据进行解析,是因为,有些参数,例如 pix_fmt(像素格式),在容器层可能是没有记录的,而是在编码层记录的,所以你必须解析编码层的数据才能拿到那些参数,然后放到 AVStreamcodecpar 里。

avformat_find_streaminfo() 解码出来的 AVFrame 是直接丢弃的,但是他从输入文件读取的 AVPacket 会放进去 internal->packet_buffer 缓存里面,后面 av_read_frame() 会优先从 internal->packet_buffer 缓存里面拿 AVPacket,而不是从文件里面读取。

可以在命令行用 -nobuffer 来禁止 packet_buffer 缓存,这样 avformat_find_streaminfo() 读取出来的 AVPacket 就会直接丢弃。这样做可以降低延迟,但是可能会导致解码器刚开始输出的数据花屏。


3,av_read_frame,读取 AVPacket 编码数据

av_read_frame()read_frame_internal() 的区别在于,av_read_frame 会优选从 packet_buffer 缓存里面读数据,缓存里没数据再调 read_frame_internal() 从输入文件读数据。


后面就让我们学习,解复用(Demuxer)三部曲的具体细节。

版权所属 xianwanzhiyin.net 罗上文 2023 all right reserved,powered by Gitbook该文件修订时间: 2023-06-09 23:36:50

results matching ""

    No results matching ""