From aeee3011eff2dde366bed200b4e54ddc77e493d2 Mon Sep 17 00:00:00 2001 From: runner365 Date: Sat, 11 Jan 2020 23:05:10 +0800 Subject: [PATCH 01/32] add srt server file --- trunk/conf/srs.conf | 10 +++++++ trunk/configure | 22 +++++++++++---- trunk/src/app/srs_app_config.cpp | 47 ++++++++++++++++++++++++++++++-- trunk/src/app/srs_app_config.hpp | 7 +++++ trunk/src/app/srs_app_server.cpp | 23 +++++++++++++++- trunk/src/app/srs_app_server.hpp | 8 ++++++ trunk/src/app/srs_app_source.cpp | 1 + trunk/src/srt/srt_server.cpp | 43 +++++++++++++++++++++++++++++ trunk/src/srt/srt_server.hpp | 25 +++++++++++++++++ 9 files changed, 177 insertions(+), 9 deletions(-) create mode 100644 trunk/src/srt/srt_server.cpp create mode 100644 trunk/src/srt/srt_server.hpp diff --git a/trunk/conf/srs.conf b/trunk/conf/srs.conf index da062849ab..a12cddcde4 100644 --- a/trunk/conf/srs.conf +++ b/trunk/conf/srs.conf @@ -14,9 +14,19 @@ http_server { listen 8080; dir ./objs/nginx/html; } + +srt_server { + enabled on; + listen 10080; +} + stats { network 0; disk sda sdb xvda xvdb; } vhost __defaultVhost__ { + forward { + enabled on; + destination 172.16.43.153:19350; + } } diff --git a/trunk/configure b/trunk/configure index 3b366397f3..e3e31ef614 100755 --- a/trunk/configure +++ b/trunk/configure @@ -96,6 +96,8 @@ END GDBDebug=" -g -O0" # the warning level. WarnLevel=" -Wall" +# c++11 enable. +cpp11=" -std=c++11 -pthread" # the compile standard. CppStd="-ansi" # for library compile @@ -107,7 +109,7 @@ SrsGprof=""; SrsGprofLink=""; if [ $SRS_GPROF = YES ]; then SrsGprof=" -pg -lc_p # performance of gperf SrsGperf=""; SrsGperfLink=""; if [ $SRS_GPERF = YES ]; then SrsGperfLink=" -lpthread"; fi # the cxx flag generated. -CXXFLAGS="${CXXFLAGS} ${CppStd}${WarnLevel}${GDBDebug}${LibraryCompile}${SrsGprof}" +CXXFLAGS="${CXXFLAGS} ${CppStd}${WarnLevel}${cpp11}${GDBDebug}${LibraryCompile}${SrsGprof}" if [ $SRS_GPERF = YES ]; then CXXFLAGS="${CXXFLAGS} -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free"; fi @@ -158,7 +160,7 @@ if [ $SRS_GPERF_MD = YES ]; then LibGperfFile="${SRS_OBJS_DIR}/gperf/lib/libtcmalloc_debug.a"; fi # the link options, always use static link -SrsLinkOptions="-ldl"; +SrsLinkOptions="-pthread -ldl"; if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL == YES ]]; then SrsLinkOptions="${SrsLinkOptions} -lssl -lcrypto"; fi @@ -206,6 +208,14 @@ MODULE_FILES=("srs_protocol_amf0" "srs_protocol_io" "srs_rtmp_stack" PROTOCOL_INCS="src/protocol"; MODULE_DIR=${PROTOCOL_INCS} . auto/modules.sh PROTOCOL_OBJS="${MODULE_OBJS[@]}" # +#srt protocol features. +MODULE_ID="SRT" +MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP") +ModuleLibIncs=(${SRS_OBJS_DIR}) +MODULE_FILES=("srt_server") +SRT_INCS="src/srt"; MODULE_DIR=${SRT_INCS} . auto/modules.sh +SRT_OBJS="${MODULE_OBJS[@]}" +# #Service Module, for both Server and Client Modules. if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="SERVICE" @@ -257,7 +267,7 @@ LIBS_OBJS="${MODULE_OBJS[@]}" #Server Module, for SRS only. if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="SERVER" - MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP") + MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP" "SRT") ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) MODULE_FILES=("srs_main_server") SERVER_INCS="src/main"; MODULE_DIR=${SERVER_INCS} . auto/modules.sh @@ -297,14 +307,14 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then # all depends libraries ModuleLibFiles=(${LibSTfile} ${LibSSLfile} ${LibGperfFile}) # all depends objects - MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${APP_OBJS[@]} ${SERVER_OBJS[@]}" + MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SRT_OBJS[@]} ${SERVICE_OBJS[@]} ${APP_OBJS[@]} ${SERVER_OBJS[@]}" LINK_OPTIONS="${SrsLinkOptions}${SrsGprofLink}${SrsGperfLink}" # # srs: srs(simple rtmp server) over st(state-threads) BUILD_KEY="srs" APP_MAIN="srs_main_server" APP_NAME="srs" . auto/apps.sh # # For modules, without the app module. - MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${MAIN_OBJS[@]}" + MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${SRT_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${MAIN_OBJS[@]}" # for SRS_MODULE in ${SRS_MODULES[*]}; do . $SRS_MODULE/config @@ -326,7 +336,7 @@ if [ $SRS_UTEST = YES ]; then "srs_utest_mp4" "srs_utest_service" "srs_utest_app") ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot}) ModuleLibFiles=(${LibSTfile} ${LibSSLfile}) - MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP") + MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP" "SRT") MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${APP_OBJS[@]}" LINK_OPTIONS="-lpthread ${SrsLinkOptions}" MODULE_DIR="src/utest" APP_NAME="srs_utest" . auto/utest.sh fi diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index a0277f3c95..e443a3318d 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -479,7 +479,7 @@ srs_error_t srs_config_transform_vhost(SrsConfDirective* root) ++it; continue; } - + // SRS3.0, change the folowing like a shadow: // mode, origin, token_traverse, vhost, debug_srs_upnode // SRS1/2: @@ -3470,7 +3470,7 @@ srs_error_t SrsConfig::check_normal_config() && n != "srs_log_tank" && n != "srs_log_level" && n != "srs_log_file" && n != "max_connections" && n != "daemon" && n != "heartbeat" && n != "http_api" && n != "stats" && n != "vhost" && n != "pithy_print_ms" - && n != "http_server" && n != "stream_caster" + && n != "http_server" && n != "stream_caster" && n != "srt_server" && n != "utc_time" && n != "work_dir" && n != "asprocess" ) { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal directive %s", n.c_str()); @@ -3504,6 +3504,15 @@ srs_error_t SrsConfig::check_normal_config() } } } + if (true) { + SrsConfDirective* conf = root->get("srt_server"); + for (int i = 0; conf && i < (int)conf->directives.size(); i++) { + string n = conf->at(i)->name; + if (n != "enabled" && n != "listen") { + return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal srt_stream.%s", n.c_str()); + } + } + } if (true) { SrsConfDirective* conf = get_heartbeart(); for (int i = 0; conf && i < (int)conf->directives.size(); i++) { @@ -3631,6 +3640,7 @@ srs_error_t SrsConfig::check_normal_config() get_vhosts(vhosts); for (int n = 0; n < (int)vhosts.size(); n++) { SrsConfDirective* vhost = vhosts[n]; + printf("virtural host name:%s, arg:%s\r\n", vhost->name.c_str(), vhost->args[0].c_str()); for (int i = 0; vhost && i < (int)vhost->directives.size(); i++) { SrsConfDirective* conf = vhost->at(i); string n = conf->name; @@ -6629,6 +6639,39 @@ bool SrsConfig::get_raw_api_allow_update() return SRS_CONF_PERFER_FALSE(conf->arg0()); } + +bool SrsConfig::get_srt_enabled() +{ + static bool DEFAULT = false; + + SrsConfDirective* conf = root->get("srt_server"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("enabled"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return SRS_CONF_PERFER_FALSE(conf->arg0()); +} + +unsigned short SrsConfig::get_srt_listen_port() +{ + static unsigned short DEFAULT = 10080; + SrsConfDirective* conf = root->get("srt_server"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("listen"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + return (unsigned short)atoi(conf->arg0().c_str()); +} + bool SrsConfig::get_http_stream_enabled() { SrsConfDirective* conf = root->get("http_server"); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index c9c03e24f5..cc936affcb 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -588,6 +588,13 @@ class SrsConfig virtual bool get_forward_enabled(std::string vhost); // Get the forward directive of vhost. virtual SrsConfDirective* get_forwards(std::string vhost); + +public: + // Whether the srt sevice enabled + virtual bool get_srt_enabled(); + // Get the srt service listen port + virtual unsigned short get_srt_listen_port(); + // http_hooks section private: // Get the http_hooks directive of vhost. diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index 8c6d214702..226f0dc1eb 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -688,7 +688,10 @@ srs_error_t SrsServer::listen() if ((err = conn_manager->start()) != srs_success) { return srs_error_wrap(err, "connection manager"); } - + if ((err = listen_srt()) != srs_success) { + return srs_error_wrap(err, "srt listen"); + } + return err; } @@ -1004,6 +1007,24 @@ srs_error_t SrsServer::do_cycle() return err; } +srs_error_t SrsServer::listen_srt() { + srs_error_t err = srs_success; + + if(_srs_config->get_srt_enabled()) { + srs_trace("srt server is enabled..."); + unsigned short srt_port = _srs_config->get_srt_listen_port(); + srs_trace("srt server listen port:%d", srt_port); + srt_ptr = std::make_shared(srt_port); + if (!srt_ptr) { + srs_error_wrap(err, "srt listen %d", srt_port); + } + srt_ptr->start(); + } else { + srs_trace("srt server is disabled..."); + } + return err; +} + srs_error_t SrsServer::listen_rtmp() { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index fd8cbe3ad7..625c161e78 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -36,6 +36,7 @@ #include #include #include +#include "../srt/srt_server.hpp" class SrsServer; class SrsConnection; @@ -209,6 +210,11 @@ class SrsServer : virtual public ISrsReloadHandler, virtual public ISrsSourceHan SrsHttpHeartbeat* http_heartbeat; SrsIngester* ingester; SrsCoroutineManager* conn_manager; + +private: + //srt server + SRT_SERVER_PTR srt_ptr; + private: // The pid file fd, lock the file write when server is running. // @remark the init.d script should cleanup the pid file, when stop service, @@ -279,6 +285,8 @@ class SrsServer : virtual public ISrsReloadHandler, virtual public ISrsSourceHan virtual srs_error_t listen_http_api(); virtual srs_error_t listen_http_stream(); virtual srs_error_t listen_stream_caster(); + //start listen srt udp port + virtual srs_error_t listen_srt(); // Close the listeners for specified type, // Remove the listen object from manager. virtual void close_listeners(SrsListenerType type); diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index 788773c800..bfe3e15774 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -1456,6 +1456,7 @@ srs_error_t SrsOriginHub::create_forwarders() if (!_srs_config->get_forward_enabled(req->vhost)) { return err; } + srs_trace("srs vhost(%s) forward is enable.", req->host.c_str()); SrsConfDirective* conf = _srs_config->get_forwards(req->vhost); for (int i = 0; conf && i < (int)conf->args.size(); i++) { diff --git a/trunk/src/srt/srt_server.cpp b/trunk/src/srt/srt_server.cpp new file mode 100644 index 0000000000..f4f7ee8dab --- /dev/null +++ b/trunk/src/srt/srt_server.cpp @@ -0,0 +1,43 @@ +#include "srt_server.hpp" +#include +#include +#include +#include +#include + +srt_server::srt_server(unsigned short port):listen_port(port) +{ + +} + +srt_server::~srt_server() +{ + +} + +int srt_server::start() +{ + run_flag = true; + srs_trace("srt server is starting... port(%d)", listen_port); + thread_run_ptr = std::make_shared(&srt_server::on_work, this); + return 0; +} + +void srt_server::stop() +{ + run_flag = false; + if (!thread_run_ptr) { + return; + } + thread_run_ptr->join(); + return; +} + +void srt_server::on_work() +{ + srs_trace("srt server is working port(%d)", listen_port); + while (run_flag) + { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } +} diff --git a/trunk/src/srt/srt_server.hpp b/trunk/src/srt/srt_server.hpp new file mode 100644 index 0000000000..49229dc6d0 --- /dev/null +++ b/trunk/src/srt/srt_server.hpp @@ -0,0 +1,25 @@ +#ifndef SRT_SERVER_H +#define SRT_SERVER_H +#include +#include + +class srt_server { +public: + srt_server(unsigned short port); + ~srt_server(); + + int start(); + void stop(); + +private: + void on_work(); + +private: + unsigned short listen_port; + bool run_flag; + std::shared_ptr thread_run_ptr; +}; + +typedef std::shared_ptr SRT_SERVER_PTR; + +#endif//SRT_SERVER_H \ No newline at end of file From b53b75ea1e143e56f29721e7578a3ae735cdd2d7 Mon Sep 17 00:00:00 2001 From: runner365 Date: Tue, 14 Jan 2020 21:10:33 +0800 Subject: [PATCH 02/32] srt pull/push server --- .gitignore | 2 + .vscode/settings.json | 75 ++++++ trunk/conf/srs.conf | 15 +- trunk/configure | 11 +- trunk/src/srt/srt_conn.cpp | 82 +++++++ trunk/src/srt/srt_conn.hpp | 69 ++++++ trunk/src/srt/srt_handle.cpp | 448 +++++++++++++++++++++++++++++++++++ trunk/src/srt/srt_handle.hpp | 76 ++++++ trunk/src/srt/srt_server.cpp | 154 +++++++++++- trunk/src/srt/srt_server.hpp | 16 +- trunk/src/srt/stringex.hpp | 39 +++ trunk/src/srt/time_help.h | 10 + 12 files changed, 982 insertions(+), 15 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 trunk/src/srt/srt_conn.cpp create mode 100644 trunk/src/srt/srt_conn.hpp create mode 100644 trunk/src/srt/srt_handle.cpp create mode 100644 trunk/src/srt/srt_handle.hpp create mode 100644 trunk/src/srt/stringex.hpp create mode 100644 trunk/src/srt/time_help.h diff --git a/.gitignore b/.gitignore index 6216052aad..f869a35448 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,8 @@ *.pyc *.swp .DS_Store +.vscode +.vscode/* /trunk/Makefile /trunk/objs /trunk/src/build-qt-Desktop-Debug diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..049520f837 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,75 @@ +{ + "files.associations": { + "string": "cpp", + "memory": "cpp", + "__bit_reference": "cpp", + "__config": "cpp", + "__debug": "cpp", + "__errc": "cpp", + "__functional_base": "cpp", + "__hash_table": "cpp", + "__locale": "cpp", + "__mutex_base": "cpp", + "__node_handle": "cpp", + "__nullptr": "cpp", + "__split_buffer": "cpp", + "__string": "cpp", + "__threading_support": "cpp", + "__tree": "cpp", + "__tuple": "cpp", + "algorithm": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "cmath": "cpp", + "complex": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "exception": "cpp", + "fstream": "cpp", + "functional": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "list": "cpp", + "locale": "cpp", + "map": "cpp", + "mutex": "cpp", + "new": "cpp", + "optional": "cpp", + "ostream": "cpp", + "ratio": "cpp", + "set": "cpp", + "sstream": "cpp", + "stack": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "thread": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeinfo": "cpp", + "unordered_map": "cpp", + "utility": "cpp", + "vector": "cpp", + "hash_map": "cpp", + "hash_set": "cpp" + } +} \ No newline at end of file diff --git a/trunk/conf/srs.conf b/trunk/conf/srs.conf index a12cddcde4..297292b1db 100644 --- a/trunk/conf/srs.conf +++ b/trunk/conf/srs.conf @@ -5,6 +5,8 @@ listen 1935; max_connections 1000; srs_log_tank file; srs_log_file ./objs/srs.log; +daemon off; + http_api { enabled on; listen 1985; @@ -24,9 +26,12 @@ stats { network 0; disk sda sdb xvda xvdb; } -vhost __defaultVhost__ { - forward { - enabled on; - destination 172.16.43.153:19350; - } +#vhost __defaultVhost__ { +# forward { +# enabled on; +# destination 172.16.43.153:19350; +# } +#} + +vhost sina.mobile.com.cn { } diff --git a/trunk/configure b/trunk/configure index e3e31ef614..5cfcc9151e 100755 --- a/trunk/configure +++ b/trunk/configure @@ -133,8 +133,7 @@ ARFLAGS = -rs LINK = g++ CXXFLAGS = ${CXXFLAGS} -.PHONY: default srs srs_ingest_hls librtmp - +.PHONY: default srs librtmp default: END @@ -160,7 +159,7 @@ if [ $SRS_GPERF_MD = YES ]; then LibGperfFile="${SRS_OBJS_DIR}/gperf/lib/libtcmalloc_debug.a"; fi # the link options, always use static link -SrsLinkOptions="-pthread -ldl"; +SrsLinkOptions="-pthread -ldl -lsrt"; if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL == YES ]]; then SrsLinkOptions="${SrsLinkOptions} -lssl -lcrypto"; fi @@ -212,7 +211,7 @@ PROTOCOL_OBJS="${MODULE_OBJS[@]}" MODULE_ID="SRT" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP") ModuleLibIncs=(${SRS_OBJS_DIR}) -MODULE_FILES=("srt_server") +MODULE_FILES=("srt_server" "srt_handle" "srt_conn") SRT_INCS="src/srt"; MODULE_DIR=${SRT_INCS} . auto/modules.sh SRT_OBJS="${MODULE_OBJS[@]}" # @@ -355,7 +354,7 @@ mv ${SRS_WORKDIR}/${SRS_MAKEFILE} ${SRS_WORKDIR}/${SRS_MAKEFILE}.bk # generate phony header cat << END > ${SRS_WORKDIR}/${SRS_MAKEFILE} -.PHONY: default _default install install-api help clean server srs_ingest_hls librtmp utest _prepare_dir $__mphonys +.PHONY: default _default install install-api help clean server librtmp _prepare_dir $__mphonys # install prefix. SRS_PREFIX=${SRS_PREFIX} @@ -370,7 +369,7 @@ END # the server, librtmp and utest # where the bellow will check and disable some entry by only echo. cat << END >> ${SRS_WORKDIR}/${SRS_MAKEFILE} -_default: server srs_ingest_hls librtmp utest __modules $__mdefaults +_default: server librtmp __modules $__mdefaults @bash objs/_srs_build_summary.sh help: diff --git a/trunk/src/srt/srt_conn.cpp b/trunk/src/srt/srt_conn.cpp new file mode 100644 index 0000000000..ab4d0584ab --- /dev/null +++ b/trunk/src/srt/srt_conn.cpp @@ -0,0 +1,82 @@ +#include "srt_conn.hpp" +#include "time_help.h" +#include "stringex.hpp" +#include + +srt_conn::srt_conn(SRTSOCKET conn_fd, const std::string& streamid):_conn_fd(conn_fd), + _streamid(streamid) { + get_streamid_info(streamid, _mode, _url_subpath); + _update_timestamp = now_ms(); + + std::vector path_vec; + + string_split(_url_subpath, "/", path_vec); + if (path_vec.size() >= 3) { + _vhost = path_vec[0]; + } else { + _vhost = "__default_host__"; + } + srs_trace("srt connect construct streamid:%s, mode:%d, subpath:%s, vhost:%s", + streamid.c_str(), _mode, _url_subpath.c_str(), _vhost.c_str()); +} + +srt_conn::~srt_conn() { + close(); +} + +std::string srt_conn::get_vhost() { + return _vhost; +} + +void srt_conn::update_timestamp(long long now_ts) { + _update_timestamp = now_ts; +} + +long long srt_conn::get_last_ts() { + return _update_timestamp; +} + +void srt_conn::close() { + if (_conn_fd == SRT_INVALID_SOCK) { + return; + } + srt_close(_conn_fd); + _conn_fd = SRT_INVALID_SOCK; +} + +SRTSOCKET srt_conn::get_conn() { + return _conn_fd; +} +int srt_conn::get_mode() { + return _mode; +} + +std::string srt_conn::get_streamid() { + return _streamid; +} + +std::string srt_conn::get_subpath() { + return _url_subpath; +} + +int srt_conn::read(unsigned char* data, int len) { + int ret = 0; + + ret = srt_recv(_conn_fd, (char*)data, len); + if (ret <= 0) { + srs_error("srt read error:%d, socket fd:%d", ret, _conn_fd); + return ret; + } + return ret; +} + +int srt_conn::write(unsigned char* data, int len) { + int ret = 0; + + ret = srt_send(_conn_fd, (char*)data, len); + if (ret <= 0) { + srs_error("srt write error:%d, socket fd:%d", ret, _conn_fd); + return ret; + } + return ret; +} \ No newline at end of file diff --git a/trunk/src/srt/srt_conn.hpp b/trunk/src/srt/srt_conn.hpp new file mode 100644 index 0000000000..91d79c06cc --- /dev/null +++ b/trunk/src/srt/srt_conn.hpp @@ -0,0 +1,69 @@ +#ifndef SRT_CONN_H +#define SRT_CONN_H +#include +#include +#include +#include +#include +#include +#include +#include + +#define PULL_SRT_MODE 0x01 +#define PUSH_SRT_MODE 0x02 + +inline void get_streamid_info(const std::string& streamid, int& mode, std::string& url_subpash) { + std::string real_streamip; + + size_t pos = streamid.find("?"); + if (pos == std::string::npos) { + mode = PULL_SRT_MODE; + url_subpash = streamid; + } else { + std::string mode_str = streamid.substr(pos+1); + + url_subpash = streamid.substr(0, pos); + + size_t mode_pos = mode_str.find("m="); + if (mode_pos == std::string::npos) { + mode = PULL_SRT_MODE; + } else { + mode_str = mode_str.substr(mode_pos+2); + if (mode_str == "push") { + mode = PUSH_SRT_MODE; + } else { + mode = PULL_SRT_MODE; + } + } + } +} + +class srt_conn { +public: + srt_conn(SRTSOCKET conn_fd, const std::string& streamid); + ~srt_conn(); + + void close(); + SRTSOCKET get_conn(); + int get_mode(); + std::string get_streamid(); + std::string get_subpath(); + std::string get_vhost(); + int read(unsigned char* data, int len); + int write(unsigned char* data, int len); + + void update_timestamp(long long now_ts); + long long get_last_ts(); + +private: + SRTSOCKET _conn_fd; + std::string _streamid; + std::string _url_subpath; + std::string _vhost; + int _mode; + long long _update_timestamp; +}; + +typedef std::shared_ptr SRT_CONN_PTR; + +#endif //SRT_CONN_H \ No newline at end of file diff --git a/trunk/src/srt/srt_handle.cpp b/trunk/src/srt/srt_handle.cpp new file mode 100644 index 0000000000..09c28267ab --- /dev/null +++ b/trunk/src/srt/srt_handle.cpp @@ -0,0 +1,448 @@ + +#include "srt_handle.hpp" +#include "time_help.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static bool MONITOR_STATICS_ENABLE = false; +static long long MONITOR_TIMEOUT = 5000; +const unsigned int DEF_DATA_SIZE = 188*7; +const long long CHECK_ALIVE_INTERVAL = 10*1000; +const long long CHECK_ALIVE_TIMEOUT = 15*1000; + +long long srt_now_ms = 0; + +srt_handle::srt_handle():_last_timestamp(0) + ,_last_check_alive_ts(0) { + +} + +srt_handle::~srt_handle() { + +} + +int srt_handle::start() { + _handle_pollid = srt_epoll_create(); + if (_handle_pollid < -1) { + srs_error("srt handle srt_epoll_create error, _handle_pollid=%d", _handle_pollid); + return -1; + } + + srs_trace("srt handle is starting..."); + _work_thread_ptr = std::make_shared(&srt_handle::onwork, this); + + return 0; +} + +void srt_handle::stop() { + _work_thread_ptr->join(); + return; +} + +void srt_handle::debug_statics(SRTSOCKET srtsocket, const std::string& streamid) { + SRT_TRACEBSTATS mon; + srt_bstats(srtsocket, &mon, 1); + std::ostringstream output; + long long now_ul = now_ms(); + + if (!MONITOR_STATICS_ENABLE) { + return; + } + if (_last_timestamp == 0) { + _last_timestamp = now_ul; + return; + } + + if ((now_ul - _last_timestamp) < MONITOR_TIMEOUT) { + return; + } + _last_timestamp = now_ul; + output << "======= SRT STATS: sid=" << streamid << std::endl; + output << "PACKETS SENT: " << std::setw(11) << mon.pktSent << " RECEIVED: " << std::setw(11) << mon.pktRecv << std::endl; + output << "LOST PKT SENT: " << std::setw(11) << mon.pktSndLoss << " RECEIVED: " << std::setw(11) << mon.pktRcvLoss << std::endl; + output << "REXMIT SENT: " << std::setw(11) << mon.pktRetrans << " RECEIVED: " << std::setw(11) << mon.pktRcvRetrans << std::endl; + output << "DROP PKT SENT: " << std::setw(11) << mon.pktSndDrop << " RECEIVED: " << std::setw(11) << mon.pktRcvDrop << std::endl; + output << "RATE SENDING: " << std::setw(11) << mon.mbpsSendRate << " RECEIVING: " << std::setw(11) << mon.mbpsRecvRate << std::endl; + output << "BELATED RECEIVED: " << std::setw(11) << mon.pktRcvBelated << " AVG TIME: " << std::setw(11) << mon.pktRcvAvgBelatedTime << std::endl; + output << "REORDER DISTANCE: " << std::setw(11) << mon.pktReorderDistance << std::endl; + output << "WINDOW FLOW: " << std::setw(11) << mon.pktFlowWindow << " CONGESTION: " << std::setw(11) << mon.pktCongestionWindow << " FLIGHT: " << std::setw(11) << mon.pktFlightSize << std::endl; + output << "LINK RTT: " << std::setw(9) << mon.msRTT << "ms BANDWIDTH: " << std::setw(7) << mon.mbpsBandwidth << "Mb/s " << std::endl; + output << "BUFFERLEFT: SND: " << std::setw(11) << mon.byteAvailSndBuf << " RCV: " << std::setw(11) << mon.byteAvailRcvBuf << std::endl; + + srs_trace("\r\n%s", output.str().c_str()); + return; +} + +void srt_handle::add_new_puller(SRT_CONN_PTR conn_ptr, std::string stream_id) { + _conn_map.insert(std::make_pair(conn_ptr->get_conn(), conn_ptr)); + + auto iter = _streamid_map.find(stream_id); + if (iter == _streamid_map.end()) { + std::unordered_map srtsocket_map; + srtsocket_map.insert(std::make_pair(conn_ptr->get_conn(), conn_ptr)); + + _streamid_map.insert(std::make_pair(stream_id, srtsocket_map)); + srs_trace("add new puller fd:%d, streamid:%s", conn_ptr->get_conn(), stream_id.c_str()); + } else { + iter->second.insert(std::make_pair(conn_ptr->get_conn(), conn_ptr)); + srs_trace("add new puller fd:%d, streamid:%s, size:%d", + conn_ptr->get_conn(), stream_id.c_str(), iter->second.size()); + } + + return; +} + +void srt_handle::close_pull_conn(SRTSOCKET srtsocket, std::string stream_id) { + srs_warn("close_pull_conn read_fd=%d, streamid=%s", srtsocket, stream_id.c_str()); + srt_epoll_remove_usock(_handle_pollid, srtsocket); + + auto streamid_iter = _streamid_map.find(stream_id); + if (streamid_iter != _streamid_map.end()) { + auto srtsocket_map = streamid_iter->second; + if (srtsocket_map.size() == 0) { + _streamid_map.erase(stream_id); + } else if (srtsocket_map.size() == 1) { + srtsocket_map.erase(srtsocket); + _streamid_map.erase(stream_id); + } else { + srtsocket_map.erase(srtsocket); + } + } else { + assert(0); + } + + auto conn_iter = _conn_map.find(srtsocket); + if (conn_iter != _conn_map.end()) { + _conn_map.erase(conn_iter); + return; + } else { + assert(0); + } + + return; +} + +SRT_CONN_PTR srt_handle::get_srt_conn(SRTSOCKET conn_srt_socket) { + SRT_CONN_PTR ret_conn; + + auto iter = _conn_map.find(conn_srt_socket); + if (iter == _conn_map.end()) { + return ret_conn; + } + + ret_conn = iter->second; + + return ret_conn; +} + +void srt_handle::add_newconn(SRT_CONN_PTR conn_ptr, int events) { + int val_i; + int opt_len = sizeof(int); + + val_i = 1000; + srt_setsockopt(conn_ptr->get_conn(), 0, SRTO_LATENCY, &val_i, opt_len); + val_i = 2048; + srt_setsockopt(conn_ptr->get_conn(), 0, SRTO_MAXBW, &val_i, opt_len); + + srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_LATENCY, &val_i, &opt_len); + srs_trace("srto SRTO_LATENCY=%d", val_i); + srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_SNDBUF, &val_i, &opt_len); + srs_trace("srto SRTO_SNDBUF=%d", val_i); + srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_RCVBUF, &val_i, &opt_len); + srs_trace("srto SRTO_RCVBUF=%d", val_i); + srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_MAXBW, &val_i, &opt_len); + srs_trace("srto SRTO_MAXBW=%d", val_i); + + if (conn_ptr->get_mode() == PULL_SRT_MODE) { + add_new_puller(conn_ptr, conn_ptr->get_subpath()); + } else { + if(add_new_pusher(conn_ptr) == false) { + conn_ptr->close(); + return; + } + } + srs_trace("new conn added fd:%d, event:0x%08x", conn_ptr->get_conn(), events); + int ret = srt_epoll_add_usock(_handle_pollid, conn_ptr->get_conn(), &events); + if (ret < 0) { + srs_error("srt handle run add epoll error:%d", ret); + return; + } + + return; +} + +int srt_handle::get_srt_mode(SRTSOCKET conn_srt_socket) { + auto iter = _conn_map.find(conn_srt_socket); + if (iter == _conn_map.end()) { + return 0; + } + return iter->second->get_mode(); +} + +void srt_handle::insert_message_queue(request_message_t msg) { + std::unique_lock lock(_queue_mutex); + _message_queue.push(msg); +} + +bool srt_handle::get_message_from_queue(request_message_t& msg) { + std::unique_lock lock(_queue_mutex); + bool ret = false; + + if (_message_queue.empty()) { + return ret; + } + ret = true; + msg = _message_queue.front(); + _message_queue.pop(); + + return ret; +} + +void srt_handle::onwork() +{ + const unsigned int SRT_FD_MAX = 1024; + SRT_SOCKSTATUS status = SRTS_INIT; + std::string streamid; + int ret; + const int64_t DEF_TIMEOUT_INTERVAL = 30; + + srs_trace("srt handle epoll work is starting..."); + while(true) + { + SRTSOCKET read_fds[SRT_FD_MAX]; + SRTSOCKET write_fds[SRT_FD_MAX]; + int rfd_num = SRT_FD_MAX; + int wfd_num = SRT_FD_MAX; + + srt_now_ms = now_ms(); + + request_message_t msg; + + if (get_message_from_queue(msg)) { + add_newconn(msg.conn_ptr, msg.events); + } + + check_alive(); + + ret = srt_epoll_wait(_handle_pollid, read_fds, &rfd_num, write_fds, &wfd_num, + DEF_TIMEOUT_INTERVAL, 0, 0, 0, 0); + if (ret < 0) { + srs_info("srt handle epoll is timeout, ret=%d, srt_now_ms=%ld", + ret, srt_now_ms); + std::this_thread::sleep_for(std::chrono::milliseconds(30)); + continue; + } + + for (int index = 0; index < rfd_num; index++) + { + status = srt_getsockstate(read_fds[index]); + srs_info("srt handle read(push) rfd num:%d, status:%d, streamid:%s, read_fd", + rfd_num, status, streamid.c_str(), read_fds[index]); + handle_srt_socket(status, read_fds[index]); + } + + for (int index = 0; index < wfd_num; index++) + { + status = srt_getsockstate(write_fds[index]); + streamid = UDT::getstreamid(write_fds[index]); + srs_info("srt handle write(puller) wfd num:%d, status:%d, streamid:%s, write_fd", + wfd_num, status, streamid.c_str(), write_fds[index]); + handle_srt_socket(status, write_fds[index]); + } + + } +} + +void srt_handle::handle_push_data(SRT_SOCKSTATUS status, const std::string& subpath, SRTSOCKET conn_fd) { + SRT_CONN_PTR srt_conn_ptr; + unsigned char data[DEF_DATA_SIZE]; + int ret; + srt_conn_ptr = get_srt_conn(conn_fd); + + if (!srt_conn_ptr) { + srs_error("handle_push_data fd:%d fail to find srt connection.", conn_fd); + return; + } + + if (status != SRTS_CONNECTED) { + srs_error("handle_push_data error status:%d fd:%d", status, conn_fd); + close_push_conn(conn_fd); + return; + } + + ret = srt_conn_ptr->read(data, DEF_DATA_SIZE); + if (ret <= 0) { + srs_error("handle_push_data srt connect read error:%d, fd:%d", ret, conn_fd); + close_push_conn(conn_fd); + return; + } + srt_conn_ptr->update_timestamp(srt_now_ms); + + //send data to subscriber(players) + //streamid, play map + auto streamid_iter = _streamid_map.find(subpath); + if (streamid_iter == _streamid_map.end()) {//no puler + srs_info("receive data size(%d) from pusher(%d) but no puller", ret, conn_fd); + return; + } + srs_info("receive data size(%d) from pusher(%d) to pullers, count:%d", + ret, conn_fd, streamid_iter->second.size()); + + for (auto puller_iter = streamid_iter->second.begin(); + puller_iter != streamid_iter->second.end(); + puller_iter++) { + auto player_conn = puller_iter->second; + if (!player_conn) { + srs_error("handle_push_data get srt connect error from fd:%d", puller_iter->first); + continue; + } + int write_ret = player_conn->write(data, ret); + srs_info("send data size(%d) to puller fd:%d", write_ret, puller_iter->first); + if (write_ret > 0) { + puller_iter->second->update_timestamp(srt_now_ms); + } + } + + return; +} + +void srt_handle::check_alive() { + long long diff_t; + std::list conn_list; + + if (_last_check_alive_ts == 0) { + _last_check_alive_ts = srt_now_ms; + return; + } + diff_t = srt_now_ms - _last_check_alive_ts; + if (diff_t < CHECK_ALIVE_INTERVAL) { + return; + } + + for (auto conn_iter = _conn_map.begin(); + conn_iter != _conn_map.end(); + conn_iter++) + { + long long timeout = srt_now_ms - conn_iter->second->get_last_ts(); + if (timeout > CHECK_ALIVE_TIMEOUT) { + conn_list.push_back(conn_iter->second); + } + } + + for (auto del_iter = conn_list.begin(); + del_iter != conn_list.end(); + del_iter++) + { + SRT_CONN_PTR conn_ptr = *del_iter; + if (conn_ptr->get_mode() == PUSH_SRT_MODE) { + srs_warn("check alive close pull connection fd:%d, streamid:%s", + conn_ptr->get_conn(), conn_ptr->get_subpath().c_str()); + close_push_conn(conn_ptr->get_conn()); + } else if (conn_ptr->get_mode() == PULL_SRT_MODE) { + srs_warn("check alive close pull connection fd:%d, streamid:%s", + conn_ptr->get_conn(), conn_ptr->get_subpath().c_str()); + close_pull_conn(conn_ptr->get_conn(), conn_ptr->get_subpath()); + } else { + srs_error("check_alive get unkown srt mode:%d, fd:%d", + conn_ptr->get_mode(), conn_ptr->get_conn()); + assert(0); + } + } +} + +void srt_handle::close_push_conn(SRTSOCKET srtsocket) { + auto iter = _conn_map.find(srtsocket); + if (iter == _conn_map.end()) { + return; + } + srt_epoll_remove_usock(_handle_pollid, srtsocket); + _conn_map.erase(iter); +} + +bool srt_handle::add_new_pusher(SRT_CONN_PTR conn_ptr) { + _conn_map.insert(std::make_pair(conn_ptr->get_conn(), conn_ptr)); + srs_trace("srt_handle add new pusher streamid:%s, subpath:%s", + conn_ptr->get_streamid().c_str(), conn_ptr->get_subpath().c_str()); + return true; +} + +void srt_handle::handle_pull_data(SRT_SOCKSTATUS status, const std::string& subpath, SRTSOCKET conn_fd) { + srs_info("handle_pull_data status:%d, subpath:%s, fd:%d", + status, subpath.c_str(), conn_fd); + auto conn_ptr = get_srt_conn(conn_fd); + if (!conn_ptr) { + srs_error("handle_pull_data fail to find fd(%d)", conn_fd); + assert(0); + return; + } + conn_ptr->update_timestamp(srt_now_ms); +} + +void srt_handle::handle_srt_socket(SRT_SOCKSTATUS status, SRTSOCKET conn_fd) +{ + std::string subpath; + int mode; + auto conn_ptr = get_srt_conn(conn_fd); + + if (!conn_ptr) { + if (status != SRTS_CLOSED) { + srs_error("handle_srt_socket find srt connection error, fd:%d, status:%d", + conn_fd, status); + } + return; + } + get_streamid_info(conn_ptr->get_streamid(), mode, subpath); + + if (mode == PUSH_SRT_MODE) { + switch (status) + { + case SRTS_CONNECTED: + { + handle_push_data(status, subpath, conn_fd); + break; + } + case SRTS_BROKEN: + { + srs_warn("srt push disconnected event fd:%d, streamid:%s", + conn_fd, conn_ptr->get_streamid().c_str()); + close_push_conn(conn_fd); + break; + } + default: + srs_error("push mode unkown status:%d, fd:%d", status, conn_fd); + break; + } + } else if (mode == PULL_SRT_MODE) { + switch (status) + { + case SRTS_CONNECTED: + { + handle_pull_data(status, subpath, conn_fd); + break; + } + case SRTS_BROKEN: + { + srs_warn("srt pull disconnected fd:%d, streamid:%s", + conn_fd, conn_ptr->get_streamid().c_str()); + close_pull_conn(conn_fd, subpath); + break; + } + default: + srs_error("pull mode unkown status:%d, fd:%d", status, conn_fd); + break; + } + } else { + assert(0); + } + return; +} \ No newline at end of file diff --git a/trunk/src/srt/srt_handle.hpp b/trunk/src/srt/srt_handle.hpp new file mode 100644 index 0000000000..3185b4678f --- /dev/null +++ b/trunk/src/srt/srt_handle.hpp @@ -0,0 +1,76 @@ +#ifndef SRT_HANDLE_H +#define SRT_HANDLE_H +#include + +#include +#include +#include +#include +#include +#include + +#include "srt_conn.hpp" + +typedef struct { + SRT_CONN_PTR conn_ptr; + int events; +} request_message_t; + +class srt_handle { +public: + srt_handle(); + ~srt_handle(); + + int start();//create srt epoll and create epoll thread + void stop();//close srt epoll and end epoll thread + + void insert_message_queue(request_message_t msg); + bool get_message_from_queue(request_message_t& msg); + +private: + //add new srt connection into epoll event + void add_newconn(SRT_CONN_PTR conn_ptr, int events); + //get srt conn object by srt socket + SRT_CONN_PTR get_srt_conn(SRTSOCKET conn_srt_socket); + //get srt connect mode: push or pull + int get_srt_mode(SRTSOCKET conn_srt_socket); + + void onwork();//epoll thread loop + //handle recv/send srt socket + void handle_srt_socket(SRT_SOCKSTATUS status, SRTSOCKET conn_fd); + void handle_push_data(SRT_SOCKSTATUS status, const std::string& subpath, SRTSOCKET conn_fd); + void handle_pull_data(SRT_SOCKSTATUS status, const std::string& subpath, SRTSOCKET conn_fd); + + //add new puller into puller list and conn_map + void add_new_puller(SRT_CONN_PTR, std::string stream_id); + //remove pull srt from play list + void close_pull_conn(SRTSOCKET srtsocket, std::string stream_id); + + //add new pusher into pusher map: + bool add_new_pusher(SRT_CONN_PTR conn_ptr); + //remove push connection and remove epoll + void close_push_conn(SRTSOCKET srtsocket); + + //check srt connection whether it's still alive. + void check_alive(); + + //debug statics + void debug_statics(SRTSOCKET srtsocket, const std::string& streamid); + +private: + int _handle_pollid; + + std::unordered_map _conn_map; + std::shared_ptr _work_thread_ptr; + + //streamid, play map + std::unordered_map> _streamid_map; + + std::mutex _queue_mutex; + std::queue _message_queue; + + long long _last_timestamp; + long long _last_check_alive_ts; +}; + +#endif //SRT_HANDLE_H \ No newline at end of file diff --git a/trunk/src/srt/srt_server.cpp b/trunk/src/srt/srt_server.cpp index f4f7ee8dab..d4f0214de4 100644 --- a/trunk/src/srt/srt_server.cpp +++ b/trunk/src/srt/srt_server.cpp @@ -1,13 +1,24 @@ #include "srt_server.hpp" +#include "srt_handle.hpp" +#include #include +#include +#include +#include +#include +#include +#include +#include + #include #include #include #include srt_server::srt_server(unsigned short port):listen_port(port) + ,server_socket(-1) { - + handle_ptr = std::make_shared(); } srt_server::~srt_server() @@ -15,8 +26,65 @@ srt_server::~srt_server() } +int srt_server::init_srt() { + if (server_socket != -1) { + return -1; + } + + server_socket = srt_create_socket(); + sockaddr_in sa; + memset(&sa, 0, sizeof sa); + sa.sin_family = AF_INET; + sa.sin_port = htons(listen_port); + + sockaddr* psa = (sockaddr*)&sa; + + int ret = srt_bind(server_socket, psa, sizeof(sa)); + if ( ret == SRT_ERROR ) + { + srt_close(server_socket); + srs_error("srt bind error: %d", ret); + return -1; + } + + ret = srt_listen(server_socket, 5); + if (ret == SRT_ERROR) + { + srt_close(server_socket); + srs_error("srt listen error: %d", ret); + return -2; + } + + _pollid = srt_epoll_create(); + if (_pollid < -1) { + srs_error("srt server srt_epoll_create error, port=%d", listen_port); + return -1; + } + + int events = SRT_EPOLL_IN | SRT_EPOLL_ERR; + ret = srt_epoll_add_usock(_pollid, server_socket, &events); + if (ret < 0) { + srs_error("srt server run add epoll error:%d", ret); + return ret; + } + + srs_trace("srt server listen port=%d, server_fd=%d", listen_port, server_socket); + + return 0; +} + int srt_server::start() { + int ret; + + if ((ret = init_srt()) < 0) { + return ret; + } + ret = handle_ptr->start(); + if (ret < 0) { + return ret; + } + run_flag = true; srs_trace("srt server is starting... port(%d)", listen_port); thread_run_ptr = std::make_shared(&srt_server::on_work, this); @@ -30,14 +98,96 @@ void srt_server::stop() return; } thread_run_ptr->join(); + + handle_ptr->stop(); return; } +void srt_server::srt_handle_connection(SRT_SOCKSTATUS status, SRTSOCKET input_fd, const std::string& dscr) { + SRTSOCKET conn_fd = -1; + sockaddr_in scl; + int sclen = sizeof(scl); + int conn_event;// = SRT_EPOLL_IN |SRT_EPOLL_OUT| SRT_EPOLL_ERR; + + switch(status) { + case SRTS_LISTENING: + { + conn_fd = srt_accept(input_fd, (sockaddr*)&scl, &sclen); + if (conn_fd == -1) { + return; + } + //add new srt connect into srt handle + std::string streamid = UDT::getstreamid(conn_fd); + + SRT_CONN_PTR srt_conn_ptr = std::make_shared(conn_fd, streamid); + + std::string vhost_str = srt_conn_ptr->get_vhost(); + srs_trace("new srt connection streamid:%s, fd:%d, vhost:%s", + streamid.c_str(), conn_fd, vhost_str.c_str()); + SrsConfDirective* vhost_p = _srs_config->get_vhost(vhost_str, true); + if (!vhost_p) { + srs_trace("srt streamid(%s): no vhost %s, fd:%d", + streamid.c_str(), vhost_str.c_str(), conn_fd); + srt_conn_ptr->close(); + return; + } + if (srt_conn_ptr->get_mode() == PULL_SRT_MODE) { + //add SRT_EPOLL_IN for information notify + conn_event = SRT_EPOLL_IN | SRT_EPOLL_ERR;//not inlucde SRT_EPOLL_OUT for save cpu + } else { + conn_event = SRT_EPOLL_IN | SRT_EPOLL_ERR; + } + request_message_t msg = {srt_conn_ptr, conn_event}; + handle_ptr->insert_message_queue(msg); + break; + } + case SRTS_CONNECTED: + { + srs_trace("srt connected: socket=%d, mode:%s", input_fd, dscr.c_str()); + break; + } + case SRTS_BROKEN: + { + srt_epoll_remove_usock(_pollid, input_fd); + srt_close(input_fd); + srs_warn("srt close: socket=%d", input_fd); + break; + } + default: + { + srs_error("srt server unkown status:%d", status); + } + } +} + void srt_server::on_work() { + const unsigned int SRT_FD_MAX = 100; srs_trace("srt server is working port(%d)", listen_port); while (run_flag) { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + SRTSOCKET read_fds[SRT_FD_MAX]; + SRTSOCKET write_fds[SRT_FD_MAX]; + int rfd_num = SRT_FD_MAX; + int wfd_num = SRT_FD_MAX; + + int ret = srt_epoll_wait(_pollid, read_fds, &rfd_num, write_fds, &wfd_num, -1, + nullptr, nullptr, nullptr, nullptr); + if (ret < 0) { + srs_error("listen srt epoll is timeout, port=%d", listen_port); + continue; + } + srs_trace("srt server epoll get: ret=%d, rfd_num=%d, wfd_num=%d", + ret, rfd_num, wfd_num); + + for (int index = 0; index < rfd_num; index++) { + SRT_SOCKSTATUS status = srt_getsockstate(read_fds[index]); + srt_handle_connection(status, read_fds[index], "read fd"); + } + + for (int index = 0; index < wfd_num; index++) { + SRT_SOCKSTATUS status = srt_getsockstate(write_fds[index]); + srt_handle_connection(status, read_fds[index], "write fd"); + } } } diff --git a/trunk/src/srt/srt_server.hpp b/trunk/src/srt/srt_server.hpp index 49229dc6d0..7201b72633 100644 --- a/trunk/src/srt/srt_server.hpp +++ b/trunk/src/srt/srt_server.hpp @@ -1,23 +1,35 @@ #ifndef SRT_SERVER_H #define SRT_SERVER_H +#include + #include #include +class srt_handle; + class srt_server { public: srt_server(unsigned short port); ~srt_server(); - int start(); - void stop(); + int start();//init srt handl and create srt main thread loop + void stop();//stop srt main thread loop private: + //init srt socket and srt epoll + int init_srt(); + //srt main epoll loop void on_work(); + //accept new srt connection + void srt_handle_connection(SRT_SOCKSTATUS status, SRTSOCKET input_fd, const std::string& dscr); private: unsigned short listen_port; + SRTSOCKET server_socket; + int _pollid; bool run_flag; std::shared_ptr thread_run_ptr; + std::shared_ptr handle_ptr; }; typedef std::shared_ptr SRT_SERVER_PTR; diff --git a/trunk/src/srt/stringex.hpp b/trunk/src/srt/stringex.hpp new file mode 100644 index 0000000000..36e8eb8b46 --- /dev/null +++ b/trunk/src/srt/stringex.hpp @@ -0,0 +1,39 @@ +#ifndef STRING_EX_H +#define STRING_EX_H +#include +#include +#include +#include +#include +#include + +inline int string_split(const std::string& input_str, const std::string& split_str, std::vector& output_vec) { + if (input_str.length() == 0) { + return 0; + } + + std::string tempString(input_str); + do { + + size_t pos = tempString.find(split_str); + if (pos == tempString.npos) { + output_vec.push_back(tempString); + break; + } + std::string seg_str = tempString.substr(0, pos); + tempString = tempString.substr(pos+split_str.size()); + output_vec.push_back(seg_str); + } while(tempString.size() > 0); + + return output_vec.size(); +} + +inline std::string string_lower(const std::string input_str) { + std::string output_str(input_str); + + std::transform(input_str.begin(), input_str.end(), output_str.begin(), ::tolower); + + return output_str; +} + +#endif//STRING_EX_H \ No newline at end of file diff --git a/trunk/src/srt/time_help.h b/trunk/src/srt/time_help.h new file mode 100644 index 0000000000..301139df7a --- /dev/null +++ b/trunk/src/srt/time_help.h @@ -0,0 +1,10 @@ +#ifndef TIME_HELP_H +#define TIME_HELP_H +#include + +inline long long now_ms() { + return std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()).count(); +} + +#endif //TIME_HELP_H \ No newline at end of file From b3c3ce9bf34789eb949724656e74a8cc7fa5e98c Mon Sep 17 00:00:00 2001 From: runner365 Date: Tue, 14 Jan 2020 21:11:03 +0800 Subject: [PATCH 03/32] rm .vscode --- .vscode/settings.json | 75 ------------------------------------------- 1 file changed, 75 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 049520f837..0000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "files.associations": { - "string": "cpp", - "memory": "cpp", - "__bit_reference": "cpp", - "__config": "cpp", - "__debug": "cpp", - "__errc": "cpp", - "__functional_base": "cpp", - "__hash_table": "cpp", - "__locale": "cpp", - "__mutex_base": "cpp", - "__node_handle": "cpp", - "__nullptr": "cpp", - "__split_buffer": "cpp", - "__string": "cpp", - "__threading_support": "cpp", - "__tree": "cpp", - "__tuple": "cpp", - "algorithm": "cpp", - "array": "cpp", - "atomic": "cpp", - "bit": "cpp", - "bitset": "cpp", - "cctype": "cpp", - "chrono": "cpp", - "cmath": "cpp", - "complex": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "deque": "cpp", - "exception": "cpp", - "fstream": "cpp", - "functional": "cpp", - "initializer_list": "cpp", - "iomanip": "cpp", - "ios": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "iterator": "cpp", - "limits": "cpp", - "list": "cpp", - "locale": "cpp", - "map": "cpp", - "mutex": "cpp", - "new": "cpp", - "optional": "cpp", - "ostream": "cpp", - "ratio": "cpp", - "set": "cpp", - "sstream": "cpp", - "stack": "cpp", - "stdexcept": "cpp", - "streambuf": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "thread": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "typeinfo": "cpp", - "unordered_map": "cpp", - "utility": "cpp", - "vector": "cpp", - "hash_map": "cpp", - "hash_set": "cpp" - } -} \ No newline at end of file From 1481928b53efc0f141f9eccf6592ee82f5fce604 Mon Sep 17 00:00:00 2001 From: runner365 Date: Wed, 15 Jan 2020 10:30:20 +0800 Subject: [PATCH 04/32] reject repeated srt pusher connection --- trunk/src/srt/srt_handle.cpp | 22 +++++++++++++++++++--- trunk/src/srt/srt_handle.hpp | 4 +++- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/trunk/src/srt/srt_handle.cpp b/trunk/src/srt/srt_handle.cpp index 09c28267ab..75495289ae 100644 --- a/trunk/src/srt/srt_handle.cpp +++ b/trunk/src/srt/srt_handle.cpp @@ -167,6 +167,8 @@ void srt_handle::add_newconn(SRT_CONN_PTR conn_ptr, int events) { add_new_puller(conn_ptr, conn_ptr->get_subpath()); } else { if(add_new_pusher(conn_ptr) == false) { + srs_trace("push connection is repeated and rejected, fd:%d, streamid:%s", + conn_ptr->get_conn(), conn_ptr->get_streamid().c_str()); conn_ptr->close(); return; } @@ -362,14 +364,28 @@ void srt_handle::check_alive() { void srt_handle::close_push_conn(SRTSOCKET srtsocket) { auto iter = _conn_map.find(srtsocket); - if (iter == _conn_map.end()) { - return; + + if (iter != _conn_map.end()) { + SRT_CONN_PTR conn_ptr = iter->second; + auto push_iter = _push_conn_map.find(conn_ptr->get_subpath()); + if (push_iter != _push_conn_map.end()) { + _push_conn_map.erase(push_iter); + } + _conn_map.erase(iter); + conn_ptr->close(); } + srt_epoll_remove_usock(_handle_pollid, srtsocket); - _conn_map.erase(iter); + + return; } bool srt_handle::add_new_pusher(SRT_CONN_PTR conn_ptr) { + auto push_iter = _push_conn_map.find(conn_ptr->get_subpath()); + if (push_iter != _push_conn_map.end()) { + return false; + } + _push_conn_map.insert(std::make_pair(conn_ptr->get_subpath(), conn_ptr)); _conn_map.insert(std::make_pair(conn_ptr->get_conn(), conn_ptr)); srs_trace("srt_handle add new pusher streamid:%s, subpath:%s", conn_ptr->get_streamid().c_str(), conn_ptr->get_subpath().c_str()); diff --git a/trunk/src/srt/srt_handle.hpp b/trunk/src/srt/srt_handle.hpp index 3185b4678f..aed8168dd5 100644 --- a/trunk/src/srt/srt_handle.hpp +++ b/trunk/src/srt/srt_handle.hpp @@ -60,9 +60,11 @@ class srt_handle { private: int _handle_pollid; - std::unordered_map _conn_map; + std::unordered_map _conn_map;//save all srt connection: pull or push std::shared_ptr _work_thread_ptr; + //save push srt connection for prevent from repeat push connection + std::unordered_map _push_conn_map;//key:streamid, value:SRT_CONN_PTR //streamid, play map std::unordered_map> _streamid_map; From 7b9e3ecdc49ffa4f650761c233f1be55a27f34b3 Mon Sep 17 00:00:00 2001 From: runner365 Date: Fri, 17 Jan 2020 19:43:54 +0800 Subject: [PATCH 05/32] add ts demux --- trunk/conf/srs.conf | 12 +- trunk/configure | 2 +- trunk/src/kernel/srs_kernel_log.hpp | 21 ++ trunk/src/srt/srt_conn.hpp | 7 +- trunk/src/srt/srt_data.cpp | 24 ++ trunk/src/srt/srt_data.hpp | 23 ++ trunk/src/srt/srt_handle.cpp | 13 +- trunk/src/srt/srt_handle.hpp | 4 + trunk/src/srt/srt_server.cpp | 7 +- trunk/src/srt/srt_to_rtmp.cpp | 427 ++++++++++++++++++++++++++++ trunk/src/srt/srt_to_rtmp.hpp | 93 ++++++ trunk/src/srt/ts_demux.cpp | 274 ++++++++++++++++++ trunk/src/srt/ts_demux.hpp | 166 +++++++++++ 13 files changed, 1058 insertions(+), 15 deletions(-) create mode 100644 trunk/src/srt/srt_data.cpp create mode 100644 trunk/src/srt/srt_data.hpp create mode 100644 trunk/src/srt/srt_to_rtmp.cpp create mode 100644 trunk/src/srt/srt_to_rtmp.hpp create mode 100644 trunk/src/srt/ts_demux.cpp create mode 100644 trunk/src/srt/ts_demux.hpp diff --git a/trunk/conf/srs.conf b/trunk/conf/srs.conf index 297292b1db..90cc389c41 100644 --- a/trunk/conf/srs.conf +++ b/trunk/conf/srs.conf @@ -22,16 +22,10 @@ srt_server { listen 10080; } +vhost sina.mobile.com.cn { +} + stats { network 0; disk sda sdb xvda xvdb; } -#vhost __defaultVhost__ { -# forward { -# enabled on; -# destination 172.16.43.153:19350; -# } -#} - -vhost sina.mobile.com.cn { -} diff --git a/trunk/configure b/trunk/configure index 5cfcc9151e..058b1f9922 100755 --- a/trunk/configure +++ b/trunk/configure @@ -211,7 +211,7 @@ PROTOCOL_OBJS="${MODULE_OBJS[@]}" MODULE_ID="SRT" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP") ModuleLibIncs=(${SRS_OBJS_DIR}) -MODULE_FILES=("srt_server" "srt_handle" "srt_conn") +MODULE_FILES=("srt_server" "srt_handle" "srt_conn" "srt_to_rtmp") SRT_INCS="src/srt"; MODULE_DIR=${SRT_INCS} . auto/modules.sh SRT_OBJS="${MODULE_OBJS[@]}" # diff --git a/trunk/src/kernel/srs_kernel_log.hpp b/trunk/src/kernel/srs_kernel_log.hpp index 1d7af37bbf..670a5b9c68 100644 --- a/trunk/src/kernel/srs_kernel_log.hpp +++ b/trunk/src/kernel/srs_kernel_log.hpp @@ -142,5 +142,26 @@ extern ISrsThreadContext* _srs_context; #define srs_trace(msg, ...) (void)0 #endif +inline void srs_trace_data(const char* data_p, int len, const char* dscr) +{ + const int MAX = 256; + char debug_data[MAX]; + char debug_len = 0; + + debug_len += sprintf(debug_data + debug_len, "%s", dscr); + + for (int index = 0; index < len; index++) { + if (index % 16 == 0) { + debug_len += sprintf(debug_data + debug_len, "\r\n"); + } + debug_len += sprintf(debug_data + debug_len, " %02x", (unsigned char)data_p[index]); + if (index >= 32) { + break; + } + } + + srs_trace("%s", debug_data); + return; +} #endif diff --git a/trunk/src/srt/srt_conn.hpp b/trunk/src/srt/srt_conn.hpp index 91d79c06cc..168ca0769a 100644 --- a/trunk/src/srt/srt_conn.hpp +++ b/trunk/src/srt/srt_conn.hpp @@ -1,5 +1,6 @@ #ifndef SRT_CONN_H #define SRT_CONN_H +#include "stringex.hpp" #include #include #include @@ -9,6 +10,7 @@ #include #include +#define ERR_SRT_MODE 0x00 #define PULL_SRT_MODE 0x01 #define PUSH_SRT_MODE 0x02 @@ -29,10 +31,13 @@ inline void get_streamid_info(const std::string& streamid, int& mode, std::strin mode = PULL_SRT_MODE; } else { mode_str = mode_str.substr(mode_pos+2); + mode_str = string_lower(mode_str); if (mode_str == "push") { mode = PUSH_SRT_MODE; - } else { + } else if(mode_str == "pull"){ mode = PULL_SRT_MODE; + } else { + mode = ERR_SRT_MODE; } } } diff --git a/trunk/src/srt/srt_data.cpp b/trunk/src/srt/srt_data.cpp new file mode 100644 index 0000000000..8cfec1864c --- /dev/null +++ b/trunk/src/srt/srt_data.cpp @@ -0,0 +1,24 @@ +#include "srt_data.hpp" + +SRT_DATA_MSG::SRT_DATA_MSG(unsigned char* data_p, unsigned int len, const std::string& path):_len(len) + ,_key_path(path) +{ + _data_p = new unsigned char[len]; + memcpy(_data_p, data_p, len); +} + +SRT_DATA_MSG::~SRT_DATA_MSG() { + delete _data_p; +} + +std::string SRT_DATA_MSG::get_path() { + return _key_path; +} + +unsigned int SRT_DATA_MSG::data_len() { + return _len; +} + +unsigned char* SRT_DATA_MSG::get_data() { + return _data_p; +} diff --git a/trunk/src/srt/srt_data.hpp b/trunk/src/srt/srt_data.hpp new file mode 100644 index 0000000000..a1a225b90c --- /dev/null +++ b/trunk/src/srt/srt_data.hpp @@ -0,0 +1,23 @@ +#ifndef SRT_DATA_H +#define SRT_DATA_H +#include +#include + +class SRT_DATA_MSG { +public: + SRT_DATA_MSG(unsigned char* data_p, unsigned int len, const std::string& path); + ~SRT_DATA_MSG(); + + unsigned int data_len(); + unsigned char* get_data(); + std::string get_path(); + +private: + unsigned int _len; + unsigned char* _data_p; + std::string _key_path; +}; + +typedef std::shared_ptr SRT_DATA_MSG_PTR; + +#endif \ No newline at end of file diff --git a/trunk/src/srt/srt_handle.cpp b/trunk/src/srt/srt_handle.cpp index 75495289ae..60914e2a45 100644 --- a/trunk/src/srt/srt_handle.cpp +++ b/trunk/src/srt/srt_handle.cpp @@ -22,9 +22,10 @@ const long long CHECK_ALIVE_TIMEOUT = 15*1000; long long srt_now_ms = 0; -srt_handle::srt_handle():_last_timestamp(0) +srt_handle::srt_handle():_run_flag(false) + ,_last_timestamp(0) ,_last_check_alive_ts(0) { - + _srt2rtmp_ptr = std::make_shared(); } srt_handle::~srt_handle() { @@ -38,14 +39,18 @@ int srt_handle::start() { return -1; } + _run_flag = true; srs_trace("srt handle is starting..."); _work_thread_ptr = std::make_shared(&srt_handle::onwork, this); + _srt2rtmp_ptr->start(); return 0; } void srt_handle::stop() { + _run_flag = false; _work_thread_ptr->join(); + _srt2rtmp_ptr->stop(); return; } @@ -219,7 +224,7 @@ void srt_handle::onwork() const int64_t DEF_TIMEOUT_INTERVAL = 30; srs_trace("srt handle epoll work is starting..."); - while(true) + while(_run_flag) { SRTSOCKET read_fds[SRT_FD_MAX]; SRTSOCKET write_fds[SRT_FD_MAX]; @@ -289,6 +294,8 @@ void srt_handle::handle_push_data(SRT_SOCKSTATUS status, const std::string& subp return; } srt_conn_ptr->update_timestamp(srt_now_ms); + + _srt2rtmp_ptr->insert_data_message(data, ret, subpath); //send data to subscriber(players) //streamid, play map diff --git a/trunk/src/srt/srt_handle.hpp b/trunk/src/srt/srt_handle.hpp index aed8168dd5..dd9e0f9268 100644 --- a/trunk/src/srt/srt_handle.hpp +++ b/trunk/src/srt/srt_handle.hpp @@ -10,6 +10,7 @@ #include #include "srt_conn.hpp" +#include "srt_to_rtmp.hpp" typedef struct { SRT_CONN_PTR conn_ptr; @@ -58,6 +59,7 @@ class srt_handle { void debug_statics(SRTSOCKET srtsocket, const std::string& streamid); private: + bool _run_flag; int _handle_pollid; std::unordered_map _conn_map;//save all srt connection: pull or push @@ -73,6 +75,8 @@ class srt_handle { long long _last_timestamp; long long _last_check_alive_ts; + + SRT2RTMP_PTR _srt2rtmp_ptr; }; #endif //SRT_HANDLE_H \ No newline at end of file diff --git a/trunk/src/srt/srt_server.cpp b/trunk/src/srt/srt_server.cpp index d4f0214de4..691abaa495 100644 --- a/trunk/src/srt/srt_server.cpp +++ b/trunk/src/srt/srt_server.cpp @@ -134,8 +134,13 @@ void srt_server::srt_handle_connection(SRT_SOCKSTATUS status, SRTSOCKET input_fd if (srt_conn_ptr->get_mode() == PULL_SRT_MODE) { //add SRT_EPOLL_IN for information notify conn_event = SRT_EPOLL_IN | SRT_EPOLL_ERR;//not inlucde SRT_EPOLL_OUT for save cpu - } else { + } else if (srt_conn_ptr->get_mode() == PUSH_SRT_MODE) { conn_event = SRT_EPOLL_IN | SRT_EPOLL_ERR; + } else { + srs_trace("stream mode error, it shoulde be m=push or m=pull, streamid:%s", + srt_conn_ptr->get_streamid().c_str()); + srt_conn_ptr->close(); + return; } request_message_t msg = {srt_conn_ptr, conn_event}; handle_ptr->insert_message_queue(msg); diff --git a/trunk/src/srt/srt_to_rtmp.cpp b/trunk/src/srt/srt_to_rtmp.cpp new file mode 100644 index 0000000000..647931738c --- /dev/null +++ b/trunk/src/srt/srt_to_rtmp.cpp @@ -0,0 +1,427 @@ +#include "srt_to_rtmp.hpp" +#include +#include +#include +#include +#include +#include + +srt2rtmp::srt2rtmp():_run_flag(false) { + +} + +srt2rtmp::~srt2rtmp() { + +} + +void srt2rtmp::start() { + _run_flag = true; + + _thread_ptr = std::make_shared(&srt2rtmp::on_work, this); + + return; +} + +void srt2rtmp::stop() { + _run_flag = false; + + _thread_ptr->join(); + return; +} + +void srt2rtmp::insert_data_message(unsigned char* data_p, unsigned int len, const std::string& key_path) { + std::unique_lock locker(_mutex); + if (!_run_flag) { + return; + } + SRT_DATA_MSG_PTR msg_ptr = std::make_shared(data_p, len, key_path); + _msg_queue.push(msg_ptr); + _notify_cond.notify_one(); + return; +} + +SRT_DATA_MSG_PTR srt2rtmp::get_data_message() { + std::unique_lock locker(_mutex); + SRT_DATA_MSG_PTR msg_ptr; + + while (_msg_queue.empty() && _run_flag) { + _notify_cond.wait(locker); + } + + msg_ptr = _msg_queue.front(); + _msg_queue.pop(); + return msg_ptr; +} + +void srt2rtmp::on_work() { + while(_run_flag) { + SRT_DATA_MSG_PTR msg_ptr = get_data_message(); + + if (!msg_ptr) { + continue; + } + handle_ts_data(msg_ptr); + } +} + +void srt2rtmp::handle_ts_data(SRT_DATA_MSG_PTR data_ptr) { + RTMP_CLIENT_PTR rtmp_ptr; + auto iter = _rtmp_client_map.find(data_ptr->get_path()); + if (iter == _rtmp_client_map.end()) { + srs_trace("new rtmp client for srt upstream, key_path:%s", data_ptr->get_path().c_str()); + rtmp_ptr = std::make_shared(data_ptr->get_path()); + _rtmp_client_map.insert(std::make_pair(data_ptr->get_path(), rtmp_ptr)); + } else { + rtmp_ptr = iter->second; + } + + rtmp_ptr->receive_ts_data(data_ptr); + + return; +} + +rtmp_client::rtmp_client(std::string key_path):_key_path(key_path) { + _ts_ctx_ptr = std::make_shared(); + _avc_ptr = std::make_shared(); + _aac_ptr = std::make_shared(); + + char url_sz[128]; + sprintf(url_sz, "rtmp://127.0.0.1/%s", key_path.c_str()); + _url = url_sz; + + _h264_sps_changed = false; + _h264_pps_changed = false; + _h264_sps_pps_sent = false; + srs_trace("rtmp client construct url:%s", url_sz); +} + +rtmp_client::~rtmp_client() { + +} + +void rtmp_client::close() { + if (!_rtmp_conn_ptr) { + return; + } + _rtmp_conn_ptr->close(); + _rtmp_conn_ptr = nullptr; +} + +srs_error_t rtmp_client::connect() { + srs_error_t err = srs_success; + srs_utime_t cto = SRS_CONSTS_RTMP_TIMEOUT; + srs_utime_t sto = SRS_CONSTS_RTMP_PULSE; + + if (_rtmp_conn_ptr.get() != nullptr) { + return srs_error_wrap(err, "repeated connect %s failed, cto=%dms, sto=%dms.", + _url.c_str(), srsu2msi(cto), srsu2msi(sto)); + } + + _rtmp_conn_ptr = std::make_shared(_url, cto, sto); + + if ((err = _rtmp_conn_ptr->connect()) != srs_success) { + close(); + return srs_error_wrap(err, "connect %s failed, cto=%dms, sto=%dms.", + _url.c_str(), srsu2msi(cto), srsu2msi(sto)); + } + + if ((err = _rtmp_conn_ptr->publish(SRS_CONSTS_RTMP_PROTOCOL_CHUNK_SIZE)) != srs_success) { + close(); + return srs_error_wrap(err, "publish error, url:%s", _url.c_str()); + } + + return err; +} +void rtmp_client::receive_ts_data(SRT_DATA_MSG_PTR data_ptr) { + SrsBuffer* buffer_p = new SrsBuffer((char*)data_ptr->get_data(), data_ptr->data_len()); + + FILE* file_p = fopen("1.ts", "ab+"); + if (file_p) { + fwrite(data_ptr->get_data(), data_ptr->data_len(), 1, file_p); + fclose(file_p); + } + //srs_trace_data((char*)data_ptr->get_data(), data_ptr->data_len(), "receive ts data"); + _ts_ctx_ptr->decode(buffer_p, this);//on_ts_message is the decode callback + return; +} + +srs_error_t rtmp_client::write_h264_sps_pps(uint32_t dts, uint32_t pts) { + srs_error_t err = srs_success; + + // TODO: FIMXE: there exists bug, see following comments. + // when sps or pps changed, update the sequence header, + // for the pps maybe not changed while sps changed. + // so, we must check when each video ts message frame parsed. + if (!_h264_sps_changed || !_h264_pps_changed) { + return err; + } + + // h264 raw to h264 packet. + std::string sh; + if ((err = _avc_ptr->mux_sequence_header(_h264_sps, _h264_pps, dts, pts, sh)) != srs_success) { + return srs_error_wrap(err, "mux sequence header"); + } + + // h264 packet to flv packet. + int8_t frame_type = SrsVideoAvcFrameTypeKeyFrame; + int8_t avc_packet_type = SrsVideoAvcFrameTraitSequenceHeader; + char* flv = NULL; + int nb_flv = 0; + if ((err = _avc_ptr->mux_avc2flv(sh, frame_type, avc_packet_type, dts, pts, &flv, &nb_flv)) != srs_success) { + return srs_error_wrap(err, "avc to flv"); + } + + // the timestamp in rtmp message header is dts. + uint32_t timestamp = dts; + if ((err = rtmp_write_packet(SrsFrameTypeVideo, timestamp, flv, nb_flv)) != srs_success) { + return srs_error_wrap(err, "write packet"); + } + + // reset sps and pps. + _h264_sps_changed = false; + _h264_pps_changed = false; + _h264_sps_pps_sent = true; + + return err; +} + +srs_error_t rtmp_client::write_h264_ipb_frame(char* frame, int frame_size, uint32_t dts, uint32_t pts) { + srs_error_t err = srs_success; + + // when sps or pps not sent, ignore the packet. + // @see https://github.com/ossrs/srs/issues/203 + if (!_h264_sps_pps_sent) { + return srs_error_new(ERROR_H264_DROP_BEFORE_SPS_PPS, "drop sps/pps"); + } + + // 5bits, 7.3.1 NAL unit syntax, + // ISO_IEC_14496-10-AVC-2003.pdf, page 44. + // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame + SrsAvcNaluType nal_unit_type = (SrsAvcNaluType)(frame[0] & 0x1f); + + // for IDR frame, the frame is keyframe. + SrsVideoAvcFrameType frame_type = SrsVideoAvcFrameTypeInterFrame; + if (nal_unit_type == SrsAvcNaluTypeIDR) { + frame_type = SrsVideoAvcFrameTypeKeyFrame; + } + + std::string ibp; + if ((err = _avc_ptr->mux_ipb_frame(frame, frame_size, ibp)) != srs_success) { + return srs_error_wrap(err, "mux frame"); + } + + int8_t avc_packet_type = SrsVideoAvcFrameTraitNALU; + char* flv = NULL; + int nb_flv = 0; + if ((err = _avc_ptr->mux_avc2flv(ibp, frame_type, avc_packet_type, dts, pts, &flv, &nb_flv)) != srs_success) { + return srs_error_wrap(err, "mux avc to flv"); + } + + // the timestamp in rtmp message header is dts. + uint32_t timestamp = dts; + return rtmp_write_packet(SrsFrameTypeVideo, timestamp, flv, nb_flv); +} + +srs_error_t rtmp_client::write_audio_raw_frame(char* frame, int frame_size, SrsRawAacStreamCodec* codec, uint32_t dts) { + srs_error_t err = srs_success; + + char* data = NULL; + int size = 0; + if ((err = _aac_ptr->mux_aac2flv(frame, frame_size, codec, dts, &data, &size)) != srs_success) { + return srs_error_wrap(err, "mux aac to flv"); + } + + return rtmp_write_packet(SrsFrameTypeAudio, dts, data, size); +} + +srs_error_t rtmp_client::rtmp_write_packet(char type, uint32_t timestamp, char* data, int size) { + srs_error_t err = srs_success; + + if ((err = connect()) != srs_success) { + return srs_error_wrap(err, "connect"); + } + + SrsSharedPtrMessage* msg = NULL; + + if ((err = srs_rtmp_create_msg(type, timestamp, data, size, _rtmp_conn_ptr->sid(), &msg)) != srs_success) { + return srs_error_wrap(err, "create message"); + } + srs_assert(msg); + + // send out encoded msg. + if ((err = _rtmp_conn_ptr->send_and_free_message(msg)) != srs_success) { + close(); + return srs_error_wrap(err, "send messages"); + } + + return err; +} + +srs_error_t rtmp_client::on_ts_video(SrsTsMessage* msg, SrsBuffer* avs) { + srs_error_t err = srs_success; + + // ensure rtmp connected. + if ((err = connect()) != srs_success) { + return srs_error_wrap(err, "connect"); + } + + // ts tbn to flv tbn. + uint32_t dts = (uint32_t)(msg->dts / 90); + uint32_t pts = (uint32_t)(msg->dts / 90); + + // send each frame. + while (!avs->empty()) { + char* frame = NULL; + int frame_size = 0; + if ((err = _avc_ptr->annexb_demux(avs, &frame, &frame_size)) != srs_success) { + return srs_error_wrap(err, "demux annexb"); + } + + // 5bits, 7.3.1 NAL unit syntax, + // ISO_IEC_14496-10-AVC-2003.pdf, page 44. + // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame + SrsAvcNaluType nal_unit_type = (SrsAvcNaluType)(frame[0] & 0x1f); + + // ignore the nalu type sps(7), pps(8), aud(9) + if (nal_unit_type == SrsAvcNaluTypeAccessUnitDelimiter) { + continue; + } + + // for sps + if (_avc_ptr->is_sps(frame, frame_size)) { + std::string sps; + if ((err = _avc_ptr->sps_demux(frame, frame_size, sps)) != srs_success) { + return srs_error_wrap(err, "demux sps"); + } + + if (_h264_sps == sps) { + continue; + } + _h264_sps_changed = true; + _h264_sps = sps; + + if ((err = write_h264_sps_pps(dts, pts)) != srs_success) { + return srs_error_wrap(err, "write sps/pps"); + } + continue; + } + + // for pps + if (_avc_ptr->is_pps(frame, frame_size)) { + std::string pps; + if ((err = _avc_ptr->pps_demux(frame, frame_size, pps)) != srs_success) { + return srs_error_wrap(err, "demux pps"); + } + + if (_h264_pps == pps) { + continue; + } + _h264_pps_changed = true; + _h264_pps = pps; + + if ((err = write_h264_sps_pps(dts, pts)) != srs_success) { + return srs_error_wrap(err, "write sps/pps"); + } + continue; + } + + // ibp frame. + // TODO: FIXME: we should group all frames to a rtmp/flv message from one ts message. + srs_info("mpegts: demux avc ibp frame size=%d, dts=%d", frame_size, dts); + if ((err = write_h264_ipb_frame(frame, frame_size, dts, pts)) != srs_success) { + return srs_error_wrap(err, "write frame"); + } + } + + return err; +} + +srs_error_t rtmp_client::on_ts_audio(SrsTsMessage* msg, SrsBuffer* avs) { + srs_error_t err = srs_success; + + // ensure rtmp connected. + if ((err = connect()) != srs_success) { + return srs_error_wrap(err, "connect"); + } + + // ts tbn to flv tbn. + uint32_t dts = (uint32_t)(msg->dts / 90); + + // send each frame. + while (!avs->empty()) { + char* frame = NULL; + int frame_size = 0; + SrsRawAacStreamCodec codec; + if ((err = _aac_ptr->adts_demux(avs, &frame, &frame_size, codec)) != srs_success) { + return srs_error_wrap(err, "demux adts"); + } + + // ignore invalid frame, + // * atleast 1bytes for aac to decode the data. + if (frame_size <= 0) { + continue; + } + srs_info("mpegts: demux aac frame size=%d, dts=%d", frame_size, dts); + + // generate sh. + if (_aac_specific_config.empty()) { + std::string sh; + if ((err = _aac_ptr->mux_sequence_header(&codec, sh)) != srs_success) { + return srs_error_wrap(err, "mux sequence header"); + } + _aac_specific_config = sh; + + codec.aac_packet_type = 0; + + if ((err = write_audio_raw_frame((char*)sh.data(), (int)sh.length(), &codec, dts)) != srs_success) { + return srs_error_wrap(err, "write raw audio frame"); + } + } + + // audio raw data. + codec.aac_packet_type = 1; + if ((err = write_audio_raw_frame(frame, frame_size, &codec, dts)) != srs_success) { + return srs_error_wrap(err, "write audio raw frame"); + } + } + + return err; +} + +srs_error_t rtmp_client::on_ts_message(SrsTsMessage* msg) { + srs_error_t err = srs_success; + + srs_trace("ts demux len:%d", msg->payload->length()); + // When the audio SID is private stream 1, we use common audio. + // @see https://github.com/ossrs/srs/issues/740 + if (msg->channel->apply == SrsTsPidApplyAudio && msg->sid == SrsTsPESStreamIdPrivateStream1) { + msg->sid = SrsTsPESStreamIdAudioCommon; + } + + // when not audio/video, or not adts/annexb format, donot support. + if (msg->stream_number() != 0) { + return srs_error_new(ERROR_STREAM_CASTER_TS_ES, "ts: unsupported stream format, sid=%#x(%s-%d)", + msg->sid, msg->is_audio()? "A":msg->is_video()? "V":"N", msg->stream_number()); + } + + // check supported codec + if (msg->channel->stream != SrsTsStreamVideoH264 && msg->channel->stream != SrsTsStreamAudioAAC) { + return srs_error_new(ERROR_STREAM_CASTER_TS_CODEC, "ts: unsupported stream codec=%d", msg->channel->stream); + } + + // parse the stream. + SrsBuffer avs(msg->payload->bytes(), msg->payload->length()); + + // publish audio or video. + if (msg->channel->stream == SrsTsStreamVideoH264) { + if ((err = on_ts_video(msg, &avs)) != srs_success) { + return srs_error_wrap(err, "ts: consume video"); + } + } + if (msg->channel->stream == SrsTsStreamAudioAAC) { + if ((err = on_ts_audio(msg, &avs)) != srs_success) { + return srs_error_wrap(err, "ts: consume audio"); + } + } + return err; +} \ No newline at end of file diff --git a/trunk/src/srt/srt_to_rtmp.hpp b/trunk/src/srt/srt_to_rtmp.hpp new file mode 100644 index 0000000000..55a9c24385 --- /dev/null +++ b/trunk/src/srt/srt_to_rtmp.hpp @@ -0,0 +1,93 @@ +#ifndef SRT_TO_RTMP_H +#define SRT_TO_RTMP_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "srt_data.hpp" + +#define SRT_VIDEO_MSG_TYPE 0x01 +#define SRT_AUDIO_MSG_TYPE 0x02 + +typedef std::shared_ptr RTMP_CONN_PTR; +typedef std::shared_ptr AVC_PTR; +typedef std::shared_ptr AAC_PTR; + +class rtmp_client : public ISrsTsHandler { +public: + rtmp_client(std::string key_path); + ~rtmp_client(); + + void receive_ts_data(SRT_DATA_MSG_PTR data_ptr); + +private: + virtual srs_error_t on_ts_message(SrsTsMessage* msg); + srs_error_t connect(); + void close(); + +private: + srs_error_t on_ts_video(SrsTsMessage* msg, SrsBuffer* avs); + srs_error_t on_ts_audio(SrsTsMessage* msg, SrsBuffer* avs); + virtual srs_error_t write_h264_sps_pps(uint32_t dts, uint32_t pts); + virtual srs_error_t write_h264_ipb_frame(char* frame, int frame_size, uint32_t dts, uint32_t pts); + virtual srs_error_t write_audio_raw_frame(char* frame, int frame_size, SrsRawAacStreamCodec* codec, uint32_t dts); + +private: + virtual srs_error_t rtmp_write_packet(char type, uint32_t timestamp, char* data, int size); + +private: + std::string _key_path; + std::string _url; + std::shared_ptr _ts_ctx_ptr; + +private: + AVC_PTR _avc_ptr; + std::string _h264_sps; + bool _h264_sps_changed; + std::string _h264_pps; + bool _h264_pps_changed; + bool _h264_sps_pps_sent; +private: + std::string _aac_specific_config; + AAC_PTR _aac_ptr; +private: + RTMP_CONN_PTR _rtmp_conn_ptr; +}; + +typedef std::shared_ptr RTMP_CLIENT_PTR; + +class srt2rtmp { +public: + srt2rtmp(); + virtual ~srt2rtmp(); + + void start(); + void stop(); + void insert_data_message(unsigned char* data_p, unsigned int len, const std::string& key_path); + +private: + SRT_DATA_MSG_PTR get_data_message(); + void on_work(); + void handle_ts_data(SRT_DATA_MSG_PTR data_ptr); + +private: + std::shared_ptr _thread_ptr; + std::mutex _mutex; + std::condition_variable_any _notify_cond; + std::queue _msg_queue; + + std::unordered_map _rtmp_client_map; + bool _run_flag; +}; + +typedef std::shared_ptr SRT2RTMP_PTR; + +#endif \ No newline at end of file diff --git a/trunk/src/srt/ts_demux.cpp b/trunk/src/srt/ts_demux.cpp new file mode 100644 index 0000000000..ba6dbb0801 --- /dev/null +++ b/trunk/src/srt/ts_demux.cpp @@ -0,0 +1,274 @@ +#include "ts_demux.hpp" +#include + +ts_demux::ts_demux() { + +} + +ts_demux::~ts_demux() { + +} + +int ts_demux::decode(SRT_DATA_MSG_PTR data_ptr, TS_DATA_CALLBACK_PTR callback) { + + return 0; +} + +int decode_ts_header(unsigned char* data_p, ts_header& ts_header_info) { + int pos = 0; + int npos = 0; + + ts_header_info._sync_byte = data_p[pos]; + pos++; + + ts_header_info._transport_error_indicator = (data_p[pos]&0x80)>>7; + ts_header_info._payload_unit_start_indicator = (data_p[pos]&0x40)>>6; + ts_header_info._transport_priority = (data_p[pos]&0x20)>>5; + ts_header_info._PID = ((data_p[pos]<<8)|data_p[pos+1])&0x1FFF; + pos += 2; + + ts_header_info._transport_scrambling_control = (data_p[pos]&0xC0)>>6; + ts_header_info._adaptation_field_control = (data_p[pos]&0x30)>>4; + ts_header_info._continuity_counter = (data_p[pos]&0x0F); + pos++; + npos = pos; + + adaptation_field* field_p = &(ts_header_info._adaptation_field_info); + if( ts_header_info._adaptation_field_control == 2 + || ts_header_info._adaptation_field_control == 3 ){ + // adaptation_field() + field_p->_adaptation_field_length = data_p[pos]; + pos++; + + if( field_p->_adaptation_field_length > 0 ){ + field_p->_discontinuity_indicator = (data_p[pos]&0x80)>>7; + field_p->_random_access_indicator = (data_p[pos]&0x40)>>6; + field_p->_elementary_stream_priority_indicator = (data_p[pos]&0x20)>>5; + field_p->_PCR_flag = (data_p[pos]&0x10)>>4; + field_p->_OPCR_flag = (data_p[pos]&0x08)>>3; + field_p->_splicing_point_flag = (data_p[pos]&0x04)>>2; + field_p->_transport_private_data_flag = (data_p[pos]&0x02)>>1; + field_p->_adaptation_field_extension_flag = (data_p[pos]&0x01); + pos++; + + if( field_p->_PCR_flag == 1 ) { // PCR info + //program_clock_reference_base 33 uimsbf + //reserved 6 bslbf + //program_clock_reference_extension 9 uimsbf + pos += 6; + } + if( field_p->_OPCR_flag == 1 ) { + //original_program_clock_reference_base 33 uimsbf + //reserved 6 bslbf + //original_program_clock_reference_extension 9 uimsbf + pos += 6; + } + if( field_p->_splicing_point_flag == 1 ) { + //splice_countdown 8 tcimsbf + pos++; + } + if( field_p->_transport_private_data_flag == 1 ) { + //transport_private_data_length 8 uimsbf + field_p->_transport_private_data_length = data_p[pos]; + pos++; + memcpy(field_p->_private_data_byte, data_p + pos, field_p->_transport_private_data_length); + } + if( field_p->_adaptation_field_extension_flag == 1 ) { + //adaptation_field_extension_length 8 uimsbf + field_p->_adaptation_field_extension_length = data_p[pos]; + pos++; + //ltw_flag 1 bslbf + field_p->_ltw_flag = (data_p[pos]&0x80)>>7; + //piecewise_rate_flag 1 bslbf + field_p->_piecewise_rate_flag = (data_p[pos]&0x40)>>6; + //seamless_splice_flag 1 bslbf + field_p->_seamless_splice_flag = (data_p[pos]&0x20)>>5; + //reserved 5 bslbf + pos++; + if (field_p->_ltw_flag == 1) { + //ltw_valid_flag 1 bslbf + //ltw_offset 15 uimsbf + pos += 2; + } + if (field_p->_piecewise_rate_flag == 1) { + //reserved 2 bslbf + //piecewise_rate 22 uimsbf + pos += 3; + } + if (field_p->_seamless_splice_flag == 1) { + //splice_type 4 bslbf + //DTS_next_AU[32..30] 3 bslbf + //marker_bit 1 bslbf + //DTS_next_AU[29..15] 15 bslbf + //marker_bit 1 bslbf + //DTS_next_AU[14..0] 15 bslbf + //marker_bit 1 bslbf + pos += 5; + } + } + } + + + npos += sizeof(field_p->_adaptation_field_length) + field_p->_adaptation_field_length; + assert(pos == npos); + } + + if(ts_header_info._adaptation_field_control == 1 + || ts_header_info._adaptation_field_control == 3 ) { + // data_byte with placeholder + // payload parser + if(ts_header_info._PID == 0x00){ + // PAT // program association table + if(ts_header_info._payload_unit_start_indicator) { + pos++; + } + _pat._table_id = data_p[pos]; + pos++; + _pat._section_syntax_indicator = (data_p[pos]>>7)&0x01; + // skip 3 bits of 1 zero and 2 reserved + _pat._section_length = ((data_p[pos]<<8)|data_p[pos+1])&0x0FFF; + pos += 2; + _pat._transport_stream_id = (data_p[pos]<<8)|data_p[pos+1]; + pos += 2; + // reserved 2 bits + _pat._version_number = (data_p[pos]&0x3E)>>1; + _pat._current_next_indicator = data_p[pos]&0x01; + pos++; + _pat._section_number = data_p[pos]; + pos++; + _pat._last_section_number = data_p[pos]; + assert(table_id == 0x00); + assert(188-npos>section_length+3); // PAT = section_length + 3 + pos++; + _pat._pid_vec.clear(); + for (;pos+4 <= section_length-5-4+9;) { // 4:CRC, 5:follow section_length item rpos + 4(following unit length) section_length + 9(above field and unit_start_first_byte ) + PID_INFO pid_info; + //program_number 16 uimsbf + pid_info._program_number = data_p[pos]<<8|data_p[pos+1]; + pos += 2; +// reserved 3 bslbf + + if (pid_info._program_number == 0) { +// // network_PID 13 uimsbf + pid_info._network_id = (data_p[pos]<<8|data_p[pos+1])&0x1FFF; + pos += 2; + } + else { +// // program_map_PID 13 uimsbf + pid_info._pid = (data_p[pos]<<8|data_p[pos+1])&0x1FFF; + pos += 2; + } + _pat._pid_vec.push_back(pid_info); + // network_PID and program_map_PID save to list + } +// CRC_32 use pat to calc crc32, eq + pos += 4; + }else if(ts_header_info._PID == 0x01){ + // CAT // conditional access table + }else if(ts_header_info._PID == 0x02){ + //TSDT // transport stream description table + }else if(ts_header_info._PID == 0x03){ + //IPMP // IPMP control information table + // 0x0004-0x000F Reserved + // 0x0010-0x1FFE May be assigned as network_PID, Program_map_PID, elementary_PID, or for other purposes + }else if(ts_header_info._PID == 0x11){ + // SDT // https://en.wikipedia.org/wiki/Service_Description_Table / https://en.wikipedia.org/wiki/MPEG_transport_stream + }else if(is_pmt(ts_header_info._PID)) { + int rpos = 0; + if(ts_header_info._payload_unit_start_indicator) + rpos++; + _pmt._table_id = data_p[rpos]; + pos++; + _pmt._section_syntax_indicator = (data_p[rpos]>>7)&0x01; + // skip 3 bits of 1 zero and 2 reserved + _pmt._section_length = ((data_p[rpos]<<8)|data_p[pos+1])&0x0FFF; + pos += 2; + _pmt._program_number = (data_p[rpos]<<8)|data_p[rpos+1]; + pos += 2; + // reserved 2 bits + _pmt._version_number = (data_p[pos]&0x3E)>>1; + _pmt._current_next_indicator = data_p[pos]&0x01; + pos++; + _pmt._section_number = data_p[pos]; + pos++; + _pmt._last_section_number = data_p[pos]; + pos++; + // skip 3 bits for reserved 3 bslbf + _pmt._PCR_PID = ((data_p[pos]<<8)|data_p[pos+1])&0x1FFF; //PCR_PID 13 uimsbf + pos += 2; + + //reserved 4 bslbf + _pmt._program_info_length = ((data_p[pos]<<8)|data_p[pos+1])&0x0FFF;//program_info_length 12 uimsbf + pos += 2; + assert(_pmt._table_id==0x02); // 0x02, // TS_program_map_section + memcpy(_pmt._dscr, data_p+pos, _pmt._program_info_length); +// for (i = 0; i < N; i++) { +// descriptor() +// } + pos += _pmt._program_info_length; + _pmt._stream_pid_vec.clear(); + for (; rpos + 5 <= _pmt._section_number + 4 - 4; ) { // rpos(above field length) i+5(following unit length) section_length +3(PMT begin three bytes)+1(payload_unit_start_indicator) -4(crc32) + STREAM_PID_INFO pid_info; + pid_info._stream_type = data_p[pos];//stream_type 8 uimsbf 0x1B AVC video stream as defined in ITU-T Rec. H.264 | ISO/IEC 14496-10 Video + pos++; + //reserved 3 bslbf + pid_info._elementary_PID = ((data_p[pos]<<8)|data_p[pos+1])&0x1FFF; //elementary_PID 13 uimsbf + pos += 2; + //reserved 4 bslbf + pid_info._ES_info_length = ((data_p[pos]<<8)|data_p[pos+1])&0x0FFF; //ES_info_length 12 uimsbf + pos += 2; + if( rpos + pid_info._ES_info_length > _pmt._section_length + 4 - 4 ) + break; + int absES_info_length = rpos + pid_info._ES_info_length; + for (; rpos +#include +#include + +class ts_media_data_callback_I { +public: + virtual void on_data_callback(SRT_DATA_MSG_PTR data_ptr); +}; + +typedef std::shared_ptr TS_DATA_CALLBACK_PTR; + +class adaptation_field { +public: + adaptation_field(){}; + ~adaptation_field(){}; + +public: + unsigned char _adaptation_field_length; + + unsigned char _discontinuity_indicator:1; + unsigned char _random_access_indicator:1; + unsigned char _elementary_stream_priority_indicator:1; + unsigned char _PCR_flag:1; + unsigned char _OPCR_flag:1; + unsigned char _splicing_point_flag:1; + unsigned char _transport_private_data_flag:1; + unsigned char _adaptation_field_extension_flag:1; + + //if(PCR_flag == '1') + unsigned long _program_clock_reference_base;//33 bits + unsigned short _program_clock_reference_extension;//9bits + //if (OPCR_flag == '1') + unsigned long _original_program_clock_reference_base;//33 bits + unsigned short _original_program_clock_reference_extension;//9bits + //if (splicing_point_flag == '1') + unsigned char _splice_countdown; + //if (transport_private_data_flag == '1') + unsigned char _transport_private_data_length; + unsigned char _private_data_byte[256]; + //if (adaptation_field_extension_flag == '1') + unsigned char _adaptation_field_extension_length; + unsigned char _ltw_flag; + unsigned char _piecewise_rate_flag; + unsigned char _seamless_splice_flag; + unsigned char _reserved0; + //if (ltw_flag == '1') + unsigned short _ltw_valid_flag:1; + unsigned short _ltw_offset:15; + //if (piecewise_rate_flag == '1') + unsigned int _piecewise_rate;//22bits + //if (seamless_splice_flag == '1') + unsigned char _splice_type;//4bits + unsigned char _DTS_next_AU1;//3bits + unsigned char _marker_bit1;//1bit + unsigned short _DTS_next_AU2;//15bit + unsigned char _marker_bit2;//1bit + unsigned short _DTS_next_AU3;//15bit +}; + +class ts_header { +public: + ts_header(){} + ~ts_header(){} + +public: + unsigned char _sync_byte; + + unsigned short _transport_error_indicator:1; + unsigned short _payload_unit_start_indicator:1; + unsigned short _transport_priority:1; + unsigned short _PID:13; + + unsigned char _transport_scrambling_control:2; + unsigned char _adaptation_field_control:2; + unsigned char _continuity_counter:4; + + adaptation_field _adaptation_field_info; +}; + +typedef struct { + unsigned short _program_number; + unsigned short _pid; + unsigned short _network_id; +} PID_INFO; + +class pat_info { +public: + pat_info(); + ~pat_info(); + +public: + unsigned char _table_id; + + unsigned short _section_syntax_indicator:1; + unsigned short _reserved0:1; + unsigned short _reserved1:2; + unsigned short _section_length:12; + + unsigned short transport_stream_id; + + unsigned char _reserved3:2; + unsigned char _version_number:5; + unsigned char _current_next_indicator:1; + + unsigned char _section_number; + unsigned char _last_section_number; + std::vector _pid_vec; +}; + +typedef struct { + unsigned char _stream_type; + unsigned short _reserved1:3; + unsigned short _elementary_PID:13; + unsigned short _reserved:4; + unsigned short _ES_info_length; + unsigned char _dscr[4096]; + unsigned int _crc_32; +} STREAM_PID_INFO; + +class pmt_info { +public: + pmt_info(){}; + ~pmt_info(){}; +private: + unsigned char _table_id; + unsigned short _section_syntax_indicator:1; + unsigned short _reserved1:1; + unsigned short _reserved2:2; + unsigned short _section_length:12; + unsigned short _program_number:16; + unsigned char _reserved:2; + unsigned char _version_number:5; + unsigned char _current_next_indicator:5; + unsigned char _section_number; + unsigned char _last_section_number; + unsigned short _reserved3:3; + unsigned short _PCR_PID:13; + unsigned short _reserved4:4; + unsigned short _program_info_length:12; + unsigned char _dscr[4096]; + + std::vector _stream_pid_vec; +}; + +class ts_demux { +public: + ts_demux(); + ~ts_demux(); + + int decode(SRT_DATA_MSG_PTR data_ptr, TS_DATA_CALLBACK_PTR callback); + +private: + int decode_ts_header(unsigned char* data_p, ts_header& ts_header_info); + bool is_pmt(unsigned short pmt_id); + +private: + std::string _key_path;//only for srt + + pat_info _pat; + pmt_info _pmt; +}; + +#endif \ No newline at end of file From 5c5fd805c563b84cdb7b45345ba43559c83e0fa8 Mon Sep 17 00:00:00 2001 From: runner365 Date: Tue, 21 Jan 2020 19:20:09 +0800 Subject: [PATCH 06/32] add srt mpegts to rtmp --- trunk/conf/srs.conf | 13 +- trunk/conf/srt.conf | 34 +++ trunk/configure | 2 +- trunk/src/app/srs_app_config.cpp | 2 +- trunk/src/app/srs_app_server.cpp | 6 + trunk/src/app/srs_app_server.hpp | 1 + trunk/src/srt/srt_conn.hpp | 16 ++ trunk/src/srt/srt_data.cpp | 7 + trunk/src/srt/srt_data.hpp | 1 + trunk/src/srt/srt_handle.cpp | 5 +- trunk/src/srt/srt_handle.hpp | 2 - trunk/src/srt/srt_server.cpp | 7 +- trunk/src/srt/srt_to_rtmp.cpp | 201 ++++++++-------- trunk/src/srt/srt_to_rtmp.hpp | 36 +-- trunk/src/srt/ts_demux.cpp | 383 +++++++++++++++++++++++++++---- trunk/src/srt/ts_demux.hpp | 83 ++++++- trunk/src/srt/ts_demux_test.cpp | 55 +++++ 17 files changed, 682 insertions(+), 172 deletions(-) create mode 100644 trunk/conf/srt.conf create mode 100644 trunk/src/srt/ts_demux_test.cpp diff --git a/trunk/conf/srs.conf b/trunk/conf/srs.conf index 90cc389c41..da062849ab 100644 --- a/trunk/conf/srs.conf +++ b/trunk/conf/srs.conf @@ -5,8 +5,6 @@ listen 1935; max_connections 1000; srs_log_tank file; srs_log_file ./objs/srs.log; -daemon off; - http_api { enabled on; listen 1985; @@ -16,16 +14,9 @@ http_server { listen 8080; dir ./objs/nginx/html; } - -srt_server { - enabled on; - listen 10080; -} - -vhost sina.mobile.com.cn { -} - stats { network 0; disk sda sdb xvda xvdb; } +vhost __defaultVhost__ { +} diff --git a/trunk/conf/srt.conf b/trunk/conf/srt.conf new file mode 100644 index 0000000000..ec37b0367b --- /dev/null +++ b/trunk/conf/srt.conf @@ -0,0 +1,34 @@ +# main config for srs. +# @see full.conf for detail config. + +listen 1935; +max_connections 1000; +srs_log_tank file; +srs_log_file ./objs/srs.log; +daemon off; + +http_api { + enabled on; + listen 1985; +} +http_server { + enabled on; + listen 8080; + dir ./objs/nginx/html; +} + +srt_server { + enabled on; + listen 10080; +} + +vhost __defaultVhost__ { +} + +vhost srs.srt.com.cn { +} + +stats { + network 0; + disk sda sdb xvda xvdb; +} diff --git a/trunk/configure b/trunk/configure index 058b1f9922..ad517dc93c 100755 --- a/trunk/configure +++ b/trunk/configure @@ -211,7 +211,7 @@ PROTOCOL_OBJS="${MODULE_OBJS[@]}" MODULE_ID="SRT" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP") ModuleLibIncs=(${SRS_OBJS_DIR}) -MODULE_FILES=("srt_server" "srt_handle" "srt_conn" "srt_to_rtmp") +MODULE_FILES=("srt_server" "srt_handle" "srt_conn" "srt_to_rtmp" "ts_demux" "srt_data") SRT_INCS="src/srt"; MODULE_DIR=${SRT_INCS} . auto/modules.sh SRT_OBJS="${MODULE_OBJS[@]}" # diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index e443a3318d..2987b48916 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -3640,7 +3640,7 @@ srs_error_t SrsConfig::check_normal_config() get_vhosts(vhosts); for (int n = 0; n < (int)vhosts.size(); n++) { SrsConfDirective* vhost = vhosts[n]; - printf("virtural host name:%s, arg:%s\r\n", vhost->name.c_str(), vhost->args[0].c_str()); + for (int i = 0; vhost && i < (int)vhost->directives.size(); i++) { SrsConfDirective* conf = vhost->at(i); string n = conf->name; diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index 226f0dc1eb..62d97fd97d 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -1014,6 +1014,12 @@ srs_error_t SrsServer::listen_srt() { srs_trace("srt server is enabled..."); unsigned short srt_port = _srs_config->get_srt_listen_port(); srs_trace("srt server listen port:%d", srt_port); + err = srt2rtmp::get_instance()->init(); + if (err != srs_success) { + srs_error_wrap(err, "srt start srt2rtmp error"); + return err; + } + srt_ptr = std::make_shared(srt_port); if (!srt_ptr) { srs_error_wrap(err, "srt listen %d", srt_port); diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index 625c161e78..c03fc996a7 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -37,6 +37,7 @@ #include #include #include "../srt/srt_server.hpp" +#include "../srt/srt_to_rtmp.hpp" class SrsServer; class SrsConnection; diff --git a/trunk/src/srt/srt_conn.hpp b/trunk/src/srt/srt_conn.hpp index 168ca0769a..6801a1c847 100644 --- a/trunk/src/srt/srt_conn.hpp +++ b/trunk/src/srt/srt_conn.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -14,6 +15,21 @@ #define PULL_SRT_MODE 0x01 #define PUSH_SRT_MODE 0x02 +inline bool is_streamid_valid(const std::string& streamid) { + bool ret = false; + if (streamid.empty()) { + return ret; + } + std::vector ret_vec; + string_split(streamid, "/", ret_vec); + + if (ret_vec.size() < 2) { + return ret; + } + ret = true; + return ret; +} + inline void get_streamid_info(const std::string& streamid, int& mode, std::string& url_subpash) { std::string real_streamip; diff --git a/trunk/src/srt/srt_data.cpp b/trunk/src/srt/srt_data.cpp index 8cfec1864c..075064b142 100644 --- a/trunk/src/srt/srt_data.cpp +++ b/trunk/src/srt/srt_data.cpp @@ -1,4 +1,11 @@ #include "srt_data.hpp" +#include + +SRT_DATA_MSG::SRT_DATA_MSG(unsigned int len, const std::string& path):_len(len) + ,_key_path(path) { + _data_p = new unsigned char[len]; + memset(_data_p, 0, len); +} SRT_DATA_MSG::SRT_DATA_MSG(unsigned char* data_p, unsigned int len, const std::string& path):_len(len) ,_key_path(path) diff --git a/trunk/src/srt/srt_data.hpp b/trunk/src/srt/srt_data.hpp index a1a225b90c..ab9cf81ea5 100644 --- a/trunk/src/srt/srt_data.hpp +++ b/trunk/src/srt/srt_data.hpp @@ -5,6 +5,7 @@ class SRT_DATA_MSG { public: + SRT_DATA_MSG(unsigned int len, const std::string& path); SRT_DATA_MSG(unsigned char* data_p, unsigned int len, const std::string& path); ~SRT_DATA_MSG(); diff --git a/trunk/src/srt/srt_handle.cpp b/trunk/src/srt/srt_handle.cpp index 60914e2a45..226013923c 100644 --- a/trunk/src/srt/srt_handle.cpp +++ b/trunk/src/srt/srt_handle.cpp @@ -25,7 +25,6 @@ long long srt_now_ms = 0; srt_handle::srt_handle():_run_flag(false) ,_last_timestamp(0) ,_last_check_alive_ts(0) { - _srt2rtmp_ptr = std::make_shared(); } srt_handle::~srt_handle() { @@ -43,14 +42,12 @@ int srt_handle::start() { srs_trace("srt handle is starting..."); _work_thread_ptr = std::make_shared(&srt_handle::onwork, this); - _srt2rtmp_ptr->start(); return 0; } void srt_handle::stop() { _run_flag = false; _work_thread_ptr->join(); - _srt2rtmp_ptr->stop(); return; } @@ -295,7 +292,7 @@ void srt_handle::handle_push_data(SRT_SOCKSTATUS status, const std::string& subp } srt_conn_ptr->update_timestamp(srt_now_ms); - _srt2rtmp_ptr->insert_data_message(data, ret, subpath); + srt2rtmp::get_instance()->insert_data_message(data, ret, subpath); //send data to subscriber(players) //streamid, play map diff --git a/trunk/src/srt/srt_handle.hpp b/trunk/src/srt/srt_handle.hpp index dd9e0f9268..da555b7149 100644 --- a/trunk/src/srt/srt_handle.hpp +++ b/trunk/src/srt/srt_handle.hpp @@ -75,8 +75,6 @@ class srt_handle { long long _last_timestamp; long long _last_check_alive_ts; - - SRT2RTMP_PTR _srt2rtmp_ptr; }; #endif //SRT_HANDLE_H \ No newline at end of file diff --git a/trunk/src/srt/srt_server.cpp b/trunk/src/srt/srt_server.cpp index 691abaa495..b938f3678f 100644 --- a/trunk/src/srt/srt_server.cpp +++ b/trunk/src/srt/srt_server.cpp @@ -118,7 +118,11 @@ void srt_server::srt_handle_connection(SRT_SOCKSTATUS status, SRTSOCKET input_fd } //add new srt connect into srt handle std::string streamid = UDT::getstreamid(conn_fd); - + if (!is_streamid_valid(streamid)) { + srs_trace("srt streamid(%s) error, fd:%d", streamid.c_str(), conn_fd); + srt_close(conn_fd); + return; + } SRT_CONN_PTR srt_conn_ptr = std::make_shared(conn_fd, streamid); std::string vhost_str = srt_conn_ptr->get_vhost(); @@ -179,7 +183,6 @@ void srt_server::on_work() int ret = srt_epoll_wait(_pollid, read_fds, &rfd_num, write_fds, &wfd_num, -1, nullptr, nullptr, nullptr, nullptr); if (ret < 0) { - srs_error("listen srt epoll is timeout, port=%d", listen_port); continue; } srs_trace("srt server epoll get: ret=%d, rfd_num=%d, wfd_num=%d", diff --git a/trunk/src/srt/srt_to_rtmp.cpp b/trunk/src/srt/srt_to_rtmp.cpp index 647931738c..ecb348b201 100644 --- a/trunk/src/srt/srt_to_rtmp.cpp +++ b/trunk/src/srt/srt_to_rtmp.cpp @@ -5,38 +5,56 @@ #include #include #include +#include "stringex.hpp" -srt2rtmp::srt2rtmp():_run_flag(false) { +std::shared_ptr srt2rtmp::s_srt2rtmp_ptr; +std::shared_ptr srt2rtmp::get_instance() { + if (!s_srt2rtmp_ptr) { + s_srt2rtmp_ptr = std::make_shared(); + } + return s_srt2rtmp_ptr; } -srt2rtmp::~srt2rtmp() { +srt2rtmp::srt2rtmp() { } -void srt2rtmp::start() { - _run_flag = true; +srt2rtmp::~srt2rtmp() { + release(); +} - _thread_ptr = std::make_shared(&srt2rtmp::on_work, this); +srs_error_t srt2rtmp::init() { + srs_error_t err = srs_success; - return; -} + if (_trd_ptr.get() != nullptr) { + return srs_error_wrap(err, "don't start thread again"); + } -void srt2rtmp::stop() { - _run_flag = false; + _trd_ptr = std::make_shared("srt2rtmp", this); - _thread_ptr->join(); - return; + if ((err = _trd_ptr->start()) != srs_success) { + return srs_error_wrap(err, "start thread"); + } + srs_trace("srt2rtmp start coroutine..."); + + return err; } -void srt2rtmp::insert_data_message(unsigned char* data_p, unsigned int len, const std::string& key_path) { - std::unique_lock locker(_mutex); - if (!_run_flag) { +void srt2rtmp::release() { + if (!_trd_ptr) { return; } + _trd_ptr->stop(); + _trd_ptr = nullptr; +} + +void srt2rtmp::insert_data_message(unsigned char* data_p, unsigned int len, const std::string& key_path) { + std::unique_lock locker(_mutex); + SRT_DATA_MSG_PTR msg_ptr = std::make_shared(data_p, len, key_path); _msg_queue.push(msg_ptr); - _notify_cond.notify_one(); + //_notify_cond.notify_one(); return; } @@ -44,23 +62,35 @@ SRT_DATA_MSG_PTR srt2rtmp::get_data_message() { std::unique_lock locker(_mutex); SRT_DATA_MSG_PTR msg_ptr; - while (_msg_queue.empty() && _run_flag) { - _notify_cond.wait(locker); + if (_msg_queue.empty()) + { + return msg_ptr; } + //while (_msg_queue.empty()) { + // _notify_cond.wait(locker); + //} msg_ptr = _msg_queue.front(); _msg_queue.pop(); return msg_ptr; } -void srt2rtmp::on_work() { - while(_run_flag) { +//the cycle is running in srs coroutine +srs_error_t srt2rtmp::cycle() { + srs_error_t err = srs_success; + + while(true) { SRT_DATA_MSG_PTR msg_ptr = get_data_message(); if (!msg_ptr) { - continue; + srs_usleep((30 * SRS_UTIME_MILLISECONDS)); + } else { + handle_ts_data(msg_ptr); + } + + if ((err = _trd_ptr->pull()) != srs_success) { + return srs_error_wrap(err, "forwarder"); } - handle_ts_data(msg_ptr); } } @@ -80,13 +110,27 @@ void srt2rtmp::handle_ts_data(SRT_DATA_MSG_PTR data_ptr) { return; } -rtmp_client::rtmp_client(std::string key_path):_key_path(key_path) { - _ts_ctx_ptr = std::make_shared(); +rtmp_client::rtmp_client(std::string key_path):_key_path(key_path) + , _connect_flag(false) { + _ts_demux_ptr = std::make_shared(); _avc_ptr = std::make_shared(); _aac_ptr = std::make_shared(); + std::vector ret_vec; + string_split(key_path, "/", ret_vec); + + if (ret_vec.size() >= 3) { + _vhost = ret_vec[0]; + _appname = ret_vec[1]; + _streamname = ret_vec[2]; + } else { + _vhost = "DEFAULT_VHOST"; + _appname = ret_vec[0]; + _streamname = ret_vec[1]; + } char url_sz[128]; - sprintf(url_sz, "rtmp://127.0.0.1/%s", key_path.c_str()); + sprintf(url_sz, "rtmp://127.0.0.1/%s?vhost=%s/%s", + _appname.c_str(), _vhost.c_str(), _streamname.c_str()); _url = url_sz; _h264_sps_changed = false; @@ -100,11 +144,13 @@ rtmp_client::~rtmp_client() { } void rtmp_client::close() { + _connect_flag = false; if (!_rtmp_conn_ptr) { return; } _rtmp_conn_ptr->close(); _rtmp_conn_ptr = nullptr; + } srs_error_t rtmp_client::connect() { @@ -112,6 +158,10 @@ srs_error_t rtmp_client::connect() { srs_utime_t cto = SRS_CONSTS_RTMP_TIMEOUT; srs_utime_t sto = SRS_CONSTS_RTMP_PULSE; + if (_connect_flag) { + return srs_success; + } + if (_rtmp_conn_ptr.get() != nullptr) { return srs_error_wrap(err, "repeated connect %s failed, cto=%dms, sto=%dms.", _url.c_str(), srsu2msi(cto), srsu2msi(sto)); @@ -129,19 +179,12 @@ srs_error_t rtmp_client::connect() { close(); return srs_error_wrap(err, "publish error, url:%s", _url.c_str()); } - + _connect_flag = true; return err; } -void rtmp_client::receive_ts_data(SRT_DATA_MSG_PTR data_ptr) { - SrsBuffer* buffer_p = new SrsBuffer((char*)data_ptr->get_data(), data_ptr->data_len()); - FILE* file_p = fopen("1.ts", "ab+"); - if (file_p) { - fwrite(data_ptr->get_data(), data_ptr->data_len(), 1, file_p); - fclose(file_p); - } - //srs_trace_data((char*)data_ptr->get_data(), data_ptr->data_len(), "receive ts data"); - _ts_ctx_ptr->decode(buffer_p, this);//on_ts_message is the decode callback +void rtmp_client::receive_ts_data(SRT_DATA_MSG_PTR data_ptr) { + _ts_demux_ptr->decode(data_ptr, shared_from_this());//on_data_callback is the decode callback return; } @@ -236,11 +279,6 @@ srs_error_t rtmp_client::write_audio_raw_frame(char* frame, int frame_size, SrsR srs_error_t rtmp_client::rtmp_write_packet(char type, uint32_t timestamp, char* data, int size) { srs_error_t err = srs_success; - - if ((err = connect()) != srs_success) { - return srs_error_wrap(err, "connect"); - } - SrsSharedPtrMessage* msg = NULL; if ((err = srs_rtmp_create_msg(type, timestamp, data, size, _rtmp_conn_ptr->sid(), &msg)) != srs_success) { @@ -257,26 +295,23 @@ srs_error_t rtmp_client::rtmp_write_packet(char type, uint32_t timestamp, char* return err; } -srs_error_t rtmp_client::on_ts_video(SrsTsMessage* msg, SrsBuffer* avs) { +srs_error_t rtmp_client::on_ts_video(std::shared_ptr avs_ptr, uint64_t dts, uint64_t pts) { srs_error_t err = srs_success; - + // ensure rtmp connected. if ((err = connect()) != srs_success) { return srs_error_wrap(err, "connect"); } - // ts tbn to flv tbn. - uint32_t dts = (uint32_t)(msg->dts / 90); - uint32_t pts = (uint32_t)(msg->dts / 90); - // send each frame. - while (!avs->empty()) { + while (!avs_ptr->empty()) { char* frame = NULL; int frame_size = 0; - if ((err = _avc_ptr->annexb_demux(avs, &frame, &frame_size)) != srs_success) { + if ((err = _avc_ptr->annexb_demux(avs_ptr.get(), &frame, &frame_size)) != srs_success) { return srs_error_wrap(err, "demux annexb"); } + //srs_trace_data(frame, frame_size, "video annexb demux:"); // 5bits, 7.3.1 NAL unit syntax, // ISO_IEC_14496-10-AVC-2003.pdf, page 44. // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame @@ -336,32 +371,31 @@ srs_error_t rtmp_client::on_ts_video(SrsTsMessage* msg, SrsBuffer* avs) { return err; } -srs_error_t rtmp_client::on_ts_audio(SrsTsMessage* msg, SrsBuffer* avs) { +srs_error_t rtmp_client::on_ts_audio(std::shared_ptr avs_ptr, uint64_t dts, uint64_t pts) { srs_error_t err = srs_success; - + // ensure rtmp connected. if ((err = connect()) != srs_success) { return srs_error_wrap(err, "connect"); } - // ts tbn to flv tbn. - uint32_t dts = (uint32_t)(msg->dts / 90); - // send each frame. - while (!avs->empty()) { + while (!avs_ptr->empty()) { char* frame = NULL; int frame_size = 0; SrsRawAacStreamCodec codec; - if ((err = _aac_ptr->adts_demux(avs, &frame, &frame_size, codec)) != srs_success) { + if ((err = _aac_ptr->adts_demux(avs_ptr.get(), &frame, &frame_size, codec)) != srs_success) { return srs_error_wrap(err, "demux adts"); } - + //srs_trace("audio annexb demux sampling_frequency_index:%d, aac_packet_type:%d, sound_rate:%d, sound_size:%d", + // codec.sampling_frequency_index, codec.aac_packet_type, codec.sound_rate, + // codec.sound_size); + //srs_trace_data(frame, frame_size, "audio annexb demux:"); // ignore invalid frame, // * atleast 1bytes for aac to decode the data. if (frame_size <= 0) { continue; } - srs_info("mpegts: demux aac frame size=%d, dts=%d", frame_size, dts); // generate sh. if (_aac_specific_config.empty()) { @@ -388,40 +422,25 @@ srs_error_t rtmp_client::on_ts_audio(SrsTsMessage* msg, SrsBuffer* avs) { return err; } -srs_error_t rtmp_client::on_ts_message(SrsTsMessage* msg) { - srs_error_t err = srs_success; - - srs_trace("ts demux len:%d", msg->payload->length()); - // When the audio SID is private stream 1, we use common audio. - // @see https://github.com/ossrs/srs/issues/740 - if (msg->channel->apply == SrsTsPidApplyAudio && msg->sid == SrsTsPESStreamIdPrivateStream1) { - msg->sid = SrsTsPESStreamIdAudioCommon; - } - - // when not audio/video, or not adts/annexb format, donot support. - if (msg->stream_number() != 0) { - return srs_error_new(ERROR_STREAM_CASTER_TS_ES, "ts: unsupported stream format, sid=%#x(%s-%d)", - msg->sid, msg->is_audio()? "A":msg->is_video()? "V":"N", msg->stream_number()); - } - - // check supported codec - if (msg->channel->stream != SrsTsStreamVideoH264 && msg->channel->stream != SrsTsStreamAudioAAC) { - return srs_error_new(ERROR_STREAM_CASTER_TS_CODEC, "ts: unsupported stream codec=%d", msg->channel->stream); - } - - // parse the stream. - SrsBuffer avs(msg->payload->bytes(), msg->payload->length()); - - // publish audio or video. - if (msg->channel->stream == SrsTsStreamVideoH264) { - if ((err = on_ts_video(msg, &avs)) != srs_success) { - return srs_error_wrap(err, "ts: consume video"); - } +void rtmp_client::on_data_callback(SRT_DATA_MSG_PTR data_ptr, unsigned int media_type, + uint64_t dts, uint64_t pts) +{ + if (!data_ptr || (data_ptr->get_data() == nullptr) || (data_ptr->data_len() == 0)) { + assert(0); + return; } - if (msg->channel->stream == SrsTsStreamAudioAAC) { - if ((err = on_ts_audio(msg, &avs)) != srs_success) { - return srs_error_wrap(err, "ts: consume audio"); - } + + auto avs_ptr = std::make_shared((char*)data_ptr->get_data(), data_ptr->data_len()); + dts = dts / 90; + pts = pts / 90; + + if (media_type == STREAM_TYPE_VIDEO_H264) { + on_ts_video(avs_ptr, dts, pts); + } else if (media_type == STREAM_TYPE_AUDIO_AAC) { + on_ts_audio(avs_ptr, dts, pts); + } else { + srs_error("mpegts demux unkown stream type:0x%02x", media_type); + assert(0); } - return err; -} \ No newline at end of file + return; +} diff --git a/trunk/src/srt/srt_to_rtmp.hpp b/trunk/src/srt/srt_to_rtmp.hpp index 55a9c24385..040b832b74 100644 --- a/trunk/src/srt/srt_to_rtmp.hpp +++ b/trunk/src/srt/srt_to_rtmp.hpp @@ -13,6 +13,7 @@ #include #include "srt_data.hpp" +#include "ts_demux.hpp" #define SRT_VIDEO_MSG_TYPE 0x01 #define SRT_AUDIO_MSG_TYPE 0x02 @@ -21,7 +22,9 @@ typedef std::shared_ptr RTMP_CONN_PTR; typedef std::shared_ptr AVC_PTR; typedef std::shared_ptr AAC_PTR; -class rtmp_client : public ISrsTsHandler { +#define DEFAULT_VHOST "__default_host__" + +class rtmp_client : public ts_media_data_callback_I, public std::enable_shared_from_this { public: rtmp_client(std::string key_path); ~rtmp_client(); @@ -29,13 +32,14 @@ class rtmp_client : public ISrsTsHandler { void receive_ts_data(SRT_DATA_MSG_PTR data_ptr); private: - virtual srs_error_t on_ts_message(SrsTsMessage* msg); + virtual void on_data_callback(SRT_DATA_MSG_PTR data_ptr, unsigned int media_type, uint64_t dts, uint64_t pts); + srs_error_t connect(); void close(); private: - srs_error_t on_ts_video(SrsTsMessage* msg, SrsBuffer* avs); - srs_error_t on_ts_audio(SrsTsMessage* msg, SrsBuffer* avs); + srs_error_t on_ts_video(std::shared_ptr avs_ptr, uint64_t dts, uint64_t pts); + srs_error_t on_ts_audio(std::shared_ptr avs_ptr, uint64_t dts, uint64_t pts); virtual srs_error_t write_h264_sps_pps(uint32_t dts, uint32_t pts); virtual srs_error_t write_h264_ipb_frame(char* frame, int frame_size, uint32_t dts, uint32_t pts); virtual srs_error_t write_audio_raw_frame(char* frame, int frame_size, SrsRawAacStreamCodec* codec, uint32_t dts); @@ -46,7 +50,10 @@ class rtmp_client : public ISrsTsHandler { private: std::string _key_path; std::string _url; - std::shared_ptr _ts_ctx_ptr; + std::string _vhost; + std::string _appname; + std::string _streamname; + TS_DEMUX_PTR _ts_demux_ptr; private: AVC_PTR _avc_ptr; @@ -60,34 +67,35 @@ class rtmp_client : public ISrsTsHandler { AAC_PTR _aac_ptr; private: RTMP_CONN_PTR _rtmp_conn_ptr; + bool _connect_flag; }; typedef std::shared_ptr RTMP_CLIENT_PTR; -class srt2rtmp { +class srt2rtmp : public ISrsCoroutineHandler { public: + static std::shared_ptr get_instance(); srt2rtmp(); virtual ~srt2rtmp(); - void start(); - void stop(); + srs_error_t init(); + void release(); + void insert_data_message(unsigned char* data_p, unsigned int len, const std::string& key_path); private: SRT_DATA_MSG_PTR get_data_message(); - void on_work(); + virtual srs_error_t cycle(); void handle_ts_data(SRT_DATA_MSG_PTR data_ptr); private: - std::shared_ptr _thread_ptr; + static std::shared_ptr s_srt2rtmp_ptr; + std::shared_ptr _trd_ptr; std::mutex _mutex; - std::condition_variable_any _notify_cond; + //std::condition_variable_any _notify_cond; std::queue _msg_queue; std::unordered_map _rtmp_client_map; - bool _run_flag; }; -typedef std::shared_ptr SRT2RTMP_PTR; - #endif \ No newline at end of file diff --git a/trunk/src/srt/ts_demux.cpp b/trunk/src/srt/ts_demux.cpp index ba6dbb0801..4c10f871b2 100644 --- a/trunk/src/srt/ts_demux.cpp +++ b/trunk/src/srt/ts_demux.cpp @@ -1,7 +1,12 @@ #include "ts_demux.hpp" #include +#include -ts_demux::ts_demux() { +ts_demux::ts_demux():_data_total(0) + ,_last_pid(0) + ,_last_dts(0) + ,_last_pts(0) +{ } @@ -9,14 +14,11 @@ ts_demux::~ts_demux() { } -int ts_demux::decode(SRT_DATA_MSG_PTR data_ptr, TS_DATA_CALLBACK_PTR callback) { - - return 0; -} - -int decode_ts_header(unsigned char* data_p, ts_header& ts_header_info) { +int ts_demux::decode_unit(unsigned char* data_p, std::string key_path, TS_DATA_CALLBACK_PTR callback) +{ int pos = 0; int npos = 0; + ts_header ts_header_info; ts_header_info._sync_byte = data_p[pos]; pos++; @@ -33,7 +35,16 @@ int decode_ts_header(unsigned char* data_p, ts_header& ts_header_info) { pos++; npos = pos; + //printf("ts header(0x%02x) payload_unit_start_indicator:%d, pid:%d, adaptation_field_control:%d, pos:%d\r\n", + // ts_header_info._sync_byte, + // ts_header_info._payload_unit_start_indicator, ts_header_info._PID, + // ts_header_info._adaptation_field_control, pos); + adaptation_field* field_p = &(ts_header_info._adaptation_field_info); + // adaptation field + // 0x01 No adaptation_field, payload only + // 0x02 Adaptation_field only, no payload + // 0x03 Adaptation_field followed by payload if( ts_header_info._adaptation_field_control == 2 || ts_header_info._adaptation_field_control == 3 ){ // adaptation_field() @@ -107,10 +118,7 @@ int decode_ts_header(unsigned char* data_p, ts_header& ts_header_info) { } } } - - npos += sizeof(field_p->_adaptation_field_length) + field_p->_adaptation_field_length; - assert(pos == npos); } if(ts_header_info._adaptation_field_control == 1 @@ -137,11 +145,11 @@ int decode_ts_header(unsigned char* data_p, ts_header& ts_header_info) { _pat._section_number = data_p[pos]; pos++; _pat._last_section_number = data_p[pos]; - assert(table_id == 0x00); - assert(188-npos>section_length+3); // PAT = section_length + 3 + assert(_pat._table_id == 0x00); + assert((188 - npos) > (_pat._section_length+3)); // PAT = section_length + 3 pos++; _pat._pid_vec.clear(); - for (;pos+4 <= section_length-5-4+9;) { // 4:CRC, 5:follow section_length item rpos + 4(following unit length) section_length + 9(above field and unit_start_first_byte ) + for (;pos+4 <= _pat._section_length-5-4+9 + npos;) { // 4:CRC, 5:follow section_length item rpos + 4(following unit length) section_length + 9(above field and unit_start_first_byte ) PID_INFO pid_info; //program_number 16 uimsbf pid_info._program_number = data_p[pos]<<8|data_p[pos+1]; @@ -151,11 +159,13 @@ int decode_ts_header(unsigned char* data_p, ts_header& ts_header_info) { if (pid_info._program_number == 0) { // // network_PID 13 uimsbf pid_info._network_id = (data_p[pos]<<8|data_p[pos+1])&0x1FFF; + //printf("#### network id:%d.\r\n", pid_info._network_id); pos += 2; } else { // // program_map_PID 13 uimsbf pid_info._pid = (data_p[pos]<<8|data_p[pos+1])&0x1FFF; + //printf("#### pmt id:%d.\r\n", pid_info._pid); pos += 2; } _pat._pid_vec.push_back(pid_info); @@ -174,16 +184,15 @@ int decode_ts_header(unsigned char* data_p, ts_header& ts_header_info) { }else if(ts_header_info._PID == 0x11){ // SDT // https://en.wikipedia.org/wiki/Service_Description_Table / https://en.wikipedia.org/wiki/MPEG_transport_stream }else if(is_pmt(ts_header_info._PID)) { - int rpos = 0; if(ts_header_info._payload_unit_start_indicator) - rpos++; - _pmt._table_id = data_p[rpos]; + pos++; + _pmt._table_id = data_p[pos]; pos++; - _pmt._section_syntax_indicator = (data_p[rpos]>>7)&0x01; + _pmt._section_syntax_indicator = (data_p[pos]>>7)&0x01; // skip 3 bits of 1 zero and 2 reserved - _pmt._section_length = ((data_p[rpos]<<8)|data_p[pos+1])&0x0FFF; + _pmt._section_length = ((data_p[pos]<<8)|data_p[pos+1])&0x0FFF; pos += 2; - _pmt._program_number = (data_p[rpos]<<8)|data_p[rpos+1]; + _pmt._program_number = (data_p[pos]<<8)|data_p[pos+1]; pos += 2; // reserved 2 bits _pmt._version_number = (data_p[pos]&0x3E)>>1; @@ -207,7 +216,9 @@ int decode_ts_header(unsigned char* data_p, ts_header& ts_header_info) { // } pos += _pmt._program_info_length; _pmt._stream_pid_vec.clear(); - for (; rpos + 5 <= _pmt._section_number + 4 - 4; ) { // rpos(above field length) i+5(following unit length) section_length +3(PMT begin three bytes)+1(payload_unit_start_indicator) -4(crc32) + _pmt._pid2steamtype.clear(); + + for (; pos + 5 <= _pmt._section_length + 4 - 4 + npos; ) { // pos(above field length) i+5(following unit length) section_length +3(PMT begin three bytes)+1(payload_unit_start_indicator) -4(crc32) STREAM_PID_INFO pid_info; pid_info._stream_type = data_p[pos];//stream_type 8 uimsbf 0x1B AVC video stream as defined in ITU-T Rec. H.264 | ISO/IEC 14496-10 Video pos++; @@ -217,12 +228,13 @@ int decode_ts_header(unsigned char* data_p, ts_header& ts_header_info) { //reserved 4 bslbf pid_info._ES_info_length = ((data_p[pos]<<8)|data_p[pos+1])&0x0FFF; //ES_info_length 12 uimsbf pos += 2; - if( rpos + pid_info._ES_info_length > _pmt._section_length + 4 - 4 ) + if( pos + pid_info._ES_info_length > _pmt._section_length + 4 - 4 + npos ) break; - int absES_info_length = rpos + pid_info._ES_info_length; - for (; rpos 0)) { + insert_into_databuf(ret_data_p, ret_size, key_path, ts_header_info._PID); + } }else{ - // rpos = pes_parse(p, rpos); - printf("PES payload_unit_start_indicator is zero; rpos=%d npos=%d remain=%d hex=%s\n", rpos, npos, 188-(npos+rpos), hexdump(p, 8)); - fwrite(p, 1, 188-(npos+rpos), pes_info[i].fd); + //fwrite(p, 1, 188-(npos+pos), pes_info[i].fd); + insert_into_databuf(data_p + npos, 188-npos, key_path, ts_header_info._PID); } } } - if(!isFound){ - printf("unknown PID = %X \n", PID); - } + //if(!isFound){ + // printf("unknown PID = %X \n", ts_header_info._PID); + //} } } return 0; } +int ts_demux::decode(SRT_DATA_MSG_PTR data_ptr, TS_DATA_CALLBACK_PTR callback) +{ + int ret = -1; + std::string path; + + if (!data_ptr || (data_ptr->data_len() < 188) || (data_ptr->data_len()%188 != 0)) + { + return -1; + } + + + unsigned int count = data_ptr->data_len()/188; + path = data_ptr->get_path(); + for (unsigned int index = 0; index < count; index++) + { + ret = decode_unit(data_ptr->get_data() + 188*index, path, callback); + if (ret < 0) + { + break; + } + } + return ret; +} + +void ts_demux::insert_into_databuf(unsigned char* data_p, size_t data_size, std::string key_path, unsigned short pid) { + _last_pid = pid; + _data_total += data_size; + _data_buffer_vec.push_back(std::make_shared(data_p, data_size, key_path)); + return; +} + +void ts_demux::on_callback(TS_DATA_CALLBACK_PTR callback, unsigned short pid, std::string key_path, + uint64_t dts, uint64_t pts) { + if ((_data_total <=0 ) || (_data_buffer_vec.empty())) { + return; + } + + auto iter = _pmt._pid2steamtype.find(pid); + if (iter == _pmt._pid2steamtype.end()) { + return; + } + unsigned char stream_type = iter->second; + auto total_data_ptr = std::make_shared(_data_total, key_path); + size_t pos = 0; + + for (size_t index = 0; index < _data_buffer_vec.size(); index++) { + memcpy(total_data_ptr->get_data() + pos, + _data_buffer_vec[index]->get_data(), + _data_buffer_vec[index]->data_len()); + pos += _data_buffer_vec[index]->data_len(); + } + _data_buffer_vec.clear(); + _data_total = 0; + + callback->on_data_callback(total_data_ptr, stream_type, dts, pts); + return; +} bool ts_demux::is_pmt(unsigned short pid) { - for (int index = 0; index < _pat._pid_vec.size(); index++) { + for (size_t index = 0; index < _pat._pid_vec.size(); index++) { if (_pat._pid_vec[index]._program_number != 0) { if (_pat._pid_vec[index]._pid == pid) { return true; @@ -272,3 +349,229 @@ bool ts_demux::is_pmt(unsigned short pid) { } return false; } + + +int ts_demux::pes_parse(unsigned char* p, size_t npos, + unsigned char** ret_pp, size_t& ret_size, + uint64_t& dts, uint64_t& pts) { + int pos = 0; + int packet_start_code_prefix = (p[pos]<<16)|(p[pos+1]<<8)|p[pos+2]; //packet_start_code_prefix 24 bslbf + pos += 3; + int stream_id = p[pos]; //stream_id 8 uimsbf + pos++; + //printf("pes parse %02x %02x.\r\n", p[pos], p[pos+1]); + int PES_packet_length = ((unsigned int)p[pos]<<8)|p[pos+1]; //PES_packet_length 16 uimsbf + (void)PES_packet_length; + pos += 2; + //printf("pes parse packet_start_code_prefix:%d, npos:%lu, PES_packet_length:%d, stream_id:%d.\r\n", + // packet_start_code_prefix, npos, PES_packet_length, stream_id); + assert(0x00000001 == packet_start_code_prefix); + if (stream_id != 188//program_stream_map 1011 1100 + && stream_id != 190//padding_stream 1011 1110 + && stream_id != 191//private_stream_2 1011 1111 + && stream_id != 240//ECM 1111 0000 + && stream_id != 241//EMM 1111 0001 + && stream_id != 255//program_stream_directory 1111 1111 + && stream_id != 242//DSMCC_stream 1111 0010 + && stream_id != 248//ITU-T Rec. H.222.1 type E stream 1111 1000 + ) + { + assert(0x80 == p[pos]); + //skip 2bits//'10' 2 bslbf + int PES_scrambling_control = (p[pos]&30)>>4; //PES_scrambling_control 2 bslbf + (void)PES_scrambling_control; + int PES_priority = (p[pos]&0x08)>>3; //PES_priority 1 bslbf + (void)PES_priority; + int data_alignment_indicator = (p[pos]&0x04)>>2;//data_alignment_indicator 1 bslbf + (void)data_alignment_indicator; + int copyright = (p[pos]&0x02)>>1; //copyright 1 bslbf + (void)copyright; + int original_or_copy = (p[pos]&0x01);//original_or_copy 1 bslbf + (void)original_or_copy; + pos++; + int PTS_DTS_flags = (p[pos]&0xC0)>>6; //PTS_DTS_flags 2 bslbf + int ESCR_flag = (p[pos]&0x20)>>5; // ESCR_flag 1 bslbf + int ES_rate_flag = (p[pos]&0x10)>>4;//ES_rate_flag 1 bslbf + int DSM_trick_mode_flag = (p[pos]&0x08)>>3;//DSM_trick_mode_flag 1 bslbf + int additional_copy_info_flag = (p[pos]&0x04)>>2; //additional_copy_info_flag 1 bslbf + int PES_CRC_flag = (p[pos]&0x02)>>1; //PES_CRC_flag 1 bslbf + int PES_extension_flag = (p[pos]&0x01);//PES_extension_flag 1 bslbf + pos++; + int PES_header_data_length = p[pos]; //PES_header_data_length 8 uimsbf + (void)PES_header_data_length; + pos++; + + if (PTS_DTS_flags == 2) { + // skip 4 bits '0010' 4 bslbf + // PTS [32..30] 3 bslbf + // marker_bit 1 bslbf + // PTS [29..15] 15 bslbf + // marker_bit 1 bslbf + // PTS [14..0] 15 bslbf + // marker_bit 1 bslbf + pts = (((p[pos]>>1)&0x07) << 30) | (p[pos+1]<<22) | (((p[pos+2]>>1)&0x7F)<<15) | (p[pos+3]<<7) | ((p[pos+4]>>1)&0x7F); + pos += 5; + } + if (PTS_DTS_flags == 3) { + // '0011' 4 bslbf + // PTS [32..30] 3 bslbf + // marker_bit 1 bslbf + //PTS [29..15] 15 bslbf + //marker_bit 1 bslbf + // PTS [14..0] 15 bslbf + // marker_bit 1 bslbf + pts = (((p[pos]>>1)&0x07) << 30) | (p[pos+1]<<22) | (((p[pos+2]>>1)&0x7F)<<15) | (p[pos+3]<<7) | ((p[pos+4]>>1)&0x7F); + pos += 5; + // '0001' 4 bslbf + // DTS [32..30] 3 bslbf + // marker_bit 1 bslbf + // DTS [29..15] 15 bslbf + // marker_bit 1 bslbf + // DTS [14..0] 15 bslbf + // marker_bit 1 bslbf + dts = (((p[pos]>>1)&0x07) << 30) | (p[pos+1]<<22) | (((p[pos+2]>>1)&0x7F)<<15) | (p[pos+3]<<7) | ((p[pos+4]>>1)&0x7F); + pos += 5; + } + if (ESCR_flag == 1) { + // reserved 2 bslbf + // ESCR_base[32..30] 3 bslbf + // marker_bit 1 bslbf + // ESCR_base[29..15] 15 bslbf + // marker_bit 1 bslbf + // ESCR_base[14..0] 15 bslbf + // marker_bit 1 bslbf + // ESCR_extension 9 uimsbf + // marker_bit 1 bslbf + uint64_t ESCR_base = ((((uint64_t)p[pos] >> 3) & 0x07) << 30) | (((uint64_t)p[pos] & 0x03) << 28) | ((uint64_t)p[pos + 1] << 20) | ((((uint64_t)p[pos + 2] >> 3) & 0x1F) << 15) | (((uint64_t)p[pos + 2] & 0x3) << 13) | ((uint64_t)p[pos + 3] << 5) | ((p[pos + 4] >> 3) & 0x1F); + int ESCR_extension = ((p[pos + 4] & 0x03) << 7) | ((p[pos + 5] >> 1) & 0x7F); + (void)ESCR_base; + (void)ESCR_extension; + pos += 6; + } + if (ES_rate_flag == 1) { + // marker_bit 1 bslbf + // ES_rate 22 uimsbf + // marker_bit 1 bslbf + int ES_rate = (p[pos]&0x7F)<<15 | (p[pos+1])<<7 | (p[pos+2]&0x7F)>>1; + (void)ES_rate; + pos += 3; + } + if (DSM_trick_mode_flag == 1) { // ignore + int trick_mode_control = (p[pos]&0xE0)>>5;//trick_mode_control 3 uimsbf + if ( trick_mode_control == 0/*fast_forward*/ ) { + // field_id 2 bslbf + // intra_slice_refresh 1 bslbf + // frequency_truncation 2 bslbf + } + else if ( trick_mode_control == 1/*slow_motion*/ ) { + //rep_cntrl 5 uimsbf + } + else if ( trick_mode_control == 2/*freeze_frame*/ ) { + // field_id 2 uimsbf + // reserved 3 bslbf + } + else if ( trick_mode_control == 3/*fast_reverse*/ ) { + // field_id 2 bslbf + // intra_slice_refresh 1 bslbf + // frequency_truncation 2 bslbf + }else if ( trick_mode_control == 4/*slow_reverse*/ ) { + // rep_cntrl 5 uimsbf + } + else{ + //reserved 5 bslbf + } + pos++; + } + if ( additional_copy_info_flag == 1) { // ignore + // marker_bit 1 bslbf + // additional_copy_info 7 bslbf + pos++; + } + if ( PES_CRC_flag == 1) { // ignore + // previous_PES_packet_CRC 16 bslbf + pos += 2; + } + if ( PES_extension_flag == 1) { // ignore + int PES_private_data_flag = (p[pos]&0x80)>>7;// PES_private_data_flag 1 bslbf + int pack_header_field_flag = (p[pos]&0x40)>>6;// pack_header_field_flag 1 bslbf + int program_packet_sequence_counter_flag = (p[pos]&0x20)>>5;// program_packet_sequence_counter_flag 1 bslbf + int P_STD_buffer_flag = (p[pos]&0x10)>>4; // P-STD_buffer_flag 1 bslbf + // reserved 3 bslbf + int PES_extension_flag_2 = (p[pos]&0x01);// PES_extension_flag_2 1 bslbf + pos++; + + if ( PES_private_data_flag == 1) { + // PES_private_data 128 bslbf + pos += 16; + } + if (pack_header_field_flag == 1) { + // pack_field_length 8 uimsbf + // pack_header() + } + if (program_packet_sequence_counter_flag == 1) { + // marker_bit 1 bslbf + // program_packet_sequence_counter 7 uimsbf + // marker_bit 1 bslbf + // MPEG1_MPEG2_identifier 1 bslbf + // original_stuff_length 6 uimsbf + pos += 2; + } + if ( P_STD_buffer_flag == 1) { + // '01' 2 bslbf + // P-STD_buffer_scale 1 bslbf + // P-STD_buffer_size 13 uimsbf + pos += 2; + } + if ( PES_extension_flag_2 == 1) { + // marker_bit 1 bslbf + int PES_extension_field_length = (p[pos]&0x7F);// PES_extension_field_length 7 uimsbf + pos++; + for (int i = 0; i < PES_extension_field_length; i++) { + // reserved 8 bslbf + pos++; + } + } + } + +// for (int i = 0; i < N1; i++) { + //stuffing_byte 8 bslbf +// rpos++; +// } +// for (int i = 0; i < N2; i++) { + //PES_packet_data_byte 8 bslbf +// rpos++; +// } + *ret_pp = p+pos; + ret_size = 188-(npos+pos); + //printf("pes parse body size:%lu, data:0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x, dts:%lu(%lu), pts:%lu(%lu)\r\n", + // ret_size, p[pos], p[pos+1], p[pos+2], p[pos+3], p[pos+4], p[pos+5], + // dts, dts/90, pts, pts/90); + } + else if ( stream_id == 188//program_stream_map 1011 1100 BC + || stream_id == 191//private_stream_2 1011 1111 BF + || stream_id == 240//ECM 1111 0000 F0 + || stream_id == 241//EMM 1111 0001 F1 + || stream_id == 255//program_stream_directory 1111 1111 FF + || stream_id == 242//DSMCC_stream 1111 0010 F2 + || stream_id == 248//ITU-T Rec. H.222.1 type E stream 1111 1000 F8 + ) { +// for (i = 0; i < PES_packet_length; i++) { + //PES_packet_data_byte 8 bslbf +// rpos++; +// } + *ret_pp = p+pos; + ret_size = 188-(npos+pos); + //fwrite(p, 1, 188-(npos+rpos), fd); + } + else if ( stream_id == 190//padding_stream 1011 1110 + ) { +// for (i = 0; i < PES_packet_length; i++) { + // padding_byte 8 bslbf +// rpos++; + *ret_pp = p+pos; + ret_size = 188-(npos+pos); +// } + } + + return pos; +} \ No newline at end of file diff --git a/trunk/src/srt/ts_demux.hpp b/trunk/src/srt/ts_demux.hpp index 4a20f11772..4d7c9fd5e6 100644 --- a/trunk/src/srt/ts_demux.hpp +++ b/trunk/src/srt/ts_demux.hpp @@ -4,10 +4,68 @@ #include #include #include +#include + +/* mpegts stream type in ts pmt +Value Description +0x00 ITU-T | ISO/IEC Reserved +0x01 ISO/IEC 11172-2 Video (mpeg video v1) +0x02 ITU-T Rec. H.262 | ISO/IEC 13818-2 Video(mpeg video v2)or ISO/IEC 11172-2 constrained parameter video stream +0x03 ISO/IEC 11172-3 Audio (MPEG 1 Audio codec Layer I, Layer II and Layer III audio specifications) +0x04 ISO/IEC 13818-3 Audio (BC Audio Codec) +0x05 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 private_sections +0x06 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 PES packets containing private data +0x07 ISO/IEC 13522 MHEG +0x08 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A DSM-CC +0x09 ITU-T Rec. H.222.1 +0x0A ISO/IEC 13818-6 type A +0x0B ISO/IEC 13818-6 type B +0x0C ISO/IEC 13818-6 type C +0x0D ISO/IEC 13818-6 type D +0x0E ITU-T Rec. H.222.0 | ISO/IEC 13818-1 auxiliary +0x0F ISO/IEC 13818-7 Audio with ADTS transport syntax +0x10 ISO/IEC 14496-2 Visual +0x11 ISO/IEC 14496-3 Audio with the LATM transport syntax as defined in ISO/IEC 14496-3/Amd.1 +0x12 ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in PES packets +0x13 ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in ISO/IEC 14496_sections +0x14 ISO/IEC 13818-6 Synchronized Download Protocol +0x15 Metadata carried in PES packets +0x16 Metadata carried in metadata_sections +0x17 Metadata carried in ISO/IEC 13818-6 Data Carousel +0x18 Metadata carried in ISO/IEC 13818-6 Object Carousel +0x19 Metadata carried in ISO/IEC 13818-6 Synchronized Download Protocol +0x1A IPMP stream (defined in ISO/IEC 13818-11, MPEG-2 IPMP) +0x1B AVC video stream as defined in ITU-T Rec. H.264 | ISO/IEC 14496-10 Video (h.264) +0x1C ISO/IEC 14496-3 Audio, without using any additional transport syntax, such as DST, ALS and SLS +0x1D ISO/IEC 14496-17 Text +0x1E Auxiliary video stream as defined in ISO/IEC 23002-3 (AVS) +0x1F-0x7E ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Reserved +0x7F IPMP stream 0x80-0xFF User Private +*/ +#define STREAM_TYPE_VIDEO_MPEG1 0x01 +#define STREAM_TYPE_VIDEO_MPEG2 0x02 +#define STREAM_TYPE_AUDIO_MPEG1 0x03 +#define STREAM_TYPE_AUDIO_MPEG2 0x04 +#define STREAM_TYPE_PRIVATE_SECTION 0x05 +#define STREAM_TYPE_PRIVATE_DATA 0x06 +#define STREAM_TYPE_AUDIO_AAC 0x0f +#define STREAM_TYPE_AUDIO_AAC_LATM 0x11 +#define STREAM_TYPE_VIDEO_MPEG4 0x10 +#define STREAM_TYPE_METADATA 0x15 +#define STREAM_TYPE_VIDEO_H264 0x1b +#define STREAM_TYPE_VIDEO_HEVC 0x24 +#define STREAM_TYPE_VIDEO_CAVS 0x42 +#define STREAM_TYPE_VIDEO_VC1 0xea +#define STREAM_TYPE_VIDEO_DIRAC 0xd1 + +#define STREAM_TYPE_AUDIO_AC3 0x81 +#define STREAM_TYPE_AUDIO_DTS 0x82 +#define STREAM_TYPE_AUDIO_TRUEHD 0x83 +#define STREAM_TYPE_AUDIO_EAC3 0x87 class ts_media_data_callback_I { public: - virtual void on_data_callback(SRT_DATA_MSG_PTR data_ptr); + virtual void on_data_callback(SRT_DATA_MSG_PTR data_ptr, unsigned int media_type, uint64_t dts, uint64_t pts) = 0; }; typedef std::shared_ptr TS_DATA_CALLBACK_PTR; @@ -88,8 +146,8 @@ typedef struct { class pat_info { public: - pat_info(); - ~pat_info(); + pat_info(){}; + ~pat_info(){}; public: unsigned char _table_id; @@ -99,7 +157,7 @@ class pat_info { unsigned short _reserved1:2; unsigned short _section_length:12; - unsigned short transport_stream_id; + unsigned short _transport_stream_id; unsigned char _reserved3:2; unsigned char _version_number:5; @@ -124,7 +182,7 @@ class pmt_info { public: pmt_info(){}; ~pmt_info(){}; -private: +public: unsigned char _table_id; unsigned short _section_syntax_indicator:1; unsigned short _reserved1:1; @@ -142,6 +200,7 @@ class pmt_info { unsigned short _program_info_length:12; unsigned char _dscr[4096]; + std::unordered_map _pid2steamtype; std::vector _stream_pid_vec; }; @@ -153,14 +212,26 @@ class ts_demux { int decode(SRT_DATA_MSG_PTR data_ptr, TS_DATA_CALLBACK_PTR callback); private: - int decode_ts_header(unsigned char* data_p, ts_header& ts_header_info); + int decode_unit(unsigned char* data_p, std::string key_path, TS_DATA_CALLBACK_PTR callback); bool is_pmt(unsigned short pmt_id); + int pes_parse(unsigned char* p, size_t npos, unsigned char** ret_pp, size_t& ret_size, + uint64_t& dts, uint64_t& pts); + void insert_into_databuf(unsigned char* data_p, size_t data_size, std::string key_path, unsigned short pid); + void on_callback(TS_DATA_CALLBACK_PTR callback, unsigned short pid, + std::string key_path, uint64_t dts, uint64_t pts); private: std::string _key_path;//only for srt pat_info _pat; pmt_info _pmt; + std::vector _data_buffer_vec; + size_t _data_total; + unsigned short _last_pid; + uint64_t _last_dts; + uint64_t _last_pts; }; +typedef std::shared_ptr TS_DEMUX_PTR; + #endif \ No newline at end of file diff --git a/trunk/src/srt/ts_demux_test.cpp b/trunk/src/srt/ts_demux_test.cpp new file mode 100644 index 0000000000..e68d06218b --- /dev/null +++ b/trunk/src/srt/ts_demux_test.cpp @@ -0,0 +1,55 @@ +#include "ts_demux.hpp" +#include +#include + +#define TS_MAX 188 + +class media_data_get : public ts_media_data_callback_I { +public: + media_data_get() {}; + virtual ~media_data_get() {}; + +public: + virtual void on_data_callback(SRT_DATA_MSG_PTR data_ptr, unsigned int media_type + , uint64_t dts, uint64_t pts) { + printf("media type:%d, data len:%d, key_path:%s, dts:%lu(%lu), pts:%lu(%lu)\r\n", + media_type, data_ptr->data_len(), data_ptr->get_path().c_str(), dts, dts/90, pts, pts/90); + FILE* file_p; + char filename[80]; + + sprintf(filename, "%u.media", media_type); + file_p = fopen(filename, "ab+"); + if (file_p) { + fwrite(data_ptr->get_data(), data_ptr->data_len(), 1, file_p); + fclose(file_p); + } + return; + } +}; + +int main(int argn, char** argv) { + unsigned char data[TS_MAX]; + ts_demux demux_obj; + auto callback_ptr = std::make_shared(); + FILE* file_p; + if (argn < 2) { + printf("please input ts name.\r\n"); + return 0; + } + + const char* file_name = argv[1]; + printf("input ts name:%s.\r\n", file_name); + + file_p = fopen(file_name, "r"); + fseek(file_p, 0L, SEEK_END); /* 定位到文件末尾 */ + size_t flen = ftell(file_p); /* 得到文件大小 */ + fseek(file_p, 0L, SEEK_SET); /* 定位到文件开头 */ + + do { + fread(data, TS_MAX, 1, file_p); + auto input_ptr = std::make_shared((unsigned char*)data, (unsigned int)TS_MAX, std::string("live/shiwei")); + demux_obj.decode(input_ptr, callback_ptr); + flen -= TS_MAX; + } while(flen > 0); + return 1; +} \ No newline at end of file From 746d188e6ffc6f349919f78903ef70783cfdbb25 Mon Sep 17 00:00:00 2001 From: runner365 Date: Tue, 21 Jan 2020 19:23:38 +0800 Subject: [PATCH 07/32] update srt.conf --- trunk/conf/srt.conf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/trunk/conf/srt.conf b/trunk/conf/srt.conf index ec37b0367b..7f101b3d08 100644 --- a/trunk/conf/srt.conf +++ b/trunk/conf/srt.conf @@ -28,6 +28,10 @@ vhost __defaultVhost__ { vhost srs.srt.com.cn { } +# srt推流:srt://127.0.0.1:10080?streamid=srs.srt.com.cn/live/test1?m=push +# srt拉流:srt://127.0.0.1:10080?streamid=srs.srt.com.cn/live/test1?m=pull +# rtmp拉流:rtmp://127.0.0.1/live?vhost=srs.srt.com.cn/test1 + stats { network 0; disk sda sdb xvda xvdb; From d4c08c44d84a475df7437354f93dfcdb420c409d Mon Sep 17 00:00:00 2001 From: runner365 Date: Tue, 21 Jan 2020 20:31:33 +0800 Subject: [PATCH 08/32] remove modules for srt compile --- trunk/configure | 11 +++++++---- trunk/modules/hls-ingester/config | 7 ------- trunk/modules/mp4-parser/config | 7 ------- trunk/modules/readme.txt | 27 --------------------------- 4 files changed, 7 insertions(+), 45 deletions(-) delete mode 100644 trunk/modules/hls-ingester/config delete mode 100644 trunk/modules/mp4-parser/config delete mode 100644 trunk/modules/readme.txt diff --git a/trunk/configure b/trunk/configure index ad517dc93c..93ee7e6670 100755 --- a/trunk/configure +++ b/trunk/configure @@ -158,6 +158,9 @@ fi if [ $SRS_GPERF_MD = YES ]; then LibGperfFile="${SRS_OBJS_DIR}/gperf/lib/libtcmalloc_debug.a"; fi +#srt code path +LibSRTRoot="${SRS_WORKDIR}/src/srt" + # the link options, always use static link SrsLinkOptions="-pthread -ldl -lsrt"; if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL == YES ]]; then @@ -212,7 +215,7 @@ MODULE_ID="SRT" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP") ModuleLibIncs=(${SRS_OBJS_DIR}) MODULE_FILES=("srt_server" "srt_handle" "srt_conn" "srt_to_rtmp" "ts_demux" "srt_data") -SRT_INCS="src/srt"; MODULE_DIR=${SRT_INCS} . auto/modules.sh +SRT_INCS=${LibSRTRoot}; MODULE_DIR=${LibSRTRoot} . auto/modules.sh SRT_OBJS="${MODULE_OBJS[@]}" # #Service Module, for both Server and Client Modules. @@ -232,7 +235,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="APP" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot} ${LibSRTRoot}) MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_source" "srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http_stream" "srs_app_thread" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config" @@ -267,7 +270,7 @@ LIBS_OBJS="${MODULE_OBJS[@]}" if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="SERVER" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP" "SRT") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot} ${LibSRTRoot}) MODULE_FILES=("srs_main_server") SERVER_INCS="src/main"; MODULE_DIR=${SERVER_INCS} . auto/modules.sh SERVER_OBJS="${MODULE_OBJS[@]}" @@ -333,7 +336,7 @@ if [ $SRS_UTEST = YES ]; then MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol" "srs_utest_kernel" "srs_utest_core" "srs_utest_config" "srs_utest_rtmp" "srs_utest_http" "srs_utest_avc" "srs_utest_reload" "srs_utest_mp4" "srs_utest_service" "srs_utest_app") - ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot}) + ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot} ${LibSRTRoot}) ModuleLibFiles=(${LibSTfile} ${LibSSLfile}) MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP" "SRT") MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${APP_OBJS[@]}" diff --git a/trunk/modules/hls-ingester/config b/trunk/modules/hls-ingester/config deleted file mode 100644 index eda6a1363d..0000000000 --- a/trunk/modules/hls-ingester/config +++ /dev/null @@ -1,7 +0,0 @@ - -# The module to ingest hls to replace ffmpeg with better behavior. -SRS_MODULE_NAME=("srs_hls_ingester") -SRS_MODULE_MAIN=("srs_main_ingest_hls") -SRS_MODULE_APP=() -SRS_MODULE_DEFINES="" -SRS_MODULE_MAKEFILE="" diff --git a/trunk/modules/mp4-parser/config b/trunk/modules/mp4-parser/config deleted file mode 100644 index 7f9adfd663..0000000000 --- a/trunk/modules/mp4-parser/config +++ /dev/null @@ -1,7 +0,0 @@ - -# The module to parse mp4 file. -SRS_MODULE_NAME=("srs_mp4_parser") -SRS_MODULE_MAIN=("srs_main_mp4_parser") -SRS_MODULE_APP=() -SRS_MODULE_DEFINES="" -SRS_MODULE_MAKEFILE="" diff --git a/trunk/modules/readme.txt b/trunk/modules/readme.txt deleted file mode 100644 index 32d7891f08..0000000000 --- a/trunk/modules/readme.txt +++ /dev/null @@ -1,27 +0,0 @@ -SRS Module Rules(SRS模块规则) -1. Each module in its seperate home directory(一个模块一个目录). -2. There is a config file in home(目录下放一个config文件). -3. All variables in configure are available(所有的configure中的变量模块中可以使用). - -The Variables in config(模块中需要定义变量,例如): -1. SRS_MODULE_NAME:The application binary name, optional. (模块名称,用来做Makefile的phony以及执行binary文件名。模块的二进制输出。为空时没有独立的二进制。) -2. SRS_MODULE_MAIN:The source file in src/main directory, optional. (模块的main函数所在的cpp文件,在src/main目录。模块在main的文件。可以为空。) -3. SRS_MODULE_APP:The source file in src/app directory, optional. (模块在src/app目录的源文件列表。模块在app的文件。可以为空。) -4. SRS_MODULE_DEFINES: The extra defined macros, optional. (模块编译时的额外宏定义。在app和main模块加入。可以为空。) -5. SRS_MODULE_MAKEFILE: The specified Makefile, optional. (模块的Makefile。在make时会执行这个Makefile。可以为空。) - -Reset all Variables at the beginning(在配置开头必须清空这些变量): -SRS_MODULE_NAME=() -SRS_MODULE_MAIN=() -SRS_MODULE_APP=() -SRS_MODULE_DEFINES="" -SRS_MODULE_MAKEFILE="" - -For example(下面是一个实例): -SRS_MODULE_NAME=("srs_rtmfpd") -SRS_MODULE_MAIN=("srs_main_rtmfpd") -SRS_MODULE_APP=("srs_app_rtfmpd") -SRS_MODULE_DEFINES="-DRTMFPD" -SRS_MODULE_MAKEFILE="modules/rtmfpd/Makefile" - -winlin, 2015.3 From 03ef01c635fffc403150408845e7098b58b47faf Mon Sep 17 00:00:00 2001 From: runner365 Date: Wed, 22 Jan 2020 10:59:50 +0800 Subject: [PATCH 09/32] update configure --- trunk/auto/options.sh | 5 +++++ trunk/conf/srt.conf | 12 +++++++++--- trunk/configure | 3 +++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/trunk/auto/options.sh b/trunk/auto/options.sh index a6436535c6..00d95d407c 100755 --- a/trunk/auto/options.sh +++ b/trunk/auto/options.sh @@ -121,6 +121,7 @@ Options: --with-librtmp enable srs-librtmp, library for client. --with-research build the research tools. --with-utest build the utest for SRS. + --with-srt build the srt for SRS. --with-gperf build SRS with gperf tools(no gmd/gmc/gmp/gcp, with tcmalloc only). --with-gmc build memory check for SRS with gperf tools. --with-gmd build memory defense(corrupt memory) for SRS with gperf tools. @@ -141,6 +142,7 @@ Options: --without-librtmp disable srs-librtmp, library for client. --without-research do not build the research tools. --without-utest do not build the utest for SRS. + --without-srt do not build the srt for SRS. --without-gperf do not build SRS with gperf tools(without tcmalloc and gmd/gmc/gmp/gcp). --without-gmc do not build memory check for SRS with gperf tools. --without-gmd do not build memory defense for SRS with gperf tools. @@ -231,6 +233,7 @@ function parse_user_option() { --with-librtmp) SRS_LIBRTMP=YES ;; --with-research) SRS_RESEARCH=YES ;; --with-utest) SRS_UTEST=YES ;; + --with-srt) SRS_SRT=YES ;; --with-gperf) SRS_GPERF=YES ;; --with-gmc) SRS_GPERF_MC=YES ;; --with-gmd) SRS_GPERF_MD=YES ;; @@ -251,6 +254,7 @@ function parse_user_option() { --without-librtmp) SRS_LIBRTMP=NO ;; --without-research) SRS_RESEARCH=NO ;; --without-utest) SRS_UTEST=NO ;; + --without-srt) SRS_SRT=NO ;; --without-gperf) SRS_GPERF=NO ;; --without-gmc) SRS_GPERF_MC=NO ;; --without-gmd) SRS_GPERF_MD=NO ;; @@ -536,6 +540,7 @@ SRS_AUTO_CONFIGURE="--prefix=${SRS_PREFIX}" if [ $SRS_LIBRTMP = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-librtmp"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-librtmp"; fi if [ $SRS_RESEARCH = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-research"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-research"; fi if [ $SRS_UTEST = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-utest"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-utest"; fi + if [ $SRS_SRT = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-srt"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-srt"; fi if [ $SRS_GPERF = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-gperf"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-gperf"; fi if [ $SRS_GPERF_MC = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-gmc"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-gmc"; fi if [ $SRS_GPERF_MD = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-gmd"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-gmd"; fi diff --git a/trunk/conf/srt.conf b/trunk/conf/srt.conf index 7f101b3d08..35614f2aa7 100644 --- a/trunk/conf/srt.conf +++ b/trunk/conf/srt.conf @@ -28,9 +28,15 @@ vhost __defaultVhost__ { vhost srs.srt.com.cn { } -# srt推流:srt://127.0.0.1:10080?streamid=srs.srt.com.cn/live/test1?m=push -# srt拉流:srt://127.0.0.1:10080?streamid=srs.srt.com.cn/live/test1?m=pull -# rtmp拉流:rtmp://127.0.0.1/live?vhost=srs.srt.com.cn/test1 +# 无vhost配置(__defaultVhost__), 示例: +# srt推流地址:srt://127.0.0.1:10080?streamid=live/test1?m=push +# srt拉流地址:srt://127.0.0.1:10080?streamid=live/test1?m=pull +# rtmp拉流地址:rtmp://127.0.0.1/live/test1 + +# 带有vhost配置, 示例: +# srt推流地址:srt://127.0.0.1:10080?streamid=srs.srt.com.cn/live/test1?m=push +# srt拉流地址:srt://127.0.0.1:10080?streamid=srs.srt.com.cn/live/test1?m=pull +# rtmp拉流地址:rtmp://127.0.0.1/live?vhost=srs.srt.com.cn/test1 stats { network 0; diff --git a/trunk/configure b/trunk/configure index 93ee7e6670..797b2207c0 100755 --- a/trunk/configure +++ b/trunk/configure @@ -211,12 +211,15 @@ PROTOCOL_INCS="src/protocol"; MODULE_DIR=${PROTOCOL_INCS} . auto/modules.sh PROTOCOL_OBJS="${MODULE_OBJS[@]}" # #srt protocol features. +if [ $SRS_SRT = YES ]; then MODULE_ID="SRT" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP") ModuleLibIncs=(${SRS_OBJS_DIR}) MODULE_FILES=("srt_server" "srt_handle" "srt_conn" "srt_to_rtmp" "ts_demux" "srt_data") SRT_INCS=${LibSRTRoot}; MODULE_DIR=${LibSRTRoot} . auto/modules.sh SRT_OBJS="${MODULE_OBJS[@]}" +fi + # #Service Module, for both Server and Client Modules. if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then From c7f6eef4ac1ccf78c45804bea3441802400a9821 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 23 Jan 2020 11:51:35 +0800 Subject: [PATCH 10/32] Refine config file, link to issue. --- trunk/conf/srt.conf | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/trunk/conf/srt.conf b/trunk/conf/srt.conf index 35614f2aa7..9dc1e564e6 100644 --- a/trunk/conf/srt.conf +++ b/trunk/conf/srt.conf @@ -1,10 +1,8 @@ -# main config for srs. -# @see full.conf for detail config. +# SRT config. listen 1935; max_connections 1000; -srs_log_tank file; -srs_log_file ./objs/srs.log; +srs_log_tank console; daemon off; http_api { @@ -22,22 +20,12 @@ srt_server { listen 10080; } +# @doc https://github.com/ossrs/srs/issues/1147#issuecomment-577492117 vhost __defaultVhost__ { } - vhost srs.srt.com.cn { } -# 无vhost配置(__defaultVhost__), 示例: -# srt推流地址:srt://127.0.0.1:10080?streamid=live/test1?m=push -# srt拉流地址:srt://127.0.0.1:10080?streamid=live/test1?m=pull -# rtmp拉流地址:rtmp://127.0.0.1/live/test1 - -# 带有vhost配置, 示例: -# srt推流地址:srt://127.0.0.1:10080?streamid=srs.srt.com.cn/live/test1?m=push -# srt拉流地址:srt://127.0.0.1:10080?streamid=srs.srt.com.cn/live/test1?m=pull -# rtmp拉流地址:rtmp://127.0.0.1/live?vhost=srs.srt.com.cn/test1 - stats { network 0; disk sda sdb xvda xvdb; From a27c4f709566fbf4580601d405bc9f1b4d75f92c Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 23 Jan 2020 12:09:54 +0800 Subject: [PATCH 11/32] Revert "remove modules for srt compile" This reverts commit d4c08c44d84a475df7437354f93dfcdb420c409d. --- trunk/configure | 11 ++++------- trunk/modules/hls-ingester/config | 7 +++++++ trunk/modules/mp4-parser/config | 7 +++++++ trunk/modules/readme.txt | 27 +++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 trunk/modules/hls-ingester/config create mode 100644 trunk/modules/mp4-parser/config create mode 100644 trunk/modules/readme.txt diff --git a/trunk/configure b/trunk/configure index 797b2207c0..9efe2fdbdc 100755 --- a/trunk/configure +++ b/trunk/configure @@ -158,9 +158,6 @@ fi if [ $SRS_GPERF_MD = YES ]; then LibGperfFile="${SRS_OBJS_DIR}/gperf/lib/libtcmalloc_debug.a"; fi -#srt code path -LibSRTRoot="${SRS_WORKDIR}/src/srt" - # the link options, always use static link SrsLinkOptions="-pthread -ldl -lsrt"; if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL == YES ]]; then @@ -216,7 +213,7 @@ MODULE_ID="SRT" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP") ModuleLibIncs=(${SRS_OBJS_DIR}) MODULE_FILES=("srt_server" "srt_handle" "srt_conn" "srt_to_rtmp" "ts_demux" "srt_data") -SRT_INCS=${LibSRTRoot}; MODULE_DIR=${LibSRTRoot} . auto/modules.sh +SRT_INCS="src/srt"; MODULE_DIR=${SRT_INCS} . auto/modules.sh SRT_OBJS="${MODULE_OBJS[@]}" fi @@ -238,7 +235,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="APP" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot} ${LibSRTRoot}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_source" "srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http_stream" "srs_app_thread" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config" @@ -273,7 +270,7 @@ LIBS_OBJS="${MODULE_OBJS[@]}" if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="SERVER" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP" "SRT") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot} ${LibSRTRoot}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) MODULE_FILES=("srs_main_server") SERVER_INCS="src/main"; MODULE_DIR=${SERVER_INCS} . auto/modules.sh SERVER_OBJS="${MODULE_OBJS[@]}" @@ -339,7 +336,7 @@ if [ $SRS_UTEST = YES ]; then MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol" "srs_utest_kernel" "srs_utest_core" "srs_utest_config" "srs_utest_rtmp" "srs_utest_http" "srs_utest_avc" "srs_utest_reload" "srs_utest_mp4" "srs_utest_service" "srs_utest_app") - ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot} ${LibSRTRoot}) + ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot}) ModuleLibFiles=(${LibSTfile} ${LibSSLfile}) MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP" "SRT") MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${APP_OBJS[@]}" diff --git a/trunk/modules/hls-ingester/config b/trunk/modules/hls-ingester/config new file mode 100644 index 0000000000..eda6a1363d --- /dev/null +++ b/trunk/modules/hls-ingester/config @@ -0,0 +1,7 @@ + +# The module to ingest hls to replace ffmpeg with better behavior. +SRS_MODULE_NAME=("srs_hls_ingester") +SRS_MODULE_MAIN=("srs_main_ingest_hls") +SRS_MODULE_APP=() +SRS_MODULE_DEFINES="" +SRS_MODULE_MAKEFILE="" diff --git a/trunk/modules/mp4-parser/config b/trunk/modules/mp4-parser/config new file mode 100644 index 0000000000..7f9adfd663 --- /dev/null +++ b/trunk/modules/mp4-parser/config @@ -0,0 +1,7 @@ + +# The module to parse mp4 file. +SRS_MODULE_NAME=("srs_mp4_parser") +SRS_MODULE_MAIN=("srs_main_mp4_parser") +SRS_MODULE_APP=() +SRS_MODULE_DEFINES="" +SRS_MODULE_MAKEFILE="" diff --git a/trunk/modules/readme.txt b/trunk/modules/readme.txt new file mode 100644 index 0000000000..32d7891f08 --- /dev/null +++ b/trunk/modules/readme.txt @@ -0,0 +1,27 @@ +SRS Module Rules(SRS模块规则) +1. Each module in its seperate home directory(一个模块一个目录). +2. There is a config file in home(目录下放一个config文件). +3. All variables in configure are available(所有的configure中的变量模块中可以使用). + +The Variables in config(模块中需要定义变量,例如): +1. SRS_MODULE_NAME:The application binary name, optional. (模块名称,用来做Makefile的phony以及执行binary文件名。模块的二进制输出。为空时没有独立的二进制。) +2. SRS_MODULE_MAIN:The source file in src/main directory, optional. (模块的main函数所在的cpp文件,在src/main目录。模块在main的文件。可以为空。) +3. SRS_MODULE_APP:The source file in src/app directory, optional. (模块在src/app目录的源文件列表。模块在app的文件。可以为空。) +4. SRS_MODULE_DEFINES: The extra defined macros, optional. (模块编译时的额外宏定义。在app和main模块加入。可以为空。) +5. SRS_MODULE_MAKEFILE: The specified Makefile, optional. (模块的Makefile。在make时会执行这个Makefile。可以为空。) + +Reset all Variables at the beginning(在配置开头必须清空这些变量): +SRS_MODULE_NAME=() +SRS_MODULE_MAIN=() +SRS_MODULE_APP=() +SRS_MODULE_DEFINES="" +SRS_MODULE_MAKEFILE="" + +For example(下面是一个实例): +SRS_MODULE_NAME=("srs_rtmfpd") +SRS_MODULE_MAIN=("srs_main_rtmfpd") +SRS_MODULE_APP=("srs_app_rtfmpd") +SRS_MODULE_DEFINES="-DRTMFPD" +SRS_MODULE_MAKEFILE="modules/rtmfpd/Makefile" + +winlin, 2015.3 From 106113c5f0743ac09864ca7440861993e27dc432 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 23 Jan 2020 12:15:02 +0800 Subject: [PATCH 12/32] For previous revert, pick some code for LibSRTRoot --- trunk/configure | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/trunk/configure b/trunk/configure index 9efe2fdbdc..c3f90ecfd8 100755 --- a/trunk/configure +++ b/trunk/configure @@ -158,6 +158,8 @@ fi if [ $SRS_GPERF_MD = YES ]; then LibGperfFile="${SRS_OBJS_DIR}/gperf/lib/libtcmalloc_debug.a"; fi +# srt code path +LibSRTRoot="${SRS_WORKDIR}/src/srt" # the link options, always use static link SrsLinkOptions="-pthread -ldl -lsrt"; if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL == YES ]]; then @@ -213,7 +215,7 @@ MODULE_ID="SRT" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP") ModuleLibIncs=(${SRS_OBJS_DIR}) MODULE_FILES=("srt_server" "srt_handle" "srt_conn" "srt_to_rtmp" "ts_demux" "srt_data") -SRT_INCS="src/srt"; MODULE_DIR=${SRT_INCS} . auto/modules.sh +SRT_INCS=${LibSRTRoot}; MODULE_DIR=${LibSRTRoot} . auto/modules.sh SRT_OBJS="${MODULE_OBJS[@]}" fi @@ -235,7 +237,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="APP" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot} ${LibSRTRoot}) MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_source" "srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http_stream" "srs_app_thread" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config" @@ -270,7 +272,7 @@ LIBS_OBJS="${MODULE_OBJS[@]}" if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="SERVER" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP" "SRT") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot} ${LibSRTRoot}) MODULE_FILES=("srs_main_server") SERVER_INCS="src/main"; MODULE_DIR=${SERVER_INCS} . auto/modules.sh SERVER_OBJS="${MODULE_OBJS[@]}" @@ -336,7 +338,7 @@ if [ $SRS_UTEST = YES ]; then MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol" "srs_utest_kernel" "srs_utest_core" "srs_utest_config" "srs_utest_rtmp" "srs_utest_http" "srs_utest_avc" "srs_utest_reload" "srs_utest_mp4" "srs_utest_service" "srs_utest_app") - ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot}) + ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot} ${LibSRTRoot}) ModuleLibFiles=(${LibSTfile} ${LibSSLfile}) MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP" "SRT") MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${APP_OBJS[@]}" From 2de8d788f62877b8ca4288ef062f134f5481e132 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 23 Jan 2020 12:32:15 +0800 Subject: [PATCH 13/32] Revert configure changes(srs_ingest_hls,utest) in previous commit --- trunk/configure | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/trunk/configure b/trunk/configure index c3f90ecfd8..06fee5cf47 100755 --- a/trunk/configure +++ b/trunk/configure @@ -133,7 +133,8 @@ ARFLAGS = -rs LINK = g++ CXXFLAGS = ${CXXFLAGS} -.PHONY: default srs librtmp +.PHONY: default srs srs_ingest_hls librtmp + default: END @@ -359,7 +360,7 @@ mv ${SRS_WORKDIR}/${SRS_MAKEFILE} ${SRS_WORKDIR}/${SRS_MAKEFILE}.bk # generate phony header cat << END > ${SRS_WORKDIR}/${SRS_MAKEFILE} -.PHONY: default _default install install-api help clean server librtmp _prepare_dir $__mphonys +.PHONY: default _default install install-api help clean server srs_ingest_hls librtmp utest _prepare_dir $__mphonys # install prefix. SRS_PREFIX=${SRS_PREFIX} @@ -374,7 +375,7 @@ END # the server, librtmp and utest # where the bellow will check and disable some entry by only echo. cat << END >> ${SRS_WORKDIR}/${SRS_MAKEFILE} -_default: server librtmp __modules $__mdefaults +_default: server srs_ingest_hls librtmp utest __modules $__mdefaults @bash objs/_srs_build_summary.sh help: From fb5928f927f7a0bbb056d04df5dfaa2dc7275e88 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 23 Jan 2020 13:24:47 +0800 Subject: [PATCH 14/32] Fix build failed for SRT with modules. --- trunk/auto/utest.sh | 2 +- trunk/configure | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/trunk/auto/utest.sh b/trunk/auto/utest.sh index d658bf7f4a..ab96caea28 100755 --- a/trunk/auto/utest.sh +++ b/trunk/auto/utest.sh @@ -58,7 +58,7 @@ USER_DIR = . CPPFLAGS += -I\$(GTEST_DIR)/include # Flags passed to the C++ compiler. -CXXFLAGS += -g -Wall -Wextra -O0 ${EXTRA_DEFINES} +CXXFLAGS += ${CXXFLAGS} -Wextra ${EXTRA_DEFINES} # All tests produced by this Makefile. Remember to add new tests you # created to the list. diff --git a/trunk/configure b/trunk/configure index 06fee5cf47..a639df52bf 100755 --- a/trunk/configure +++ b/trunk/configure @@ -319,7 +319,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then BUILD_KEY="srs" APP_MAIN="srs_main_server" APP_NAME="srs" . auto/apps.sh # # For modules, without the app module. - MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${SRT_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${MAIN_OBJS[@]}" + MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${MAIN_OBJS[@]}" # for SRS_MODULE in ${SRS_MODULES[*]}; do . $SRS_MODULE/config @@ -342,7 +342,7 @@ if [ $SRS_UTEST = YES ]; then ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot} ${LibSRTRoot}) ModuleLibFiles=(${LibSTfile} ${LibSSLfile}) MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP" "SRT") - MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${APP_OBJS[@]}" + MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${APP_OBJS[@]} ${SRT_OBJS[@]}" LINK_OPTIONS="-lpthread ${SrsLinkOptions}" MODULE_DIR="src/utest" APP_NAME="srs_utest" . auto/utest.sh fi From fb29096505184fe3a1668651aa1d73c20baecb3b Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 23 Jan 2020 14:22:22 +0800 Subject: [PATCH 15/32] For SRT, allow/default disable it by --without-srt --- trunk/auto/options.sh | 1 + trunk/configure | 59 ++++++++++++++++++++++++++++++------------- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/trunk/auto/options.sh b/trunk/auto/options.sh index 00d95d407c..a46685e6f8 100755 --- a/trunk/auto/options.sh +++ b/trunk/auto/options.sh @@ -16,6 +16,7 @@ help=no ################################################################ # feature options SRS_HDS=NO +SRS_SRT=NO SRS_NGINX=NO SRS_FFMPEG_TOOL=NO SRS_LIBRTMP=NO diff --git a/trunk/configure b/trunk/configure index a639df52bf..5b8cd4b0f6 100755 --- a/trunk/configure +++ b/trunk/configure @@ -96,10 +96,11 @@ END GDBDebug=" -g -O0" # the warning level. WarnLevel=" -Wall" -# c++11 enable. -cpp11=" -std=c++11 -pthread" # the compile standard. CppStd="-ansi" +if [[ $SRS_SRT == YES ]]; then + CppStd="-std=c++11" +fi # for library compile if [[ $SRS_EXPORT_LIBRTMP_PROJECT == YES ]]; then LibraryCompile=" -fPIC" @@ -109,7 +110,7 @@ SrsGprof=""; SrsGprofLink=""; if [ $SRS_GPROF = YES ]; then SrsGprof=" -pg -lc_p # performance of gperf SrsGperf=""; SrsGperfLink=""; if [ $SRS_GPERF = YES ]; then SrsGperfLink=" -lpthread"; fi # the cxx flag generated. -CXXFLAGS="${CXXFLAGS} ${CppStd}${WarnLevel}${cpp11}${GDBDebug}${LibraryCompile}${SrsGprof}" +CXXFLAGS="${CXXFLAGS} ${CppStd}${WarnLevel}${GDBDebug}${LibraryCompile}${SrsGprof}" if [ $SRS_GPERF = YES ]; then CXXFLAGS="${CXXFLAGS} -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free"; fi @@ -160,9 +161,14 @@ if [ $SRS_GPERF_MD = YES ]; then LibGperfFile="${SRS_OBJS_DIR}/gperf/lib/libtcmalloc_debug.a"; fi # srt code path -LibSRTRoot="${SRS_WORKDIR}/src/srt" +if [[ $SRS_SRT == YES ]]; then + LibSRTRoot="${SRS_WORKDIR}/src/srt" +fi # the link options, always use static link -SrsLinkOptions="-pthread -ldl -lsrt"; +SrsLinkOptions="-ldl"; +if [[ $SRS_SRT == YES ]]; then + SrsLinkOptions="${SrsLinkOptions} -pthread -lsrt"; +fi if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL == YES ]]; then SrsLinkOptions="${SrsLinkOptions} -lssl -lcrypto"; fi @@ -212,12 +218,12 @@ PROTOCOL_OBJS="${MODULE_OBJS[@]}" # #srt protocol features. if [ $SRS_SRT = YES ]; then -MODULE_ID="SRT" -MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP") -ModuleLibIncs=(${SRS_OBJS_DIR}) -MODULE_FILES=("srt_server" "srt_handle" "srt_conn" "srt_to_rtmp" "ts_demux" "srt_data") -SRT_INCS=${LibSRTRoot}; MODULE_DIR=${LibSRTRoot} . auto/modules.sh -SRT_OBJS="${MODULE_OBJS[@]}" + MODULE_ID="SRT" + MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP") + ModuleLibIncs=(${SRS_OBJS_DIR}) + MODULE_FILES=("srt_server" "srt_handle" "srt_conn" "srt_to_rtmp" "ts_demux" "srt_data") + SRT_INCS=${LibSRTRoot}; MODULE_DIR=${LibSRTRoot} . auto/modules.sh + SRT_OBJS="${MODULE_OBJS[@]}" fi # @@ -238,7 +244,10 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="APP" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot} ${LibSRTRoot}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) + if [[ $SRS_SRT == YES ]]; then + ModuleLibIncs+=("${LibSRTRoot[*]}") + fi MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_source" "srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http_stream" "srs_app_thread" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config" @@ -272,8 +281,14 @@ LIBS_OBJS="${MODULE_OBJS[@]}" #Server Module, for SRS only. if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="SERVER" - MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP" "SRT") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot} ${LibSRTRoot}) + MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP") + if [[ $SRS_SRT == YES ]]; then + MODULE_DEPENDS+=("SRT") + fi + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + if [[ $SRS_SRT == YES ]]; then + ModuleLibIncs+=("${LibSRTRoot[*]}") + fi MODULE_FILES=("srs_main_server") SERVER_INCS="src/main"; MODULE_DIR=${SERVER_INCS} . auto/modules.sh SERVER_OBJS="${MODULE_OBJS[@]}" @@ -312,7 +327,11 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then # all depends libraries ModuleLibFiles=(${LibSTfile} ${LibSSLfile} ${LibGperfFile}) # all depends objects - MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SRT_OBJS[@]} ${SERVICE_OBJS[@]} ${APP_OBJS[@]} ${SERVER_OBJS[@]}" + MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${APP_OBJS[@]} ${SERVER_OBJS[@]}" + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + if [[ $SRS_SRT == YES ]]; then + MODULE_OBJS="${MODULE_OBJS} ${SRT_OBJS[@]}" + fi LINK_OPTIONS="${SrsLinkOptions}${SrsGprofLink}${SrsGperfLink}" # # srs: srs(simple rtmp server) over st(state-threads) @@ -339,9 +358,15 @@ if [ $SRS_UTEST = YES ]; then MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol" "srs_utest_kernel" "srs_utest_core" "srs_utest_config" "srs_utest_rtmp" "srs_utest_http" "srs_utest_avc" "srs_utest_reload" "srs_utest_mp4" "srs_utest_service" "srs_utest_app") - ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot} ${LibSRTRoot}) + ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot}) + if [[ $SRS_SRT == YES ]]; then + ModuleLibIncs+=("${LibSRTRoot[*]}") + fi ModuleLibFiles=(${LibSTfile} ${LibSSLfile}) - MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP" "SRT") + MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP") + if [[ $SRS_SRT == YES ]]; then + MODULE_DEPENDS+=("SRT") + fi MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${APP_OBJS[@]} ${SRT_OBJS[@]}" LINK_OPTIONS="-lpthread ${SrsLinkOptions}" MODULE_DIR="src/utest" APP_NAME="srs_utest" . auto/utest.sh fi From f1437574293598e41c9e46dca8e15de794b7553d Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 23 Jan 2020 14:23:09 +0800 Subject: [PATCH 16/32] Use macro to disable SRT in code --- trunk/auto/auto_headers.sh | 6 ++++++ trunk/src/app/srs_app_server.cpp | 4 ++++ trunk/src/app/srs_app_server.hpp | 9 ++++++--- trunk/src/main/srs_main_server.cpp | 1 + 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/trunk/auto/auto_headers.sh b/trunk/auto/auto_headers.sh index 10e76e99f7..96f5526d34 100755 --- a/trunk/auto/auto_headers.sh +++ b/trunk/auto/auto_headers.sh @@ -70,6 +70,12 @@ else srs_undefine_macro "SRS_AUTO_HDS" $SRS_AUTO_HEADERS_H fi +if [ $SRS_SRT = YES ]; then + srs_define_macro "SRS_AUTO_SRT" $SRS_AUTO_HEADERS_H +else + srs_undefine_macro "SRS_AUTO_SRT" $SRS_AUTO_HEADERS_H +fi + if [ $SRS_MEM_WATCH = YES ]; then srs_define_macro "SRS_AUTO_MEM_WATCH" $SRS_AUTO_HEADERS_H else diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index 62d97fd97d..c85930da37 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -688,9 +688,11 @@ srs_error_t SrsServer::listen() if ((err = conn_manager->start()) != srs_success) { return srs_error_wrap(err, "connection manager"); } +#ifdef SRS_AUTO_SRT if ((err = listen_srt()) != srs_success) { return srs_error_wrap(err, "srt listen"); } +#endif return err; } @@ -1007,6 +1009,7 @@ srs_error_t SrsServer::do_cycle() return err; } +#ifdef SRS_AUTO_SRT srs_error_t SrsServer::listen_srt() { srs_error_t err = srs_success; @@ -1030,6 +1033,7 @@ srs_error_t SrsServer::listen_srt() { } return err; } +#endif srs_error_t SrsServer::listen_rtmp() { diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index c03fc996a7..a852f0a144 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -36,8 +36,10 @@ #include #include #include +#ifdef SRS_AUTO_SRT #include "../srt/srt_server.hpp" #include "../srt/srt_to_rtmp.hpp" +#endif class SrsServer; class SrsConnection; @@ -211,11 +213,10 @@ class SrsServer : virtual public ISrsReloadHandler, virtual public ISrsSourceHan SrsHttpHeartbeat* http_heartbeat; SrsIngester* ingester; SrsCoroutineManager* conn_manager; - -private: +#ifdef SRS_AUTO_SRT //srt server SRT_SERVER_PTR srt_ptr; - +#endif private: // The pid file fd, lock the file write when server is running. // @remark the init.d script should cleanup the pid file, when stop service, @@ -286,8 +287,10 @@ class SrsServer : virtual public ISrsReloadHandler, virtual public ISrsSourceHan virtual srs_error_t listen_http_api(); virtual srs_error_t listen_http_stream(); virtual srs_error_t listen_stream_caster(); +#ifdef SRS_AUTO_SRT //start listen srt udp port virtual srs_error_t listen_srt(); +#endif // Close the listeners for specified type, // Remove the listen object from manager. virtual void close_listeners(SrsListenerType type); diff --git a/trunk/src/main/srs_main_server.cpp b/trunk/src/main/srs_main_server.cpp index 3bfd9ebb13..797e0d90ae 100644 --- a/trunk/src/main/srs_main_server.cpp +++ b/trunk/src/main/srs_main_server.cpp @@ -214,6 +214,7 @@ void show_macro_features() ss << ", dash:" << "on"; ss << ", hls:" << srs_bool2switch(true); ss << ", hds:" << srs_bool2switch(SRS_AUTO_HDS_BOOL); + ss << ", srt:" << srs_bool2switch(SRS_AUTO_SRT_BOOL); // hc(http callback) ss << ", hc:" << srs_bool2switch(true); // ha(http api) From a7b8695cb0fcf39f3f10ba3b467cb5b3365bf6f3 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 23 Jan 2020 14:33:11 +0800 Subject: [PATCH 17/32] Refactor code, include without path --- trunk/src/app/srs_app_server.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index a852f0a144..e08a5f8d96 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -37,8 +37,8 @@ #include #include #ifdef SRS_AUTO_SRT -#include "../srt/srt_server.hpp" -#include "../srt/srt_to_rtmp.hpp" +#include +#include #endif class SrsServer; @@ -214,7 +214,7 @@ class SrsServer : virtual public ISrsReloadHandler, virtual public ISrsSourceHan SrsIngester* ingester; SrsCoroutineManager* conn_manager; #ifdef SRS_AUTO_SRT - //srt server + // srt server SRT_SERVER_PTR srt_ptr; #endif private: From aacf519169ce088c43777640fd1f38306d2f3eaf Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 23 Jan 2020 14:42:06 +0800 Subject: [PATCH 18/32] Revert log for forwarder in source --- trunk/src/app/srs_app_source.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index bfe3e15774..788773c800 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -1456,7 +1456,6 @@ srs_error_t SrsOriginHub::create_forwarders() if (!_srs_config->get_forward_enabled(req->vhost)) { return err; } - srs_trace("srs vhost(%s) forward is enable.", req->host.c_str()); SrsConfDirective* conf = _srs_config->get_forwards(req->vhost); for (int i = 0; conf && i < (int)conf->args.size(); i++) { From bc26df4893f1e5bb1ce2a4ae88997c5f24d7df35 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 23 Jan 2020 14:44:30 +0800 Subject: [PATCH 19/32] Remove noused debug function srs_trace_data --- trunk/src/kernel/srs_kernel_log.hpp | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/trunk/src/kernel/srs_kernel_log.hpp b/trunk/src/kernel/srs_kernel_log.hpp index 670a5b9c68..1d7af37bbf 100644 --- a/trunk/src/kernel/srs_kernel_log.hpp +++ b/trunk/src/kernel/srs_kernel_log.hpp @@ -142,26 +142,5 @@ extern ISrsThreadContext* _srs_context; #define srs_trace(msg, ...) (void)0 #endif -inline void srs_trace_data(const char* data_p, int len, const char* dscr) -{ - const int MAX = 256; - char debug_data[MAX]; - char debug_len = 0; - - debug_len += sprintf(debug_data + debug_len, "%s", dscr); - - for (int index = 0; index < len; index++) { - if (index % 16 == 0) { - debug_len += sprintf(debug_data + debug_len, "\r\n"); - } - debug_len += sprintf(debug_data + debug_len, " %02x", (unsigned char)data_p[index]); - if (index >= 32) { - break; - } - } - - srs_trace("%s", debug_data); - return; -} #endif From d7437834d416e35a9031a7dd39ca09776e7966c6 Mon Sep 17 00:00:00 2001 From: runner365 Date: Thu, 23 Jan 2020 16:12:22 +0800 Subject: [PATCH 20/32] update is_streamid_valid --- trunk/src/srt/srt_conn.hpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/trunk/src/srt/srt_conn.hpp b/trunk/src/srt/srt_conn.hpp index 6801a1c847..9c46d05bda 100644 --- a/trunk/src/srt/srt_conn.hpp +++ b/trunk/src/srt/srt_conn.hpp @@ -20,12 +20,29 @@ inline bool is_streamid_valid(const std::string& streamid) { if (streamid.empty()) { return ret; } + //check whether subpath is valid, eg. live/test or srs.srt.com.cn/live/test std::vector ret_vec; string_split(streamid, "/", ret_vec); - if (ret_vec.size() < 2) { return ret; } + + //check whether mode is valid, eg. live/test?m=push or live/test?m=pull + size_t pos = streamid.find("?"); + if (pos == streamid.npos) { + return ret; + } + + std::string mode = streamid.substr(pos+1); + string_split(mode, "=", ret_vec); + if (ret_vec.size() != 2) { + return ret; + } + //it must be m=push or m=pull + std::string mode_oper = string_lower(ret_vec[1]); + if ((ret_vec[0] != "m") || ((mode_oper != "push") && (mode_oper != "pull"))) { + return ret; + } ret = true; return ret; } @@ -35,7 +52,7 @@ inline void get_streamid_info(const std::string& streamid, int& mode, std::strin size_t pos = streamid.find("?"); if (pos == std::string::npos) { - mode = PULL_SRT_MODE; + mode = ERR_SRT_MODE; url_subpash = streamid; } else { std::string mode_str = streamid.substr(pos+1); From d88d42279422c700404c5919b1ce87a8fba1c800 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 23 Jan 2020 16:49:05 +0800 Subject: [PATCH 21/32] Update doc for SRT. --- README.md | 53 +++++++++++++++++++++++--------------------- trunk/conf/full.conf | 11 +++++++++ 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index d66e35146a..95c406aded 100755 --- a/README.md +++ b/README.md @@ -1015,31 +1015,33 @@ Remark: +---------+ +----------+ | Publish | | Deliver | +---|-----+ +----|-----+ -+----------------------+-------------------------+----------------+ -| Input | SRS(Simple RTMP Server) | Output | -+----------------------+-------------------------+----------------+ -| | +-> DASH -------------+-> DASH player | -| Encoder(1) | +-> RTMP/HDS --------+-> Flash player | -| (FMLE,FFMPEG, -rtmp-+->-+-> HLS/HTTP ---------+-> M3U8 player | -| Flash,XSPLIT, | +-> FLV/MP3/Aac/Ts ---+-> HTTP player | -| ......) | +-> Fowarder ---------+-> RTMP server | -| | +-> Transcoder -------+-> RTMP server | -| | +-> EXEC(5) ----------+-> External app | -| | +-> DVR --------------+-> FLV file | -| | +-> BandwidthTest ----+-> Flash | -+----------------------+ | | -| MediaSource(2) | | | -| (RTSP,FILE, | | | -| HTTP,HLS, --pull-+->-- Ingester(3) -(rtmp)-+-> SRS | -| Device, | | | -| ......) | | | -+----------------------+ | | -| MediaSource(2) | | | -| (RTSP,FILE, | | | -| HTTP,HLS, --push-+->-- Streamer(4) -(rtmp)-+-> SRS | -| Device, | | | -| ......) | | | -+----------------------+-------------------------+----------------+ ++----------------------+----------------------------+----------------+ +| Input | SRS(Simple RTMP Server) | Output | ++----------------------+----------------------------+----------------+ +| | +-> DASH ----------------+-> DASH player | +| Encoder(1) | +-> RTMP/HDS -----------+-> Flash player | +| (FMLE,FFMPEG, -rtmp-+->-+-> HLS/HTTP ------------+-> M3U8 player | +| Flash,XSPLIT, | +-> FLV/MP3/Aac/Ts ------+-> HTTP player | +| ......) | +-> Fowarder ------------+-> RTMP server | +| | +-> Transcoder ----------+-> RTMP server | +| | +-> EXEC(5) -------------+-> External app | +| | +-> DVR -----------------+-> FLV file | +| | +-> BandwidthTest -------+-> Flash | ++----------------------+ | | +| MediaSource(2) | | | +| (RTSP,FILE, | | | +| HTTP,HLS, --pull-+->-- Ingester(3) -(rtmp)----+-> SRS | +| Device, | | | +| ......) | | | ++----------------------+ | | +| MediaSource(2) | | | +| (RTSP,FILE, | | | +| HTTP,HLS, --push-+->- StreamCaster(4) -(rtmp)-+-> SRS | +| Device, | | | +| ......) | | | ++----------------------+ | | +| FFMPEG --push(srt)--+->- SRTModule(5) ---(rtmp)-+-> SRS | ++----------------------+----------------------------+----------------+ ``` @@ -1050,6 +1052,7 @@ Remark: 1. Ingester: Forks a ffmpeg(or other tools) to ingest as rtmp to SRS, please read [Ingest][v1_CN_Ingest]. 1. Streamer: Remuxs other protocols to RTMP, please read [Streamer][v2_CN_Streamer]. 1. EXEC: Like NGINX-RTMP, EXEC forks external tools for events, please read [ng-exec][v3_CN_NgExec]. +1. SRTModule: A isolate module which run in [hybrid](https://github.com/ossrs/srs/issues/1147#issuecomment-577574883) model. ## AUTHORS diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 1160877a43..4ae7bf98e6 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -247,6 +247,17 @@ stream_caster { listen 8936; } +############################################################################################# +# SRT server section +############################################################################################# +srt_server { + # whether SRT server is enabled. + # default: off + enabled on; + # The UDP listen port for SRT. + listen 10080; +} + ############################################################################################# # Kafka sections ############################################################################################# From 06e7a20b5fd03b2d37bf6a2c0b534a79cac6c43f Mon Sep 17 00:00:00 2001 From: runner365 Date: Thu, 23 Jan 2020 17:19:06 +0800 Subject: [PATCH 22/32] update streamid decode --- trunk/src/srt/srt_conn.cpp | 87 ++++++++++++++++++++++++++++++++++++ trunk/src/srt/srt_conn.hpp | 63 ++------------------------ trunk/src/srt/srt_handle.cpp | 7 ++- 3 files changed, 96 insertions(+), 61 deletions(-) diff --git a/trunk/src/srt/srt_conn.cpp b/trunk/src/srt/srt_conn.cpp index ab4d0584ab..2df80b011f 100644 --- a/trunk/src/srt/srt_conn.cpp +++ b/trunk/src/srt/srt_conn.cpp @@ -3,6 +3,93 @@ #include "stringex.hpp" #include +bool is_streamid_valid(const std::string& streamid) { + int mode = ERR_SRT_MODE; + std::string url_subpash; + + bool ret = get_streamid_info(streamid, mode, url_subpash); + if (!ret) { + return ret; + } + + if ((mode != PULL_SRT_MODE) && (mode != PUSH_SRT_MODE)) { + return false; + } + + if (url_subpash.empty()) { + return false; + } + + std::vector info_vec; + string_split(url_subpash, "/", info_vec); + if (info_vec.size() < 2) { + return false; + } + + return true; +} + +bool get_key_value(const std::string& info, std::string& key, std::string& value) { + size_t pos = info.find("="); + + if (pos == info.npos) { + return false; + } + + key = info.substr(0, pos); + value = info.substr(pos+1); + + if (key.empty() || value.empty()) { + return false; + } + return true; +} + +//eg. streamid=#!::h:live/livestream,m:publish +bool get_streamid_info(const std::string& streamid, int& mode, std::string& url_subpash) { + std::vector info_vec; + std::string real_streamid; + + size_t pos = streamid.find("#!::h"); + if (pos != 0) { + return false; + } + real_streamid = streamid.substr(4); + + string_split(real_streamid, ",", info_vec); + if (info_vec.size() < 2) { + return false; + } + + for (int index = 0; index < info_vec.size(); index++) { + std::string key; + std::string value; + + bool ret = get_key_value(info_vec[index], key, value); + if (!ret) { + continue; + } + + if (key == "h") { + url_subpash = value;//eg. h=live/stream + } else if (key == "m") { + std::string mode_str = string_lower(value);//m=publish or m=request + if (mode_str == "publish") { + mode = PUSH_SRT_MODE; + } else if (mode_str == "request") { + mode = PULL_SRT_MODE; + } else { + mode = ERR_SRT_MODE; + return false; + } + } else {//not suport + continue; + } + } + + return true; +} + srt_conn::srt_conn(SRTSOCKET conn_fd, const std::string& streamid):_conn_fd(conn_fd), _streamid(streamid) { get_streamid_info(streamid, _mode, _url_subpath); diff --git a/trunk/src/srt/srt_conn.hpp b/trunk/src/srt/srt_conn.hpp index 9c46d05bda..adc79eaf47 100644 --- a/trunk/src/srt/srt_conn.hpp +++ b/trunk/src/srt/srt_conn.hpp @@ -15,66 +15,9 @@ #define PULL_SRT_MODE 0x01 #define PUSH_SRT_MODE 0x02 -inline bool is_streamid_valid(const std::string& streamid) { - bool ret = false; - if (streamid.empty()) { - return ret; - } - //check whether subpath is valid, eg. live/test or srs.srt.com.cn/live/test - std::vector ret_vec; - string_split(streamid, "/", ret_vec); - if (ret_vec.size() < 2) { - return ret; - } - - //check whether mode is valid, eg. live/test?m=push or live/test?m=pull - size_t pos = streamid.find("?"); - if (pos == streamid.npos) { - return ret; - } - - std::string mode = streamid.substr(pos+1); - string_split(mode, "=", ret_vec); - if (ret_vec.size() != 2) { - return ret; - } - //it must be m=push or m=pull - std::string mode_oper = string_lower(ret_vec[1]); - if ((ret_vec[0] != "m") || ((mode_oper != "push") && (mode_oper != "pull"))) { - return ret; - } - ret = true; - return ret; -} - -inline void get_streamid_info(const std::string& streamid, int& mode, std::string& url_subpash) { - std::string real_streamip; - - size_t pos = streamid.find("?"); - if (pos == std::string::npos) { - mode = ERR_SRT_MODE; - url_subpash = streamid; - } else { - std::string mode_str = streamid.substr(pos+1); - - url_subpash = streamid.substr(0, pos); - - size_t mode_pos = mode_str.find("m="); - if (mode_pos == std::string::npos) { - mode = PULL_SRT_MODE; - } else { - mode_str = mode_str.substr(mode_pos+2); - mode_str = string_lower(mode_str); - if (mode_str == "push") { - mode = PUSH_SRT_MODE; - } else if(mode_str == "pull"){ - mode = PULL_SRT_MODE; - } else { - mode = ERR_SRT_MODE; - } - } - } -} +bool is_streamid_valid(const std::string& streamid); +bool get_key_value(const std::string& info, std::string& key, std::string& value); +bool get_streamid_info(const std::string& streamid, int& mode, std::string& url_subpash); class srt_conn { public: diff --git a/trunk/src/srt/srt_handle.cpp b/trunk/src/srt/srt_handle.cpp index 226013923c..ea25b2c831 100644 --- a/trunk/src/srt/srt_handle.cpp +++ b/trunk/src/srt/srt_handle.cpp @@ -421,7 +421,12 @@ void srt_handle::handle_srt_socket(SRT_SOCKSTATUS status, SRTSOCKET conn_fd) } return; } - get_streamid_info(conn_ptr->get_streamid(), mode, subpath); + bool ret = get_streamid_info(conn_ptr->get_streamid(), mode, subpath); + if (!ret) { + conn_ptr->close(); + conn_ptr = nullptr; + return; + } if (mode == PUSH_SRT_MODE) { switch (status) From 225c830971b4db85af5bf8e16a9fe555a6e97733 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 23 Jan 2020 17:44:36 +0800 Subject: [PATCH 23/32] Refine main run process --- trunk/src/main/srs_main_server.cpp | 32 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/trunk/src/main/srs_main_server.cpp b/trunk/src/main/srs_main_server.cpp index 797e0d90ae..33009d9d46 100644 --- a/trunk/src/main/srs_main_server.cpp +++ b/trunk/src/main/srs_main_server.cpp @@ -50,8 +50,8 @@ using namespace std; #include // pre-declare -srs_error_t run(SrsServer* svr); -srs_error_t run_master(SrsServer* svr); +srs_error_t run_directly_or_daemon(); +srs_error_t run_hybrid_server(); void show_macro_features(); string srs_getenv(const char* name); @@ -177,10 +177,7 @@ srs_error_t do_main(int argc, char** argv) // features show_macro_features(); - SrsServer* svr = new SrsServer(); - SrsAutoFree(SrsServer, svr); - - if ((err = run(svr)) != srs_success) { + if ((err = run_directly_or_daemon()) != srs_success) { return srs_error_wrap(err, "run"); } @@ -359,18 +356,13 @@ string srs_getenv(const char* name) return ""; } -srs_error_t run(SrsServer* svr) +srs_error_t run_directly_or_daemon() { srs_error_t err = srs_success; - - // Initialize the whole system, set hooks to handle server level events. - if ((err = svr->initialize(NULL)) != srs_success) { - return srs_error_wrap(err, "server initialize"); - } // If not daemon, directly run master. if (!_srs_config->get_daemon()) { - if ((err = run_master(svr)) != srs_success) { + if ((err = run_hybrid_server()) != srs_success) { return srs_error_wrap(err, "run master"); } return srs_success; @@ -407,16 +399,24 @@ srs_error_t run(SrsServer* svr) // son srs_trace("son(daemon) process running."); - if ((err = run_master(svr)) != srs_success) { + if ((err = run_hybrid_server()) != srs_success) { return srs_error_wrap(err, "daemon run master"); } return err; } -srs_error_t run_master(SrsServer* svr) +srs_error_t run_hybrid_server() { srs_error_t err = srs_success; + + SrsServer* svr = new SrsServer(); + SrsAutoFree(SrsServer, svr); + + // Initialize the whole system, set hooks to handle server level events. + if ((err = svr->initialize(NULL)) != srs_success) { + return srs_error_wrap(err, "server initialize"); + } if ((err = svr->initialize_st()) != srs_success) { return srs_error_wrap(err, "initialize st"); @@ -445,7 +445,7 @@ srs_error_t run_master(SrsServer* svr) if ((err = svr->ingest()) != srs_success) { return srs_error_wrap(err, "ingest"); } - + if ((err = svr->cycle()) != srs_success) { return srs_error_wrap(err, "main cycle"); } From 1959d1d920c175083b261a170d33aaa8c30527be Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 23 Jan 2020 18:21:11 +0800 Subject: [PATCH 24/32] Extract hybrid server for SRT --- trunk/configure | 2 +- trunk/src/app/srs_app_hybrid.cpp | 115 +++++++++++++++++++++++++++++ trunk/src/app/srs_app_hybrid.hpp | 51 +++++++++++++ trunk/src/app/srs_app_server.cpp | 31 -------- trunk/src/app/srs_app_server.hpp | 12 --- trunk/src/main/srs_main_server.cpp | 44 ++--------- 6 files changed, 175 insertions(+), 80 deletions(-) create mode 100644 trunk/src/app/srs_app_hybrid.cpp create mode 100644 trunk/src/app/srs_app_hybrid.hpp diff --git a/trunk/configure b/trunk/configure index 5b8cd4b0f6..faf5ec4c7e 100755 --- a/trunk/configure +++ b/trunk/configure @@ -258,7 +258,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then "srs_app_mpegts_udp" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" "srs_app_caster_flv" "srs_app_process" "srs_app_ng_exec" "srs_app_hourglass" "srs_app_dash" "srs_app_fragment" "srs_app_dvr" - "srs_app_coworkers") + "srs_app_coworkers" "srs_app_hybrid") DEFINES="" # add each modules for app for SRS_MODULE in ${SRS_MODULES[*]}; do diff --git a/trunk/src/app/srs_app_hybrid.cpp b/trunk/src/app/srs_app_hybrid.cpp new file mode 100644 index 0000000000..1aab1a632d --- /dev/null +++ b/trunk/src/app/srs_app_hybrid.cpp @@ -0,0 +1,115 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#include + +SrsHybridServer::SrsHybridServer() +{ + srs = new SrsServer(); +} + +SrsHybridServer::~SrsHybridServer() +{ + srs_freep(srs); +} + +srs_error_t SrsHybridServer::initialize() +{ + srs_error_t err = srs_success; + + // Initialize the whole system, set hooks to handle server level events. + if ((err = srs->initialize(NULL)) != srs_success) { + return srs_error_wrap(err, "server initialize"); + } + + if ((err = srs->initialize_st()) != srs_success) { + return srs_error_wrap(err, "initialize st"); + } + +#ifdef SRS_AUTO_SRT + if(_srs_config->get_srt_enabled()) { + srs_trace("srt server is enabled..."); + unsigned short srt_port = _srs_config->get_srt_listen_port(); + srs_trace("srt server listen port:%d", srt_port); + err = srt2rtmp::get_instance()->init(); + if (err != srs_success) { + srs_error_wrap(err, "srt start srt2rtmp error"); + return err; + } + + srt_ptr = std::make_shared(srt_port); + if (!srt_ptr) { + srs_error_wrap(err, "srt listen %d", srt_port); + } + } else { + srs_trace("srt server is disabled..."); + } +#endif + + return err; +} + +srs_error_t SrsHybridServer::run() +{ + srs_error_t err = srs_success; + + if ((err = srs->initialize_signal()) != srs_success) { + return srs_error_wrap(err, "initialize signal"); + } + + if ((err = srs->acquire_pid_file()) != srs_success) { + return srs_error_wrap(err, "acquire pid file"); + } + + if ((err = srs->listen()) != srs_success) { + return srs_error_wrap(err, "listen"); + } + + if ((err = srs->register_signal()) != srs_success) { + return srs_error_wrap(err, "register signal"); + } + + if ((err = srs->http_handle()) != srs_success) { + return srs_error_wrap(err, "http handle"); + } + + if ((err = srs->ingest()) != srs_success) { + return srs_error_wrap(err, "ingest"); + } + +#ifdef SRS_AUTO_SRT + if(_srs_config->get_srt_enabled()) { + srt_ptr->start(); + } +#endif + + if ((err = srs->cycle()) != srs_success) { + return srs_error_wrap(err, "main cycle"); + } + + return err; +} + diff --git a/trunk/src/app/srs_app_hybrid.hpp b/trunk/src/app/srs_app_hybrid.hpp new file mode 100644 index 0000000000..d978b27e96 --- /dev/null +++ b/trunk/src/app/srs_app_hybrid.hpp @@ -0,0 +1,51 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SRS_APP_HYBRID_HPP +#define SRS_APP_HYBRID_HPP + +#include + +#ifdef SRS_AUTO_SRT +#include +#include +#endif + +class SrsServer; + +class SrsHybridServer +{ +private: + SrsServer* srs; +#ifdef SRS_AUTO_SRT + SRT_SERVER_PTR srt_ptr; +#endif +public: + SrsHybridServer(); + virtual ~SrsHybridServer(); +public: + virtual srs_error_t initialize(); + virtual srs_error_t run(); +}; + +#endif diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index c85930da37..3bdb5f99a5 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -688,11 +688,6 @@ srs_error_t SrsServer::listen() if ((err = conn_manager->start()) != srs_success) { return srs_error_wrap(err, "connection manager"); } -#ifdef SRS_AUTO_SRT - if ((err = listen_srt()) != srs_success) { - return srs_error_wrap(err, "srt listen"); - } -#endif return err; } @@ -1009,32 +1004,6 @@ srs_error_t SrsServer::do_cycle() return err; } -#ifdef SRS_AUTO_SRT -srs_error_t SrsServer::listen_srt() { - srs_error_t err = srs_success; - - if(_srs_config->get_srt_enabled()) { - srs_trace("srt server is enabled..."); - unsigned short srt_port = _srs_config->get_srt_listen_port(); - srs_trace("srt server listen port:%d", srt_port); - err = srt2rtmp::get_instance()->init(); - if (err != srs_success) { - srs_error_wrap(err, "srt start srt2rtmp error"); - return err; - } - - srt_ptr = std::make_shared(srt_port); - if (!srt_ptr) { - srs_error_wrap(err, "srt listen %d", srt_port); - } - srt_ptr->start(); - } else { - srs_trace("srt server is disabled..."); - } - return err; -} -#endif - srs_error_t SrsServer::listen_rtmp() { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index e08a5f8d96..fd8cbe3ad7 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -36,10 +36,6 @@ #include #include #include -#ifdef SRS_AUTO_SRT -#include -#include -#endif class SrsServer; class SrsConnection; @@ -213,10 +209,6 @@ class SrsServer : virtual public ISrsReloadHandler, virtual public ISrsSourceHan SrsHttpHeartbeat* http_heartbeat; SrsIngester* ingester; SrsCoroutineManager* conn_manager; -#ifdef SRS_AUTO_SRT - // srt server - SRT_SERVER_PTR srt_ptr; -#endif private: // The pid file fd, lock the file write when server is running. // @remark the init.d script should cleanup the pid file, when stop service, @@ -287,10 +279,6 @@ class SrsServer : virtual public ISrsReloadHandler, virtual public ISrsSourceHan virtual srs_error_t listen_http_api(); virtual srs_error_t listen_http_stream(); virtual srs_error_t listen_stream_caster(); -#ifdef SRS_AUTO_SRT - //start listen srt udp port - virtual srs_error_t listen_srt(); -#endif // Close the listeners for specified type, // Remove the listen object from manager. virtual void close_listeners(SrsListenerType type); diff --git a/trunk/src/main/srs_main_server.cpp b/trunk/src/main/srs_main_server.cpp index 33009d9d46..150339f3d3 100644 --- a/trunk/src/main/srs_main_server.cpp +++ b/trunk/src/main/srs_main_server.cpp @@ -48,6 +48,7 @@ using namespace std; #include #include #include +#include // pre-declare srs_error_t run_directly_or_daemon(); @@ -410,46 +411,17 @@ srs_error_t run_hybrid_server() { srs_error_t err = srs_success; - SrsServer* svr = new SrsServer(); - SrsAutoFree(SrsServer, svr); + SrsHybridServer* svr = new SrsHybridServer(); + SrsAutoFree(SrsHybridServer, svr); - // Initialize the whole system, set hooks to handle server level events. - if ((err = svr->initialize(NULL)) != srs_success) { - return srs_error_wrap(err, "server initialize"); - } - - if ((err = svr->initialize_st()) != srs_success) { - return srs_error_wrap(err, "initialize st"); - } - - if ((err = svr->initialize_signal()) != srs_success) { - return srs_error_wrap(err, "initialize signal"); - } - - if ((err = svr->acquire_pid_file()) != srs_success) { - return srs_error_wrap(err, "acquire pid file"); - } - - if ((err = svr->listen()) != srs_success) { - return srs_error_wrap(err, "listen"); - } - - if ((err = svr->register_signal()) != srs_success) { - return srs_error_wrap(err, "register signal"); - } - - if ((err = svr->http_handle()) != srs_success) { - return srs_error_wrap(err, "http handle"); - } - - if ((err = svr->ingest()) != srs_success) { - return srs_error_wrap(err, "ingest"); + if ((err = svr->initialize()) != srs_success) { + return srs_error_wrap(err, "hybrid initialize"); } - if ((err = svr->cycle()) != srs_success) { - return srs_error_wrap(err, "main cycle"); + if ((err = svr->run()) != srs_success) { + return srs_error_wrap(err, "hybrid run"); } - + return err; } From 87ba204a42376964545a7394d9050a7e74e1c5d0 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 23 Jan 2020 18:25:44 +0800 Subject: [PATCH 25/32] Update doc for SRT url. --- trunk/conf/full.conf | 1 + trunk/conf/srt.conf | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 4ae7bf98e6..b4f0f95c3d 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -250,6 +250,7 @@ stream_caster { ############################################################################################# # SRT server section ############################################################################################# +# @doc https://github.com/ossrs/srs/issues/1147#issuecomment-577607026 srt_server { # whether SRT server is enabled. # default: off diff --git a/trunk/conf/srt.conf b/trunk/conf/srt.conf index 9dc1e564e6..d648b16b32 100644 --- a/trunk/conf/srt.conf +++ b/trunk/conf/srt.conf @@ -20,7 +20,7 @@ srt_server { listen 10080; } -# @doc https://github.com/ossrs/srs/issues/1147#issuecomment-577492117 +# @doc https://github.com/ossrs/srs/issues/1147#issuecomment-577607026 vhost __defaultVhost__ { } vhost srs.srt.com.cn { From 33c6bf1f8fa922ad713716a1d270c088fc922bca Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 23 Jan 2020 19:40:40 +0800 Subject: [PATCH 26/32] Refactor SRT, using reverse dependency, SRT depends on APP. --- README.md | 14 ++-- trunk/configure | 3 - trunk/src/app/srs_app_hybrid.cpp | 118 +++++++++++++++++++++-------- trunk/src/app/srs_app_hybrid.hpp | 36 +++++++-- trunk/src/app/srs_app_server.cpp | 5 -- trunk/src/main/srs_main_server.cpp | 14 +++- trunk/src/srt/srt_server.cpp | 44 +++++++++++ trunk/src/srt/srt_server.hpp | 15 ++++ 8 files changed, 192 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 95c406aded..5127507821 100755 --- a/README.md +++ b/README.md @@ -990,13 +990,13 @@ SRS always use the simplest architecture to solve complex domain problems. ## Modularity Architecture ``` -+------------------------------------------------------+ -| SRS server | Programs in Main or Research | -+------------------------------------------------------+ -| App(For SRS) | Modules(1) | research/librtmp | -+------------------------------------------------------+ -| Service(C/S apps over ST) | Libs(Export librtmp) | -+------------------------------------------------------+ ++----------------+-------------------------------------+ +| SRS/SRT server | Programs in Main or Research | ++----------------+--+------------+---------------------+ +| App(For SRS) | Modules(1) | research/librtmp | ++-------------------+------------+---------------------+ +| Service(C/S apps over ST) | srs-librtmp | ++--------------------------------+---------------------+ | Protocol Stack(RTMP/HTTP/RTSP/JSON/AMF/Format) | +------------------------------------------------------+ | Kernel(File, Codec, Stream, LB services) | diff --git a/trunk/configure b/trunk/configure index faf5ec4c7e..afb4dc26ec 100755 --- a/trunk/configure +++ b/trunk/configure @@ -245,9 +245,6 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="APP" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE") ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) - if [[ $SRS_SRT == YES ]]; then - ModuleLibIncs+=("${LibSRTRoot[*]}") - fi MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_source" "srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http_stream" "srs_app_thread" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config" diff --git a/trunk/src/app/srs_app_hybrid.cpp b/trunk/src/app/srs_app_hybrid.cpp index 1aab1a632d..1d33b49837 100644 --- a/trunk/src/app/srs_app_hybrid.cpp +++ b/trunk/src/app/srs_app_hybrid.cpp @@ -25,18 +25,30 @@ #include #include +#include +#include -SrsHybridServer::SrsHybridServer() +using namespace std; + +ISrsHybridServer::ISrsHybridServer() +{ +} + +ISrsHybridServer::~ISrsHybridServer() +{ +} + +SrsServerAdapter::SrsServerAdapter() { srs = new SrsServer(); } -SrsHybridServer::~SrsHybridServer() +SrsServerAdapter::~SrsServerAdapter() { srs_freep(srs); } -srs_error_t SrsHybridServer::initialize() +srs_error_t SrsServerAdapter::initialize() { srs_error_t err = srs_success; @@ -49,30 +61,10 @@ srs_error_t SrsHybridServer::initialize() return srs_error_wrap(err, "initialize st"); } -#ifdef SRS_AUTO_SRT - if(_srs_config->get_srt_enabled()) { - srs_trace("srt server is enabled..."); - unsigned short srt_port = _srs_config->get_srt_listen_port(); - srs_trace("srt server listen port:%d", srt_port); - err = srt2rtmp::get_instance()->init(); - if (err != srs_success) { - srs_error_wrap(err, "srt start srt2rtmp error"); - return err; - } - - srt_ptr = std::make_shared(srt_port); - if (!srt_ptr) { - srs_error_wrap(err, "srt listen %d", srt_port); - } - } else { - srs_trace("srt server is disabled..."); - } -#endif - return err; } -srs_error_t SrsHybridServer::run() +srs_error_t SrsServerAdapter::run() { srs_error_t err = srs_success; @@ -100,12 +92,6 @@ srs_error_t SrsHybridServer::run() return srs_error_wrap(err, "ingest"); } -#ifdef SRS_AUTO_SRT - if(_srs_config->get_srt_enabled()) { - srt_ptr->start(); - } -#endif - if ((err = srs->cycle()) != srs_success) { return srs_error_wrap(err, "main cycle"); } @@ -113,3 +99,75 @@ srs_error_t SrsHybridServer::run() return err; } +SrsHybridServer::SrsHybridServer() +{ +} + +SrsHybridServer::~SrsHybridServer() +{ + vector::iterator it; + for (it = servers.begin(); it != servers.end(); ++it) { + ISrsHybridServer* server = *it; + srs_freep(server); + } + servers.clear(); +} + +void SrsHybridServer::register_server(ISrsHybridServer* svr) +{ + servers.push_back(svr); +} + +srs_error_t SrsHybridServer::initialize() +{ + srs_error_t err = srs_success; + + // init st + if ((err = srs_st_init()) != srs_success) { + return srs_error_wrap(err, "initialize st failed"); + } + + vector::iterator it; + for (it = servers.begin(); it != servers.end(); ++it) { + ISrsHybridServer* server = *it; + + if ((err = server->initialize()) != srs_success) { + return srs_error_wrap(err, "init server"); + } + } + + return err; +} + +srs_error_t SrsHybridServer::run() +{ + srs_error_t err = srs_success; + + // Run master server in this main thread. + SrsServerAdapter* master_server = NULL; + + vector::iterator it; + for (it = servers.begin(); it != servers.end(); ++it) { + ISrsHybridServer* server = *it; + + if (!master_server) { + master_server = dynamic_cast(server); + if (master_server) { + continue; + } + } + + if ((err = server->run()) != srs_success) { + return srs_error_wrap(err, "run server"); + } + } + + if (master_server) { + return master_server->run(); + } + + return err; +} + +SrsHybridServer* _srs_hybrid = new SrsHybridServer(); + diff --git a/trunk/src/app/srs_app_hybrid.hpp b/trunk/src/app/srs_app_hybrid.hpp index d978b27e96..58aa6dff9e 100644 --- a/trunk/src/app/srs_app_hybrid.hpp +++ b/trunk/src/app/srs_app_hybrid.hpp @@ -26,26 +26,46 @@ #include -#ifdef SRS_AUTO_SRT -#include -#include -#endif +#include class SrsServer; -class SrsHybridServer +class ISrsHybridServer +{ +public: + ISrsHybridServer(); + virtual ~ISrsHybridServer(); +public: + virtual srs_error_t initialize() = 0; + virtual srs_error_t run() = 0; +}; + +class SrsServerAdapter : public ISrsHybridServer { private: SrsServer* srs; -#ifdef SRS_AUTO_SRT - SRT_SERVER_PTR srt_ptr; -#endif +public: + SrsServerAdapter(); + virtual ~SrsServerAdapter(); +public: + virtual srs_error_t initialize(); + virtual srs_error_t run(); +}; + +class SrsHybridServer +{ +private: + std::vector servers; public: SrsHybridServer(); virtual ~SrsHybridServer(); +public: + virtual void register_server(ISrsHybridServer* svr); public: virtual srs_error_t initialize(); virtual srs_error_t run(); }; +extern SrsHybridServer* _srs_hybrid; + #endif diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index 3bdb5f99a5..e5d3bbc9f4 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -565,11 +565,6 @@ srs_error_t SrsServer::initialize_st() { srs_error_t err = srs_success; - // init st - if ((err = srs_st_init()) != srs_success) { - return srs_error_wrap(err, "initialize st failed"); - } - // @remark, st alloc segment use mmap, which only support 32757 threads, // if need to support more, for instance, 100k threads, define the macro MALLOC_STACK. // TODO: FIXME: maybe can use "sysctl vm.max_map_count" to refine. diff --git a/trunk/src/main/srs_main_server.cpp b/trunk/src/main/srs_main_server.cpp index 150339f3d3..d3c5277617 100644 --- a/trunk/src/main/srs_main_server.cpp +++ b/trunk/src/main/srs_main_server.cpp @@ -50,6 +50,10 @@ using namespace std; #include #include +#ifdef SRS_AUTO_SRT +#include +#endif + // pre-declare srs_error_t run_directly_or_daemon(); srs_error_t run_hybrid_server(); @@ -411,14 +415,16 @@ srs_error_t run_hybrid_server() { srs_error_t err = srs_success; - SrsHybridServer* svr = new SrsHybridServer(); - SrsAutoFree(SrsHybridServer, svr); + _srs_hybrid->register_server(new SrsServerAdapter()); +#ifdef SRS_AUTO_SRT + _srs_hybrid->register_server(new SrtServerAdapter()); +#endif - if ((err = svr->initialize()) != srs_success) { + if ((err = _srs_hybrid->initialize()) != srs_success) { return srs_error_wrap(err, "hybrid initialize"); } - if ((err = svr->run()) != srs_success) { + if ((err = _srs_hybrid->run()) != srs_success) { return srs_error_wrap(err, "hybrid run"); } diff --git a/trunk/src/srt/srt_server.cpp b/trunk/src/srt/srt_server.cpp index b938f3678f..011545ad01 100644 --- a/trunk/src/srt/srt_server.cpp +++ b/trunk/src/srt/srt_server.cpp @@ -199,3 +199,47 @@ void srt_server::on_work() } } } + +SrtServerAdapter::SrtServerAdapter() +{ +} + +SrtServerAdapter::~SrtServerAdapter() +{ +} + +srs_error_t SrtServerAdapter::initialize() +{ + srs_error_t err = srs_success; + + if(_srs_config->get_srt_enabled()) { + srs_trace("srt server is enabled..."); + unsigned short srt_port = _srs_config->get_srt_listen_port(); + srs_trace("srt server listen port:%d", srt_port); + err = srt2rtmp::get_instance()->init(); + if (err != srs_success) { + srs_error_wrap(err, "srt start srt2rtmp error"); + return err; + } + + srt_ptr = std::make_shared(srt_port); + if (!srt_ptr) { + srs_error_wrap(err, "srt listen %d", srt_port); + } + } else { + srs_trace("srt server is disabled..."); + } + + return err; +} + +srs_error_t SrtServerAdapter::run() +{ + srs_error_t err = srs_success; + + if(_srs_config->get_srt_enabled()) { + srt_ptr->start(); + } + + return err; +} diff --git a/trunk/src/srt/srt_server.hpp b/trunk/src/srt/srt_server.hpp index 7201b72633..d235dfad6c 100644 --- a/trunk/src/srt/srt_server.hpp +++ b/trunk/src/srt/srt_server.hpp @@ -1,10 +1,13 @@ #ifndef SRT_SERVER_H #define SRT_SERVER_H + #include #include #include +#include + class srt_handle; class srt_server { @@ -34,4 +37,16 @@ class srt_server { typedef std::shared_ptr SRT_SERVER_PTR; +class SrtServerAdapter : public ISrsHybridServer +{ +private: + SRT_SERVER_PTR srt_ptr; +public: + SrtServerAdapter(); + virtual ~SrtServerAdapter(); +public: + virtual srs_error_t initialize(); + virtual srs_error_t run(); +}; + #endif//SRT_SERVER_H \ No newline at end of file From 2363d258de196ffb560140ceb29a15474b137e45 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 23 Jan 2020 20:42:50 +0800 Subject: [PATCH 27/32] Refactor hybrid server model --- trunk/src/app/srs_app_hybrid.cpp | 19 +++++++++---------- trunk/src/srt/srt_server.cpp | 13 ++++++------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/trunk/src/app/srs_app_hybrid.cpp b/trunk/src/app/srs_app_hybrid.cpp index 1d33b49837..313c5e0c80 100644 --- a/trunk/src/app/srs_app_hybrid.cpp +++ b/trunk/src/app/srs_app_hybrid.cpp @@ -49,6 +49,12 @@ SrsServerAdapter::~SrsServerAdapter() } srs_error_t SrsServerAdapter::initialize() +{ + srs_error_t err = srs_success; + return err; +} + +srs_error_t SrsServerAdapter::run() { srs_error_t err = srs_success; @@ -61,21 +67,14 @@ srs_error_t SrsServerAdapter::initialize() return srs_error_wrap(err, "initialize st"); } - return err; -} - -srs_error_t SrsServerAdapter::run() -{ - srs_error_t err = srs_success; + if ((err = srs->acquire_pid_file()) != srs_success) { + return srs_error_wrap(err, "acquire pid file"); + } if ((err = srs->initialize_signal()) != srs_success) { return srs_error_wrap(err, "initialize signal"); } - if ((err = srs->acquire_pid_file()) != srs_success) { - return srs_error_wrap(err, "acquire pid file"); - } - if ((err = srs->listen()) != srs_success) { return srs_error_wrap(err, "listen"); } diff --git a/trunk/src/srt/srt_server.cpp b/trunk/src/srt/srt_server.cpp index 011545ad01..e518385a88 100644 --- a/trunk/src/srt/srt_server.cpp +++ b/trunk/src/srt/srt_server.cpp @@ -209,6 +209,12 @@ SrtServerAdapter::~SrtServerAdapter() } srs_error_t SrtServerAdapter::initialize() +{ + srs_error_t err = srs_success; + return err; +} + +srs_error_t SrtServerAdapter::run() { srs_error_t err = srs_success; @@ -230,13 +236,6 @@ srs_error_t SrtServerAdapter::initialize() srs_trace("srt server is disabled..."); } - return err; -} - -srs_error_t SrtServerAdapter::run() -{ - srs_error_t err = srs_success; - if(_srs_config->get_srt_enabled()) { srt_ptr->start(); } From db5788b205c361793de664e12d98582bc5f95316 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 23 Jan 2020 20:47:32 +0800 Subject: [PATCH 28/32] Update README for SRT --- README.md | 2 ++ trunk/configure | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/README.md b/README.md index 5127507821..d0c4869e8f 100755 --- a/README.md +++ b/README.md @@ -126,6 +126,7 @@ For previous versions, please read: - [x] [Experimental] Support a simple [mgmt console][console], please read [srs-ngb][srs-ngb]. - [x] [Experimental] Support RTMP client library: srs-librtmp([CN][v3_CN_SrsLibrtmp], [EN][v3_EN_SrsLibrtmp]) - [x] [Experimental] Support HTTP RAW API, please read [#459][bug #459], [#470][bug #470], [#319][bug #319]. +- [x] [Experimental] Support SRT server, read [#1147][bug #1147]. - [x] [Deprecated] Support Adobe HDS(f4m), please read wiki([CN][v2_CN_DeliveryHDS], [EN][v2_EN_DeliveryHDS]) and [#1535][bug #1535]. - [x] [Deprecated] Support bandwidth testing([CN][v1_CN_BandwidthTestTool], [EN][v1_EN_BandwidthTestTool]), please read [#1535][bug #1535]. - [x] [Deprecated] Support Adobe FMS/AMS token traverse([CN][v3_CN_DRM2], [EN][v3_EN_DRM2]) authentication, please read [#1535][bug #1535]. @@ -1595,6 +1596,7 @@ Winlin [bug #1544]: https://github.com/ossrs/srs/issues/1544 [bug #1255]: https://github.com/ossrs/srs/issues/1255 [bug #1543]: https://github.com/ossrs/srs/issues/1543 +[bug #1147]: https://github.com/ossrs/srs/issues/1147 [bug #xxxxxxxxxxxxx]: https://github.com/ossrs/srs/issues/xxxxxxxxxxxxx [exo #828]: https://github.com/google/ExoPlayer/pull/828 diff --git a/trunk/configure b/trunk/configure index afb4dc26ec..2ddc9f6317 100755 --- a/trunk/configure +++ b/trunk/configure @@ -621,6 +621,11 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then else echo -e "${GREEN}Warning: HDS is disabled.${BLACK}" fi + if [ $SRS_SRT = YES ]; then + echo -e "${YELLOW}Experiment: SRT is enabled. https://github.com/ossrs/srs/issues/1147${BLACK}" + else + echo -e "${GREEN}Warning: SRT is disabled.${BLACK}" + fi if [ $SRS_DVR = YES ]; then echo -e "${GREEN}DVR is enabled.${BLACK}" else From 7c9b31815fc12edbbe396319395cf5055fc02e71 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 23 Jan 2020 21:16:34 +0800 Subject: [PATCH 29/32] Refactor code, add stop for hybrid server to do cleanup. --- trunk/src/app/srs_app_hybrid.cpp | 13 +++++++++++++ trunk/src/app/srs_app_hybrid.hpp | 9 +++++++++ trunk/src/main/srs_main_server.cpp | 5 +++++ trunk/src/srt/srt_server.cpp | 10 ++++++++++ trunk/src/srt/srt_server.hpp | 1 + 5 files changed, 38 insertions(+) diff --git a/trunk/src/app/srs_app_hybrid.cpp b/trunk/src/app/srs_app_hybrid.cpp index 313c5e0c80..cd8147327b 100644 --- a/trunk/src/app/srs_app_hybrid.cpp +++ b/trunk/src/app/srs_app_hybrid.cpp @@ -98,6 +98,10 @@ srs_error_t SrsServerAdapter::run() return err; } +void SrsServerAdapter::stop() +{ +} + SrsHybridServer::SrsHybridServer() { } @@ -168,5 +172,14 @@ srs_error_t SrsHybridServer::run() return err; } +void SrsHybridServer::stop() +{ + vector::iterator it; + for (it = servers.begin(); it != servers.end(); ++it) { + ISrsHybridServer* server = *it; + server->stop(); + } +} + SrsHybridServer* _srs_hybrid = new SrsHybridServer(); diff --git a/trunk/src/app/srs_app_hybrid.hpp b/trunk/src/app/srs_app_hybrid.hpp index 58aa6dff9e..3834566608 100644 --- a/trunk/src/app/srs_app_hybrid.hpp +++ b/trunk/src/app/srs_app_hybrid.hpp @@ -30,16 +30,22 @@ class SrsServer; +// The hibrid server interfaces, we could register many servers. class ISrsHybridServer { public: ISrsHybridServer(); virtual ~ISrsHybridServer(); public: + // Only ST initialized before each server, we could fork processes as such. virtual srs_error_t initialize() = 0; + // Run each server, should never block except the SRS master server. virtual srs_error_t run() = 0; + // Stop each server, should do cleanup, for example, kill processes forked by server. + virtual void stop() = 0; }; +// The SRS server adapter, the master server. class SrsServerAdapter : public ISrsHybridServer { private: @@ -50,8 +56,10 @@ class SrsServerAdapter : public ISrsHybridServer public: virtual srs_error_t initialize(); virtual srs_error_t run(); + virtual void stop(); }; +// The hybrid server manager. class SrsHybridServer { private: @@ -64,6 +72,7 @@ class SrsHybridServer public: virtual srs_error_t initialize(); virtual srs_error_t run(); + virtual void stop(); }; extern SrsHybridServer* _srs_hybrid; diff --git a/trunk/src/main/srs_main_server.cpp b/trunk/src/main/srs_main_server.cpp index d3c5277617..76ce742f71 100644 --- a/trunk/src/main/srs_main_server.cpp +++ b/trunk/src/main/srs_main_server.cpp @@ -420,14 +420,19 @@ srs_error_t run_hybrid_server() _srs_hybrid->register_server(new SrtServerAdapter()); #endif + // Do some system initialize. if ((err = _srs_hybrid->initialize()) != srs_success) { return srs_error_wrap(err, "hybrid initialize"); } + // Should run util hybrid servers all done. if ((err = _srs_hybrid->run()) != srs_success) { return srs_error_wrap(err, "hybrid run"); } + // After all done, stop and cleanup. + _srs_hybrid->stop(); + return err; } diff --git a/trunk/src/srt/srt_server.cpp b/trunk/src/srt/srt_server.cpp index e518385a88..d7212c6a53 100644 --- a/trunk/src/srt/srt_server.cpp +++ b/trunk/src/srt/srt_server.cpp @@ -211,6 +211,9 @@ SrtServerAdapter::~SrtServerAdapter() srs_error_t SrtServerAdapter::initialize() { srs_error_t err = srs_success; + + // TODO: FIXME: We could fork processes here, because here only ST is initialized. + return err; } @@ -218,6 +221,8 @@ srs_error_t SrtServerAdapter::run() { srs_error_t err = srs_success; + // TODO: FIXME: We could start a coroutine to dispatch SRT task to processes. + if(_srs_config->get_srt_enabled()) { srs_trace("srt server is enabled..."); unsigned short srt_port = _srs_config->get_srt_listen_port(); @@ -242,3 +247,8 @@ srs_error_t SrtServerAdapter::run() return err; } + +void SrtServerAdapter::stop() +{ + // TODO: FIXME: If forked processes, we should do cleanup. +} diff --git a/trunk/src/srt/srt_server.hpp b/trunk/src/srt/srt_server.hpp index d235dfad6c..27bb3bdfbd 100644 --- a/trunk/src/srt/srt_server.hpp +++ b/trunk/src/srt/srt_server.hpp @@ -47,6 +47,7 @@ class SrtServerAdapter : public ISrsHybridServer public: virtual srs_error_t initialize(); virtual srs_error_t run(); + virtual void stop(); }; #endif//SRT_SERVER_H \ No newline at end of file From 307a4315f19c44b09171ee47216d76475dad5e66 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 23 Jan 2020 21:33:59 +0800 Subject: [PATCH 30/32] Fix bug, should return error when wrapped --- trunk/src/srt/srt_server.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/trunk/src/srt/srt_server.cpp b/trunk/src/srt/srt_server.cpp index d7212c6a53..021f714ec8 100644 --- a/trunk/src/srt/srt_server.cpp +++ b/trunk/src/srt/srt_server.cpp @@ -229,13 +229,12 @@ srs_error_t SrtServerAdapter::run() srs_trace("srt server listen port:%d", srt_port); err = srt2rtmp::get_instance()->init(); if (err != srs_success) { - srs_error_wrap(err, "srt start srt2rtmp error"); - return err; + return srs_error_wrap(err, "srt start srt2rtmp error"); } srt_ptr = std::make_shared(srt_port); if (!srt_ptr) { - srs_error_wrap(err, "srt listen %d", srt_port); + return srs_error_wrap(err, "srt listen %d", srt_port); } } else { srs_trace("srt server is disabled..."); From e3169a080b4aeda2c184934b85129c4965e5b1fa Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 24 Jan 2020 07:06:30 +0800 Subject: [PATCH 31/32] Refactor SRT build, use libsrt.a static library --- trunk/auto/depends.sh | 16 ++++++++++++++++ trunk/configure | 11 +++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index dd4471f620..7d7994496e 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -476,6 +476,22 @@ if [ $SRS_FFMPEG_TOOL = YES ]; then if [ ! -f ${SRS_OBJS}/ffmpeg/bin/ffmpeg ]; then echo "build ffmpeg-4.1 failed."; exit -1; fi fi +##################################################################################### +# SRT module, https://github.com/ossrs/srs/issues/1147#issuecomment-577469119 +##################################################################################### +if [[ $SRS_SRT == YES ]]; then + if [[ -f /usr/local/lib64/libsrt.a && ! -f ${SRS_OBJS}/srt/lib/libsrt.a ]]; then + mkdir -p ${SRS_OBJS}/srt/lib && ln -sf /usr/local/lib64/libsrt.a ${SRS_OBJS}/srt/lib/libsrt.a + mkdir -p ${SRS_OBJS}/srt/include && ln -sf /usr/local/include/srt ${SRS_OBJS}/srt/include/ + fi + if [[ -f ${SRS_OBJS}/srt/lib/libsrt.a ]]; then + echo "libsrt-1.4.1 is ok."; + else + echo "no libsrt, please use srs-docker or build from source https://github.com/ossrs/srs/issues/1147#issuecomment-577469119"; + exit -1; + fi +fi + ##################################################################################### # build research code, librtmp ##################################################################################### diff --git a/trunk/configure b/trunk/configure index 2ddc9f6317..f59c94a50d 100755 --- a/trunk/configure +++ b/trunk/configure @@ -162,12 +162,12 @@ if [ $SRS_GPERF_MD = YES ]; then fi # srt code path if [[ $SRS_SRT == YES ]]; then - LibSRTRoot="${SRS_WORKDIR}/src/srt" + LibSRTRoot="${SRS_WORKDIR}/src/srt"; LibSRTfile="${SRS_OBJS_DIR}/srt/lib/libsrt.a" fi # the link options, always use static link SrsLinkOptions="-ldl"; if [[ $SRS_SRT == YES ]]; then - SrsLinkOptions="${SrsLinkOptions} -pthread -lsrt"; + SrsLinkOptions="${SrsLinkOptions} -pthread"; fi if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL == YES ]]; then SrsLinkOptions="${SrsLinkOptions} -lssl -lcrypto"; @@ -323,6 +323,9 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then # # all depends libraries ModuleLibFiles=(${LibSTfile} ${LibSSLfile} ${LibGperfFile}) + if [[ $SRS_SRT == YES ]]; then + ModuleLibFiles+=("${LibSRTfile[*]}") + fi # all depends objects MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${APP_OBJS[@]} ${SERVER_OBJS[@]}" ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) @@ -336,6 +339,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then # # For modules, without the app module. MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${MAIN_OBJS[@]}" + ModuleLibFiles=(${LibSTfile} ${LibSSLfile} ${LibGperfFile}) # for SRS_MODULE in ${SRS_MODULES[*]}; do . $SRS_MODULE/config @@ -360,6 +364,9 @@ if [ $SRS_UTEST = YES ]; then ModuleLibIncs+=("${LibSRTRoot[*]}") fi ModuleLibFiles=(${LibSTfile} ${LibSSLfile}) + if [[ $SRS_SRT == YES ]]; then + ModuleLibFiles+=("${LibSRTfile[*]}") + fi MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP") if [[ $SRS_SRT == YES ]]; then MODULE_DEPENDS+=("SRT") From db1e06d3c9cca5217c186044f0b09f3f725568c7 Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 24 Jan 2020 16:03:32 +0800 Subject: [PATCH 32/32] Update README --- README.md | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index d0c4869e8f..4d8f353a83 100755 --- a/README.md +++ b/README.md @@ -47,21 +47,23 @@ docker run -p 1935:1935 -p 1985:1985 -p 8080:8080 ossrs/srs:3 **From here,** strongly recommend to read bellow wikis: * Usage: How to delivery RTMP?([CN][v1_CN_SampleRTMP], [EN][v1_EN_SampleRTMP]) -* Usage: How to delivery RTMP Edge Cluster?([CN][v3_CN_SampleRTMPCluster], [EN][v3_EN_SampleRTMPCluster]) -* Usage: How to create a RTMP Origin Cluster?([CN][v3_CN_SampleOriginCluster], [EN][v3_EN_SampleOriginCluster]) -* Usage: How to delivery HTTP FLV Live Streaming?([CN][v3_CN_SampleHttpFlv], [EN][v3_EN_SampleHttpFlv]) -* Usage: How to delivery HTTP FLV Live Streaming Cluster?([CN][v3_CN_SampleHttpFlvCluster], [EN][v3_EN_SampleHttpFlvCluster]) +* Usage: How to delivery RTMP-Edge Cluster?([CN][v3_CN_SampleRTMPCluster], [EN][v3_EN_SampleRTMPCluster]) +* Usage: How to create a RTMP-Origin Cluster?([CN][v3_CN_SampleOriginCluster], [EN][v3_EN_SampleOriginCluster]) +* Usage: How to delivery HTTP-FLV?([CN][v3_CN_SampleHttpFlv], [EN][v3_EN_SampleHttpFlv]) +* Usage: How to delivery HTTP-FLV Cluster?([CN][v3_CN_SampleHttpFlvCluster], [EN][v3_EN_SampleHttpFlvCluster]) * Usage: How to delivery HLS?([CN][v3_CN_SampleHLS], [EN][v3_EN_SampleHLS]) -* Usage: How to delivery HLS for other codec?([CN][v3_CN_SampleTranscode2HLS], [EN][v3_EN_SampleTranscode2HLS]) -* Usage: How to transode RTMP stream by FFMPEG?([CN][v2_CN_SampleFFMPEG], [EN][v2_EN_SampleFFMPEG]) +* Usage: How to transcode to h.264+aac for HLS?([CN][v3_CN_SampleTranscode2HLS], [EN][v3_EN_SampleTranscode2HLS]) +* Usage: How to transode stream by FFMPEG?([CN][v2_CN_SampleFFMPEG], [EN][v2_EN_SampleFFMPEG]) * Usage: How to forward stream to other servers?([CN][v3_CN_SampleForward], [EN][v3_EN_SampleForward]) -* Usage: How to deploy in low lantency mode?([CN][v3_CN_SampleRealtime], [EN][v3_EN_SampleRealtime]) -* Usage: How to ingest file/stream/device to RTMP?([CN][v1_CN_SampleIngest], [EN][v1_EN_SampleIngest]) +* Usage: How to enable low lantency live streaming?([CN][v3_CN_SampleRealtime], [EN][v3_EN_SampleRealtime]) +* Usage: How to ingest file/stream/device to SRS?([CN][v1_CN_SampleIngest], [EN][v1_EN_SampleIngest]) * Usage: How to delivery HLS by SRS HTTP server?([CN][v3_CN_SampleHTTP], [EN][v3_EN_SampleHTTP]) +* Usage: How to delivery DASH(Experimental)?([CN][v3_CN_SampleDASH], [EN][v3_EN_SampleDASH]) +* Usage: How to transmux SRT(Experimental) to live streaming?([CN][v4_CN_SampleSRT], [EN][v4_EN_SampleSRT]) * Usage: How to publish h.264 raw stream as RTMP? ([CN][v3_CN_SrsLibrtmp2], [EN][v3_EN_SrsLibrtmp2]) -* Usage: How to improve edge performance by multiple CPUs? ([CN][v3_CN_REUSEPORT], [EN][v3_EN_REUSEPORT]) -* Usage: Why choose SRS? About the milestone and product plan? ([CN][v1_CN_Product], [EN][v1_EN_Product]) -* Usage: How to file bug or chat with us? ([CN][v1_CN_Contact], [EN][v1_EN_Contact]) +* Usage: How to enable multiple processes? ([CN][v3_CN_REUSEPORT], [EN][v3_EN_REUSEPORT]) +* Usage: Why SRS? What's the milestones? ([CN][v1_CN_Product], [EN][v1_EN_Product]) +* Usage: Want to contact us? ([CN][v1_CN_Contact], [EN][v1_EN_Contact]) Or file an issue [here](https://github.com/ossrs/srs/issues/new)? ## Wiki