0.引言
阅读本文前,可以先阅读前面的文章,能够帮助你更好理解本篇文章。文章列表如下:
SRS流媒体服务器之HLS源码分析(1)
SRS流媒体服务器之HLS源码分析(2)
SRS流媒体服务器之HLS配置、测试和技术选型
SRS流媒体服务器集群之Edge模式(3)
SRS流媒体服务器集群之Edge模式(2)
SRS流媒体服务器集群之Edge模式(1)
SRS流媒体服务器集群之Forward模式(2)
SRS流媒体服务器集群之Forward模式(1)
SRS流媒体服务器之HTTP-FLV框架分析(1)
SRS流媒体服务器之RTMP推流消息处理(1)
SRS流媒体服务器之RTMP协议分析(2)
SRS流媒体框架分析(1)
SRS流媒体之RTMP推流框架分析(2)
SRS流媒体之RTMP拉流框架分析(3)
SRS流媒体服务器之RTMP协议分析(1)
简述SRS流媒体服务器相关技术
流媒体推拉流实战之RTMP协议分析(BAT面试官推荐)
流媒体服务器架构与应用分析
手把手搭建流媒体服务器详细步骤
手把手搭建FFmpeg的Windows环境
超详细手把手搭建在ubuntu系统的FFmpeg环境
本篇文章主要讲解的是在推流时,音频数据是如何通过RTMP协议转化为HLS的ts封装,视频也是类似。以源码的方式进行分析。
![e5f7ea75cd34d3c189bcc57935e4713c.png](https://img-blog.csdnimg.cn/img_convert/e5f7ea75cd34d3c189bcc57935e4713c.png)
1.源码分析
SrsSharedPtrMessage是rtmp的消息格式。
srs_error_t SrsSource::on_audio_imp(SrsSharedPtrMessage* msg){ srs_error_t err = srs_success; bool is_aac_sequence_header = SrsFlvAudio::sh(msg->payload, msg->size); bool is_sequence_header = is_aac_sequence_header; // whether consumer should drop for the duplicated sequence header. bool drop_for_reduce = false; if (is_sequence_header && meta->previous_ash() && _srs_config->get_reduce_sequence_header(req->vhost)) { if (meta->previous_ash()->size == msg->size) { drop_for_reduce = srs_bytes_equals(meta->previous_ash()->payload, msg->payload, msg->size); srs_warn("drop for reduce sh audio, size=%d", msg->size); } } // copy to all consumer if (!drop_for_reduce) { for (int i = 0; i < (int)consumers.size(); i++) { SrsConsumer* consumer = consumers.at(i); if ((err = consumer->enqueue(msg, atc, jitter_algorithm)) != srs_success) { return srs_error_wrap(err, "consume message"); } } } // Copy to hub to all utilities. if ((err = hub->on_audio(msg)) != srs_success) { return srs_error_wrap(err, "consume audio"); } // cache the sequence header of aac, or first packet of mp3. // for example, the mp3 is used for hls to write the "right" audio codec. // TODO: FIXME: to refine the stream info system. if (is_aac_sequence_header || !meta->ash()) { if ((err = meta->update_ash(msg)) != srs_success) { return srs_error_wrap(err, "meta consume audio"); } } // when sequence header, donot push to gop cache and adjust the timestamp. if (is_sequence_header) { return err; } // cache the last gop packets if ((err = gop_cache->cache(msg)) != srs_success) { return srs_error_wrap(err, "gop cache consume audio"); } // if atc, update the sequence header to abs time. if (atc) { if (meta->ash()) { meta->ash()->timestamp = msg->timestamp; } if (meta->data()) { meta->data()->timestamp = msg->timestamp; } } return err;}
把Rtmp封装好的数据,转为音视频裸数据。
srs_error_t SrsOriginHub::on_audio(SrsSharedPtrMessage* shared_audio){ srs_error_t err = srs_success; SrsSharedPtrMessage* msg = shared_audio; //转换封装格式 if ((err = format->on_audio(msg)) != srs_success) { return srs_error_wrap(err, "format consume audio"); } // cache the sequence header if aac // donot cache the sequence header to gop_cache, return here. if (format->is_aac_sequence_header()) { srs_assert(format->acodec); SrsAudioCodecConfig* c = format->acodec; static int flv_sample_sizes[] = {8, 16, 0}; static int flv_sound_types[] = {1, 2, 0}; // when got audio stream info. SrsStatistic* stat = SrsStatistic::instance(); if ((err = stat->on_audio_info(req, SrsAudioCodecIdAAC, c->sound_rate, c->sound_type, c->aac_object)) != srs_success) { return srs_error_wrap(err, "stat audio"); } srs_trace("%dB audio sh, codec(%d, profile=%s, %dchannels, %dkbps, %dHZ), flv(%dbits, %dchannels, %dHZ)", msg->size, c->id, srs_aac_object2str(c->aac_object).c_str(), c->aac_channels, c->audio_data_rate / 1000, srs_aac_sr