推流项目的ffmpeg配置和流程重点总结一下

        

        ffmpeg的初始化配置,在合成工作都是根据这个ffmpeg的配置来做的,是和成ts流还是flv,是推动远端还是保存到本地, FFmpeg 的核心数据结构,负责协调编码、封装和写入操作。它相当于推流的“总指挥”。

        先来看一下ffmpeg的推流器配置。


typedef struct
{
    AVStream *stream;    // 输出流
    AVCodecContext *enc; // 编码器
    int64_t next_timestamp; //下一个时间戳
    int samples_count;     // 采样数
    AVPacket *packet;   // 编码数据包
} OutputStream;

typedef struct
{
    unsigned int config_id; //用与多路码流
    int protocol_type; //流媒体TYPE
    char network_addr[NETWORK_ADDR_LENGTH];//流媒体地址
    enum AVCodecID video_codec; //视频编码器ID
    enum AVCodecID audio_codec; //音频编码器ID
    OutputStream video_stream; //VIDEO的STREAM配置
    OutputStream audio_stream; //AUDIO的STREAM配置
    AVFormatContext *oc; //是存储音视频封装格式中包含的信息的结构体,也是FFmpeg中统领全局的结构体,对文件的封装、编码操作从这里开始。
} RKMEDIA_FFMPEG_CONFIG; //FFMPEG配置

        定义了我们流媒体的地址,和复合流是ts/flv等等。 

        在使用 FFmpeg 实现推流的过程中,每个步骤都有其特定的作用,这些步骤是基于音视频处理和网络传输的基本原理设计的。以下是对每个主要步骤的详细解释,以及它们为什么必不可少:

1. 初始化网络模块 (avformat_network_init)

        作用: 初始化 FFmpeg 的网络功能,支持像 RTMP、HTTP 这样的网络协议。

        为什么需要: FFmpeg 默认不加载网络相关模块,此步骤启用网络支持,确保推流到远程服务器(如 RTMP 服务器)时能够正确建立连接。如果不初始化,推流会因为缺少网络协议支持而失败。

        原理: FFmpeg 的网络功能依赖底层库(如 librtmp 或内置的 TCP/UDP 实现),初始化会加载这些模块并注册相关协议。



2. 分配输出格式上下文 (avformat_alloc_output_context2)

    //FLV_PROTOCOL is RTMP TCP
    if (ffmpeg_config->protocol_type == FLV_PROTOCOL)
    {
        //初始化一个FLV的AVFormatContext
        ret = avformat_alloc_output_context2(&ffmpeg_config->oc, NULL, "flv", ffmpeg_config->network_addr); 
        if (ret < 0)
        {
            return -1;
        }
    }
    //TS_PROTOCOL is SRT UDP RTSP
    else if (ffmpeg_config->protocol_type == TS_PROTOCOL)
    {
        //初始化一个TS的AVFormatContext
        ret = avformat_alloc_output_context2(&ffmpeg_config->oc, NULL, "mpegts", ffmpeg_config->network_addr);
        if (ret < 0)
        {
            return -1;
        }
    }

        作用: 创建一个用于输出的容器对象(AVFormatContext),并指定输出格式(FLV/)。

        为什么需要: 推流需要将音视频数据封装成某种格式(比如 FLV 是 RTMP 的常用容器格式),这个上下文对象管理流的元数据、格式信息和输出目标。如果没有这个对象,FFmpeg 无法知道数据要以什么形式输出到哪里。
        原理: 输出格式上下文是 FFmpeg 的核心数据结构,负责协调编码、封装和写入操作。它相当于推流的“总指挥”。


3. 创建输出流 (avformat_new_stream)

    //是否指定了视频编解码器。
    if (fmt->video_codec != AV_CODEC_ID_NONE)
    {
        // 添加一个流(如视频流或音频流),并为其分配编码参数。
        ret = add_stream(&ffmpeg_config->video_stream, ffmpeg_config->oc, &video_codec, fmt->video_codec);
        if (ret < 0)
        {
            avcodec_free_context(&ffmpeg_config->video_stream.enc);
            free_stream(ffmpeg_config->oc, &ffmpeg_config->video_stream);
            avformat_free_context(ffmpeg_config->oc);
            return -1;
        }

        ret = open_video(ffmpeg_config->oc, video_codec, &ffmpeg_config->video_stream, NULL);
        if (ret < 0)
        {
            avformat_free_context(ffmpeg_config->oc);
        }
    }

        //是否指定了音频编解码器。
    if (fmt->audio_codec != AV_CODEC_ID_NONE)
    {
        //添加一路视频流
        ret = add_stream(&ffmpeg_config->audio_stream, ffmpeg_config->oc, &audio_codec, fmt->audio_codec);
        if (ret < 0)
        {
            avcodec_free_context(&ffmpeg_config->audio_stream.enc);
            free_stream(ffmpeg_config->oc, &ffmpeg_config->audio_stream);
            avformat_free_context(ffmpeg_config->oc);
            return -1;
        }

        ret = open_audio(ffmpeg_config->oc, audio_codec, &ffmpeg_config->audio_stream, NULL);
        if (ret < 0)
        {
            avformat_free_context(ffmpeg_config->oc);
        }
    }

         作用: 在输出格式上下文中添加一个流(如视频流或音频流),并为其分配编码参数。

        为什么需要: 推流通常包含视频和音频两种数据,每种数据需要独立的流来承载。创建流是为了定义这些数据的结构(如分辨率、帧率、采样率等),否则 FFmpeg 无法组织数据。

        原理: 流(AVStream)是容器中的独立轨道,推流时服务器和客户端会根据流信息解码数据

4. 打开输出 URL (avio_open)

   if (!(fmt->flags & AVFMT_NOFILE))
    {
        //第四步:打开输出文件
        /**
        * 作用: 
        * 建立与目标服务器(如 RTMP 服务器)的物理连接。
        * 为什么需要: 
        * 推流是将数据发送到远程服务器的过程,必须先打开一个通道(类似于文件句柄或网络 socket),
        * 否则数据无法传输。如果没有这一步,程序会因为找不到输出目标而报错。
        * 原理: 
        * avio_open 使用底层 I/O 抽象层(AVIOContext)与服务器通信,支持多种协议(如 RTMP、HLS)。
        * 对于 RTMP,它会通过 librtmp 初始化连接并完成握手。
         */
        ret = avio_open(&ffmpeg_config->oc->pb, ffmpeg_config->network_addr, AVIO_FLAG_WRITE);
        if (ret < 0)
        {
            free_stream(ffmpeg_config->oc, &ffmpeg_config->video_stream);
            free_stream(ffmpeg_config->oc, &ffmpeg_config->audio_stream);
            avformat_free_context(ffmpeg_config->oc);
            return -1;
        }
    }

        作用: 建立与目标服务器(如 RTMP 服务器)的物理连接。

        为什么需要: 推流是将数据发送到远程服务器的过程,必须先打开一个通道(类似于文件句柄或网络 socket),否则数据无法传输。如果没有这一步,程序会因为找不到输出目标而报错

        原理: avio_open 使用底层 I/O 抽象层(AVIOContext)与服务器通信,支持多种协议(如 RTMP、HLS)。对于 RTMP,它会通过 librtmp 初始化连接并完成握手


 

5. 写入流头部信息 (avformat_write_header)

    // 第五步:写入文件头信息
    //这行代码会根据ffmpeg_config->oc中指定的输出格式(如FLV或TS),
    //生成并写入相应的头部信息到输出文件或流中。
    avformat_write_header(ffmpeg_config->oc, NULL);

        作用: 将流的元数据(比如编码格式、分辨率、时长等)写入输出流的开头。

        为什么需要: 接收端(比如直播服务器或播放器)需要这些信息来正确解析后续的数据。如果缺少头部信息,接收端可能无法识别流格式,导致播放失败。

        原理: 头部信息是容器格式(如 FLV)的标准部分,包含流的描述性数据,类似于文件的“索引”。 


6. 写入数据 (av_interleaved_write_frame)

int write_ffmpeg_avpacket(AVFormatContext *fmt_ctx, const AVRational *time_base, AVStream *st, AVPacket *pkt)
{
    /*将输出数据包时间戳值从编解码器重新调整为流时基 */
    av_packet_rescale_ts(pkt, *time_base, st->time_base);
    pkt->stream_index = st->index;

    /**
     * 第六步:写入数据 
     * 作用: 
     * 将编码后的音视频数据(AVPacket)写入输出流,发送到服务器。
     * 为什么需要: 
     * 这是推流的核心步骤,所有的音视频内容都通过这一步传输到目标。
     * 如果没有这一步,之前的准备工作就毫无意义,因为数据没有实际发送。
     * 原理: 
     * FFmpeg 使用“交错写入”(interleaved)方式处理多路流(如视频和音频),确保时间戳对齐,符合实时传输的要求。
     * 数据会被封装为 FLV 标签(Tag)并通过网络发送。
     */
    return av_interleaved_write_frame(fmt_ctx, pkt);
}

        作用: 将编码后的音视频数据(AVPacket)写入输出流,发送到服务器。

        为什么需要: 这是推流的核心步骤,所有的音视频内容都通过这一步传输到目标。如果没有这一步,之前的准备工作就毫无意义,因为数据没有实际发送。

        原理: FFmpeg 使用“交错写入”(interleaved)方式处理多路流(如视频和音频),确保时间戳对齐,符合实时传输的要求。数据会被封装为 FLV 标签(Tag)并通过网络发送。



7. 写入流尾部 (av_write_trailer)

    //第7步: 写入流尾部 (av_write_trailer)
    /**
     * 
     * 作用: 标记流的结束,并写入必要的结尾信息
     */
    av_write_trailer(ffmpeg_config.oc); // 写入AVFormatContext的尾巴

        作用: 标记流的结束,并写入必要的结尾信息。

        为什么需要: 某些容器格式需要在结束时添加元数据(如索引表),以确保接收端能正确处理整个流。如果不写入尾部,流可能会出现不完整或无法播放的问题。

        原理: 尾部信息是容器格式规范的一部分,对于 FLV 来说,它可能只是简单地关闭流,但对于其他格式(如 MP4),它可能包含关键的索引。


8. 清理资源 (avio_closep, avformat_free_context)

   //第八步:清理资源 (avio_closep, avformat_free_context)
    /**
     * 
     * 作用: 关闭网络连接并释放内存
     */
    free_stream(ffmpeg_config.oc, &ffmpeg_config.video_stream); // 释放VIDEO_STREAM的资源
    free_stream(ffmpeg_config.oc, &ffmpeg_config.audio_stream); // 释放AUDIO_STREAM的资源
    avio_closep(&ffmpeg_config.oc->pb);                         // 释放AVIO资源
    avformat_free_context(ffmpeg_config.oc);                    // 释放AVFormatContext资源

        作用: 关闭网络连接并释放内存。
        为什么需要: 推流结束后,如果不清理资源,会导致内存泄漏或网络连接未正确关闭,影响程序稳定性。对于长时间运行的推流任务尤其重要。
        原理: FFmpeg 的上下文对象和 I/O 句柄占用系统资源(如内存和 socket),需要显式释放以遵循良好的编程实践。


整体工作流程的意义,这些步骤共同构成了 FFmpeg 推流的完整工作流,反映了音视频处理和网络传输的本质:

    1.    准备阶段: 初始化环境、定义格式和目标(步骤 1-3)。
    2.    连接阶段: 建立与服务器的通信(步骤 4)。
    3.    传输阶段: 发送元数据和实际数据(步骤 5-6)。
    4.    结束阶段: 完成传输并清理(步骤 7-8)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/981969.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数字电子技术基础(二十四)——TTL门电路的高、低电平的输出特性曲线

目录 1 TTL门电路的特性曲线 1.1 高电平输出特性 1.1.2 高电平输出特性的实验过程 1.1.2 TTL门电路的输出特性的实验结果 1.2 低电平的输出特性 1 TTL门电路的特性曲线 1.1 高电平输出特性 1.1.2 高电平输出特性的实验过程 现在想要测试TTL门电路的输出特性&#xff0c…

盛铂科技SCP4000射频微波功率计与SPP5000系列脉冲峰值 USB功率计 区别

在射频&#xff08;RF&#xff09;和微波测试领域&#xff0c;快速、精准的功率测量是确保通信系统、雷达、卫星设备等高性能运行的核心需求。无论是连续波&#xff08;CW&#xff09;信号的稳定性测试&#xff0c;还是脉冲信号的瞬态功率分析&#xff0c;工程师都需要轻量化、…

GCC RISCV 后端 -- cc1 入口

GCC编译工具链中的 gcc 可执行程序&#xff0c;实际上是个驱动程序&#xff08;Driver&#xff09;&#xff0c;其根据输入的参数&#xff0c;然后调用其它不同的程序&#xff0c;对输入文件进行处理&#xff0c;包括编译、链接等。可以通过以下命令查看&#xff1a; gcc -v h…

C++第二十讲:C++11

C第二十讲&#xff1a;C11 1.列表初始化1.1C98时的{}初始化1.2C11的新规{}初始化1.3initializer_list初始化 2.右值引用和移动语义2.1右值引用2.1.1左值和右值2.1.2左值引用和右值引用2.1.3引用延长声明周期2.1.4左值和右值的参数匹配 2.2右值引用和移动语义的使用2.2.1移动构造…

Finebi_求组内占比和组内累计占比

需求&#xff1a;原始数据结构如下&#xff0c;要求各每个月的各产品销量占比&#xff0c;至每月的各产品销量累计占比 实现步骤&#xff1a; ①维度拖入日期&#xff0c;按年月分组 ②各产品销量占比DEF(SUM_AGG(${&#xfeff;产品销量表&#xfeff;_&#xfeff;销量&…

PE文件结构详解(DOS头/NT头/节表/导入表)使用010 Editor手动解析notepad++.exe的PE结构

一&#xff1a;DOS部分 DOS部分分为DOS MZ文件头和DOS块&#xff0c;其中DOS MZ头实际是一个64位的IMAGE_DOS——HEADER结构体。 DOS MZ头部结构体的内容如下&#xff0c;我们所需要关注的是前面两个字节&#xff08;e_magic&#xff09;和后面四个字节&#xff08;e_lfanew&a…

自由学习记录(41)

代理服务器的核心功能是在客户端&#xff08;用户设备&#xff09;和目标服务器&#xff08;网站/资源服务器&#xff09;之间充当“中介”&#xff0c;具体过程如下&#xff1a; 代理服务器的工作流程 当客户端希望访问某个网站&#xff08;比如 example.com&#xff09;时&…

学习工具的一天之(burp)

第一呢一定是先下载 【Java环境】&#xff1a;Java Downloads | Oracle 下来是burp的下载 Download Burp Suite Community Edition - PortSwigger 【下载方法二】关注的一个博主 【BurpSuite 安装激活使用详细上手教程 web安全测试工具】https://www.bilibili.com/video/BV…

大模型gpt结合drawio绘制流程图

draw下载地址 根据不同操作系统选择不同的安装 截图给gpt 并让他生成drawio格式的&#xff0c;选上推理 在本地将生成的内容保存为xml格式 使用drawio打开 保存的xml文件 只能说效果一般。

K8S学习之基础六:k8s中pod亲和性

Pod节点亲和性和反亲和性 podaffinity&#xff1a;pod节点亲和性指的是pod会被调度到更趋近与哪个pod或哪类pod。 podunaffinity&#xff1a;pod节点反亲和性指的是pod会被调度到远离哪个pod或哪类pod 1. Pod节点亲和性 requiredDuringSchedulingIgnoredDuringExecution&am…

FPGA学习篇——Verilog学习4

1.1 结构语句 结构语句主要是initial语句和always语句&#xff0c;initial 语句它在模块中只执行一次&#xff0c;而always语句则不断重复执行&#xff0c;以下是一个比较好解释的图: (图片来源于知乎博主罗成&#xff0c;画的很好很直观&#xff01;) 1.1.1 initial语句 ini…

[Computer Vision]图像分割技术

一、技术介绍 1.1 GrabCut 算法 1.1.1 算法原理 GrabCut 算法是一种交互式的图像分割方法,整体流程围绕着用户提供的少量先验信息(如用矩形框大致框选前景区域等),通过构建图模型、拟合高斯混合模型,利用图割算法不断迭代优化,实现了一种有效的交互式图像分割,最终将…

原型链与继承

#搞懂还是得自己动手# 原型链 function Person(name) { this.name name; } Person.prototype.sayName function() { console.log(this.name); };const p new Person("Alice"); 原型链关系图&#xff1a; 原型链&#xff1a;person->Person.prototype->O…

MagicDriveDiT:具有自适应控制的自动驾驶高分辨率长视频生成

24年11月来自香港中文大学、香港科技大学和华为公司的论文“MagicDriveDiT: High-Resolution Long Video Generation for Autonomous Driving with Adaptive Control”。 扩散模型的快速进步极大地改善视频合成&#xff0c;特别是可控视频生成&#xff0c;这对于自动驾驶等应用…

YOLOv8 自定义目标检测

一、引言 YOLOv8 不仅支持预训练模型的推理&#xff0c;还允许用户将其应用于自定义对象检测。本文将详细介绍如何使用 YOLOv8 训练一个新的模型&#xff0c;并在自定义数据集上进行对象检测。 二、数据集准备 1. 数据集格式 YOLOv8 支持多种数据集格式&#xff0c;包括 CO…

Node JS 调用模型Xenova_all-MiniLM-L6-v2实战

本篇通过将句子数组转换为句子的向量表示&#xff0c;并通过平均池化和归一化处理&#xff0c;生成适合机器学习或深度学习任务使用的特征向量为例&#xff0c;演示通过NodeJS 的方式调用Xenova/all-MiniLM-L6-v2 的过程。 关于 all-MiniLM-L6-v2 的介绍&#xff0c;可以参照上…

记录一次Spring事务失效导致的生产问题

一、背景介绍 公司做的是“聚合支付”业务&#xff0c;对接了微信、和包、数字人民币等等多家支付机构&#xff0c;我们提供统一的支付、退款、自动扣款签约、解约等能力给全国的省公司、机构、商户等。 同时&#xff0c;需要做对账功能&#xff0c;即支付机构将对账文件给到…

AORO P9000 PRO三防平板携手RTK高精度定位,电力巡检效率倍增

电网系统覆盖幅员辽阔&#xff0c;每年因设备故障导致的巡检耗时超过百万工日。传统巡检模式受限于定位误差、设备防护不足和作业效率低下三大核心痛点&#xff0c;亟需智能化工具的突破性革新。为了满足这一需求&#xff0c;遨游通讯推出AORO P9000 PRO三防平板&#xff0c;以…

开启AI短剧新纪元!SkyReels-V1/A1双剑合璧!昆仑万维开源首个面向AI短剧的视频生成模型

论文链接&#xff1a;https://arxiv.org/abs/2502.10841 项目链接&#xff1a;https://skyworkai.github.io/skyreels-a1.github.io/ Demo链接&#xff1a;https://www.skyreels.ai/ 开源地址&#xff1a;https://github.com/SkyworkAI/SkyReels-A1 https://github.com/Skywork…

CentOS 7中安装Dify

Dify 是一个开源的 LLM 应用开发平台。其直观的界面结合了 AI 工作流、RAG 管道、Agent、模型管理、可观测性功能等&#xff0c;让您可以快速从原型到生产。尤其是我们本地部署DeepSeek等大模型时&#xff0c;会需要用到Dify来帮我们快捷的开发和应用。 大家可以参考学习它的中…