快捷搜索:  汽车  科技

搭建http服务器主要功能(SRS流媒体服务器之HTTP-FLV框架分析)

搭建http服务器主要功能(SRS流媒体服务器之HTTP-FLV框架分析)SRS流媒体服务器之RTMP协议分析(1)SRS流媒体之RTMP拉流框架分析(3)SRS流媒体服务器之RTMP协议分析(2)SRS流媒体框架分析(1)SRS流媒体之RTMP推流框架分析(2)

0.引言

阅读本文前,可以先阅读前面的文章,能够帮助你更好理解本篇文章。文章列表如下:

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环境

HTTP实战之Wireshark抓包分析

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

界面如下:

搭建http服务器主要功能(SRS流媒体服务器之HTTP-FLV框架分析)(1)

继续输入命令:

b SrsConfig::get_vhost_http_remux_enabled(string vhost)

界面如下:

搭建http服务器主要功能(SRS流媒体服务器之HTTP-FLV框架分析)(2)

继续设置参数,输入命令:

set args -c ./conf/srs.conf

界面如下:

搭建http服务器主要功能(SRS流媒体服务器之HTTP-FLV框架分析)(3)

继续输入命令:

r

到这里就可以运行起来了。

搭建http服务器主要功能(SRS流媒体服务器之HTTP-FLV框架分析)(4)

根据配置⽂件进⾏初始化

函数调用关系是从下至上(即从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

界面如下:

搭建http服务器主要功能(SRS流媒体服务器之HTTP-FLV框架分析)(5)

继续输入命令:

b SrsLiveEntry::SrsLiveEntry(std::string m)

界面如下:

搭建http服务器主要功能(SRS流媒体服务器之HTTP-FLV框架分析)(6)

可以从源码了解到,不仅仅支持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

界面如下:

搭建http服务器主要功能(SRS流媒体服务器之HTTP-FLV框架分析)(7)

继续输入命令:

print *conf

界面如下:

搭建http服务器主要功能(SRS流媒体服务器之HTTP-FLV框架分析)(8)

可以反复的使用命令n和print *conf,观打印参数的变化。

继续输入命令:

finish

n

然后到指定的断点出去运行。界面如下:

搭建http服务器主要功能(SRS流媒体服务器之HTTP-FLV框架分析)(9)

继续输入命令:

C

这时就会进入SrsLiveEntry::SrsLiveEntry

界面如下:

搭建http服务器主要功能(SRS流媒体服务器之HTTP-FLV框架分析)(10)

再连续输入命令:

n

输入命令:

print ext

finish

界面如下:

搭建http服务器主要功能(SRS流媒体服务器之HTTP-FLV框架分析)(11)

输入命令:

print vhost

界面如下:

搭建http服务器主要功能(SRS流媒体服务器之HTTP-FLV框架分析)(12)

关于SRS流媒体服务器的配置文件,是可以修改为其它格式:

搭建http服务器主要功能(SRS流媒体服务器之HTTP-FLV框架分析)(13)

连续输入命令:

n

查看后缀,输入命令:

print ext

界面如下:

搭建http服务器主要功能(SRS流媒体服务器之HTTP-FLV框架分析)(14)

再输入命令:

c

就可以运行起来:

搭建http服务器主要功能(SRS流媒体服务器之HTTP-FLV框架分析)(15)

注意:在这里之前,需要开启推送RTMP流。拉流的时候,由于在配置文件没有设置其它格式,只设置了aac,就只能拉取aac流。

也可以修改为mp3(会涉及到转码,可能会更加复杂点),如下界面:

搭建http服务器主要功能(SRS流媒体服务器之HTTP-FLV框架分析)(16)

继续输入命令:

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

搭建http服务器主要功能(SRS流媒体服务器之HTTP-FLV框架分析)(17)

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”

猜您喜欢: