目标:
RTMP是Adobe 公司为 Flash 播放器和服务器之间音视频数据传输开发的私有协议,因为出现的比较早,所以RTMP协议已经成为国内直播领域尤其是CDN之间推流的标准协议。
Adobe在2017年宣布到2020年底将不再支持Flash,所以很多系统平台的浏览器也都不再支持RTMP协议,如果流媒体服务器只支持RTMP协议,则最新的浏览器就无法通过无插件的方式从服务器获取媒体流,所以SRS服务器有个很重要的工作就是针对音视频数据的转码。
例如,HLS(HTTP Live Streaming)是一个被各种流媒体播放客户端广泛支持的标准协议,SRS流媒体服务器将RTMP推流端发送的音视频数据,转换为满足HLS协议要求的m3u8文件和ts文件,最终,浏览器通过HTTP协议从服务器获取m3u8文件和ts文件并实现本地播放。
本章将深入学习SRS4.0源代码中Origin模式下RTMP协议的解封装处理逻辑,为理解后续的各种转码逻辑打下基础。
内容:
SRS如果工作在Edge模式下,则属于纯转发,此时不会做HLS(ts、m3u8文件)转码处理,只有工作在Origin模式下的SRS服务器才会执行HLS(ts、m3u8文件)转码处理。所以从Origin模式的入口函数开始分析:
srs_error_t SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_sequence_header)
srs_error_t SrsOriginHub::on_audio(SrsSharedPtrMessage* shared_audio)
- 1、对于RTMP协议,视频数据总是以FLV格式封装成Message中的payload部分,所以,首先分析SRS代码中针对视频FLV格式报文的解析处理:
srs_error_t SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_sequence_header)
{
// 因为RTMP客户端发送的SPS+PPS报文,可能存在格式不统一,导致SRS解析失败
// 实际上SPS+PPS是编码器生成用于指导解码器解码的信息,对于流媒体服务器其实意义不大
// 更多的时候是服务器缓存后直接转发给播放器客户端
// 所以,SRS作者在配置文件中增加了一个配置项,用于禁用SPS解析,防止不必要的失败导致无法推流
if (is_sequence_header) {
format->avc_parse_sps = _srs_config->get_parse_sps(req->vhost);
}
// 我们知道,对于RTMP协议,视频数据总是以FLV格式封装成Message中的payload部分
// 所以SrsFormat::on_video()函数其实就是对FLV封装格式的H264报文进行格式化解析,后面详细分析
if ((err = format->on_video(msg)) != srs_success) {
return srs_error_wrap(err, "format consume video");
}
// 这里是为了过滤掉不支持的视频格式,例如H263
if (!format->vcodec) {
return err; }
if (format->is_avc_sequence_header()) {
// 这里主要是为了把视频帧的SPS+PPS信息打印出来
}
// 这里的判断,是为了保证先收到SPS+PPS后,再处理普通视频帧
if (format->vcodec && !format->vcodec->is_avc_codec_ok()) {
return err; }
// HLS协议转码及其错误处理
if ((err = hls->on_video(msg, format)) != srs_success) {
......
}
// DASH、DVR、HDS、FORWARDER处理,转码处理大同小异,暂不分析
dash->on_video(msg, format);
dvr->on_video(msg, format);
hds->on_video(msg);
forwarder->on_video(msg); // copy to all forwarders.
}
上面的函数基本包括了SRS源站在进行HLS转码之前针对Message的逻辑处理,其中的难点主要是SrsFormat::on_video()函数针对Message的解析处理。其实,如果知道了在RTMP协议中,音视频数据总是以FLV格式经行封装,就不难理解此函数内部的处理逻辑。
这里我们先回顾一下H264视频帧的FLV封装格式:
FLV VideoTagHeader 后续数据类型描述符 是SPS+PPS时,这里3字节为全零
+---------------------+ +---------------+ +------------------+
|Frame Type | CodecID | + | AVCPacketType | + | CompositionTime |
+---------------------+ +---------------+ +------------------+
4 bits 4 bits 1 byte 3 byte
视频帧类型 编码器ID 0:SPS+PPS;1:NALU cts字段,用于计算pts和dts
所以,SrsFormat::on_video()处理逻辑是:
- 读取一个字节的FLV videoTag,并根据高4bit判断帧类型,低4bit判断是否是H264编码类型
- 创建SrsVideoCodecConfig对象用于保存处理SPS+PPS
- 使用SrsFormat::video_avc_demux()处理H264视频帧
srs_error_t SrsFormat::on_video(int64_t timestamp, char* data, int size)
{
SrsBuffer* buffer = new SrsBuffer(data, size);
// 读取一个字节的FLV videoTag,并根据低4bit判断是否是H264编码类型,不是则直接返回
int8_t frame_type = buffer->read_1bytes();
SrsVideoCodecId codec_id = (SrsVideoCodecId)(frame_type & 0x0f);
if (codec_id != SrsVideoCodecIdAVC) {
return err; }
// 创建处理SPS+PPS的SrsVideoCodecConfig对象,创建SrsVideoFrame对象
if (!vcodec) {
vcodec = new SrsVideoCodecConfig(); }
if (!video) {
video = new SrsVideoFrame(); }
// 初始化SrsVideoCodecConfig对象
if ((err = video

本文深入剖析SRS4.0源代码,探讨Origin模式下RTMP协议的视频和音频解封装处理,特别是FLV格式的H264和AAC数据解析。SrsFormat类的on_video和on_audio方法处理RTMP报文,去除FLV封装,为后续HLS、DASH等协议的转码做准备。HLS转码涉及SrsHlsController和SrsHlsMuxer,处理音视频数据并生成m3u8和ts文件。
最低0.47元/天 解锁文章
3984

被折叠的 条评论
为什么被折叠?



