avformat_open_input函数分析

今天来对avformat_open_input这个函数进行分析,主要参考网上大牛们的博客,节省了很多时间,特记录下来,以免忘记
函数的结构如下:
这里写图片描述
avformat_open_input定义在libavformat/utils.c中:

//参数ps包含一切媒体相关的上下文结构,有它就有了一切,本函数如果打开媒体成功,
//会返回一个AVFormatContext的实例.
//参数filename是媒体文件名或URL.
//参数fmt是要打开的媒体格式的操作结构,因为是读,所以是inputFormat.此处可以
//传入一个调用者定义的inputFormat,对应命令行中的 -f xxx段,如果指定了它,
//在打开文件中就不会探测文件的实际格式了,以它为准了.
//参数options是对某种格式的一些操作,是为了在命令行中可以对不同的格式传入
//特殊的操作参数而建的, 为了了解流程,完全可以无视它.
int avformat_open_input(AVFormatContext **ps,
        const char *filename,
        AVInputFormat *fmt,
        AVDictionary **options)
{
    AVFormatContext *s = *ps;
    int ret = 0;
    AVFormatParameters ap = { { 0 } };
    AVDictionary *tmp = NULL;

    //创建上下文结构
    if (!s && !(s = avformat_alloc_context()))
        return AVERROR(ENOMEM);
    //如果用户指定了输入格式,直接使用它
    if (fmt)
        s->iformat = fmt;

    //忽略,不做分析
    if (options)
        av_dict_copy(&tmp, *options, 0);

    if ((ret = av_opt_set_dict(s, &tmp)) < 0)
        goto fail;

    //打开输入媒体(如果需要的话),初始化所有与媒体读写有关的结构们,比如
    //AVIOContext,AVInputFormat等等
    if ((ret = **init_input**(s, filename)) < 0)
        goto fail;
    //执行完此函数后,s->pb和s->iformat都已经指向了有效实例.pb是用于读写数据的,它
    //把媒体数据当做流来读写,不管是什么媒体格式,而iformat把pb读出来的流按某种媒体格
    //式进行分析,也就是说pb在底层,iformat在上层.

    //很多静态图像文件格式,都被当作一个格式处理,比如要打开.jpeg文件,需要的格式
    //名为image2.此处还不是很了解具体细节,作不得准哦.
    /* check filename in case an image number is expected */
    if (s->iformat->flags & AVFMT_NEEDNUMBER) {
        if (!av_filename_number_test(filename)) {
            ret = AVERROR(EINVAL);
            goto fail;
        }
    }

    s->duration = s->start_time = AV_NOPTS_VALUE;
    //上下文中保存下文件名
    av_strlcpy(s->filename, filename, sizeof(s->filename));

    /* allocate private data */
    //为当前格式分配私有数据,主要用于某格式的读写操作时所用的私有结构.
    //此结构的大小在定义AVInputFormat时已指定了.
    if (s->iformat->priv_data_size > 0) {
        if (!(s->priv_data = av_mallocz(s->iformat->priv_data_size))) {
            ret = AVERROR(ENOMEM);
            goto fail;
        }
        //这个可以先不必管它
        if (s->iformat->priv_class) {
            *(const AVClass**) s->priv_data = s->iformat->priv_class;
            av_opt_set_defaults(s->priv_data);
            if ((ret = av_opt_set_dict(s->priv_data, &tmp)) < 0)
                goto fail;
        }
    }

    /* e.g. AVFMT_NOFILE formats will not have a AVIOContext */
    //从mp3文件中读ID3数据并保存之.
    if (s->pb)
        ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC);

    //读一下媒体的头部,在read_header()中主要是做某种格式的初始化工作,比如填充自己的
    //私有结构,根据流的数量分配流结构并初始化,把文件指针指向数据区开始处等.
    if (!(s->flags & AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header)
        if ((ret = s->iformat->read_header(s, &ap)) < 0)
            goto fail;

    //保存数据区开始的位置
    if (!(s->flags & AVFMT_FLAG_PRIV_OPT) && s->pb && !s->data_offset)
        s->data_offset = avio_tell(s->pb);

    s->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;

    if (options) {
        av_dict_free(options);
        *options = tmp;
    }
    *ps = s;
    //执行成功
    return 0;

    //执行失败
    fail: av_dict_free(&tmp);
    if (s->pb && !(s->flags & AVFMT_FLAG_CUSTOM_IO))
        avio_close(s->pb);
    avformat_free_context(s);
    *ps = NULL;
    return ret;
}

下面再来看init_input

/* 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;
    //当调用者已指定了pb(数据取得的方式)--一般不会这样.
    if (s->pb) {
        s->flags |= AVFMT_FLAG_CUSTOM_IO;
        if (!s->iformat)//如果已指定了pb但没指定iformat,以pb读取媒体数据进行探测,取得.取得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");
        //如果已指定pb也指定了iformat,但是又指定了不需要文件(也包括URL指定的地址),这就矛盾了,    
        //此时应是不需要pb的,因为不需操作文件,提示一下吧,也不算错. 
        return 0;
    }
    //一般会执行到这里 
    if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
        (!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score))))
     //如果已指定了iformat并且不需要文件,也就不需要pb了,可以直接返回    
        //如果没指定iformat,但是可以从文件名中猜出iformat,也成功. 
        return score;
    //如果从文件名中也猜不出媒体格式,则只能打开这个文件进行探测了,先打开文件  
    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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值