VLC优化(2)修改VLC读缓冲机制

0x00 前置信息

为进一步降低延迟,采用极端方法修改VLC读缓冲机制。

0x01 VLC读缓冲机制

对于一个rtmp流的读取,发起端在Demux module中,具体在该模块的Demux方法中调用ffmepg的接口av_read_frame读取每一帧数据。但是这个read的接口实在不清晰,经过了多个抽象层的封装,最后真正指向了rtmp_read接口。还是通过一个图来看会比较清晰:

vlc_demux_read_analysis.png

上图描述了read指针的指向,由read的指向可以看出VLC中抽象层次的关系。
Demux layer 开始调用av_read_frame接口,在ffmpeg中经过层层调用,s->read_packet实际指向了Demux layer中IORead接口,然后再进一步指向Stream layer;Stream layer的AReadStream指向了Access layer的Read接口,最终Read接口调用了ffmpeg的接口avio_read,至进一步指向了rtmp_read接口。

- 阅读剩余部分 -

avformat_open_input详细分析

0x00 前置信息

版本:ffmpeg2.2.0。

0x01 代码

int avformat_open_input(AVFormatContext **ps, const char *filename,
                                        AVInputFormat *fmt, AVDictionary **options)
{
        AVFormatContext *s = *ps;
        int ret = 0;
        AVDictionary *tmp = NULL;
        ID3v2ExtraMeta *id3v2_extra_meta = 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;

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

        /* 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 ? filename : "", sizeof(s->filename));

        /* Allocate private data. */
        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 */
        if (s->pb)
                ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta);

        if (s->iformat->read_header)
                if ((ret = s->iformat->read_header(s)) < 0)
                        goto fail;

        if (id3v2_extra_meta &&
                (ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0)
                goto fail;
        ff_id3v2_free_extra_meta(&id3v2_extra_meta);

        if ((ret = queue_attached_pictures(s)) < 0)
                goto fail;

        if (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:
        ff_id3v2_free_extra_meta(&id3v2_extra_meta);
        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;
}

0x02 接口功能

  1. 创建AVFormatContext结构并填充其中的关键字段
  2. 打开一个指定URI,初始化输入模块。
  3. 解析多媒体文件或流的头信息,为每个流创建AVStream结构。

- 阅读剩余部分 -