live555搭建流式rtsp服务器
源代码已上传gitee
一、需求
live555
源代码中的liveMediaServer
是将本地文件作为源文件搭建rtsp服务器,我想用live555
封装一个第三方库,接收流数据搭建Rtsp服务器;预想接口如下:
class LiveRtspServer {
public:/***@brief构造一个新的Live Rtsp服务器对象**@param videoCodec要用于流式传输的视频编解码器*@param audioCodec要用于流式传输的音频编解码器*@param fps流的帧速率*@param port用于流传输的端口*@param suffix要添加到流URL的后缀*@param username身份验证的用户名*@param password身份验证的密码*/LiveRtspServer(const std::string &videoCodec = "h264",const std::string &audioCodec = "none", unsigned fps = 60,unsigned port = 8554, const std::string &suffix = "",const std::string &username = "",const std::string &password = "");/***@brief设置客户端上状态已更改的回调**@param callback客户端状态更改时要调用的回调*/void setOnClientStateChanged(clientConnectCallback callback){clientConnectCallback_ = callback;}/***@brief启动服务器*/void start();/***@brief停止服务器*/void stop();/***@brief向客户端发送视频数据**@param buf包含视频数据的缓冲区*@param len视频数据的长度*如果数据发送成功,@return true,否则为false*/bool sendVideoData(const unsigned char *buf, int len);/***@brief向客户端发送音频数据**@param buf包含视频数据的缓冲区*@param len视频数据的长度*如果数据发送成功,@return true,否则为false*/bool sendAudioData(const unsigned char *buf, int len);/***@brief获取服务器的RTSP URL**@param ipv6是否使用ipv6*@return const char*RTSP URL*/const char *RtspUrl(int ipv6 = 0);
};
二、实现
2.1 阅读代码
阅读LiveMediaServer
源码可以发现建立Rtsp服务器的大致过程比较简单,创建一个继承RTSPServer
的类,重写lookupServerMediaSession
方法创建ServerMediaSession
实例,并调用addServerMediaSession
将实例添加到RTSPServer
中,再通过创建对应不同数据格式的ServerMediaSubsession
实例和ServerMediaSession
的addSubsession
方法,将ServerMediaSubsession
实例添加到ServerMediaSession
中,最终读取数据通过ServerMediaSubsession
的createNewStreamSource
创建的FramedSource
实现;写的有点乱,回头做个流程图,整体来说过程比较简单;
详细的源码分析可以查看live555学习笔记【3】—RTSP服务器(一);这里摘录其中RTSP链接建立过程:
- 客户端发起RTSP OPTION请求,目的是得到服务器提供什么方法。RTSP提供的方法一般包括OPTIONS、DESCRIBE、SETUP、TEARDOWN、PLAY、PAUSE、SCALE、GET_PARAMETER。
- 服务器对RTSP OPTION回应,服务器实现什么方法就回应哪些方法。在此系统中,我们只对DESCRIBE、SETUP、TEARDOWN、PLAY、PAUSE方法做了实现。
- 客户端发起RTSP DESCRIBE请求,服务器收到的信息主要有媒体的名字,解码类型,视频分辨率等描述,目的是为了从服务器那里得到会话描述信息(SDP)。
- 服务器对RTSP DESCRIBE响应,发送必要的媒体参数,在传输H.264文件时,主要包括SPS/PPS、媒体名、传输协议等信息。
- 客户端发起RTSP SETUP请求,目的是请求会话建立并准备传输。请求信息主要包括传输协议和客户端端口号。
- 服务器对RTSP SETUP响应,发出相应服务器端的端口号和会话标识符。
- 客户端发出了RTSP PLAY的请求,目的是请求播放视频流。
- 服务器对RTSP PLAY响应,响应的消息包括会话标识符,RTP包的序列号,时间戳。此时服务器对H264视频流封装打包进行传输。
- 客户端发出RTSP TEARDOWN请求,目的是关闭连接,终止传输。
- 服务器关闭连接,停止传输。
2.2 搭建RTSP服务器
所以我们照着这个流程走一遍即可;
- 仿照
liveMedia/include/ByteStreamFileSource.hh
创建自己的liveMedia/include/ByteStreamFrameSource.hh
,重写doGetNextFrame
获取数据接口,并添加一个doPutFrames(const uint8_t *buffer,unsigned bufferSize)
传递视频数据接口;将传递进的数据在doGetNextFrame
中拷贝到fTo
地址,设置fFrameSize
; - 仿照
liveMedia/include/FileServerMediaSubsession.hh
创建自己的liveMedia/include/StreamServerMediaSubsession.hh
,以及对应的子类liveMedia/include/H265VideoStreamServerMediaSubsession.hh
和liveMedia/include/H264VideoStreamServerMediaSubsession.hh
,这两个子类调用createNewStreamSource
方法创建第一步的ByteStreamFrameSource
实例; - 仿照
mediaServer/DynamicRTSPServer.hh
创建自己的liveRtspServer/include/StreamRTSPServer.hh
,其中createNewSMS
方法我们根据传入的视频编码格式创建我们自己的H264/H265VideoStreamServerMediaSubsession
; - 关键的一步如何把
ByteStreamFileSource
中数据传入接口doPutFrames
导出到我们自己的StreamRTSPServer
中,在这里我通过1、2、3步创建自己的类中层层传递void onFrameSourceStateChanged(void* clientData, Boolean state)
回调的方式,将在第2步里创建或析构ByteStreamFrameSource
的实例指针传到StreamRTSPServer
的std::vector<ByteStreamFrameSource* > fFrameSources
成员中,这样就可以将数据传入了;
2.3 问题
流程走通后,遇到有时候rtsp客户端无法连接到客户端问题,经层层跟踪发现,rtsp链接建立时也就是服务器对RTSP DESCRIBE响应,这一步服务器端要读取一帧IDR帧获取其中视频流信息的SPS/PPS/VPS信息,发送必要的媒体参数给客户端,LiveMediaServer
中创建RTSP服务器时,每次链接建立都是从开始读取文件,必然能读取到IDR帧。而流式推送,如果编码参数GOP过大,长时间读取不到IDR帧,链接就会超时退出,因此需要将IDR帧保存,链接建立中第一次读取数据时保证读取到的是IDR帧;
三、遗留问题
- 目前虽然送进解析类的是一帧帧数据,但是
ByteStreamFrameSource
仍然保留了文件读取的BANK_SIZE
限制,没有找到控制发送地方,没有完全看懂这部分代码,所以在获取数据是加了等待数据到达超时方式,感觉不太友好; - 对音频处理不熟,音频功能没有添加;
live555
源代码为单线程读取数据,多客户端连接会有性能瓶颈,如何修改多线程;- 没有稳定性测试,也没有用于项目中,可能会有各种BUG,还需继续优化
抛砖引玉,希望路过大佬不吝指点一二。
相关文章:
live555搭建流式rtsp服务器
源代码已上传gitee 一、需求 live555源代码中的liveMediaServer是将本地文件作为源文件搭建rtsp服务器,我想用live555封装一个第三方库,接收流数据搭建Rtsp服务器;预想接口如下: class LiveRtspServer { public:/***brief构造一…...
Apache孵化器领路人与导师的职责
对于捐赠到 ASF 孵化器的项目来说, ASF 孵化器项目管理委员会(IPMC)的成员会扮演两个角色,一个 孵化器领路人(Champion),另外一个是孵化器导师(Mentor)。 本文源自 ALC …...

【C++中STL】set/multiset容器
set/multiset容器 Set基本概念set构造和赋值set的大小和交换set的插入和删除set查找和统计 set和multiset的区别pair对组两种创建方式 set容器排序 Set基本概念 所有元素都会在插入时自动被排序。 set/multist容器属于关联式容器,底层结构属于二叉树。 set不允许容…...

使用 create-react-app 创建 react 应用
一、创建项目并启动 第一步:全局安装:npm install -g create-react-app 第二步:切换到想创建项目的目录,使用命令create-react-app hello-react 第三步:进入项目目录,cd hello-react 第四步:启…...
obs-studio 源码学习 obs.h
obs.h 引用头文件介绍 c99defs.h:这个头文件提供了一些 C99 标准的定义和声明,包括一些常用的宏定义和类型定义,用于提高代码的可移植性和兼容性。 bmem.h:这个头文件提供了对内存分配和管理的功能,包括一些内存分配…...

C语言-指针的基本知识(上)
一、关于内存 存储器:存储数据器件 外存 外存又叫外部存储器,长期存放数据,掉电不丢失数据 常见的外存设备:硬盘、flash、rom、u盘、光盘、磁带 内存 内存又叫内部存储器,暂时存放数据,掉电数据…...

4核16G幻兽帕鲁服务器优惠价格表,阿里云和腾讯云报价
幻兽帕鲁服务器价格多少钱?4核16G服务器Palworld官方推荐配置,阿里云4核16G服务器32元1个月、96元3个月,腾讯云幻兽帕鲁服务器服务器4核16G14M带宽66元一个月、277元3个月,8核32G22M配置115元1个月、345元3个月,16核64…...

GitHub 上传文件夹到远程仓库、再次上传修改文件、如何使用lfs上传大文件、github报错一些问题
按照大家的做法,把自己遇到的问题及解决方案写出来(注意:Error里面有些方法有时候我用可以成功,有时候我用也不能成功,写出来仅供参考,实在不行重头再clone,add,commit,p…...

一些es的基本操作
目录 给索引增加字段:给索引删除字段[^1]:创建索引:插入document删除document(应该是按ID) : 给索引增加字段: 用postMan: 给名为population_portrait_hash_seven的索引增加了一个text类型的字段。 用chrome插件Elasticvue 的Re…...

酒鬼酒2024年展望:稳发展动能,迈入恢复性增长轨道
文 | 琥珀酒研社 作者 | 渡过 最近几个月来,白酒估值回落到近十年来低位,反映出了整个白酒行业的市场低迷和虚弱现状。不管是头部企业五粮液、泸州老窖,还是区域酒企口子窖、金种子酒等,最近都通过“回购”或“增持”࿰…...

1002. HarmonyOS 开发问题:鸿蒙 OS 技术特性是什么?
1002. HarmonyOS 开发问题:鸿蒙 OS 技术特性是什么? 硬件互助,资源共享 分布式软总线 分布式软总线是多种终端设备的统一基座,为设备之间的互联互通提供了统一的分布式通信能力,能够快速发现并连接设备,高效地分发…...
vue-cli 无法安装问题解决
在macOS上安装vue-cli,但一直都失败,最后终于解决。 先后报错了2个问题。 报错无法安装 其实原因是源被切断,默认的源是官方的,但在CN是无法正常访问,各种问题。直接将源修改才可以。但可能需要试多次。 npm config…...

spring-bus消息总线的使用
文章目录 依赖bus应用接口用到的封装参数类 接收的应用监听器定义的事件类 使用bus定义bus远程调用A应用数据更新后通过bus数据同步给B应用 依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bus-amqp…...

isctf---re
crackme 解压得到crackme.exe 运行得到flag babyRe 先猜e65537的rsa 先用Z3强行求出p、q,算出常规rsa中的phi,然后套用公式求出m exp #babyre wp from z3 import * import libnum from Crypto.Util.number import * p,q,cInts(p q c) S Solver() S…...

C语言第十二弹--扫雷
✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】 扫雷 1、扫雷游戏分析和设计 1.1、扫雷游戏的功能说明 1.2 游戏的分析和设计 1.2.1、数据结构的分析 1.2.2、文件结构设计 2、扫雷游戏的结构分析 2.1、用…...
网路服务器——线程池技术
文章目录 一、线程池技术二、使用原理三、优点总结 一、线程池技术 预创建原则,线程池内部准备线程备用, 不宜过多。线程应该重用性,可以一对多处理任务或服务不同的客户端。处理单元(线程)数量并不固定,动态扩容与缩减(任务量)。…...

探索设计模式的魅力:深入了解适配器模式-优雅地解决接口不匹配问题
设计模式专栏:http://t.csdnimg.cn/nolNS 目录 一、引言 1. 概述 2. 为什么需要适配器模式 3. 本文的目的和结构 二、简价 1. 适配器模式的定义和特点 定义 特点 2. 适配器模式的作用和适用场景 作用 适用场景 3. 适配器模式与其他设计模式的比较 三、适配…...

matlab窗函数-hann窗和hamming窗函数
窗函数的作用 在时域上,窗函数可以看作是对原始信号进行截断或调制的加权函数。这些窗函数通常在时域上是有限的宽度,并且具有对称性,如矩形窗、汉宁窗、汉明窗和布莱克曼窗等。例如,汉明窗是一种对称窗函数,它可以用…...

Java项目实战--瑞吉外卖DAY03
目录 P22新增员工_编写全局异常处理器 P23新增员工_完善全局异常处理器并测试 p24新增员工_小结 P27员工分页查询_代码开发1 P28员工分页查询_代码开发2 P22新增员工_编写全局异常处理器 在COMMON新增全局异常捕获的类,其实就是代理我们这些controlle。通过aop把…...
docker 里使用vcs 2018 verdi等eda 图形界面
书接上文。之前借用别人的docker,使用EDA工具,苦于没有图形界面。如果只是编码,编译可能问题不大,但是如果要看波形之类的,就没法实现了。 docker 使用 vcs/2018 Verdi等 eda 软件-CSDN博客https://blog.csdn.net/guy…...

微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...

Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...

ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

Unity UGUI Button事件流程
场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...
人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型
在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重,适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解,并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...