网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
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) { //接收
return srs\_error\_wrap(err, "source on audio");
}
is_first_audio = false;
}
std::vector<SrsAudioFrame \*> out_pkts;
SrsRtpRawPayload \*payload = dynamic\_cast<SrsRtpRawPayload \*>(pkt->payload());
SrsAudioFrame frame;
frame.add\_sample(payload->payload, payload->nn_payload);
frame.dts = ts;
frame.cts = 0;
err = codec_->transcode(&frame, out_pkts); // 转码
if (err != srs_success) {
return err;
}
for (std::vector<SrsAudioFrame \*>::iterator it = out_pkts.begin(); it != out_pkts.end(); ++it) {
SrsCommonMessage out_rtmp;
out_rtmp.header.timestamp = (\*it)->dts;
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
(std::vector<SrsAudioFrame *>::iterator it = out_pkts.begin(); it != out_pkts.end(); ++it) {
SrsCommonMessage out_rtmp;
out_rtmp.header.timestamp = (*it)->dts;
[外链图片转存中…(img-KhMTrFLr-1715658499800)]
[外链图片转存中…(img-ywxX1ftX-1715658499801)]
[外链图片转存中…(img-KCD7XYwi-1715658499801)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新