2024年最全SRS学习 - rtc转rtmp流程分析_webrtc推流到rtmp,2024年最新成体系化的神级Golang进阶笔记,

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

if ((err = create\_publisher(req, stream_desc)) != srs_success) {
    return srs\_error\_wrap(err, "create publish");
}

return err;

}


src/app/srs\_app\_rtc\_conn.cpp大约3569行 SrsRtcConnection::create\_publisher 创建推流对象,用于接收流



srs_error_t SrsRtcConnection::create_publisher(SrsRequest* req, SrsRtcSourceDescription* stream_desc)
{
srs_error_t err = srs_success;

srs\_assert(stream_desc);

// Ignore if exists.
if(publishers_.end() != publishers_.find(req->get\_stream\_url())) {
    return err;
}

// 创建推流对象并初始化
SrsRtcPublishStream\* publisher = new SrsRtcPublishStream(this, _srs_context->get\_id());
if ((err = publisher->initialize(req, stream_desc)) != srs_success) {
    srs\_freep(publisher);
    return srs\_error\_wrap(err, "rtc publisher init");
}
publishers_[req->get\_stream\_url()] = publisher;

...

// If DTLS done, start the publisher. Because maybe create some publishers after DTLS done.
// For example, for single PC, we maybe start publisher when create it, because DTLS is done.
if(ESTABLISHED == state()) {
    if(srs_success != (err = publisher->start())) { //启动流接收
        return srs\_error\_wrap(err, "start publisher");
    }
}

return err;

}


src/app/srs\_app\_rtc\_conn.cpp大约1217行 SrsRtcPublishStream::start



srs_error_t SrsRtcPublishStream::start()
{
srs_error_t err = srs_success;

if (is_started) {
    return err;
}

if ((err = source->on\_publish()) != srs_success) {
    return srs\_error\_wrap(err, "on publish");
}

if ((err = pli_worker_->start()) != srs_success) {
    return srs\_error\_wrap(err, "start pli worker");
}

if (_srs_rtc_hijacker) {
    if ((err = _srs_rtc_hijacker->on\_start\_publish(session_, this, req_)) != srs_success) {
        return srs\_error\_wrap(err, "on start publish");
    }
}

// update the statistic when client discoveried.
SrsStatistic\* stat = SrsStatistic::instance();
if ((err = stat->on\_client(cid_.c\_str(), req_, session_, SrsRtcConnPublish)) != srs_success) {
    return srs\_error\_wrap(err, "rtc: stat client");
}

is_started = true;

return err;

}


src/app/srs\_app\_rtc\_source.cpp大约在518行SrsRtcSource::on\_publish



srs_error_t SrsRtcSource::on_publish()
{
srs_error_t err = srs_success;

// update the request object.
srs\_assert(req);

// For RTC, DTLS is done, and we are ready to deliver packets.
// @note For compatible with RTMP, we also set the is\_created\_, it MUST be created here.
is_created_ = true;
is_delivering_packets_ = true;

// Notify the consumers about stream change event.
if ((err = on\_source\_changed()) != srs_success) {
    return srs\_error\_wrap(err, "source id change");
}

// If bridge to other source, handle event and start timer to request PLI.
if (bridger_) {
    if ((err = bridger_->on\_publish()) != srs_success) {
        return srs\_error\_wrap(err, "bridger on publish");
    }

    // The PLI interval for RTC2RTMP.
    pli_for_rtmp_ = _srs_config->get\_rtc\_pli\_for\_rtmp(req->vhost);

    // @see SrsRtcSource::on\_timer()
    _srs_hybrid->timer100ms()->subscribe(this);
}

SrsStatistic\* stat = SrsStatistic::instance();
stat->on\_stream\_publish(req, _source_id.c\_str());

return err;

}


### WebRTC转RTMP


断点:


1. srs\_app\_source.cpp:1847 SrsLiveSource::SrsLiveSource()



SrsLiveSource::SrsLiveSource srs_app_source.cpp:1847
SrsLiveSourceManager::fetch_or_create srs_app_source.cpp:1734
SrsRtcPublishStream::initialize srs_app_rtc_conn.cpp:1196
SrsRtcConnection::create_publisher srs_app_rtc_conn.cpp:3582
SrsRtcConnection::add_publisher srs_app_rtc_conn.cpp:2008
SrsRtcServer::do_create_session srs_app_rtc_server.cpp:545
SrsRtcServer::create_session srs_app_rtc_server.cpp:526
SrsGoApiRtcPublish::do_serve_http srs_app_rtc_api.cpp:457
SrsGoApiRtcPublish::serve_http srs_app_rtc_api.cpp:323
SrsHttpServeMux::serve_http srs_http_stack.cpp:727
SrsHttpCorsMux::serve_http srs_http_stack.cpp:875
SrsHttpConn::process_request srs_app_http_conn.cpp:233
SrsHttpConn::process_requests srs_app_http_conn.cpp:206
SrsHttpConn::do_cycle srs_app_http_conn.cpp:160
SrsHttpConn::cycle srs_app_http_conn.cpp:105
SrsFastCoroutine::cycle srs_app_st.cpp:272
SrsFastCoroutine::pfn srs_app_st.cpp:287
_st_thread_main sched.c:363
st_thread_create sched.c:694


2. srs\_app\_souce.cpp:1273 SrsRtmpFromRtcBridger::SrsRtmpFromRtcBridger



SrsRtmpFromRtcBridger::SrsRtmpFromRtcBridger srs_app_rtc_source.cpp:1273
SrsRtcPublishStream::initialize srs_app_rtc_conn.cpp:1204
SrsRtcConnection::create_publisher srs_app_rtc_conn.cpp:3582
SrsRtcConnection::add_publisher srs_app_rtc_conn.cpp:2008
SrsRtcServer::do_create_session srs_app_rtc_server.cpp:545
SrsRtcServer::create_session srs_app_rtc_server.cpp:526
SrsGoApiRtcPublish::do_serve_http srs_app_rtc_api.cpp:457
SrsGoApiRtcPublish::serve_http srs_app_rtc_api.cpp:323
SrsHttpServeMux::serve_http srs_http_stack.cpp:727
SrsHttpCorsMux::serve_http srs_http_stack.cpp:875
SrsHttpConn::process_request srs_app_http_conn.cpp:233
SrsHttpConn::process_requests srs_app_http_conn.cpp:206
SrsHttpConn::do_cycle srs_app_http_conn.cpp:160
SrsHttpConn::cycle srs_app_http_conn.cpp:105
SrsFastCoroutine::cycle srs_app_st.cpp:272
SrsFastCoroutine::pfn srs_app_st.cpp:287
_st_thread_main sched.c:363
st_thread_create sched.c:694


fetch\_or\_create创建了rtmp对象,SrsRtmpFromRtcBridger将其从rtc转化成rtmp,其转化过程为  
 SrsRtcSource -> SrsRtmpFromRtcBridger -> SrsLiveSource



bool rtc_to_rtmp = _srs_config->get\_rtc\_to\_rtmp(req_->vhost);
if (rtc_to_rtmp) {
    if ((err = _srs_sources->fetch\_or\_create(r, _srs_hybrid->srs()->instance(), &rtmp)) != srs_success) {
        return srs\_error\_wrap(err, "create source");
    }

    // Disable GOP cache for RTC2RTMP bridger, to keep the streams in sync,
    // especially for stream merging.
    rtmp->set\_cache(false);

    SrsRtmpFromRtcBridger \*bridger = new SrsRtmpFromRtcBridger(rtmp);
    if ((err = bridger->initialize(r)) != srs_success) {
        srs\_freep(bridger);
        return srs\_error\_wrap(err, "create bridger");
    }
	
    //设置桥接器
    source->set\_bridger(bridger);
}

然后我们再在下面打下断点


1. srs\_app\_rtc\_source.cpp大约1560 SrsRtmpFromRtcBridger::packet\_video\_rtmp



SrsRtmpFromRtcBridger::packet_video_rtmp srs_app_rtc_source.cpp:1561
SrsRtmpFromRtcBridger::packet_video srs_app_rtc_source.cpp:1451
SrsRtmpFromRtcBridger::on_rtp srs_app_rtc_source.cpp:1347
SrsRtcSource::on_rtp srs_app_rtc_source.cpp:632
SrsRtcVideoRecvTrack::on_rtp srs_app_rtc_source.cpp:2520
SrsRtcPublishStream::do_on_rtp_plaintext srs_app_rtc_conn.cpp:1451
SrsRtcPublishStream::on_rtp_plaintext srs_app_rtc_conn.cpp:1419
SrsRtcPublishStream::on_rtp srs_app_rtc_conn.cpp:1386
SrsRtcConnection::on_rtp srs_app_rtc_conn.cpp:2276
SrsRtcServer::on_udp_packet srs_app_rtc_server.cpp:462
SrsUdpMuxListener::cycle srs_app_listener.cpp:620
SrsFastCoroutine::cycle srs_app_st.cpp:272
SrsFastCoroutine::pfn srs_app_st.cpp:287
_st_thread_main sched.c:363
st_thread_create sched.c:694
SrsFileLog::info srs_app_log.cpp:118
0x00005555560ed6f0
__libc_calloc 0x00007ffff7af3d15
st_cond_new sync.c:157
st_thread_create sched.c:702
SrsFastCoroutine::start srs_app_st.cpp:180
SrsSTCoroutine::start srs_app_st.cpp:95
SrsResourceManager::start srs_app_conn.cpp:72
0x000055555613c0c0
0x00007fffffffe060
SrsWaitGroup::wait srs_app_st.cpp:328
SrsHybridServer::run srs_app_hybrid.cpp:281
run_hybrid_server srs_main_server.cpp:477
run_directly_or_daemon srs_main_server.cpp:407
do_main srs_main_server.cpp:198
main srs_main_server.cpp:207
__libc_start_main 0x00007ffff7a7c0b3
_start 0x0000555555809a1e


2. srs\_app\_rtc\_source.cpp大约1465 SrsRtmpFromRtcBridger::packet\_video\_key\_frame



SrsRtmpFromRtcBridger::packet_video_key_frame srs_app_rtc_source.cpp:1466
SrsRtmpFromRtcBridger::packet_video srs_app_rtc_source.cpp:1433
SrsRtmpFromRtcBridger::on_rtp srs_app_rtc_source.cpp:1347
SrsRtcSource::on_rtp srs_app_rtc_source.cpp:632
SrsRtcVideoRecvTrack::on_rtp srs_app_rtc_source.cpp:2520
SrsRtcPublishStream::do_on_rtp_plaintext srs_app_rtc_conn.cpp:1451
SrsRtcPublishStream::on_rtp_plaintext srs_app_rtc_conn.cpp:1419
SrsRtcPublishStream::on_rtp srs_app_rtc_conn.cpp:1386
SrsRtcConnection::on_rtp srs_app_rtc_conn.cpp:2276
SrsRtcServer::on_udp_packet srs_app_rtc_server.cpp:462
SrsUdpMuxListener::cycle srs_app_listener.cpp:620
SrsFastCoroutine::cycle srs_app_st.cpp:272
SrsFastCoroutine::pfn srs_app_st.cpp:287
_st_thread_main sched.c:363
st_thread_create sched.c:694
SrsFileLog::info srs_app_log.cpp:118
0x00005555560ed6f0
__libc_calloc 0x00007ffff7af3d15
st_cond_new sync.c:157
st_thread_create sched.c:702
SrsFastCoroutine::start srs_app_st.cpp:180
SrsSTCoroutine::start srs_app_st.cpp:95
SrsResourceManager::start srs_app_conn.cpp:72
0x000055555613c0c0
0x00007fffffffe060
SrsWaitGroup::wait srs_app_st.cpp:328
SrsHybridServer::run srs_app_hybrid.cpp:281
run_hybrid_server srs_main_server.cpp:477
run_directly_or_daemon srs_main_server.cpp:407
do_main srs_main_server.cpp:198
main srs_main_server.cpp:207
__libc_start_main 0x00007ffff7a7c0b3
_start 0x0000555555809a1e



srs_error_t SrsRtmpFromRtcBridger::packet_video_key_frame(SrsRtpPacket* pkt)
{
srs_error_t err = srs_success;

// TODO: handle sps and pps in 2 rtp packets
SrsRtpSTAPPayload\* stap_payload = dynamic\_cast<SrsRtpSTAPPayload\*>(pkt->payload());
if (stap_payload) {
    SrsSample\* sps = stap_payload->get\_sps();
    SrsSample\* pps = stap_payload->get\_pps();
    if (NULL == sps || NULL == pps) {
        return srs\_error\_new(ERROR_RTC_RTP_MUXER, "no sps or pps in stap-a rtp. sps: %p, pps:%p", sps, pps);
    } else {
        //type\_codec1 + avc\_type + composition time + fix header + count of sps + len of sps + sps + count of pps + len of pps + pps
        int nb_payload = 1 + 1 + 3 + 5 + 1 + 2 + sps->size + 1 + 2 + pps->size;
        SrsCommonMessage rtmp;
        rtmp.header.initialize\_video(nb_payload, pkt->get\_avsync\_time(), 1);
        rtmp.create\_payload(nb_payload);
        rtmp.size = nb_payload;
        SrsBuffer payload(rtmp.payload, rtmp.size);
        //TODO: call api
        payload.write\_1bytes(0x17);// type(4 bits): key frame; code(4bits): avc
        payload.write\_1bytes(0x0); // avc\_type: sequence header
        payload.write\_1bytes(0x0); // composition time
        payload.write\_1bytes(0x0);
        payload.write\_1bytes(0x0);
        payload.write\_1bytes(0x01); // version
        payload.write\_1bytes(sps->bytes[1]);
        payload.write\_1bytes(sps->bytes[2]);
        payload.write\_1bytes(sps->bytes[3]);
        payload.write\_1bytes(0xff);
        payload.write\_1bytes(0xe1);
        payload.write\_2bytes(sps->size);
        payload.write\_bytes(sps->bytes, sps->size);
        payload.write\_1bytes(0x01);
        payload.write\_2bytes(pps->size);
        payload.write\_bytes(pps->bytes, pps->size);
        if ((err = source_->on\_video(&rtmp)) != srs_success) { 
            return err;
        }
    }
}

if (-1 == rtp_key_frame_ts_) {
    rtp_key_frame_ts_ = pkt->header.get\_timestamp();
    header_sn_ = pkt->header.get\_sequence();
    lost_sn_ = header_sn_ + 1;
    // Received key frame and clean cache of old p frame pkts
    clear\_cached\_video();
    srs\_trace("set ts=%u, header=%hu, lost=%hu", (uint32\_t)rtp_key_frame_ts_, header_sn_, lost_sn_);
} else if (rtp_key_frame_ts_ != pkt->header.get\_timestamp()) {
    //new key frame, clean cache
    int64\_t old_ts = rtp_key_frame_ts_;
    uint16\_t old_header_sn = header_sn_;
    uint16\_t old_lost_sn = lost_sn_;
    rtp_key_frame_ts_ = pkt->header.get\_timestamp();
    header_sn_ = pkt->header.get\_sequence();
    lost_sn_ = header_sn_ + 1;
    clear\_cached\_video();
    srs\_warn("drop old ts=%u, header=%hu, lost=%hu, set new ts=%u, header=%hu, lost=%hu",
        (uint32\_t)old_ts, old_header_sn, old_lost_sn, (uint32\_t)rtp_key_frame_ts_, header_sn_, lost_sn_);
}

uint16\_t index = cache\_index(pkt->header.get\_sequence());
cache_video_pkts_[index].in_use = true;
srs\_freep(cache_video_pkts_[index].pkt);
cache_video_pkts_[index].pkt = pkt;
cache_video_pkts_[index].sn = pkt->header.get\_sequence();
cache_video_pkts_[index].ts = pkt->get\_avsync\_time();
cache_video_pkts_[index].rtp_ts = pkt->header.get\_timestamp();

int32\_t sn = lost_sn_;
uint16\_t tail_sn = 0;
if (srs\_rtp\_seq\_distance(header_sn_, pkt->header.get\_sequence()) < 0){
    // When receive previous pkt in the same frame, update header sn;
    header_sn_ = pkt->header.get\_sequence();
    sn = find\_next\_lost\_sn(header_sn_, tail_sn);
} else if (lost_sn_ == pkt->header.get\_sequence()) {
    sn = find\_next\_lost\_sn(lost_sn_, tail_sn);
}

if (-1 == sn) {
    if (check\_frame\_complete(header_sn_, tail_sn)) {
        if ((err = packet\_video\_rtmp(header_sn_, tail_sn)) != srs_success) {
            err = srs\_error\_wrap(err, "fail to packet key frame");
        }
    }
} else if (-2 == sn) {
    return srs\_error\_new(ERROR_RTC_RTP_MUXER, "video cache is overflow");
} else {
    lost_sn_ = (uint16\_t)sn;
}

return err;

}


3. 音频转码 srs\_app\_rtc\_codec.cpp 大约156行 SrsAudioTranscoder::transcode



SrsAudioTranscoder::transcode srs_app_rtc_codec.cpp:157
SrsRtmpFromRtcBridger::transcode_audio srs_app_rtc_source.cpp:1388
SrsRtmpFromRtcBridger::on_rtp srs_app_rtc_source.cpp:1345
SrsRtcSource::on_rtp srs_app_rtc_source.cpp:632
SrsRtcAudioRecvTrack::on_rtp srs_app_rtc_source.cpp:2462
SrsRtcPublishStream::do_on_rtp_plaintext srs_app_rtc_conn.cpp:1446
SrsRtcPublishStream::on_rtp_plaintext srs_app_rtc_conn.cpp:1419
SrsRtcPublishStream::on_rtp srs_app_rtc_conn.cpp:1386
SrsRtcConnection::on_rtp srs_app_rtc_conn.cpp:2276
SrsRtcServer::on_udp_packet srs_app_rtc_server.cpp:462
SrsUdpMuxListener::cycle srs_app_listener.cpp:620
SrsFastCoroutine::cycle srs_app_st.cpp:272
SrsFastCoroutine::pfn srs_app_st.cpp:287
_st_thread_main sched.c:363
st_thread_create sched.c:694
SrsFileLog::info srs_app_log.cpp:118
0x00005555560ed6f0
__libc_calloc 0x00007ffff7af3d15
st_cond_new sync.c:157
st_thread_create sched.c:702
SrsFastCoroutine::start srs_app_st.cpp:180
SrsSTCoroutine::start srs_app_st.cpp:95
SrsResourceManager::start srs_app_conn.cpp:72
0x000055555613c0c0
0x00007fffffffe060
SrsWaitGroup::wait srs_app_st.cpp:328
SrsHybridServer::run srs_app_hybrid.cpp:281
run_hybrid_server srs_main_server.cpp:477
run_directly_or_daemon srs_main_server.cpp:407
do_main srs_main_server.cpp:198
main srs_main_server.cpp:207
__libc_start_main 0x00007ffff7a7c0b3
_start 0x0000555555809a1e


4. 音频包分发 srs\_app\_rtc\_source.cpp:1360 SrsRtmpFromRtcBridger::transcode\_audio



SrsRtmpFromRtcBridger::transcode_audio srs_app_rtc_source.cpp:1360
SrsRtmpFromRtcBridger::on_rtp srs_app_rtc_source.cpp:1345
SrsRtcSource::on_rtp srs_app_rtc_source.cpp:632
SrsRtcAudioRecvTrack::on_rtp srs_app_rtc_source.cpp:2462
SrsRtcPublishStream::do_on_rtp_plaintext srs_app_rtc_conn.cpp:1446
SrsRtcPublishStream::on_rtp_plaintext srs_app_rtc_conn.cpp:1419
SrsRtcPublishStream::on_rtp srs_app_rtc_conn.cpp:1386
SrsRtcConnection::on_rtp srs_app_rtc_conn.cpp:2276
SrsRtcServer::on_udp_packet srs_app_rtc_server.cpp:462
SrsUdpMuxListener::cycle srs_app_listener.cpp:620
SrsFastCoroutine::cycle srs_app_st.cpp:272
SrsFastCoroutine::pfn srs_app_st.cpp:287
_st_thread_main sched.c:363
st_thread_create sched.c:694
SrsFileLog::info srs_app_log.cpp:118
0x00005555560ed6f0
__libc_calloc 0x00007ffff7af3d15
st_cond_new sync.c:157
st_thread_create sched.c:702
SrsFastCoroutine::start srs_app_st.cpp:180
SrsSTCoroutine::start srs_app_st.cpp:95
SrsResourceManager::start srs_app_conn.cpp:72
0x000055555613c0c0
0x00007fffffffe060
SrsWaitGroup::wait srs_app_st.cpp:328
SrsHybridServer::run srs_app_hybrid.cpp:281
run_hybrid_server srs_main_server.cpp:477
run_directly_or_daemon srs_main_server.cpp:407
do_main srs_main_server.cpp:198
main srs_main_server.cpp:207
__libc_start_main 0x00007ffff7a7c0b3
_start 0x0000555555809a1e



srs_error_t SrsRtmpFromRtcBridger::transcode_audio(SrsRtpPacket *pkt)
{
srs_error_t err = srs_success;

// to common message.
uint32\_t ts = pkt->get\_avsync\_time();
if (is_first_audio) {
    int header_len = 0;
    uint8\_t\* header = NULL;
    codec_->aac\_codec\_header(&header, &header_len);

    SrsCommonMessage out_rtmp;
    packet\_aac(&out_rtmp, (char \*)header, header_len, ts, is_first_audio);

    if ((err = source_->on\_audio(&out_rtmp)) != srs_success) { //接收

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

mmonMessage out_rtmp;
packet_aac(&out_rtmp, (char *)header, header_len, ts, is_first_audio);

    if ((err = source_->on\_audio(&out_rtmp)) != srs_success) { //接收

[外链图片转存中…(img-JYhzpUDx-1715404158232)]
[外链图片转存中…(img-0jfwPg5v-1715404158232)]
[外链图片转存中…(img-mYS2ug4H-1715404158233)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

  • 29
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值