温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

FFmpeg av_find_input_format函数剖析

发布时间:2020-07-30 13:36:08 来源:网络 阅读:4787 作者:fengyuzaitu 栏目:编程语言

AVInputFormat结构体
AVInputFormat 每种码流输入格式(例如h364,FLV, MKV, MP4, AVI)对应一个结构体,用来保存视音频的解码参数,目前以h364码流格式为例,描述结构体成员:
name:封装格式名称简写(short_name)[h364]
long_name:码流输入格式的长名称[raw H.264 video]
extensions:码流输入格式的扩展名[h36l,h364,264,avc]
raw_codec_id:码流输入格式ID[28]
read_packet:avformat-57.dll!0x000007fee101ca90 (加载符号以获取其他信息)
read_header:avformat-57.dll!0x000007fee101cb70 (加载符号以获取其他信息)

关键函数:int (*read_packet)(struct AVFormatContext *, AVPacket *pkt);
read_packet函数读取一个AVPacket,然后放在pkt,这个函数在进行分帧
av_read_frame函数的里面会被调用到,调用相应的×××获取一帧的完整数据


问题:各种码流输入格式是什么时候被加载的?
回答:当第一次调用av_register_all的时候就会注册复用器,其中就包含了各种码流的输入格式的处理函数

查看调用关系
av_register_all
    register_all
        REGISTER_MUXDEMUX(H264,             h364);
            #define REGISTER_MUXDEMUX(X, x) REGISTER_MUXER(X, x); REGISTER_DEMUXER(X, x)

#define REGISTER_MUXER(X, x)                                            \
    {                                                                   \
        extern AVOutputFormat ff_##x##_muxer;                           \
        if (CONFIG_##X##_MUXER)                                         \
            av_register_output_format(&ff_##x##_muxer);                 \
    }

#define REGISTER_DEMUXER(X, x)                                          \
    {                                                                   \
        extern AVInputFormat ff_##x##_demuxer;                          \
        if (CONFIG_##X##_DEMUXER)                                       \
            av_register_input_format(&ff_##x##_demuxer);                \
    }

看看注册码流输入格式的函数
void av_register_input_format(AVInputFormat *format)
{
    AVInputFormat **p = last_iformat;

    // Note, format could be added after the first 2 checks but that implies that *p is no longer NULL
    while(p != &format->next && !format->next && avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format))
        p = &(*p)->next;

    if (!format->next)
        last_iformat = &format->next;
}
其中关键的全局变量是
static AVInputFormat *first_iformat = NULL;
static AVInputFormat **last_iformat = &first_iformat;
保存了所有码流格式

AVInputFormat *av_iformat_next(const AVInputFormat *f)
{
    if (f)
        return f->next;
    else
        return first_iformat;
}

AVInputFormat *av_find_input_format(const char *short_name)
{
    AVInputFormat *fmt = NULL;
    while ((fmt = av_iformat_next(fmt)))//获取×××的链表指针,
        if (av_match_name(short_name, fmt->name))//根据输入的码流格式简写,轮询链表查找×××
            return fmt;
    return NULL;
}

在avformat_open_input函数优化篇就直接指定码流的输入格式,从而减少了探测码流格式的时间

参考
http://blog.csdn.net/leixiaohua1020/article/details/12677129
http://blog.csdn.net/neustar1/article/details/38231937


AVFMT_NOFILE宏定义剖析
使用说明
    当前为了避免在调用init_input函数的时候,读取缓存区的数据,从而设置了该标志位,但是最终在avformat_open_input的其他地方还是读取了缓冲区的数据
        pAVInputFormat = av_find_input_format("h364");
        pAVInputFormat->flags |= AVFMT_NOFILE;

宏定义
/// Demuxer will use avio_open, no opened file should be provided by the caller.
//解复用器将调用avio_open函数,调用者提供一个没有打开的文件,估计是打开的文件会被占用
#define AVFMT_NOFILE        0x0001
#define AVFMT_NEEDNUMBER    0x0002 /**< Needs '%d' in filename. */
#define AVFMT_SHOW_IDS      0x0008 /**< Show format stream IDs numbers. */


AVFMT_NOFILE formats will not have a AVIOContext
当设置了AVFMT_NOFILE标志,将不会携带AVIOContext


/* Open input file and probe the format if necessary. */
static int init_input(AVFormatContext *s, const char *filename,
                      AVDictionary **options)
{
    int ret;
    AVProbeData pd = { filename, NULL, 0 };
    int score = AVPROBE_SCORE_RETRY;

    //这里探测码流的方式,企图通过AVIOContext结构体中的read_packet函数
    //如果码流格式已经指定并且指定了标志位,直接返回
    if (s->pb) {
        s->flags |= AVFMT_FLAG_CUSTOM_IO;
    //如果没有指定输入格式,开始探测码流格式
        if (!s->iformat)
            return av_probe_input_buffer2(s->pb, &s->iformat, filename,
                                         s, 0, s->format_probesize);
        else if (s->iformat->flags & AVFMT_NOFILE)
            av_log(s, AV_LOG_WARNING, "Custom AVIOContext makes no sense and "
                                      "will be ignored with AVFMT_NOFILE format.\n");
        return 0;
    }
   //这里探测码流的方式,企图通过通过进来的文件名称
   //如果码流格式已经指定并且指定了标志位,直接返回
   //这里非常明显网络RTSP流,肯定是不会走到这里
    if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
        (!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score))))
        return score;

    //如果指定了iformat结构体,并且没有设置标志位,肯定执行下面的语句,该语句会调用read_packet函数
    //进行分析码流
    if ((ret = s->io_open(s, &s->pb, filename, AVIO_FLAG_READ | s->avio_flags, options)) < 0)
        return ret;

    if (s->iformat)
        return 0;
    return av_probe_input_buffer2(s->pb, &s->iformat, filename,
                                 s, 0, s->format_probesize);
}


从下面的说明可以得知,当添加了AVFMT_NOFILE标志位,AVIOContext *pb会设置为空
    /**
     * I/O context.
     *
     * - demuxing: either set by the user before avformat_open_input() (then
     *             the user must close it manually) or set by avformat_open_input().
     * - muxing: set by the user before avformat_write_header(). The caller must
     *           take care of closing / freeing the IO context.
     *
     * Do NOT set this field if AVFMT_NOFILE flag is set in
     * iformat/oformat.flags. In such a case, the (de)muxer will handle
     * I/O in some other way and this field will be NULL.
     */
    AVIOContext *pb;

    /**
     * Custom interrupt callbacks for the I/O layer.
     *
     * demuxing: set by the user before avformat_open_input().
     * muxing: set by the user before avformat_write_header()
     * (mainly useful for AVFMT_NOFILE formats). The callback
     * should also be passed to avio_open2() if it's used to
     * open the file.
     */
    AVIOInterruptCB interrupt_callback;

/**
 * Guess the file format.
 *
 * @param pd        data to be probed
 * @param is_opened Whether the file is already opened; determines whether
 *                  demuxers with or without AVFMT_NOFILE are probed.
 */
AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened);
AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max);
AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score_ret);

 

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI