SRS流媒体服务器之HTTP-FLV框架分析(2)
nanshan 2024-12-06 17:58 7 浏览 0 评论
0.引言
阅读本文前,可以先阅读前面的文章,能够帮助你更好理解本篇文章。文章列表如下:
1.断点调试,源码分析
关于配置文件源码,在文件srs_app_config.cpp,源码初始化,如下:
bool SrsConfig::get_vhost_http_remux_enabled(string vhost)
{
static bool DEFAULT = false;
SrsConfDirective* conf = get_vhost(vhost);
if (!conf) {
return DEFAULT;
}
conf = conf->get("http_remux");
if (!conf) {
return DEFAULT;
}
conf = conf->get("enabled");
if (!conf || conf->arg0().empty()) {
return DEFAULT;
}
return SRS_CONF_PERFER_FALSE(conf->arg0());
}
在SRS流媒体服务器中,启动gdb调试。输入命令:
gdb ./objs/srs
界面如下:
继续输入命令:
b SrsConfig::get_vhost_http_remux_enabled(string vhost)
界面如下:
继续设置参数,输入命令:
set args -c ./conf/srs.conf
界面如下:
继续输入命令:
r
到这里就可以运行起来了。
根据配置?件进?初始化
函数调用关系是从下至上(即从7到0),
0 SrsHttpStreamServer::initialize_flv_entry (this=0xa11fd0, vhost="__defaultVhost__")
at src/app/srs_app_http_stream.cpp:1163
1 0x00000000005028d3 in SrsHttpStreamServer::initialize_flv_streaming (this=0xa11fd0)
at src/app/srs_app_http_stream.cpp:1154
2 0x0000000000500a2a in SrsHttpStreamServer::initialize (this=0xa11fd0) at
src/app/srs_app_http_stream.cpp:873
3 0x0000000000561eb7 in SrsHttpServer::initialize (this=0xa11e00) at
src/app/srs_app_http_conn.cpp:279
4 0x00000000004c84c0 in SrsServer::initialize (this=0xa11ea0, ch=0x0) at
src/app/srs_app_server.cpp:757
5 0x00000000005bcb57 in run (svr=0xa11ea0) at src/main/srs_main_server.cpp:395
6 0x00000000005bb769 in do_main (argc=3, argv=0x7fffffffe4f8) at
src/main/srs_main_server.cpp:184
7 0x00000000005bb8ad in main (argc=3, argv=0x7fffffffe4f8) at
src/main/srs_main_server.cpp:192
在函数SrsHttpStreamServer::initialize_flv_entry(std::string vhost)内部,回调了配置文件的函数get_vhost_http_remux_enabled(vhost),这个回调函数会检测是否支持,如果不支持,就直接返回。
srs_error_t SrsHttpStreamServer::initialize_flv_entry(std::string vhost)
{
srs_error_t err = srs_success;
if (!_srs_config->get_vhost_http_remux_enabled(vhost)) {
return err;
}
SrsLiveEntry* entry = new SrsLiveEntry(_srs_config->get_vhost_http_remux_mount(vhost));
tflvs[vhost] = entry;
srs_trace("http flv live stream, vhost=%s, mount=%s", vhost.c_str(), entry->mount.c_str());
return err;
}
继续输入命令:
b srs_app_http_stream.cpp:1173
界面如下:
继续输入命令:
b SrsLiveEntry::SrsLiveEntry(std::string m)
界面如下:
可以从源码了解到,不仅仅支持flv,ts,还有mp3,AAC等格式。SrsLiveEntry表示是一一对应关系,url与source的映射关系。对应源码如下:
SrsLiveEntry::SrsLiveEntry(std::string m)
{
mount = m;
stream = NULL;
cache = NULL;
req = NULL;
source = NULL;
//根据mount的值,?如[vhos t]/[app]/[stream].flv
std::string ext = srs_path_filext(m);
_is_flv = (ext == ".flv");
_is_ts = (ext == ".ts");
_is_mp3 = (ext == ".mp3");
_is_aac = (ext == ".aac");
}
连续输入命令:
n
界面如下:
继续输入命令:
print *conf
界面如下:
可以反复的使用命令n和print *conf,观打印参数的变化。
继续输入命令:
finish
n
然后到指定的断点出去运行。界面如下:
继续输入命令:
C
这时就会进入SrsLiveEntry::SrsLiveEntry
界面如下:
再连续输入命令:
n
输入命令:
print ext
finish
界面如下:
输入命令:
print vhost
界面如下:
关于SRS流媒体服务器的配置文件,是可以修改为其它格式:
连续输入命令:
n
查看后缀,输入命令:
print ext
界面如下:
再输入命令:
c
就可以运行起来:
注意:在这里之前,需要开启推送RTMP流。拉流的时候,由于在配置文件没有设置其它格式,只设置了aac,就只能拉取aac流。
也可以修改为mp3(会涉及到转码,可能会更加复杂点),如下界面:
继续输入命令:
c
综上所述,http不仅仅?持FLV的拉流,还支持flv,ts,aac,mp3的使用。如下配置文件:
http_remux {
enabled on;
mount [vhost]/[app]/[stream].flv;
hstrs on;
}
每个播放的SrsFlvStreamEncoder是独?。根据不同的后缀名,会有不同的Encoder,默认支持的有SrsFlvStreamEncoder()、SrsAacStreamEncoder()、SrsMp3StreamEncoder()、SrsTsStreamEncoder。SrsLiveEntry表示一一对应,主要是供http拉流客户端访问,即同一路的多个拉流客户端共用一个SrsLiveStream对象。源码如下:
srs_error_t SrsLiveStream::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
{
srs_error_t err = srs_success;
string enc_desc;
ISrsBufferEncoder* enc = NULL;
srs_assert(entry);
if (srs_string_ends_with(entry->pattern, ".flv")) {
w->header()->set_content_type("video/x-flv");
enc_desc = "FLV";
enc = new SrsFlvStreamEncoder();
} else if (srs_string_ends_with(entry->pattern, ".aac")) {
w->header()->set_content_type("audio/x-aac");
enc_desc = "AAC";
enc = new SrsAacStreamEncoder();
} else if (srs_string_ends_with(entry->pattern, ".mp3")) {
w->header()->set_content_type("audio/mpeg");
enc_desc = "MP3";
enc = new SrsMp3StreamEncoder();
} else if (srs_string_ends_with(entry->pattern, ".ts")) {
w->header()->set_content_type("video/MP2T");
enc_desc = "TS";
enc = new SrsTsStreamEncoder();
} else {
return srs_error_new(ERROR_HTTP_LIVE_STREAM_EXT, "invalid pattern=%s", entry->pattern.c_str());
}
SrsAutoFree(ISrsBufferEncoder, enc);
// Enter chunked mode, because we didn't set the content-length.
w->write_header(SRS_CONSTS_HTTP_OK);
// create consumer of souce, ignore gop cache, use the audio gop cache.
SrsConsumer* consumer = NULL;
if ((err = source->create_consumer(NULL, consumer, true, true, !enc->has_cache())) != srs_success) {
return srs_error_wrap(err, "create consumer");
}
SrsAutoFree(SrsConsumer, consumer);
srs_verbose("http: consumer created success.");
SrsPithyPrint* pprint = SrsPithyPrint::create_http_stream();
SrsAutoFree(SrsPithyPrint, pprint);
SrsMessageArray msgs(SRS_PERF_MW_MSGS);
// Use receive thread to accept the close event to avoid FD leak.
// @see https://github.com/ossrs/srs/issues/636#issuecomment-298208427
SrsHttpMessage* hr = dynamic_cast<SrsHttpMessage*>(r);
SrsResponseOnlyHttpConn* hc = dynamic_cast<SrsResponseOnlyHttpConn*>(hr->connection());
// update the statistic when source disconveried.
SrsStatistic* stat = SrsStatistic::instance();
if ((err = stat->on_client(_srs_context->get_id(), req, hc, SrsRtmpConnPlay)) != srs_success) {
return srs_error_wrap(err, "stat on client");
}
// the memory writer.
SrsBufferWriter writer(w);
if ((err = enc->initialize(&writer, cache)) != srs_success) {
return srs_error_wrap(err, "init encoder");
}
// if gop cache enabled for encoder, dump to consumer.
if (enc->has_cache()) {
if ((err = enc->dump_cache(consumer, source->jitter())) != srs_success) {
return srs_error_wrap(err, "encoder dump cache");
}
}
SrsFlvStreamEncoder* ffe = dynamic_cast<SrsFlvStreamEncoder*>(enc);
// Set the socket options for transport.
bool tcp_nodelay = _srs_config->get_tcp_nodelay(req->vhost);
if (tcp_nodelay) {
if ((err = hc->set_tcp_nodelay(tcp_nodelay)) != srs_success) {
return srs_error_wrap(err, "set tcp nodelay");
}
}
srs_utime_t mw_sleep = _srs_config->get_mw_sleep(req->vhost);
if ((err = hc->set_socket_buffer(mw_sleep)) != srs_success) {
return srs_error_wrap(err, "set mw_sleep %" PRId64, mw_sleep);
}
SrsHttpRecvThread* trd = new SrsHttpRecvThread(hc);
SrsAutoFree(SrsHttpRecvThread, trd);
if ((err = trd->start()) != srs_success) {
return srs_error_wrap(err, "start recv thread");
}
srs_trace("FLV %s, encoder=%s, nodelay=%d, mw_sleep=%dms, cache=%d, msgs=%d",
entry->pattern.c_str(), enc_desc.c_str(), tcp_nodelay, srsu2msi(mw_sleep),
enc->has_cache(), msgs.max);
// TODO: free and erase the disabled entry after all related connections is closed.
// TODO: FXIME: Support timeout for player, quit infinite-loop.
while (entry->enabled) {
// Whether client closed the FD.
if ((err = trd->pull()) != srs_success) {
return srs_error_wrap(err, "recv thread");
}
pprint->elapse();
// get messages from consumer.
// each msg in msgs.msgs must be free, for the SrsMessageArray never free them.
int count = 0;
if ((err = consumer->dump_packets(&msgs, count)) != srs_success) {
return srs_error_wrap(err, "consumer dump packets");
}
if (count <= 0) {
// Directly use sleep, donot use consumer wait, because we couldn't awake consumer.
srs_usleep(mw_sleep);
// ignore when nothing got.
continue;
}
if (pprint->can_print()) {
srs_trace("-> " SRS_CONSTS_LOG_HTTP_STREAM " http: got %d msgs, age=%d, min=%d, mw=%d",
count, pprint->age(), SRS_PERF_MW_MIN_MSGS, srsu2msi(mw_sleep));
}
// sendout all messages.
if (ffe) {
err = ffe->write_tags(msgs.msgs, count);
} else {
err = streaming_send_messages(enc, msgs.msgs, count);
}
// free the messages.
for (int i = 0; i < count; i++) {
SrsSharedPtrMessage* msg = msgs.msgs[i];
srs_freep(msg);
}
// check send error code.
if (err != srs_success) {
return srs_error_wrap(err, "send messages");
}
}
// Here, the entry is disabled by encoder un-publishing or reloading,
// so we must return a io.EOF error to disconnect the client, or the client will never quit.
return srs_error_new(ERROR_HTTP_STREAM_EOF, "Stream EOF");
}
为了更详细学习配置文件的不同格式使用,可以在这些函数下,继续使用断点。如下:
断点:SrsHttpCorsMux::initialize
SrsHttpCorsMux::SrsHttpCorsMux
SrsHttpCorsMux::serve_http
断点:SrsLiveStream::do_serve_http
断点:SrsHttpServeMux::hijack
SrsHttpServeMux::SrsHttpServeMux
SrsHttpServeMux::initialize
0 SrsHttpServeMux::hijack (this=0xa11dd0, h=0xa11eb0) at
src/protocol/srs_http_stack.cpp:618
1 0x0000000000500294 in SrsHttpStreamServer::SrsHttpStreamServer (this=0xa11dc0,
svr=0xa103a0,
__in_chrg=<optimized out>, __vtt_parm=<optimized out>) at
src/app/srs_app_http_stream.cpp:841
2 0x0000000000561c45 in SrsHttpServer::SrsHttpServer (this=0xa118f0, svr=0xa103a0)
at src/app/srs_app_http_conn.cpp:260
3 0x00000000004c7675 in SrsServer::SrsServer (this=0xa103a0, __in_chrg=<optimized out>,
__vtt_parm=<optimized out>) at src/app/srs_app_server.cpp:635
4 0x00000000005bb735 in do_main (argc=3, argv=0x7fffffffe4f8) at
src/main/srs_main_server.cpp:181
5 0x00000000005bb8ad in main (argc=3, argv=0x7fffffffe4f8) at
src/main/srs_main_server.cpp:192
0 SrsFlvStreamEncoder::SrsFlvStreamEncoder (this=0xa57820) at
src/app/srs_app_http_stream.cpp:250
1 0x00000000004fe2fd in SrsLiveStream::do_serve_http (this=0xa3da20, w=0x7ffff7eb5bd0,
r=0xa5d7c0) at src/app/srs_app_http_stream.cpp:562
2 0x00000000004fe108 in SrsLiveStream::serve_http (this=0xa3da20, w=0x7ffff7eb5bd0,
r=0xa5d7c0) at src/app/srs_app_http_stream.cpp:544
3 0x000000000049c86f in SrsHttpServeMux::serve_http (this=0xa11fe0, w=0x7ffff7eb5bd0,
r=0xa5d7c0) at src/protocol/srs_http_stack.cpp:711
4 0x0000000000562080 in SrsHttpServer::serve_http (this=0xa11e00, w=0x7ffff7eb5bd0,
r=0xa5d7c0) at src/app/srs_app_http_conn.cpp:300
5 0x000000000049d6be in SrsHttpCorsMux::serve_http (this=0xa52930, w=0x7ffff7eb5bd0,
r=0xa5d7c0) at src/protocol/srs_http_stack.cpp:859
6 0x0000000000561086 in SrsHttpConn::process_request (this=0xa5d120,
w=0x7ffff7eb5bd0, r=0xa5d7c0) at src/app/srs_app_http_conn.cpp:161
7 0x0000000000560ce8 in SrsHttpConn::do_cycle (this=0xa5d120) at
src/app/srs_app_http_conn.cpp:133
8 0x00000000004d10fb in SrsConnection::cycle (this=0xa5d120) at
src/app/srs_app_conn.cpp:171
9 0x0000000000509c88 in SrsSTCoroutine::cycle (this=0xa5d1c0) at
src/app/srs_app_st.cpp:198
10 0x0000000000509cfd in SrsSTCoroutine::pfn (arg=0xa5d1c0) at
src/app/srs_app_st.cpp:213
11 0x00000000005bdd9d in _st_thread_main () at sched.c:337
0 SrsHttpFileServer::serve_http (this=0xa122b0, w=0x7ffff7f42bd0, r=0xa71210)
at src/protocol/srs_http_stack.cpp:360
1 0x000000000049c86f in SrsHttpServeMux::serve_http (this=0xa11ed0, w=0x7ffff7f42bd0,
r=0xa71210) at src/protocol/srs_http_stack.cpp:711
2 0x00000000005620a1 in SrsHttpServer::serve_http (this=0xa118f0, w=0x7ffff7f42bd0,
r=0xa71210) at src/app/srs_app_http_conn.cpp:303 这?是http_static->mux.serve_http(w, r); 不属于直播
的
3 0x000000000049d6be in SrsHttpCorsMux::serve_http (this=0xa840f0, w=0x7ffff7f42bd0,
r=0xa71210) at src/protocol/srs_http_stack.cpp:859
4 0x0000000000561086 in SrsHttpConn::process_request (this=0xa70cc0, w=0x7ffff7f42bd0,
r=0xa71210) at src/app/srs_app_http_conn.cpp:161
5 0x0000000000560ce8 in SrsHttpConn::do_cycle (this=0xa70cc0) at
src/app/srs_app_http_conn.cpp:133
6 0x00000000004d10fb in SrsConnection::cycle (this=0xa70cc0) at
src/app/srs_app_conn.cpp:171
7 0x0000000000509c88 in SrsSTCoroutine::cycle (this=0xa70f00) at
src/app/srs_app_st.cpp:198
8 0x0000000000509cfd in SrsSTCoroutine::pfn (arg=0xa70f00) at
src/app/srs_app_st.cpp:213
9 0x00000000005bdd9d in _st_thread_main () at sched.c:337
断点:SrsLiveStream::do_serve_http
SrsHttpResponseWriter::send_header
输入如下命令:
Breakpoint 2, SrsHttpResponseWriter::write (this=0x7ffff7eb5bd0, data=0x7ffff7eb5470
"FLV\001\005", size=9)
at src/service/srs_service_http_conn.cpp:727
727 {
(gdb) bt
#0 SrsHttpResponseWriter::write (this=0x7ffff7eb5bd0, data=0x7ffff7eb5470 "FLV\001\005",
size=9)
1 0x00000000004fde19 in SrsBufferWriter::write (this=0x7ffff7eb5860, buf=0x7ffff7eb5470,
count=9, pnwrite=0x0) at src/app/srs_app_http_stream.cpp:506
2 0x000000000040e9e1 in SrsFlvTransmuxer::write_header (this=0xa71b10,
flv_header=0x7ffff7eb5470 "FLV\001\005") at src/kernel/srs_kernel_flv.cpp:411
3 0x000000000040e90d in SrsFlvTransmuxer::write_header (this=0xa71b10, has_video=true,
has_audio=true) at src/kernel/srs_kernel_flv.cpp:399
4 0x00000000004fd11a in SrsFlvStreamEncoder::write_header (this=0xa68b10,
has_video=true, has_audio=true) at src/app/srs_app_http_stream.cpp:355
5 0x00000000004fd04f in SrsFlvStreamEncoder::write_tags (this=0xa68b10,
msgs=0xa6da30, count=10) at src/app/srs_app_http_stream.cpp:340
6 0x00000000004ff0dc in SrsLiveStream::do_serve_http (this=0xa3d9d0, w=0x7ffff7eb5bd0,
r=0xa91c00) at src/app/srs_app_http_stream.cpp:677
7 0x00000000004fe108 in SrsLiveStream::serve_http (this=0xa3d9d0, w=0x7ffff7eb5bd0,
r=0xa91c00) at src/app/srs_app_http_stream.cpp:544
8 0x000000000049c86f in SrsHttpServeMux::serve_http (this=0xa11fe0, w=0x7ffff7eb5bd0,
r=0xa91c00) at src/protocol/srs_http_stack.cpp:711
9 0x0000000000562080 in SrsHttpServer::serve_http (this=0xa11e00, w=0x7ffff7eb5bd0,
r=0xa91c00) at src/app/srs_app_http_conn.cpp:300
10 0x000000000049d6be in SrsHttpCorsMux::serve_http (this=0xa3aa60, w=0x7ffff7eb5bd0,
r=0xa91c00) at src/protocol/srs_http_stack.cpp:859
11 0x0000000000561086 in SrsHttpConn::process_request (this=0xa626e0,
w=0x7ffff7eb5bd0, r=0xa91c00) at src/app/srs_app_http_conn.cpp:161
12 0x0000000000560ce8 in SrsHttpConn::do_cycle (this=0xa626e0) at
src/app/srs_app_http_conn.cpp:133
13 0x00000000004d10fb in SrsConnection::cycle (this=0xa626e0) at
src/app/srs_app_conn.cpp:171
14 0x0000000000509c88 in SrsSTCoroutine::cycle (this=0xa62a70) at
src/app/srs_app_st.cpp:198
15 0x0000000000509cfd in SrsSTCoroutine::pfn (arg=0xa62a70) at
src/app/srs_app_st.cpp:213
16 0x00000000005bdd9d in _st_thread_main () at sched.c:337
17 0x00000000005be515 in st_thread_create (start=0x5bd719 <_st_vp_schedule+170>,
arg=0x900000001, joinable=1,stk_size=1) at sched.c:616
3.关于vhost配置
vhost配置,在商用的环境下,相对学习使用,比较复杂,在这篇文章就不赘述了,后面有机会,会有专门的文章来讲解。其专业的wiki如下:
链接如下: https://github.com/ossrs/srs/wiki/v3_CN_RtmpUrlVhost
RTMP推流时候根据url创建对应的handler,拉流的时候根据url找到对应处理的handler,这个分析在前面的文章已经讲过了,也可以参考前面的文章。推流的时候,SRS流媒体函数调用关系,如下(调用关系从下到上,即从14到0)。
0 SrsLiveEntry::SrsLiveEntry
1 0x0000000000500ffa in SrsHttpStreamServer::http_mount (this=0xa11dc0, s=0xa3bf80, r=0xa3ae90) at src/app/srs_app_http_stream.cpp:907
2 0x00000000005620f5 in SrsHttpServer::http_mount (this=0xa118f0, s=0xa3bf80,
r=0xa3ae90)
at src/app/srs_app_http_conn.cpp:308
3 0x00000000004cd3cc in SrsServer::on_publish (this=0xa103a0, s=0xa3bf80, r=0xa3ae90)
at src/app/srs_app_server.cpp:1608
4 0x00000000004e6a9b in SrsSource::on_publish (this=0xa3bf80) at
src/app/srs_app_source.cpp:2466
5 0x00000000004d89f2 in SrsRtmpConn::acquire_publish (this=0xa30ce0, source=0xa3bf80)
at src/app/srs_app_rtmp_conn.cpp:940
6 0x00000000004d7a74 in SrsRtmpConn::publishing (this=0xa30ce0, source=0xa3bf80) at
src/app/srs_app_rtmp_conn.cpp:822
7 0x00000000004d5229 in SrsRtmpConn::stream_service_cycle (this=0xa30ce0) at
src/app/srs_app_rtmp_conn.cpp:534
8 0x00000000004d4141 in SrsRtmpConn::service_cycle (this=0xa30ce0) at
src/app/srs_app_rtmp_conn.cpp:388
9 0x00000000004d2f09 in SrsRtmpConn::do_cycle (this=0xa30ce0) at
src/app/srs_app_rtmp_conn.cpp:209
10 0x00000000004d10fb in SrsConnection::cycle (this=0xa30d58) at
src/app/srs_app_conn.cpp:171
---Type <return> to continue, or q <return> to quit---
11 0x0000000000509c88 in SrsSTCoroutine::cycle (this=0xa30f70) at
src/app/srs_app_st.cpp:198
12 0x0000000000509cfd in SrsSTCoroutine::pfn (arg=0xa30f70) at
src/app/srs_app_st.cpp:213
13 0x00000000005bdd9d in _st_thread_main () at sched.c:337
14 0x00000000005be515 in st_thread_create (start=0x5bd719 <_st_vp_schedule+170>,
arg=0x700000001, joinable=1,
stk_size=1) at sched.c:616
在SRS流媒体服务器源码的Srs_app_server.cpp中,在函数on_publish中,使用http_mount做了一个路由规则。源码如下:
srs_error_t SrsServer::on_publish(SrsSource* s, SrsRequest* r)
{
srs_error_t err = srs_success;
if ((err = http_server->http_mount(s, r)) != srs_success) {
return srs_error_wrap(err, "http mount");
}
SrsCoWorkers* coworkers = SrsCoWorkers::instance();
if ((err = coworkers->on_publish(s, r)) != srs_success) {
return srs_error_wrap(err, "coworkers");
}
return err;
}
// TODO: FIXME: rename for HTTP FLV mount.
srs_error_t SrsHttpStreamServer::http_mount(SrsSource* s, SrsRequest* r)
{
srs_error_t err = srs_success;
// the id to identify stream.
std::string sid = r->get_stream_url();//如/live/stream
SrsLiveEntry* entry = NULL;
// create stream from template when not found.
if (sflvs.find(sid) == sflvs.end()) {//找不到
if (tflvs.find(r->vhost) == tflvs.end()) {//查找对应的vhost
return err;
}
SrsLiveEntry* tmpl = tflvs[r->vhost];
std::string mount = tmpl->mount;
// replace the vhost variable,路由规则的替换
mount = srs_string_replace(mount, "[vhost]", r->vhost);
mount = srs_string_replace(mount, "[app]", r->app);
mount = srs_string_replace(mount, "[stream]", r->stream);
// remove the default vhost mount
mount = srs_string_replace(mount, SRS_CONSTS_RTMP_DEFAULT_VHOST"/", "/");
entry = new SrsLiveEntry(mount);
entry->source = s;//指向source
entry->req = r->copy()->as_http();
entry->cache = new SrsBufferCache(s, r);
entry->stream = new SrsLiveStream(s, r, entry->cache);//一个源对应一个SrsLiveStream
// TODO: FIXME: maybe refine the logic of http remux service.
// if user push streams followed:
// rtmp://test.com/live/stream1
// rtmp://test.com/live/stream2
// and they will using the same template, such as: [vhost]/[app]/[stream].flv
// so, need to free last request object, otherwise, it will cause memory leak.
srs_freep(tmpl->req);
tmpl->source = s;
tmpl->req = r->copy()->as_http();
//保存地址,但是后缀.ts没有记录下来
sflvs[sid] = entry;
// mount the http flv stream.
// we must register the handler, then start the thread,
// for the thread will cause thread switch context.
// @see https://github.com/ossrs/srs/issues/404
//这个函数非常重要,真正路由的类是由mux(即SrsHttpServerMux)
if ((err = mux.handle(mount, entry->stream)) != srs_success) {
return srs_error_wrap(err, "http: mount flv stream for vhost=%s failed", sid.c_str());
}
// start http stream cache thread
if ((err = entry->cache->start()) != srs_success) {
return srs_error_wrap(err, "http: start stream cache failed");
}
srs_trace("http: mount flv stream for sid=%s, mount=%s", sid.c_str(), mount.c_str());
} else {
entry = sflvs[sid];
entry->stream->update(s, r);
entry->cache->update(s, r);
}
if (entry->stream) {
entry->stream->entry->enabled = true;
return err;
}
return err;
}
在SRS流媒体服务器源码的Srs_http_stack.cpp文件中,使用SrsHttpServerMux的handle函数去创建路由规则。如下函数的pattern表示一个url,handler表示一个SrsliveStream对象(即每个source都会绑定一个),这个url和handler去匹配,一一对应。源码如下:
srs_error_t SrsHttpServeMux::handle(std::string pattern, ISrsHttpHandler* handler)
{
srs_assert(handler);
if (pattern.empty()) {
return srs_error_new(ERROR_HTTP_PATTERN_EMPTY, "empty pattern");
}
if (entries.find(pattern) != entries.end()) {
SrsHttpMuxEntry* exists = entries[pattern];
if (exists->explicit_match) {
return srs_error_new(ERROR_HTTP_PATTERN_DUPLICATED, "pattern=%s exists", pattern.c_str());
}
}
std::string vhost = pattern;
if (pattern.at(0) != '/') {
if (pattern.find("/") != string::npos) {
vhost = pattern.substr(0, pattern.find("/"));
}
vhosts[vhost] = handler;
}
if (true) {
SrsHttpMuxEntry* entry = new SrsHttpMuxEntry();//创建路由
entry->explicit_match = true;
entry->handler = handler;//由谁来处理,handler与pattern一一对应,放在一个map的数据结构中
entry->pattern = pattern;//对应url
entry->handler->entry = entry;
if (entries.find(pattern) != entries.end()) {
SrsHttpMuxEntry* exists = entries[pattern];
srs_freep(exists);
}
entries[pattern] = entry;
}
// Helpful behavior:
// If pattern is /tree/, insert an implicit permanent redirect for /tree.
// It can be overridden by an explicit registration.
if (pattern != "/" && !pattern.empty() && pattern.at(pattern.length() - 1) == '/') {
std::string rpattern = pattern.substr(0, pattern.length() - 1);
SrsHttpMuxEntry* entry = NULL;
// free the exists implicit entry
if (entries.find(rpattern) != entries.end()) {
entry = entries[rpattern];
}
// create implicit redirect.
if (!entry || !entry->explicit_match) {
srs_freep(entry);
entry = new SrsHttpMuxEntry();
entry->explicit_match = false;
entry->handler = new SrsHttpRedirectHandler(pattern, SRS_CONSTS_HTTP_Found);
entry->pattern = pattern;
entry->handler->entry = entry;
entries[rpattern] = entry;
}
}
return srs_success;
}
一个source,对应一个LiveStream。
0 SrsLiveStream::SrsLiveStream (this=0xa3da40, s=0xa3bbd0, r=0xa3ad40, c=0xa3d520)
at src/app/srs_app_http_stream.cpp:514
1 0x00000000005010bb in SrsHttpStreamServer::http_mount (this=0xa11fd0, s=0xa3bbd0,
r=0xa3ad40)
at src/app/srs_app_http_stream.cpp:912
2 0x00000000005620f5 in SrsHttpServer::http_mount (this=0xa11e00, s=0xa3bbd0,
r=0xa3ad40)
at src/app/srs_app_http_conn.cpp:308
3 0x00000000004cd3cc in SrsServer::on_publish (this=0xa11ea0, s=0xa3bbd0, r=0xa3ad40)
at src/app/srs_app_server.cpp:1608
4 0x00000000004e6a9b in SrsSource::on_publish (this=0xa3bbd0) at
src/app/srs_app_source.cpp:2466
5 0x00000000004d89f2 in SrsRtmpConn::acquire_publish (this=0xa30d00,
source=0xa3bbd0)
at src/app/srs_app_rtmp_conn.cpp:940
6 0x00000000004d7a74 in SrsRtmpConn::publishing (this=0xa30d00, source=0xa3bbd0) at
src/app/srs_app_rtmp_conn.cpp:822
7 0x00000000004d5229 in SrsRtmpConn::stream_service_cycle (this=0xa30d00) at
src/app/srs_app_rtmp_conn.cpp:534
8 0x00000000004d4141 in SrsRtmpConn::service_cycle (this=0xa30d00) at
src/app/srs_app_rtmp_conn.cpp:388
9 0x00000000004d2f09 in SrsRtmpConn::do_cycle (this=0xa30d00) at
src/app/srs_app_rtmp_conn.cpp:209
10 0x00000000004d10fb in SrsConnection::cycle (this=0xa30d78) at
src/app/srs_app_conn.cpp:171
11 0x0000000000509c88 in SrsSTCoroutine::cycle (this=0xa30f90) at
src/app/srs_app_st.cpp:198
12 0x0000000000509cfd in SrsSTCoroutine::pfn (arg=0xa30f90) at
src/app/srs_app_st.cpp:213
13 0x00000000005bdd9d in _st_thread_main () at sched.c:337
14 0x00000000005be515 in st_thread_create (start=0x5bd719 <_st_vp_schedule+170>,
arg=0x700000001, joinable=1,
stk_size=1) at sched.c:616
3.总结
关于配置文件的这个功能的配置及源码分析,就写到这里。欢迎关注,转发,点赞,收藏,分享,评论区讨论。
后期关于项目的知识,会在微信公众号上更新,如果想要学习项目,可以关注微信公众号“记录世界 from antonio”
相关推荐
- 爆肝 30 天!从 JVM 调优到百万级 QPS,我的 Java 性能飞升全记录(2)
-
前言:从崩溃边缘到百万级QPS的逆袭凌晨3点的办公室,监控大屏突然飙红,QPS从5万断崖式下跌到800,CPU满载报警,GC时间突破3秒大关——这是我们的电商大促系统在压测中遭...
- 如何彻底清除服务器上的恶意软件与后门 ?
-
当服务器遭受入侵后,清除恶意软件和后门是恢复系统安全性的关键步骤。如果清除不彻底,攻击者可能通过隐藏后门程序再次发动攻击。以下是一个系统化的操作指南,帮助您彻底清除服务器上的恶意软件和后门,同时加强服...
- Docker 部署高性能抖音 TikTok数据爬取工具,支持无水印视频下载
-
一、项目简介此项目基于PyWebIO、FastAPI和HTTPX,是一个高效的异步数据爬取工具,专注于抖音/TikTok平台的数据提取。通过Web端界面,用户可以在线批量解析并下载无水印的视频或...
- 我如何将Unix时间转换为可读的值?
-
高频处理时间问题在处理时间值时,程序中的一种常见方法是将其转换为线性刻度表示。无法将"2005年1月17日下午5:37"这样的日期存储为变量,并期望能够进行任何操作。因此,在合格的程序...
- 用shell进行ASCII字符转换与URL编码技巧
-
如何将ASCII字符转换为十进制(或十六进制)值并进行相反的转换?如何进行URL编码和URL解码?如果你在编写脚本时已知八进制或十六进制值,你可以使用printf命令实现:#POSIXprintf...
- Linux远程shell登录出现bash-4.2#问题
-
出现以上问题的原因是/root目录下丢失了.bashrc和.bash_profile文件/etc/skel/.bash_profile和/etc/skel/.bashrc的文件复制到/root下即可命...
- 三部门:推进算力互联互通 推动国家枢纽节点和需求地之间400G/800G 高带宽全光连接
-
每经AI快讯,1月6日,国家发展改革委等三部门印发《国家数据基础设施建设指引》。其中提出,加强新兴网络技术创新应用,优化网络计费方式,降低东西部数据传输成本,促进东部中高时延业务向西部转移。推进算力互...
- 三部门:推动国家枢纽节点和需求地之间400G/800G高带宽全光连接
-
国家发展改革委、国家数据局、工业和信息化部等印发《国家数据基础设施建设指引》的通知。其中提到,加强新兴网络技术创新应用,优化网络计费方式,降低东西部数据传输成本,促进东部中高时延业务向西部转移。推进算...
- 高带宽低延迟如何开启?实际效果如何?
-
在上次的《实测AMD平台玩游戏用什么频率的内存更好?》中通过测试已经得知,AMDCPU的最佳频率是6000,具体该如何选择,如何设置能提升游戏帧数,往下看小白新手也能看明白。内存选择6000频率内存...
- 排列五第22237期规律预测走势图分享
-
二定头尾:03458,X,X,035890XX00XX30XX50XX80XX93XX03XX33XX53XX83XX94XX04XX34XX54XX84XX95...
- 格式化字符串漏洞及利用_萌新食用
-
前言格式化字符串漏洞具有任意地址读,任意地址写。printfprintf--一个参数:情况1当参数只有1个字符串的话(含有%?),//?即i,x,s等等<br>第一个...
- Linux配置ip地址的两种方法(linux配置ip详细步骤)
-
Linux配置ip地址的两种方法,实验环境为centos7.6方法1:nmcli工具配置(centos7以下版本不支持该方法)第一步,通过nmcliconnection查看网卡名称[root@lo...
- 排列五9月30日第22263期最新规律走势预测讲解
-
二定头尾:034589,X,X,0125670XX00XX10XX20XX50XX60XX73XX03XX13XX23XX53XX63XX74XX04XX14XX2...
- GDB调试的高级技巧(gdb调试工具的使用)
-
GDB是我们平时调试c/c++程序的利器,查起复杂的bug问题,比打印大法要好得多,但是也不得不说,gdb在默认情况下用起来并不是很好用,最近学习到几个高级点的技巧,分享下:一美化打印先上个例子...
- 给NAS测评打个样:QNAP TS-251D双盘位NAS全面测评体验
-
这两年随着大家网络条件越来越好,视频、电影资源越来越丰富。以及智能手机的普及拍照也更加方便,大家对于存储的需求也越来越高。除了传统的优盘、移动硬盘之外现在私有云方面也有了更多的选择。那么日常私有云选购...
你 发表评论:
欢迎- 一周热门
-
-
极空间如何无损移机,新Z4 Pro又有哪些升级?极空间Z4 Pro深度体验
-
UOS服务器操作系统防火墙设置(uos20关闭防火墙)
-
如何修复用户配置文件服务在 WINDOWS 上登录失败的问题
-
手机如何设置与显示准确时间的详细指南
-
如何在安装前及安装后修改黑群晖的Mac地址和Sn系列号
-
日本海上自卫队的军衔制度(日本海上自卫队的军衔制度是什么)
-
爱折腾的特斯拉车主必看!手把手教你TESLAMATE的备份和恢复
-
10个免费文件中转服务站,分享文件简单方便,你知道几个?
-
FANUC 0i-TF数据备份方法(fanuc系统备份教程)
-
NAS:DS video/DS file/DS photo等群晖移动端APP远程访问的教程
-
- 最近发表
- 标签列表
-
- linux 查询端口号 (58)
- docker映射容器目录到宿主机 (66)
- 杀端口 (60)
- yum更换阿里源 (62)
- internet explorer 增强的安全配置已启用 (65)
- linux自动挂载 (56)
- 禁用selinux (55)
- sysv-rc-conf (69)
- ubuntu防火墙状态查看 (64)
- windows server 2022激活密钥 (56)
- 无法与服务器建立安全连接是什么意思 (74)
- 443/80端口被占用怎么解决 (56)
- ping无法访问目标主机怎么解决 (58)
- fdatasync (59)
- 405 not allowed (56)
- 免备案虚拟主机zxhost (55)
- linux根据pid查看进程 (60)
- dhcp工具 (62)
- mysql 1045 (57)
- 宝塔远程工具 (56)
- ssh服务器拒绝了密码 请再试一次 (56)
- ubuntu卸载docker (56)
- linux查看nginx状态 (63)
- tomcat 乱码 (76)
- 2008r2激活序列号 (65)