ffmpeg面向对象——rtsp拉流探索(1)

目录

  • 0.avformat_open_input的rtsp流程程纯净版
  • 1.rtsp拉流流程图
  • 2.rtsp拉流对象图
    • 2.1 sdp解析出来的信息

本节探索下ffmpeg的rtsp拉流协议tcp的创建及rtsp协商过程。

0.avformat_open_input的rtsp流程程纯净版

ffmpeg拉流,从avformat_open_input接口开始,去除与rtsp拉流无关的代码后,如下:


int avformat_open_input(AVFormatContext **ps, const char *filename,
                        const AVInputFormat *fmt, AVDictionary **options)
{
    AVFormatContext *s = *ps;
    FFFormatContext *si;
    AVDictionary *tmp = NULL;
    int ret = 0;

    if (!s && !(s = avformat_alloc_context()))
        return AVERROR(ENOMEM);
    si = ffformatcontext(s);
    if (!s->av_class) {
        av_log(NULL, AV_LOG_ERROR, "Input context has not been properly allocated by avformat_alloc_context() and is not NULL either\n");
        return AVERROR(EINVAL);
    }

    if (options)
        av_dict_copy(&tmp, *options, 0);

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

    if (!(s->url = av_strdup(filename ? filename : ""))) {
        ret = AVERROR(ENOMEM);
        goto fail;
    }

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

    s->duration = s->start_time = AV_NOPTS_VALUE;

    /* 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;
        }
    }

    if (s->iformat->read_header)
    {
        if ((ret = s->iformat->read_header(s)) < 0) {
            if (s->iformat->flags_internal & FF_FMT_INIT_CLEANUP)
                goto close;
            goto fail;
        }
    }

    si->raw_packet_buffer_size = 0;

    update_stream_avctx(s);

    if (options) {
        av_dict_free(options);
        *options = tmp;
    }
    *ps = s;
    return 0;

close:
    if (s->iformat->read_close)
        s->iformat->read_close(s);
fail:
    av_dict_free(&tmp);
    avformat_free_context(s);
    *ps = NULL;
    return ret;
}

其中留下了参数配置流程,因为一般会配置些参数,参数配置参见《ffmpeg面向对象——参数配置机制及其设计模式探索》。

输入格式匹配(看下面流程图会清晰点),参见《ffmpeg面向对象-rtsp拉流相关对象》的第2节。

协议匹配机制(看下面流程图会清晰点),参见《ffmpeg面向对象——拉流协议匹配机制探索》。

输入格式类与协议类什么关系参见《ffmpeg面向对象——AVInputFormat与URLProtocol啥关系》。

这些结合流层图与对象图看会清晰点。

1.rtsp拉流流程图

在这里插入图片描述

rtsp的tcp链接创建在图中最右边。

rtsp协商流程也比较清晰,可以看到ff_rtsp_send_cmd是各个协商方法最终都要调用的中心转发节点。其中SDP解析后创建了一堆解码信息对象并根据解析赋值。
这种统一到同一个接口上(ff_rtsp_send_cmd)的设计模式是什么?外观模式。其内部的实现,又无视是什么命令,都同样的流程——如ff_rtsp_read_reply,尤其ffurl_read接口对所有协议的封装(这也是抽象出一个URLContxt类原因所在吧)——这种模式抽象出了共性的代码,走同样的流程,这种是什么设计模式?模板模式

可以看到在retry_transfer_wrapper中有睡眠机制,也就是说avformat_open_input是阻塞的调用。

在此,也可以发现avformat_open_input调用完成,那么rtsp协商也完成了。

另外可以看到底层tcp协议读写是如何对接的,结合下面对象图,就能深入理解输入格式类与协议类的关系,它们面向接口编程,各自分层迭代开发,互不影响。

最后是解码信息的拷贝——从RTSP协议的DESCRIBE的SDP里解析出来的,有对象承载这些信息,要拷贝到AVFormatContext的streams对应元素成员中。

流程图里应该标记下各个对象创建的时机,这样下面对象图就能对应上了,否则得看源码。

2.rtsp拉流对象图

在这里插入图片描述

可琢磨的比较多,其中,输入格式类与底层协议类型都是“可变的”,因为这两者都是代码运行中匹配出来的,所以它们都被更上一层的进行“托管”。参见《ffmpeg面向对象——priv_data设计原理探索》。

2.1 sdp解析出来的信息

因为rtsp协商有sdp信息,所以可以在rtsp协商阶段获取到该rtsp会话里有几路流,这样就早早创建了AVStream,RTSPStream等对象。

可以看到它们的关系:
第1个层次
AVFormatContext管理了AVStream、rtsp的私有数据类RTSPState。

第2个层次
AVStream管理了AVCodecParameters(里面包含了流格式——音视频字幕等类型,包含了编码格式——264/265/AAC等)。

RTSPState管理了RTSPStream等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值