推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习
测试环境搭建
Clion运行srs
详情请参考我的另一篇文章Windows11+wsl+clion调试SRS
![image.png](https://img-blog.csdnimg.cn/img_convert/4af6e1c0a0394f50fb9ebb45f68a3fe1.png#clientId=u325e4c65-4edd-4&from=paste&height=1142&id=u000229b7&margin=[object Object]&name=image.png&originHeight=1142&originWidth=1908&originalType=binary&ratio=1&size=299871&status=done&style=none&taskId=u5e833296-b4c2-4b57-abe0-c3295f1b042&width=1908)
goland运行signaling
srs有自带一个webrtc的信令服务器使用go语言编写的,测试可以使用,如果实际生产环境不推荐使用。其源码位于srs/trunk/3rdparty/signaling。使用goland打开,然后找到main.go
运行即可。
推荐将其输出目录更改到当前目录,方便更改前端代码
![image.png](https://img-blog.csdnimg.cn/img_convert/1f4a52422cc43e47e7a4ad53187c9abe.png#clientId=u325e4c65-4edd-4&from=paste&height=677&id=u8485e6d8&margin=[object Object]&name=image.png&originHeight=677&originWidth=1044&originalType=binary&ratio=1&size=60419&status=done&style=none&taskId=u539779be-a745-4041-9ebc-a61bee54716&width=1044)
运行后如图
![image.png](https://img-blog.csdnimg.cn/img_convert/b3abbd26c640774ee6a437e86cde9249.png#clientId=u325e4c65-4edd-4&from=paste&height=1196&id=u83caef91&margin=[object Object]&name=image.png&originHeight=1196&originWidth=1920&originalType=binary&ratio=1&size=317595&status=done&style=none&taskId=ud5b158f3-3814-4d09-a41e-78eb3688203&width=1920)
访问demo前端
信令有运行了一个web服务器,其端口为1989,所以我们直接访问1989即可,注意如果使用ip访问由于谷歌浏览器的限制必须要使用https,如果使用http我们需要将其加入到白名单中。
- 在浏览器中输入
chrome://flags
- 找到
**Insecure origins treated as secure**
将白名单的url添加并设置为enabled
![image.png](https://img-blog.csdnimg.cn/img_convert/98523879595a3bd502f05a0e842ececa.png#clientId=u325e4c65-4edd-4&from=paste&height=518&id=u49775d81&margin=[object Object]&name=image.png&originHeight=518&originWidth=1502&originalType=binary&ratio=1&size=76804&status=done&style=none&taskId=u587163a2-1f6f-4eef-b022-48beeb0957e&width=1502)
然后访问localhost:1989
或ip:1989
选择一对一通话进入,注意这里如果使用wsl的话需要将srs的ip设置成wsl的ip,然后点击开始通话就可以通话了。
![image.png](https://img-blog.csdnimg.cn/img_convert/31130fa85be1ace3229715cbe7457dd6.png#clientId=u325e4c65-4edd-4&from=paste&height=492&id=u4c07b779&margin=[object Object]&name=image.png&originHeight=492&originWidth=1302&originalType=binary&ratio=1&size=155948&status=done&style=none&taskId=u3f6e8263-8362-488a-9da4-c7f5cb880e1&width=1302)
WebRTC转rtmp
webrtc转rtmp主要是:
- 编码转化,webrtc使用的音频编码是Opus,而rtmp使用的是aac则需要将opus转成aac
- 协议转化,将RTP转RTMP封装
注:SRS目前在高码率转化下后RTMP会卡顿:https://github.com/ossrs/srs/issues/2677
WebRTC推流流程
开启http监听listen_api
srs_error_t SrsRtcServer::listen_api()
{
srs_error_t err = srs_success;
// TODO: FIXME: Fetch api from hybrid manager, not from SRS.
SrsHttpServeMux* http_api_mux = _srs_hybrid->srs()->instance()->api_server();
if ((err = http_api_mux->handle("/rtc/v1/play/", new SrsGoApiRtcPlay(this))) != srs_success) {
return srs_error_wrap(err, "handle play");
}
if ((err = http_api_mux->handle("/rtc/v1/publish/", new SrsGoApiRtcPublish(this))) != srs_success) {
return srs_error_wrap(err, "handle publish");
}
...
return err;
}
src/app/srs_app_rtc_api.cpp大约331行SrsGoApiRtcPublish::do_serve_http:处理客户端请求的SDP,并创建RTC连接(SrsRtcConnection)
srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, SrsJsonObject* res)
{
srs_error_t err = srs_success;
...
// 解析SDP
if ((err = ruc.remote_sdp_.parse(remote_sdp_str)) != srs_success) {
return srs_error_wrap(err, "parse sdp failed: %s", remote_sdp_str.c_str());
}
if ((err = check_remote_sdp(ruc.remote_sdp_)) != srs_success) {
return srs_error_wrap(err, "remote sdp check failed");
}
// 设置响应SDP
SrsSdp local_sdp;
// Config for SDP and session.
local_sdp.session_config_.dtls_role = _srs_config->get_rtc_dtls_role(ruc.req_->vhost);
local_sdp.session_config_.dtls_version = _srs_config->get_rtc_dtls_version(ruc.req_->vhost);
// Whether enabled.
bool server_enabled = _srs_config->get_rtc_server_enabled();
bool rtc_enabled = _srs_config->get_rtc_enabled(ruc.req_->vhost);
if (server_enabled && !rtc_enabled) {
srs_warn("RTC disabled in vhost %s", ruc.req_->vhost.c_str());
}
if (!server_enabled || !rtc_enabled) {
return srs_error_new(ERROR_RTC_DISABLED, "Disabled server=%d, rtc=%d, vhost=%s",
server_enabled, rtc_enabled, ruc.req_->vhost.c_str());
}
// Whether RTC stream is active.
bool is_rtc_stream_active = false;
if (true) {
SrsRtcSource* source = _srs_rtc_sources->fetch(ruc.req_);
is_rtc_stream_active = (source && !source->can_publish());
}
// For RTMP to RTC, fail if disabled and RTMP is active, see https://github.com/ossrs/srs/issues/2728
if (!is_rtc_stream_active && !_srs_config->get_rtc_from_rtmp(ruc.req_->vhost)) {
SrsLiveSource* rtmp = _srs_sources->fetch(ruc.req_);
if (rtmp && !rtmp->inactive()) {
return srs_error_new(ERROR_RTC_DISABLED, "Disabled rtmp_to_rtc of %s, see #2728", ruc.req_->vhost.c_str());
}
}
// 创建RTC会话
SrsRtcConnection* session = NULL;
if ((err = server_->create_session(&ruc, local_sdp, &session)) != srs_success) {
return srs_error_wrap(err, "create session, dtls=%u, srtp=%u, eip=%s", ruc.dtls_, ruc.srtp_, eip.c_str());
}
...
return err;
}
src/app/srs_app_rtc.cpp大约53行SrsRtcServer::do_create_session
srs_error_t SrsRtcServer::do_create_session(SrsRtcUserConfig* ruc, SrsSdp& local_sdp, SrsRtcConnection* session)
{
srs_error_t err = srs_success;
SrsRequest* req = ruc->req_;
// first add publisher/player for negotiate sdp media info
if (ruc->publish_) {
// 创建推流
if ((err = session->add_publisher(ruc, local_sdp)) != srs_success) {
return srs_error_wrap(err, "add publisher");
}
} else {
if ((err = session->add_player(ruc, local_sdp)) != srs_success) {
return srs_error_wrap(err, "add player");
}
}
// All tracks default as inactive, so we must enable them.
session->set_all_tracks_status(req->get_stream_url(), ruc->publish_, true);
std::string local_pwd = srs_random_str(32);
std::string local_ufrag = "";
// TODO: FIXME: Rename for a better name, it's not an username.
std::string username = "";
while (true) {
local_ufrag = srs_random_str(8);
username = local_ufrag + ":" + ruc->remote_sdp_.get_ice_ufrag();
if (!_srs_rtc_manager->find_by_name(username)) {
break;
}
}
local_sdp.set_ice_ufrag(local_ufrag);
local_sdp.set_ice_pwd(local_pwd);
local_sdp.set_fingerprint_algo("sha-256");
local_sdp.set_fingerprint(_srs_rtc_dtls_certificate->get_fingerprint());
// We allows to mock the eip of server.
if (true) {
int listen_port = _srs_config->get_rtc_server_listen();
set<string> candidates = discover_candidates(ruc);
for (set<string>::iterator it = candidates.begin(); it != candidates.end(); ++it) {
string hostname; int port = listen_port;
srs_parse_hostport(*it, hostname,port);
local_sdp.add_candidate(hostname, port, "host");
}
vector<string> v = vector<string>(candidates.begin(), candidates.end());
srs_trace("RTC: Use candidates %s", srs_join_vector_string(v, ", ").c_str());
}
// Setup the negotiate DTLS by config.
local_sdp.session_negotiate_ = local_sdp.session_config_;
// Setup the negotiate DTLS role.
if (ruc->remote_sdp_.get_dtls_role() == "active") {
local_sdp.session_negotiate_.dtls_role = "passive";
} else if (ruc->remote_sdp_.get_dtls_role() == "passive") {
local_sdp.session_negotiate_.dtls_role = "active";
} else if (ruc->remote_sdp_.get_dtls_role() == "actpass") {
local_sdp.session_negotiate_.dtls_role = local_sdp.session_config_.dtls_role;
} else {
// @see: https://tools.ietf.org/html/rfc4145#section-4.1
// The default value of the setup attribute in an offer/answer exchange
// is 'active' in the offer and 'passive' in the answer.
local_sdp.session_negotiate_.dtls_role = "passive";
}
local_sdp.set_dtls_role(local_sdp.session_negotiate_.dtls_role);
session->set_remote_sdp(ruc->remote_sdp_);
// We must setup the local SDP, then initialize the session object.
session->set_local_sdp(local_sdp);
session->set_state(WAITING_STUN);
// Before session initialize, we must setup the local SDP.
if ((err = session->initialize(req, ruc->dtls_, ruc->srtp_, username)) != srs_success) {
return srs_error_wrap(err, "init");
}
// We allows username is optional, but it never empty here.
_srs_rtc_manager->add_with_name(username, session);
return err;
}
src/app/srs_app_rtc_conn.cpp大约1970行 SrsRtcConnection::add_publisher 进行媒体协商,并创建SrsRtcSource对象和SrsRtcPublisherStream对象
srs_error_t SrsRtcConnection::add_publisher(SrsRtcUserConfig* ruc, SrsSdp& local_sdp)
{
srs_error_t err = srs_success;
SrsRequest* req = ruc->req_;
SrsRtcSourceDescription* stream_desc = new SrsRtcSourceDescription();
SrsAutoFree(SrsRtcSourceDescription, stream_desc);
// 媒体协商
// TODO: FIXME: Change to api of stream desc.
if ((err = negotiate_publish_capability(ruc, stream_desc)) != srs_success) {
return srs_error_wrap(err, "publish negotiate");
}
//生成响应SDP
if ((err = generate_publish_local_sdp(req, local_sdp, stream_desc, ruc->remote_sdp_.is_unified())) != srs_success) {
return srs_error_wrap(err, "generate local sdp");
}
SrsRtcSource* source = NULL;
//创建SrsRtcSource对象
if ((err = _srs_rtc_sources->fetch_or_create(req, &source)) != srs_success) {
return srs_error_wrap(err, "create source");
}
// When SDP is done, we set the stream to create state, to prevent multiple publisher.
// @note Here, we check the stream again.
if (!source->can_publish()) {
return srs_error_new(ERROR_RTC_SOURCE_BUSY, "stream %s busy", req->get_stream_url().c_str());
}
source->set_stream_created();
// Apply the SDP to source.
source->set_stream_desc(stream_desc);
// 创建推流对象用于接收流
// TODO: FIXME: What happends when error?
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
断点:
- 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
- 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);
}
然后我们再在下面打下断点
- 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
<unknown> 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
<unknown> 0x000055555613c0c0
<unknown> 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_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
<unknown> 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
<unknown> 0x000055555613c0c0
<unknown> 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;
}
- 音频转码 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
<unknown> 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
<unknown> 0x000055555613c0c0
<unknown> 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_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
<unknown> 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
<unknown> 0x000055555613c0c0
<unknown> 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;
packet_aac(&out_rtmp, (*it)->samples[0].bytes, (*it)->samples[0].size, ts, is_first_audio);
if ((err = source_->on_audio(&out_rtmp)) != srs_success) { //转码后的数据
err = srs_error_wrap(err, "source on audio");
break;
}
}
codec_->free_frames(out_pkts);
return err;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/137639.html