6、SRS4.0源代码分析之Origin模式下RTMP协议解封装处理

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

目标:

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()处理逻辑是:

  1. 读取一个字节的FLV videoTag,并根据高4bit判断帧类型,低4bit判断是否是H264编码类型
  2. 创建SrsVideoCodecConfig对象用于保存处理SPS+PPS
  3. 使用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
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值