live555--搭建RTSP服务器
职责分离:数据采集、编码、推送各司其职易于扩展:更换摄像头只需修改,更换编码器只需修改复用性强可以被不同的上层应用复用。
搭建RTSP服务器
本文介绍如何使用 live555 搭建 RTSP 服务器,重点分析继承 FramedSource 类的实现方式。
一、简介
使用 live555 实现实时流推送,网上有很多例子,其结构大致都是一样的:
1.1 基本结构
-
以
FramedSource为基类,自定义一个子类,用于获取要推送的媒体流数据。在这个类中,一般使用 ffmpeg 将 raw video 编码为对应格式的 ES 流。 -
如果要实现的是多播场景(比如投屏、会议),那么实现一个
PassiveServerMediaSubsession的实例,指定多播地址,主动调用startPlay来推送数据。 -
如果要实现的是单播场景(注意:RTP-over-UDP 和 RTP-over-TCP 都是单播),那么就要以
OnDemandServerMediaSubsession为基类,自定义一个 SubSession,将自定义的 Source 关联到这个 SubSession 中。当访问这个 SubSession 时,就会创建对应的 Source 和 Sink,然后开始推送数据。
1.2 开发者需要做的工作
RTSP 服务器的核心部分(任务调度、数据接收与发送等)可以直接使用 live555 官方例子 testOnDemandRTSPServer 中的核心部分,开发者需要做的主要工作如下:
-
以
FramedSource为基类,自定义一个子类:用于获取要推送的媒体流数据。 -
以
OnDemandServerMediaSubsession为基类,自定义一个 SubSession:将上述自定义的 Source 关联到这个 SubSession 中。当访问这个 SubSession 时,就会创建对应的 Source 和 Sink,然后开始推送数据。 -
将自定义的 SubSession 加入到
ServerMediaSession中。
二、继承 FramedSource 类的分析
以项目 liveRtspServer 为例进行分析。该项目实现了:
- 从摄像头获取 YUV 数据
- 使用 x264 将 YUV 编码为 H264
- 使用 live555 将 H264 推流
2.1 继承关系
该项目 FramedSource 派生的类有:
DevFramedSourceV4l2DevFramedSourceV4l2H264DevFramedSource
继承关系如下:
V4l2H264DevFramedSource
↓
V4l2DevFramedSource
↓
DevFramedSource
↓
FramedSource
2.2 各个类的作用
| 类名 | 主要职责 |
|---|---|
V4l2H264DevFramedSource |
主要负责编码 |
V4l2DevFramedSource |
主要负责从摄像头获取数据 |
DevFramedSource |
主要负责上层交互,上层通过该类中的接口来获取 H264 数据,进而将 H264 数据推送出去 |
2.3 类之间的联系
上述几个类存在继承关系,可实现动态多态,子类对父类提供功能。
父类定义接口,子类实现功能:
// V4l2DevFramedSource 通过 createFrame() 函数为 DevFramedSource 提供 H264 数据
// createFrame() 在父类 DevFramedSource 中为纯虚函数
// 继承它的类"必须"实现 createFrame() 函数
// 达到子类为父类提供功能的目的
数据流转方式:
V4l2H264DevFramedSource 通过 getFrame() 和 encode() 为 V4l2DevFramedSource 提供 H264 数据:
V4l2H264DevFramedSource将编码好的数据放在队列中V4l2DevFramedSource先通过getFrame()从队列中获取 H264 数据- 当队列中没有数据(即
getFrame()返回 false)时,再调用encode()来编码
2.4 设计思想总结
这种分层设计的好处:
- 职责分离:数据采集、编码、推送各司其职
- 易于扩展:更换摄像头只需修改
V4l2DevFramedSource,更换编码器只需修改V4l2H264DevFramedSource - 复用性强:
DevFramedSource可以被不同的上层应用复用
三、实现要点
3.1 FramedSource 核心方法
自定义 FramedSource 子类时,核心需要实现的方法是 doGetNextFrame():
virtual void doGetNextFrame();
当 live555 需要数据时,会调用此方法。开发者需要在此方法中:
- 填充
fTo指向的缓冲区 - 设置
fFrameSize为实际数据大小 - 调用
afterGetting(this)通知框架数据已准备好
3.2 数据流向
摄像头/文件 → 自定义FramedSource → H264Framer → RTPSink → 网络
每一层只负责一个微小的任务,通过 Pipeline 模式串联起来。
参考资料
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐



所有评论(0)