SRS3
一 定义
SRS是一个流媒体集群,支持RTMP/HLS/FLV,高效、稳定、易用。
二 安装*
configure -use-sys-ssl --full && make -j3
三 运行
./etc/init.d/srs stop 停止指令
./etc/init.d/srs restart 重启
RTMP媒体端口监听
./obj/srs -c conf/rtmp.confg
查看实时日志
tail ./obj/srs.log
用FFmpeg的方式推流(略)
ffmpeg -re -i night.mp4 -c copy -f flv rtmp://192.168.31.53/live2/night
四 源码分析
1、 目录
3rdparty 第三方包,zip格式。估计是一些公共的方法。
auto sh脚本。服务运维使用。
conf sh脚本。配置和修改配置。
doc 英文文档。
etc 略。编译使用。
ide 略。调试工具。
modules 空。扩展模块。HLS音频和MP4音视频。
research 其他平台接入SRS。Golong、arm、python、player
scripts 脚本。
src 主要源码。
|
|----- app API层(主要逻辑)
|----- core 工具类通用
|----- kernel 音视频、文本输入输出、网络连接
|----- libs 略。就是普通代码
|----- main 控制台、单元测试。
|----- protool 协议的字符解析。json、avc、握手、rtmp、rtsp
|----- server 处理服务。线程消息相关。
先主要看下RTMP的协议和处理。
2、 代码跟踪
源码文件:/truck/src/main/src_main_server.cpp
这个src_main_server.cpp里面有个 int main() 入口。程序会走到 /truck/src/app/srs_app_server.cpp
srs_app_server.cpp里面有listen监听和Handler消息。通过订阅设计模式实现。
srs_app_server.cpp 文件夹下accept_client() 、fd2conn()接口。RTMP媒体端口接听从这里开始。
*pconn = new SrsRtmpConn(this, stfd, ip);
这里开始RTMP的协议流处理。
SrsRtmpConn类里面新建SrsRtmpServer()类。SrsHandshakeBytes()握手后绑定当前通信接口。
SrsProtocol()是解析协议的。
主要看下srs_app_rtmp_conn.cpp 类,这里面是协议通信相关。
编解码的先不需要看,这个SRS本来只是开RTMP端口和会议室的。
3、 二次开发技巧
自己打日志,改方法和改类的重载。梳理流程后,想怎么接入都不难。SRS服务器对接GB28181的一个标准开源平台。
官方类图
SRS server类
SRS connect类
SRS 类和流的问题
客户端发送RTMP连接请求,SrsListener接受后,创建一个SrsConnection。每个SrsConnection会启动一个线程来完成相应任务。
SrsRtmpConn首先按照RTMP协议交互成功后,根据URL创建流的信息。同时调用fetch_or_create生成一个处理音视频源的SrsSource。
如果是推流:
创建SrsPublishRecvThread线程,接受客户端发过来的RTMP数据包。数据包由SrsRtmpServer来处理。如果是音视频数据,由process_publish_message来处理。它会通过SrsSource对媒体流进行处理。
如果是边缘服务,SrsSource直接将媒体proxy publish到源站服务
否则SrsSource会将publish流放入每个SrsConsumer的媒体数据队列,一个SrsConsumber就是一个播放客户端。同事调用SrsOriginHub将媒体流按照配置来生成FLV、HLS、MP4录像文件,以及是否将流发布到其他RTMP服务器。最后检查如果启用GopCache会将流写入它的队列。对一个新的播放请求,保证首先获取一个gop数据,防止开始播放时黑屏和花屏。
如果是拉流:
如果是源站拉流同时启用源站集群,如果流不是该源站发布,则根据配置的发送api请求到其他源站,检查是否在其他源站发布流。如果是,发送一个redirect,要求拉流客户重定向到指定服务器拉流。注意:RTMP重定向信令,如果客户端直接请求的源站,要求RTMP客户端支持redirect,如果SRS边缘回源到源站后再重定向,是可以。因为SRS支持redirect。
如果不走第一步,则创建一个SrsConsumer与SrsQueueRecvThread线程,创建SrsConsumer时,如果启用gopcache,首先会将gopcache媒体数据插入SrsConsumer的数据队列。如果是边缘拉流,则使用SrsPlayEdge回源拉流。将回源拉的媒体流数据插入SrsConsumer的数据队列中。
SrsQueueRecvThread线程负责将SrsConsumer的数据队列中的媒体数据发送给客户端。SrsConsumer队列中数据来源于GopCache,源站publish的数据,以及回源拉流的数据。
SRS线程模型
SRS程序启动流程
(1)首先检查解析启动命令参数,初始日志接口,检查配置文件是否正确
(2)创建SrsServer服务,初始化一些变量
(3)检查是否后台运行还是控制台运行
(4)初始化st 协程库,信息号管理器
(5)如果后台运行写进程pid到文件
(6)监听连接:
listen_rtmp: rtmp推流或拉流连接
listen_http_api: api请求连接
listen_http_stream: http拉流连接,http-flv ,http-ts,http-aac,http-mp3
listen_stream_caster: 接收MpegTSOverUdp流请求,rtsp推流请求,http-flv推流请求
(7)初始化http_api接口处理
(8)启动ingest协程,使用ffmpeg, 拉取文件或流转发到本服务
(9)启动主线程
8.1 RTMP监听
(1)SerServer调用listern启动rtmp监听线程
(2)客户端发送连接请求,监听线程收到请求后,发送on_tcp_accetpt()事件
(3)SrsrServer处理accetp_client() 创建一个新的SrsRtmpConn,同时启动SrsRtmpConnThread连接线程
(4)SrsRtmpConnThread收到客户端rtmp握手,同时根据rtmp连接流程创建一个rtmp连接
(5)连接成功之后,调用stream_service_cycle对rtmp媒体流处理
8.2 RTMP媒体流处理流程
ALL PICTURE FROM: https://github.com/xialixin/srs_code_note/blob/master/doc/srs_note.md