ffmpeg面向对象-rtsp拉流相关对象

目录

    • 1.AVFormatContext和FFFormatContext类。
      • 1.1 概述
      • 1.2 构造函数
      • 1.3 oopc的继承实现
    • 2. AVInputFormat 类。
      • 2.1 多态的实现
    • 3.所用设计模式
        • 3.1模板模式
          • 3.2 工厂模式?
        • 3.3 rtsp拉流建链
    • 4.this指针
    • 5.小结
    • 6.rtsp拉流对象流程图
    • 7.rtsp拉流流程

1.AVFormatContext和FFFormatContext类。

1.1 概述

ffmpeg5.x以后,把AVFormatContext类进行了拆分,把用户需要看到的共性部分抽取为父类AVFormatContext类,把用户用不到/不需要知道的剩余部分变成了子类FFFormatContext类——隐藏用户不用关心的内容。

5.x以后,实例化流对象FFFormatContext,然后返回给用户可见的基类AVFormatContext指针

其他的函数调用就是以FFFormatContext这个类为中心,实质是实例化这个类(初始化,构造函数)、调用这个类的方法,最后销毁这个类对象。
比如拉流的必经流程:
avformat_open_input
av_read_frame
avformat_close_input

很明显的对应构造,调用方法和析构函数。

1.2 构造函数

rtsp拉流第一步都是avformat_open_input,同时也是流对象FFFormatContext的构造函数。

AVFormatContext *fmt_ctx = NULL;
result = avformat_open_input(&fmt_ctx, input_filename, NULL, NULL);

其中fmt_ctx 如何分配内存的?如下

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

    if (!s && !(s = avformat_alloc_context()))
……
}

avformat_alloc_context来给fmt_ctx 分配内存的,看它实质分配的内存有多大:

AVFormatContext *avformat_alloc_context(void)
{
   
   
    FFFormatContext *const si = av_mallocz(sizeof(*si));
    AVFormatContext *s;

    if (!si)
        return NULL;

    s = &si->pub;
    s->av_class = &av_format_context_class;
    s->io_open  = io_open_default;
    s->io_close = ff_format_io_close_default;
    s->io_close2= io_close2_default;

    av_opt_set_defaults(s);

    si->pkt = av_packet_alloc();
    si->parse_pkt = av_packet_alloc();
    if (!si->pkt || !si->parse_pkt) {
   
   
        avformat_free_context(s);
        return NULL;
    }

    si->shortest_end = AV_NOPTS_VALUE;

    return s;
}

1.3 oopc的继承实现

可以看到它实际分配的内存是FFFormatContext这么大的,但是返回的地址是AVFormatContext *类型的,缩小了。这就是典型的oopc的接口继承

FFFormatContext类如下实现:

typedef struct FFFormatContext {
   
   
    /**
     * The public context.
     */
    AVFormatContext pub;

    /**
     * Number of streams relevant for interleaving.
     * Muxing only.
     */
    int nb_interleaved_streams;
    ……
}

oopc的继承实现是结构体套结构体。如上结构体,FFFormatContext继承自AVFormatContext。

同时可以看到它的特点,一般父类都是作为子类第一个成员,这样方便强转更改访问权限。
FFFormatContext第1个成员就是父类AVFormatContext的成员,把它命名为pub——注释中说是public公共上下文——公共的——这就是面向对象中常用的抽象出的基类的基本方法。

所谓接口继承,就是创建子类返父类的地址,这是多态实现的基础。

oopc中,这种继承是个老套路,也是经典套路,linux中,还有rtthread RTOS的内核实现中常用这种套路,这个应该是oopc的经典。

对应的对象图简略示意图如下:
1

2. AVInputFormat 类。

就像linux一切统一于文件,ffmpeg的一切拉流输入格式统一于AVInputFormat类——对所有拉流输入格式进行了抽象——体现了面向对象的抽象与多态——不同子类的方法不同,在oopc中就是采用函数指针实现。
什么意思?在代码上,说的“子类”具体代码体现在demuxer_list指针数组——定义在libavformat/demuxer_list.c中——该文件是编译FFMPEG configure的时候生成的(也就是说下载的源码中是没有的,config时才生成),举例生成的数组如下:

static const AVInputFormat * const demuxer_list[] = {
   
   
    &ff_aa_demuxer,
    &ff_aac_demuxer,
    &ff_ac3_demuxer,
    &ff_acm_demuxer,
    &ff_act_demuxer,
    &ff_adf_demuxer,
    &ff_adp_demuxer,
    &ff_ads_demuxer,
    &ff_adx_demuxer,
    &ff_aea_demuxer,
    &ff_afc_demuxer,
    &ff_aiff_demuxer,
    &ff_aix_demuxer,
    &ff_amr_demuxer,
    &ff_amrnb_demuxer,
    &ff_amrwb_demuxer,
    &ff_anm_demuxer,
    &ff_apc_demuxer,
    &ff_ape_demuxer,
    &ff_apng_demuxer,
    &ff_aptx_demuxer,
    &ff_aptx_hd_demuxer,
    &ff_aqtitle_demuxer,
    &ff_asf_demuxer,
    &ff_asf_o_demuxer,
    &ff_ass_demuxer,
    &ff_ast_demuxer,
    &ff_au_demuxer,
    &ff_avi_demuxer,
    &ff_avr_demuxer,
    &ff_avs_demuxer
ffmpeg 是一个强大的音视频处理工具,它可以用来进行各种音视频格式的编解码、转码、剪辑等操作。下面是基于 C++ 使用 ffmpeg 进行 RTSP 和推程: 1. 引入 ffmpeg 库:首先需要在项目中引入 ffmpeg 库,可以使用静态库或者动态库,具体方法不再赘述。 2. 初始化 ffmpeg:在使用 ffmpeg 前,需要初始化 ffmpeg,这可以通过调用 av_register_all() 函数实现。 3. 创建 AVFormatContext:创建一个 AVFormatContext 对象,用于存储音视频相关信息,包括音视频编码格式、的时间基等信息。可以通过调用 avformat_alloc_context() 函数来创建。 4. 打开 RTSP :调用 avformat_open_input() 函数打开 RTSP ,传入 RTSP 地址、AVFormatContext 对象等参数,函数会自动解析出音视频的信息并存储到 AVFormatContext 对象中。 5. 查找音视频:通过调用 avformat_find_stream_info() 函数,可以查找音视频的索引,该函数会自动解析音视频的信息,并将音视频的索引存储到 AVFormatContext 对象中。 6. 获取音视频的信息:可以通过遍历 AVFormatContext 对象的 streams 属性,获取每个音视频的详细信息,包括编码格式、分辨率、码率等等。 7. 打开音视频解码器:对于每个音视频,需要打开相应的解码器,可以通过调用 avcodec_find_decoder() 函数查找对应的解码器,然后调用 avcodec_open2() 函数打开解码器。 8. 创建 AVFrame 和 AVPacket:解码音视频帧需要使用 AVFrame 和 AVPacket 对象,可以通过调用 av_frame_alloc() 和 av_packet_alloc() 函数创建。 9. 读取音视频帧:通过调用 av_read_frame() 函数读取音视频帧,该函数会返回一个 AVPacket 对象,包含了音视频帧的数据和相关信息。 10. 解码音视频帧:根据 AVPacket 对象中的信息,可以调用对应的解码器进行解码,解码后的结果存储在 AVFrame 对象中。 11. 处理音视频帧:可以对解码后的音视频帧进行各种处理,比如转换格式、合并音视频等。 12. 推:可以使用 avformat_new_stream() 函数创建一个新的音视频,并设置相应的参数,然后使用 avio_open() 函数打开一个输出,最后调用 avformat_write_header() 函数开始推。 13. 写入音视频帧:对于每一帧音视频数据,可以调用 av_interleaved_write_frame() 函数写入输出中,该函数会自动进行封装和编码。 14. 关闭和解码器:最后记得关闭输入、输出和解码器,释放相应的资源。 以上是基于 C++ 使用 ffmpeg 进行 RTSP 和推的大致程,具体实现还需要根据具体的需求和情况进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值