ZLMediaKit中的RingBuffer

news2024/9/28 17:29:41

前面的文章讲到ZLMediaKit转流,提到过RingBuffer,它是比较核心的数据结构。这篇文章就来讲讲RingBuffer的用法。

RingBuffer的类体系

RingBuffer是由多个类组成,分为两大功能:存储和数据分发。
存储功能由类RingStorage实现,分发功能由RingReaderDispactcher,RingDelegateRingReader)。下面是它们的类图:
ZLMediaServer RingBuffer (1).jpg
RingBuffer类是"大总管",封装整个体系的功能,提供对外的接口。

数据存储

RingStorage是数据存储类,它是一个循环队列,有最大容量定义,从尾部插入最新数据,当队列满了,从头部删除老数据。

它的对所存储的数据的定义,借用了视频GOP的概念。
将GOP视为一个元素(一个视频GOP中包含多个视频nalu)。
RingStorage中将GOP称为更适合,里有包含的更基本的元素,下面是它的定义:

template <typename T>
class _RingStorage 

基本元素为模板类型,可以存入任意类型。

它包含了一个类型为GopType容器,如下:
using GopType = List<List<std::pair<bool, T>>>;
GopType _data_cache;
它是一个List,元素也是一个List。可见是以组为单位存储数据。

在视频数据中,GOP包含的是两个关键帧之间的的nalu数据,所以它的write接口有一个是否为key的参数,如下:

void write(T in, bool is_key = true)

它的构造函数如下:

_RingStorage(size_t max_size, size_t max_gop_size)

max_size是指最大元素个数,就是GOP的数量*GOP的大小。
max_gop_size是指最大GOP的个数。

下面是一个使用示例:

//RingBuffer是_RingStorage的封装
//最大size为100,GOP最大个数为1
RingBuffer<int>::Ptr g_ringBuf(new RingBuffer<int>(100,nullptr,1));
//GOP 011
g_ringBuf->write(0,true);
g_ringBuf->write(1,false);
g_ringBuf->write(1,false);
//GOP 022
g_ringBuf->write(0,true);
g_ringBuf->write(2,false);
g_ringBuf->write(2,false);
//GOP 033
g_ringBuf->write(0,true);
g_ringBuf->write(3,false);
g_ringBuf->write(3,false);

上面的例子将0作为key(当然可以是任意值),两个key之间就是GOP的数据(GOP的长度可以是任意长度)。
因为定义的GOP个数为1,所以buffer最终缓存的是0,3,3。前面的0,1,1,0,2,2都被删除了。
对视频nalu数据来说,**RingStorage**就是一个GOP buffer,缓存最少一个GOP的数据。这样可以保证快速出图。

数据分发

先看RingBuffer的整体结构图

RingBuffer结构图.jpg

RingBuffer中的数据结构std::unordered_map<EventPoller::Ptr, typename RingReaderDispatcher::Ptr, HashOfPtr> _dispatcher_map,是以EventPoller对象为key,所以它可以跨线程的分发数据。

RingReaderDispatcher内有多个RingReader对象,是数据流向的目的端。

RingReader就是数据的出口,调用RingBuffer类的attch方法获取一个RingReader对象,再调用setReadCB方法设置数据回调,就可以取到数据了。

attch有一个EventPoller类型的形参,需要传入的是目的对象所在的线程。

在这篇文章中提到过,MediaSource对象作为数据源,内部都有一个RingBuffer,通过它拿到一个RingReader对象后就可以取到这个MediaSource的源了。

比如,以rtmp推流,http-flv拉流时,那么连接rtmp源和flv的基本代码结构如下:

//poller为_ring_reader对象所在的线程
_ring_reader = media->getRing()->attach(poller);
//获取源信息的回调
_ring_reader->setGetInfoCB(...);
//当源关闭时的回调
_ring_reader->setDetachCB(...);
//设置读取数据的回调
_ring_reader->setReadCB(...);

具体的代码见,void FlvMuxer::start方法。

下面是RingBuffer中数据流转图

ZLMediaKit RingBuffer数据分发图.jpg
通过write写入数据,数据从RingBufferRingReaderDispatcher,再到RingReader,再通过onReadCB回调至dst。

RingBuffer使用的例子

#include <iostream>
#include "Util/logger.h"
#include "Util/util.h"
#include "Util/RingBuffer.h"

using namespace std;
using namespace toolkit;

//创建一个RingBuffer对象,存储int元素
//最大size为100,缓存(max_gop_size)为1
RingBuffer<int>::Ptr g_ringBuf(new RingBuffer<int>(100,nullptr,1));

//数据回调
void onReadEvent1(int i) {
    std::cout<<i<<std::endl;
}

//src释放时的回调
void onDetachEvent(){
    WarnL;
}

int main() {
    //初始化日志
    auto fileChannel = std::make_shared<toolkit::FileChannel>("FileChannel", toolkit::exeDir());
    Logger::Instance().add(fileChannel);
    Logger::Instance().setWriter(std::make_shared<toolkit::AsyncLogWriter>());

    //RingBuffer reader线程
    auto poller1 = EventPollerPool::Instance().getPoller(false);
    //在线程中设置reader
    poller1->async([&]{
        //通过attach方法获取一个RingReader,设置为使用cache
        auto reader = g_ringBuf->attach(poller1,true);
        //设置数据读取回调
        reader->setReadCB([](int i){
            onReadEvent1(i);
        });
    	//设置src关闭时的回调
        reader->setDetachCB([](){
            onDetachEvent();
        });
    });

    //在主线程中写入数据
    //GOP 011
    g_ringBuf->write(0,true);
    g_ringBuf->write(1,false);
    g_ringBuf->write(1,false);
    //GOP 022
    g_ringBuf->write(0,true);
    g_ringBuf->write(2,false);
    g_ringBuf->write(2,false);
    //GOP 033
    g_ringBuf->write(0,true);
    g_ringBuf->write(3,false);
    g_ringBuf->write(3,false);

    std::this_thread::sleep_for(std::chrono::seconds(10));
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

React 路由传参

引言 在上一篇中&#xff0c;我们学习了 React 中使用路由技术&#xff0c;以及如何使用 MyNavLink 去优化使用路由时的代码冗余的情况。 这一节我们继续上一篇 React 路由进行一些补充 1. Switch 解决相同路径问题 首先我们看一段这样的代码 <Route path"/home&q…

Android 13 - Media框架(26)- OMXNodeInstance(三)

上一节我们了解了OMXNodeInstance中的端口定义&#xff0c;这一节我们一起来学习ACodec、OMXNode、OMX 组件使用的 buffer 到底是怎么分配出来的&#xff0c;以及如何关联起来的。&#xff08;我们只会去了解 graphic buffer的创建、input bytebuffer的创建、secure buffer的创…

技术阅读周刊第十一期

技术阅读周刊&#xff0c;每周更新。 历史更新 20231124&#xff1a;第七期20231201&#xff1a;第八期20231215&#xff1a;第十‍期 A Comprehensive guide to Spring Boot 3.2 with Java 21, Virtual Threads, Spring Security, PostgreSQL, Flyway, Caching, Micrometer, O…

61.SVN版本控制系统

SVN&#xff08;Subversion&#xff09;是一种集中式版本控制系统&#xff0c;它有一个中央仓库用于存储代码库的完整历史记录。相对于分布式版本控制系统&#xff08;例如 Git&#xff09;&#xff0c;SVN 不支持本地仓库。 一、SVN 安装。 &#xff08;1&#xff09;在windo…

Sharding JDBC 学习了解 - 总览和概念

第一部分&#xff1a;概述 ShardingSphere是一个由一套分布式数据库中间件解决方案组成的开源生态圈&#xff0c;包括Sharding-JDBC、Sharding-Proxy和Sharding-Proxy 3个独立产品。它们都提供了数据分片、分布式事务、数据库编排等功能&#xff0c;适用于Java同构、异构语言、…

【音视频】remb twcc原理

目录 twcc简介 WebRTC REMB 参考文档 twcc简介 TWCC全称是Transport wide Congestion Control&#xff0c;是webrtc的最新的拥塞控制算法。其原理是在接收端保存数据包状态&#xff0c;然后构造RTCP包反馈给发送端&#xff0c;反馈信息包括包到达时间、丢包状态等&#xff…

开源路由工具NextTrace Web

什么是 NextTrace &#xff1f; NextTrace 是一个由 Golang 语言开发的开源可视路由工具。它不仅支持 IPv4 和 IPv6 协议&#xff0c;而且在轻量级的同时&#xff0c;提供了快速、准确的路由信息。不论您是网络管理员、开发者还是普通用户&#xff0c;NextTrace 都是您网络问题…

【English】水果单词小小汇总~~

废物研究生&#xff0c;只要不搞科研干啥都是开心的&#xff0c;啊啊啊啊啊科研要命。作为一个水果怪&#xff08;每天不吃水果就要命的那种哈哈哈哈&#xff09;突然发现竟然就知道什么apple、banana、orange&#xff01;惭愧惭愧&#xff0c;正好兴致正浓&#xff0c;来整理一…

编写第一个APP自动化脚本 appium_helloworld ,将脚本跑起来

一、前置说明 我们把学习 Appium 的第一个脚本称为 appium_helloworld&#xff0c;它用于展示 Appium 的基本用法&#xff0c;验证配置和环境是否正确。 Appium 自动化操作 APP 的基本流程&#xff08;Android平台&#xff09;&#xff1a; 启动 Appium Serveradb 连接设备&…

分类预测 | Matlab实现MTF-CNN-Mutilhead-Attention基于马尔可夫转移场-卷积神经网络融合多头注意力多特征数据分类预测

分类预测 | Matlab实现MTF-CNN-Mutilhead-Attention基于马尔可夫转移场-卷积神经网络融合多头注意力多特征数据分类预测 目录 分类预测 | Matlab实现MTF-CNN-Mutilhead-Attention基于马尔可夫转移场-卷积神经网络融合多头注意力多特征数据分类预测分类效果基本描述程序设计参考…

Python的基本数据类型和数据类型的转换

TOC 数据类型 类型查看 type 可以使用type内置函数查看变量所指的对象类型 a1 b1.0 c"1" d1, e[1] f{1:1} g{1}print(type(a)) print(type(b)) print(type(c)) print(type(d)) print(type(e)) print(type(f)) print(type(g))isinstance **如字面意思,isinstance()…

Flask+Mysql项目docker-compose部署(Pythondocker-compose详细步骤)

一、前言 环境&#xff1a; Linux、docker、docker-compose、python(Flask)、Mysql 简介&#xff1a; 简单使用Flask框架写的查询Mysql数据接口&#xff0c;使用docker部署&#xff0c;shell脚本启动 优势&#xff1a; 采用docker方式部署更加便于维护&#xff0c;更加简单快…

多维时序 | MATLAB实CNN-Mutilhead-Attention卷积神经网络融合多头注意力机制多变量时间序列预测

多维时序 | MATLAB实CNN-Mutilhead-Attention卷积神经网络融合多头注意力机制多变量时间序列预测 目录 多维时序 | MATLAB实CNN-Mutilhead-Attention卷积神经网络融合多头注意力机制多变量时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 多维时序 | …

CUMT--Java复习--文件及IO流

目录 一、文件 1、文件系统和路径 2、File类 3、FilenameFilter接口 二、IO流 1、流的分类 2、流的体系结构 三、字节流 1、InputStream 2、OutputStream 四、字符流 1、Reader 2、Writer 五、过滤流和转换流 1、过滤流 2、转换流 六、序列化 1、对象序列化…

继承易错总结

1.继承会将所有的成员继承下来&#xff0c;但是继承方式限定的是继承下来成员的可见类型(如果是private继承&#xff0c;那么他不论哪里都是不可见的&#xff1b;如果是protected继承在类中是可见的&#xff0c;在类外是不可见的&#xff1b;如果是public继承&#xff0c;在任何…

[机器人-2]:开源MIT Min cheetah机械狗设计(二):机械结构设计

目录 1、四肢朝向的选择 2、电机布局形式的选择 3、电机的选型及测试&#xff08;非常重要&#xff09; 4、结构优化 5、尺寸效应 6、其他 1、四肢朝向的选择 机械狗的结构设计&#xff0c;第一个摆在我们面前的就说四肢的朝向问题&#xff0c;如下图&#xff0c;我们是…

白龙地铁消费项目(地铁消费系统,包括用户端、管理端)

大一学的C#可视化项目文件&#xff0c;所有功能均可使用。可以直接下载 下方是演示照片

Vue 3 Composition API:让组件开发更高效、灵活(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

修改第三方npm包

文章目录 一、前言二、补丁方案2.1、patch-package2.2、pnpm patch 三、换日方案四、总结五、最后 一、前言 在开发过程中&#xff0c;发现某个npm包有Bug&#xff0c;应该怎么办&#xff1f;可以试试下面这2种方案&#xff1a; 代码量少&#xff0c;可以直接修改npm包代码的&…

【计算机四级(网络工程师)笔记】操作系统运行机制

目录 一、中央处理器&#xff08;CPU&#xff09; 1.1CPU的状态 1.2指令分类 二、寄存器 2.1寄存器分类 2.2程序状态字&#xff08;PSW&#xff09; 三、系统调用 3.1系统调用与一般过程调用的区别 3.2系统调用的分类 四、中断与异常 4.1中断 4.2异常 &#x1f308;嗨&#xff…