ZLMediaKit的转流流程(一)

zlmediakit的优势就是支持多种媒体容器和媒体协议。我从推流和拉流的两个角度,梳理出了转流的核心骨架。

推流

协议和容器格式的转换,最基本的内核就是音视频数据的扭转。
对视频而言就是,解封装帧数据,组帧,封装帧。
对音频而言简单些,只有解封装,封装。
如下是rtsp中的视频转换为rtmp,mp4,webrtc的简单示意图。

image.png
源端是rtsp的推流,目的端是各种协议的拉流。

  1. 最开始的是rtsp信令协商。
  2. 信令协议协商成功后,通过rtp传输媒体数据。
  3. 从rtp包中解出视频nalu数据。
  4. 组成完整的nalu数据,再根据具体的目的协议或容器进行封装。
  5. 目标协议也是媒体的协商,在媒体协商完成后,由拉流端主动发起转流。

下面是以rtsp推流中的整个流程为例子,画了一个视频的流转图(音频也类似)。

在这里插入图片描述

**当一个rtsp推流端推流后,媒体流会经过解封装,组帧再经过封装成不同协议放到对应的ringbuffer中。流程图中可以很明显的看到整个过程。

对推到ZLMediaKit的流,都会固定的产生FMP4MediaSource(有宏控制)RtmpMediaSourceRtspMediaSourceTSMediaSourceMP4Recorder(mp4存储,按需产生)HlsRecorder(Hls存储,按需产生)RingBuffer(未经过封装的裸帧数据)

在这几个MediaSource中,缓存的就是对应的格式的包,比如RtmpMediaSourceRingBuffer中为RtmpPakcetTSMediaSourceRingBuffer中为TSPacket

这里比较特殊的是MultiMediaSourceMuxer中的_ring,它也作为一个MediaSource,存放的裸H264/H265 nalu。在开启RTPPROXY模式时,是用的这个_ring作为源。

这些对象都会注册到全局的MediaSource容器中,就是s_media_source_map,下面是它的定义

using StreamMap = unordered_map<string/*strema_id*/, weak_ptr<MediaSource> >;
using AppStreamMap = unordered_map<string/*app*/, StreamMap>;
using VhostAppStreamMap = unordered_map<string/*vhost*/, AppStreamMap>;
using SchemaVhostAppStreamMap = unordered_map<string/*schema*/, VhostAppStreamMap>;
static SchemaVhostAppStreamMap s_media_source_map;

就是多个unorder_map的套娃,记录了流的信息和对应的MediaSource对象。当有需要该流时,会根据流信息在容器中找对应的MediaSource

每路推流(不同的stream id)都会这样的流程,产生几个对应协议的MediaSource对象。

所以在媒体层面,不管该流是否有被消费(拉流),媒体层面的rtsp,rtmp,fmp4,ts数据都已准备好。那么在消息(拉流)时,只需要媒体信令完成,就可以直接发流了。

拉流

上面了解了推流的处理流程,那么拉流的流程就比较好理解了,如下图:image.png

  1. 以rtmp协议拉流,rtmp的信令协商处理最终会放到RtmpSession中处理。
  2. 在协商完成后,会在s_media_source_map找到MediaSource
  3. 再通过MediaSoruce取到RingBuffer对象。
  4. 通过调用RingBuffer对象的attch方法,打通转流。

下面是rtmp拉流与源端对接的代码,位于RtmpSession::sendPlayResponse中。

_ring_reader = src->getRing()->attach(getPoller());
    weak_ptr<RtmpSession> weak_self = static_pointer_cast<RtmpSession>(shared_from_this());
    _ring_reader->setGetInfoCB([weak_self]() {
        Any ret;
        ret.set(static_pointer_cast<SockInfo>(weak_self.lock()));
        return ret;
    });
    _ring_reader->setReadCB([weak_self](const RtmpMediaSource::RingDataType &pkt) {
        auto strong_self = weak_self.lock();
        if (!strong_self) {
            return;
        }
        size_t i = 0;
        auto size = pkt->size();
        strong_self->setSendFlushFlag(false);
        pkt->for_each([&](const RtmpPacket::Ptr &rtmp){
            if(++i == size){
                strong_self->setSendFlushFlag(true);
            }
            strong_self->onSendMedia(rtmp);
        });
    });

通过RingBufferattach方法将RtmpSession对象关联到源buffer中,再将数据发送出去。

这就是ZLMediaKit转流的骨架,当然整个流程涉及到很多"皮毛",比如媒体格式的匹配,时间戳的转换,同步等。掌握了骨架在解读细节就不会困难了。

### 使用 ZLMediaKit 实现 GB28181 推流的详细步骤 #### 1. 环境准备 为了成功部署并使用 ZLMediaKit 来处理 GB28181 推流,需先准备好开发环境。这包括安装必要的依赖库以及获取最新的源码版本。 对于 Linux 用户来说,可以通过包管理器来简化这过程;而对于 Windows 或 macOS 用户,则可能需要额外配置交叉编译工具链或其他特定设置[^2]。 #### 2. 编译与安装 ZLMediaKit 下载官方仓库中的最新稳定版代码后,在本地环境中按照给定说明完成项目的构建工作: ```bash cd ZLMediaKit mkdir build && cd build cmake .. make -j4 sudo make install ``` 上述命令会创建个名为 `build` 的目录用于存放编译过程中产生的文件,并调用 CMake 工具生成 Makefile 文件以便后续执行多线程编译任务[-^4]. #### 3. 配置 WVP 平台对接 GB28181 设备 WVP 是款基于 gb/t28181-2016 标准设计而成的支持多种品牌 IPC/NVR 设备接入的服务端软件。它能够很好地配合 ZLMediaKit 进行音视频数据传输及控制指令交互等功能实现[^3]。 在实际应用中,通常会在 WVP 中注册相应的国标编码(如:3402),并将此信息同步至前端页面供用户查看或操作所连接的摄像装置列表。 #### 4. 设置推流参数 当切就绪之后,便可以开始调整具体的推送参数了。这些选项涵盖了 RTP/RTSP 协议的选择、目标地址指定等内容。具体做法是在启动服务之前编辑配置文件(通常是 JSON 或 XML 格式),确保其中包含了正确的 IP 地址和其他必要字段以匹配远端接收方的要求[^1]。 例如,在某些情况下可能会看到类似下面这样的片段: ```json { "rtp": { "port_min": 9000, "port_max": 9500 }, "rtsp": { "enabled": true, "listen_port": 554 } } ``` 以上内容展示了如何开启 RTSP 支持及其监听端口设定方式。 #### 5. 测试验证 最后步就是进行全面的功能检测——不仅限于简单的连通性测试,还应该涵盖画质表现评估等方面的工作。借助 Wireshark 抓包分析工具可以帮助更深入地理解整个通信流程中存在的潜在问题所在。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mo4776

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值