diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 362d603ee..3a97603f9 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -943,6 +943,16 @@ vhost exec.srs.com { } } +# The vhost for MPEG-DASH. +vhost dash.srs.com { + dash { + # Whether DASH is enabled. + # Transmux RTMP to DASH if on. + # default: off + enabled on; + } +} + # the vhost with hls specified. vhost hls.srs.com { hls { diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 1a86c03d2..60e2e2b09 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -1353,6 +1353,18 @@ int SrsConfig::reload_vhost(SrsConfDirective* old_root) srs_trace("vhost %s reload forward success.", vhost.c_str()); } + // To reload DASH. + if (!srs_directive_equals(new_vhost->get("dash"), old_vhost->get("dash"))) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_vhost_dash(vhost)) != ERROR_SUCCESS) { + srs_error("Reload vhost %s dash failed, ret=%d", vhost.c_str(), ret); + return ret; + } + } + srs_trace("Reload vhost %s dash ok.", vhost.c_str()); + } + // hls, only one per vhost // @remark, the hls_on_error directly support reload. if (!srs_directive_equals(new_vhost->get("hls"), old_vhost->get("hls"))) { @@ -3808,7 +3820,7 @@ int SrsConfig::check_config() && n != "dvr" && n != "ingest" && n != "hls" && n != "http_hooks" && n != "refer" && n != "forward" && n != "transcode" && n != "bandcheck" && n != "play" && n != "publish" && n != "cluster" - && n != "security" && n != "http_remux" + && n != "security" && n != "http_remux" && n != "dash" && n != "http_static" && n != "hds" && n != "exec" && n != "in_ack_size" && n != "out_ack_size" ) { @@ -3819,7 +3831,7 @@ int SrsConfig::check_config() // for each sub directives of vhost. if (n == "dvr") { for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); + string m = conf->at(j)->name; if (m != "enabled" && m != "dvr_apply" && m != "dvr_path" && m != "dvr_plan" && m != "dvr_duration" && m != "dvr_wait_keyframe" && m != "time_jitter" ) { @@ -3830,7 +3842,7 @@ int SrsConfig::check_config() } } else if (n == "refer") { for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); + string m = conf->at(j)->name; if (m != "enabled" && m != "all" && m != "publish" && m != "play") { ret = ERROR_SYSTEM_CONFIG_INVALID; srs_error("unsupported vhost refer directive %s, ret=%d", m.c_str(), ret); @@ -3839,7 +3851,7 @@ int SrsConfig::check_config() } } else if (n == "exec") { for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); + string m = conf->at(j)->name; if (m != "enabled" && m != "publish") { ret = ERROR_SYSTEM_CONFIG_INVALID; srs_error("unsupported vhost exec directive %s, ret=%d", m.c_str(), ret); @@ -3848,7 +3860,7 @@ int SrsConfig::check_config() } } else if (n == "play") { for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); + string m = conf->at(j)->name; if (m != "time_jitter" && m != "mix_correct" && m != "atc" && m != "atc_auto" && m != "mw_latency" && m != "gop_cache" && m != "queue_length" && m != "send_min_interval" && m != "reduce_sequence_header" ) { @@ -3859,7 +3871,7 @@ int SrsConfig::check_config() } } else if (n == "cluster") { for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); + string m = conf->at(j)->name; if (m != "mode" && m != "origin" && m != "token_traverse" && m != "vhost" && m != "debug_srs_upnode") { ret = ERROR_SYSTEM_CONFIG_INVALID; srs_error("unsupported vhost cluster directive %s, ret=%d", m.c_str(), ret); @@ -3868,7 +3880,7 @@ int SrsConfig::check_config() } } else if (n == "publish") { for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); + string m = conf->at(j)->name; if (m != "mr" && m != "mr_latency" && m != "firstpkt_timeout" && m != "normal_timeout" && m != "parse_sps") { ret = ERROR_SYSTEM_CONFIG_INVALID; srs_error("unsupported vhost publish directive %s, ret=%d", m.c_str(), ret); @@ -3877,7 +3889,7 @@ int SrsConfig::check_config() } } else if (n == "ingest") { for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); + string m = conf->at(j)->name; if (m != "enabled" && m != "input" && m != "ffmpeg" && m != "engine") { ret = ERROR_SYSTEM_CONFIG_INVALID; srs_error("unsupported vhost ingest directive %s, ret=%d", m.c_str(), ret); @@ -3886,7 +3898,7 @@ int SrsConfig::check_config() } } else if (n == "http_static") { for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); + string m = conf->at(j)->name; if (m != "enabled" && m != "mount" && m != "dir") { ret = ERROR_SYSTEM_CONFIG_INVALID; srs_error("unsupported vhost http directive %s, ret=%d", m.c_str(), ret); @@ -3895,16 +3907,25 @@ int SrsConfig::check_config() } } else if (n == "http_remux") { for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); + string m = conf->at(j)->name; if (m != "enabled" && m != "mount" && m != "fast_cache") { ret = ERROR_SYSTEM_CONFIG_INVALID; srs_error("unsupported vhost http_remux directive %s, ret=%d", m.c_str(), ret); return ret; } } + } else if (n == "dash") { + for (int j = 0; j < (int)conf->directives.size(); j++) { + string m = conf->at(j)->name; + if (m != "enabled") { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("Illegal directive %s in vhost.dash, ret=%d", m.c_str(), ret); + return ret; + } + } } else if (n == "hls") { for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); + string m = conf->at(j)->name; if (m != "enabled" && m != "hls_entry_prefix" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error" && m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" && m != "hls_aof_ratio" && m != "hls_acodec" && m != "hls_vcodec" && m != "hls_m3u8_file" && m != "hls_ts_file" && m != "hls_ts_floor" && m != "hls_cleanup" && m != "hls_nb_notify" @@ -3922,7 +3943,7 @@ int SrsConfig::check_config() } } else if (n == "http_hooks") { for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); + string m = conf->at(j)->name; if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish" && m != "on_unpublish" && m != "on_play" && m != "on_stop" && m != "on_dvr" && m != "on_hls" && m != "on_hls_notify" @@ -3934,7 +3955,7 @@ int SrsConfig::check_config() } } else if (n == "forward") { for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); + string m = conf->at(j)->name; if (m != "enabled" && m != "destination") { ret = ERROR_SYSTEM_CONFIG_INVALID; srs_error("unsupported vhost forward directive %s, ret=%d", m.c_str(), ret); @@ -3979,7 +4000,7 @@ int SrsConfig::check_config() } } else if (n == "bandcheck") { for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); + string m = conf->at(j)->name; if (m != "enabled" && m != "key" && m != "interval" && m != "limit_kbps") { ret = ERROR_SYSTEM_CONFIG_INVALID; srs_error("unsupported vhost bandcheck directive %s, ret=%d", m.c_str(), ret); @@ -5944,15 +5965,33 @@ string SrsConfig::get_ffmpeg_log_dir() return conf->arg0(); } +SrsConfDirective* SrsConfig::get_dash(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + return conf? conf->get("dash") : NULL; +} + +bool SrsConfig::get_dash_enabled(string vhost) +{ + static bool DEFAULT = false; + + SrsConfDirective* conf = get_dash(vhost); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("enabled"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return SRS_CONF_PERFER_FALSE(conf->arg0()); +} + SrsConfDirective* SrsConfig::get_hls(string vhost) { SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return NULL; - } - - return conf->get("hls"); + return conf? conf->get("hls") : NULL; } bool SrsConfig::get_hls_enabled(string vhost) diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index c658bc4d9..fc9a7188e 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -1134,6 +1134,12 @@ public: * @remark, /dev/null to disable it. */ virtual std::string get_ffmpeg_log_dir(); +// The MPEG-DASH section. +private: + virtual SrsConfDirective* get_dash(std::string vhost); +public: + // Whether DASH is enabled. + virtual bool get_dash_enabled(std::string vhost); // hls section private: /** diff --git a/trunk/src/app/srs_app_dash.cpp b/trunk/src/app/srs_app_dash.cpp index 0ffa7de99..8513d6d2c 100644 --- a/trunk/src/app/srs_app_dash.cpp +++ b/trunk/src/app/srs_app_dash.cpp @@ -23,4 +23,80 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include +#include +#include +#include +#include + +SrsMpegDash::SrsMpegDash() +{ + hub = NULL; + req = NULL; + + enabled = false; +} + +SrsMpegDash::~SrsMpegDash() +{ +} + +int SrsMpegDash::initialize(SrsOriginHub* h, SrsRequest* r) +{ + int ret = ERROR_SUCCESS; + + hub = h; + req = r; + + return ret; +} + +int SrsMpegDash::on_publish() +{ + int ret = ERROR_SUCCESS; + + // Prevent duplicated publish. + if (enabled) { + return ret; + } + + if (!_srs_config->get_dash_enabled(req->vhost)) { + return ret; + } + + enabled = true; + + return ret; +} + +int SrsMpegDash::on_audio(SrsSharedPtrMessage* shared_audio) +{ + int ret = ERROR_SUCCESS; + + if (!enabled) { + return ret; + } + + return ret; +} + +int SrsMpegDash::on_video(SrsSharedPtrMessage* shared_video, bool is_sequence_header) +{ + int ret = ERROR_SUCCESS; + + if (!enabled) { + return ret; + } + + return ret; +} + +void SrsMpegDash::on_unpublish() +{ + // Prevent duplicated unpublish. + if (!enabled) { + return; + } + + enabled = false; +} diff --git a/trunk/src/app/srs_app_dash.hpp b/trunk/src/app/srs_app_dash.hpp index 1b30b5cff..b623a62ab 100644 --- a/trunk/src/app/srs_app_dash.hpp +++ b/trunk/src/app/srs_app_dash.hpp @@ -29,4 +29,34 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include +class SrsRequest; +class SrsOriginHub; +class SrsSharedPtrMessage; + +/** + * The MPEG-DASH encoder, transmux RTMP to DASH. + */ +class SrsMpegDash +{ +private: + bool enabled; +private: + SrsRequest* req; + SrsOriginHub* hub; +public: + SrsMpegDash(); + virtual ~SrsMpegDash(); +public: + // Initalize the encoder. + virtual int initialize(SrsOriginHub* h, SrsRequest* r); + // When stream start publishing. + virtual int on_publish(); + // When got an shared audio message. + virtual int on_audio(SrsSharedPtrMessage* shared_audio); + // When got an shared video message. + virtual int on_video(SrsSharedPtrMessage* shared_video, bool is_sequence_header); + // When stream stop publishing. + virtual void on_unpublish(); +}; + #endif diff --git a/trunk/src/app/srs_app_dvr.cpp b/trunk/src/app/srs_app_dvr.cpp index 07b5d3cf1..812d78c5f 100644 --- a/trunk/src/app/srs_app_dvr.cpp +++ b/trunk/src/app/srs_app_dvr.cpp @@ -1019,7 +1019,7 @@ int SrsDvr::initialize(SrsOriginHub* h, SrsRequest* r) return ret; } -int SrsDvr::on_publish(bool fetch_sequence_header) +int SrsDvr::on_publish() { int ret = ERROR_SUCCESS; @@ -1032,10 +1032,6 @@ int SrsDvr::on_publish(bool fetch_sequence_header) return ret; } - if (fetch_sequence_header && (ret = hub->on_dvr_request_sh()) != ERROR_SUCCESS) { - return ret; - } - return ret; } @@ -1088,11 +1084,21 @@ int SrsDvr::on_reload_vhost_dvr_apply(string vhost) bool v = srs_config_apply_filter(conf, req); // the apply changed, republish the dvr. - if (v != actived) { - actived = v; - - on_unpublish(); - return on_publish(true); + if (v == actived) { + return ret; + } + actived = v; + + on_unpublish(); + if (!actived) { + return ret; + } + + if ((ret = on_publish()) != ERROR_SUCCESS) { + return ret; + } + if ((ret = hub->on_dvr_request_sh()) != ERROR_SUCCESS) { + return ret; } return ret; diff --git a/trunk/src/app/srs_app_dvr.hpp b/trunk/src/app/srs_app_dvr.hpp index 8f270f813..d57e06ee4 100644 --- a/trunk/src/app/srs_app_dvr.hpp +++ b/trunk/src/app/srs_app_dvr.hpp @@ -289,7 +289,7 @@ public: * when encoder start to publish RTMP stream. * @param fetch_sequence_header whether fetch sequence from source. */ - virtual int on_publish(bool fetch_sequence_header); + virtual int on_publish(); /** * the unpublish event., * when encoder stop(unpublish) to publish RTMP stream. diff --git a/trunk/src/app/srs_app_hds.cpp b/trunk/src/app/srs_app_hds.cpp index 3c146adfc..c98d6eb48 100644 --- a/trunk/src/app/srs_app_hds.cpp +++ b/trunk/src/app/srs_app_hds.cpp @@ -260,7 +260,7 @@ private: string path; }; -SrsHds::SrsHds(SrsSource *s) +SrsHds::SrsHds() : currentSegment(NULL) , fragment_index(1) , video_sh(NULL) @@ -273,7 +273,6 @@ SrsHds::SrsHds(SrsSource *s) SrsHds::~SrsHds() { - } int SrsHds::on_publish(SrsRequest *req) diff --git a/trunk/src/app/srs_app_hds.hpp b/trunk/src/app/srs_app_hds.hpp index f0305f542..d41fa5c86 100644 --- a/trunk/src/app/srs_app_hds.hpp +++ b/trunk/src/app/srs_app_hds.hpp @@ -38,8 +38,8 @@ class SrsSource; class SrsHds { public: - SrsHds(SrsSource* s); - ~SrsHds(); + SrsHds(); + virtual ~SrsHds(); int on_publish(SrsRequest* req); int on_unpublish(); diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp index 0b13cf141..e54555d11 100644 --- a/trunk/src/app/srs_app_hls.cpp +++ b/trunk/src/app/srs_app_hls.cpp @@ -1118,8 +1118,8 @@ SrsHls::SrsHls() req = NULL; hub = NULL; - hls_enabled = false; - hls_can_dispose = false; + enabled = false; + disposable = false; last_update_time = 0; codec = new SrsAvcAacCodec(); @@ -1127,7 +1127,7 @@ SrsHls::SrsHls() jitter = new SrsRtmpJitter(); muxer = new SrsHlsMuxer(); - hls_cache = new SrsHlsCache(); + cache = new SrsHlsCache(); pprint = SrsPithyPrint::create_hls(); stream_dts = 0; @@ -1140,14 +1140,14 @@ SrsHls::~SrsHls() srs_freep(jitter); srs_freep(muxer); - srs_freep(hls_cache); + srs_freep(cache); srs_freep(pprint); } void SrsHls::dispose() { - if (hls_enabled) { + if (enabled) { on_unpublish(); } @@ -1177,10 +1177,10 @@ int SrsHls::cycle() } last_update_time = srs_get_system_time_ms(); - if (!hls_can_dispose) { + if (!disposable) { return ret; } - hls_can_dispose = false; + disposable = false; srs_trace("hls cycle to dispose hls %s, timeout=%dms", req->get_stream_url().c_str(), hls_dispose); dispose(); @@ -1202,7 +1202,7 @@ int SrsHls::initialize(SrsOriginHub* h, SrsRequest* r) return ret; } -int SrsHls::on_publish(bool fetch_sequence_header) +int SrsHls::on_publish() { int ret = ERROR_SUCCESS; @@ -1210,36 +1210,23 @@ int SrsHls::on_publish(bool fetch_sequence_header) last_update_time = srs_get_system_time_ms(); // support multiple publish. - if (hls_enabled) { + if (enabled) { return ret; } - std::string vhost = req->vhost; - if (!_srs_config->get_hls_enabled(vhost)) { + if (!_srs_config->get_hls_enabled(req->vhost)) { return ret; } - if ((ret = hls_cache->on_publish(muxer, req, stream_dts)) != ERROR_SUCCESS) { + if ((ret = cache->on_publish(muxer, req, stream_dts)) != ERROR_SUCCESS) { return ret; } // if enabled, open the muxer. - hls_enabled = true; + enabled = true; // ok, the hls can be dispose, or need to be dispose. - hls_can_dispose = true; - - // when publish, don't need to fetch sequence header, which is old and maybe corrupt. - // when reload, we must fetch the sequence header from source cache. - if (fetch_sequence_header) { - // notice the source to get the cached sequence header. - // when reload to start hls, hls will never get the sequence header in stream, - // use the SrsSource.on_hls_start to push the sequence header to HLS. - if ((ret = hub->on_hls_start()) != ERROR_SUCCESS) { - srs_error("callback source hls start failed. ret=%d", ret); - return ret; - } - } + disposable = true; return ret; } @@ -1249,22 +1236,22 @@ void SrsHls::on_unpublish() int ret = ERROR_SUCCESS; // support multiple unpublish. - if (!hls_enabled) { + if (!enabled) { return; } - if ((ret = hls_cache->on_unpublish(muxer)) != ERROR_SUCCESS) { + if ((ret = cache->on_unpublish(muxer)) != ERROR_SUCCESS) { srs_error("ignore m3u8 muxer flush/close audio failed. ret=%d", ret); } - hls_enabled = false; + enabled = false; } int SrsHls::on_audio(SrsSharedPtrMessage* shared_audio) { int ret = ERROR_SUCCESS; - if (!hls_enabled) { + if (!enabled) { return ret; } @@ -1302,7 +1289,7 @@ int SrsHls::on_audio(SrsSharedPtrMessage* shared_audio) // ignore sequence header if (acodec == SrsCodecAudioAAC && sample->aac_packet_type == SrsCodecAudioTypeSequenceHeader) { - return hls_cache->on_sequence_header(muxer); + return cache->on_sequence_header(muxer); } // TODO: FIXME: config the jitter of HLS. @@ -1317,7 +1304,7 @@ int SrsHls::on_audio(SrsSharedPtrMessage* shared_audio) // for pure audio, we need to update the stream dts also. stream_dts = dts; - if ((ret = hls_cache->write_audio(codec, muxer, dts, sample)) != ERROR_SUCCESS) { + if ((ret = cache->write_audio(codec, muxer, dts, sample)) != ERROR_SUCCESS) { srs_error("hls cache write audio failed. ret=%d", ret); return ret; } @@ -1329,7 +1316,7 @@ int SrsHls::on_video(SrsSharedPtrMessage* shared_video, bool is_sps_pps) { int ret = ERROR_SUCCESS; - if (!hls_enabled) { + if (!enabled) { return ret; } @@ -1366,7 +1353,7 @@ int SrsHls::on_video(SrsSharedPtrMessage* shared_video, bool is_sps_pps) // ignore sequence header if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame && sample->avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) { - return hls_cache->on_sequence_header(muxer); + return cache->on_sequence_header(muxer); } // TODO: FIXME: config the jitter of HLS. @@ -1377,7 +1364,7 @@ int SrsHls::on_video(SrsSharedPtrMessage* shared_video, bool is_sps_pps) int64_t dts = video->timestamp * 90; stream_dts = dts; - if ((ret = hls_cache->write_video(codec, muxer, dts, sample)) != ERROR_SUCCESS) { + if ((ret = cache->write_video(codec, muxer, dts, sample)) != ERROR_SUCCESS) { srs_error("hls cache write video failed. ret=%d", ret); return ret; } diff --git a/trunk/src/app/srs_app_hls.hpp b/trunk/src/app/srs_app_hls.hpp index e9285f200..dc856266c 100644 --- a/trunk/src/app/srs_app_hls.hpp +++ b/trunk/src/app/srs_app_hls.hpp @@ -351,11 +351,11 @@ class SrsHls { private: SrsHlsMuxer* muxer; - SrsHlsCache* hls_cache; + SrsHlsCache* cache; private: SrsRequest* req; - bool hls_enabled; - bool hls_can_dispose; + bool enabled; + bool disposable; int64_t last_update_time; private: SrsOriginHub* hub; @@ -393,7 +393,7 @@ public: * for the muxer object not destroyed. * @param fetch_sequence_header whether fetch sequence from source. */ - virtual int on_publish(bool fetch_sequence_header); + virtual int on_publish(); /** * the unpublish event, only close the muxer, donot destroy the * muxer, for when we continue to publish, the m3u8 will continue. diff --git a/trunk/src/app/srs_app_log.cpp b/trunk/src/app/srs_app_log.cpp index c105b58e1..fe589cee6 100644 --- a/trunk/src/app/srs_app_log.cpp +++ b/trunk/src/app/srs_app_log.cpp @@ -147,7 +147,7 @@ void SrsFastLog::verbose(const char* tag, int context_id, const char* fmt, ...) } int size = 0; - if (!generate_header(false, tag, context_id, "verb", &size)) { + if (!generate_header(false, tag, context_id, "Verb", &size)) { return; } @@ -167,7 +167,7 @@ void SrsFastLog::info(const char* tag, int context_id, const char* fmt, ...) } int size = 0; - if (!generate_header(false, tag, context_id, "debug", &size)) { + if (!generate_header(false, tag, context_id, "Debug", &size)) { return; } @@ -187,7 +187,7 @@ void SrsFastLog::trace(const char* tag, int context_id, const char* fmt, ...) } int size = 0; - if (!generate_header(false, tag, context_id, "trace", &size)) { + if (!generate_header(false, tag, context_id, "Trace", &size)) { return; } @@ -207,7 +207,7 @@ void SrsFastLog::warn(const char* tag, int context_id, const char* fmt, ...) } int size = 0; - if (!generate_header(true, tag, context_id, "warn", &size)) { + if (!generate_header(true, tag, context_id, "Warn", &size)) { return; } @@ -227,7 +227,7 @@ void SrsFastLog::error(const char* tag, int context_id, const char* fmt, ...) } int size = 0; - if (!generate_header(true, tag, context_id, "error", &size)) { + if (!generate_header(true, tag, context_id, "Error", &size)) { return; } diff --git a/trunk/src/app/srs_app_reload.cpp b/trunk/src/app/srs_app_reload.cpp index c91fd9275..82d398bb1 100644 --- a/trunk/src/app/srs_app_reload.cpp +++ b/trunk/src/app/srs_app_reload.cpp @@ -145,6 +145,11 @@ int ISrsReloadHandler::on_reload_vhost_forward(string /*vhost*/) return ERROR_SUCCESS; } +int ISrsReloadHandler::on_reload_vhost_dash(string /*vhost*/) +{ + return ERROR_SUCCESS; +} + int ISrsReloadHandler::on_reload_vhost_hls(string /*vhost*/) { return ERROR_SUCCESS; diff --git a/trunk/src/app/srs_app_reload.hpp b/trunk/src/app/srs_app_reload.hpp index ef512b17f..1fbb30978 100644 --- a/trunk/src/app/srs_app_reload.hpp +++ b/trunk/src/app/srs_app_reload.hpp @@ -68,6 +68,7 @@ public: virtual int on_reload_vhost_removed(std::string vhost); virtual int on_reload_vhost_play(std::string vhost); virtual int on_reload_vhost_forward(std::string vhost); + virtual int on_reload_vhost_dash(std::string vhost); virtual int on_reload_vhost_hls(std::string vhost); virtual int on_reload_vhost_hds(std::string vhost); virtual int on_reload_vhost_dvr(std::string vhost); diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index b33d66237..f0f51597c 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -47,6 +47,7 @@ using namespace std; #include #include #include +#include #define CONST_MAX_JITTER_MS 250 #define CONST_MAX_JITTER_MS_NEG -250 @@ -836,19 +837,20 @@ SrsSharedPtrMessage* SrsMixQueue::pop() return msg; } -SrsOriginHub::SrsOriginHub(SrsSource* s) +SrsOriginHub::SrsOriginHub() { - source = s; + source = NULL; req = NULL; is_active = false; hls = new SrsHls(); + dash = new SrsMpegDash(); dvr = new SrsDvr(); #ifdef SRS_AUTO_TRANSCODE encoder = new SrsEncoder(); #endif #ifdef SRS_AUTO_HDS - hds = new SrsHds(s); + hds = new SrsHds(); #endif ng_exec = new SrsNgExec(); @@ -870,6 +872,7 @@ SrsOriginHub::~SrsOriginHub() srs_freep(ng_exec); srs_freep(hls); + srs_freep(dash); srs_freep(dvr); #ifdef SRS_AUTO_TRANSCODE srs_freep(encoder); @@ -879,16 +882,21 @@ SrsOriginHub::~SrsOriginHub() #endif } -int SrsOriginHub::initialize(SrsRequest* r) +int SrsOriginHub::initialize(SrsSource* s, SrsRequest* r) { int ret = ERROR_SUCCESS; req = r; + source = s; if ((ret = hls->initialize(this, req)) != ERROR_SUCCESS) { return ret; } + if ((ret = dash->initialize(this, req)) != ERROR_SUCCESS) { + return ret; + } + if ((ret = dvr->initialize(this, req)) != ERROR_SUCCESS) { return ret; } @@ -899,6 +907,8 @@ int SrsOriginHub::initialize(SrsRequest* r) void SrsOriginHub::dispose() { hls->dispose(); + + // TODO: Support dispose DASH. } int SrsOriginHub::cycle() @@ -909,6 +919,8 @@ int SrsOriginHub::cycle() return ret; } + // TODO: Support cycle DASH. + return ret; } @@ -967,6 +979,12 @@ int SrsOriginHub::on_audio(SrsSharedPtrMessage* shared_audio) } } + if ((ret = dash->on_audio(msg)) != ERROR_SUCCESS) { + srs_warn("DASH failed, ignore and disable it. ret=%d", ret); + dash->on_unpublish(); + ret = ERROR_SUCCESS; + } + if ((ret = dvr->on_audio(msg)) != ERROR_SUCCESS) { srs_warn("dvr process audio message failed, ignore and disable dvr. ret=%d", ret); @@ -1034,6 +1052,12 @@ int SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_sequence_h } } + if ((ret = dash->on_video(msg, is_sequence_header)) != ERROR_SUCCESS) { + srs_warn("DASH failed, ignore and disable it. ret=%d", ret); + dash->on_unpublish(); + ret = ERROR_SUCCESS; + } + if ((ret = dvr->on_video(msg)) != ERROR_SUCCESS) { srs_warn("dvr process video message failed, ignore and disable dvr. ret=%d", ret); @@ -1088,12 +1112,17 @@ int SrsOriginHub::on_publish() } #endif - if ((ret = hls->on_publish(false)) != ERROR_SUCCESS) { + if ((ret = hls->on_publish()) != ERROR_SUCCESS) { srs_error("start hls failed. ret=%d", ret); return ret; } - if ((ret = dvr->on_publish(false)) != ERROR_SUCCESS) { + if ((ret = dash->on_publish()) != ERROR_SUCCESS) { + srs_error("Start DASH failed. ret=%d", ret); + return ret; + } + + if ((ret = dvr->on_publish()) != ERROR_SUCCESS) { srs_error("start dvr failed. ret=%d", ret); return ret; } @@ -1129,6 +1158,7 @@ void SrsOriginHub::on_unpublish() #endif hls->on_unpublish(); + dash->on_unpublish(); dvr->on_unpublish(); #ifdef SRS_AUTO_HDS @@ -1164,29 +1194,6 @@ int SrsOriginHub::on_forwarder_start(SrsForwarder* forwarder) return ret; } -int SrsOriginHub::on_hls_start() -{ - int ret = ERROR_SUCCESS; - - SrsSharedPtrMessage* cache_sh_video = source->meta->vsh(); - SrsSharedPtrMessage* cache_sh_audio = source->meta->ash(); - - // feed the hls the metadata/sequence header, - // when reload to start hls, hls will never get the sequence header in stream, - // use the SrsSource.on_hls_start to push the sequence header to HLS. - // TODO: maybe need to decode the metadata? - if (cache_sh_video && (ret = hls->on_video(cache_sh_video, true)) != ERROR_SUCCESS) { - srs_error("hls process video sequence header message failed. ret=%d", ret); - return ret; - } - if (cache_sh_audio && (ret = hls->on_audio(cache_sh_audio)) != ERROR_SUCCESS) { - srs_error("hls process audio sequence header message failed. ret=%d", ret); - return ret; - } - - return ret; -} - int SrsOriginHub::on_dvr_request_sh() { int ret = ERROR_SUCCESS; @@ -1243,6 +1250,40 @@ int SrsOriginHub::on_reload_vhost_forward(string vhost) return ret; } +int SrsOriginHub::on_reload_vhost_dash(string vhost) +{ + int ret = ERROR_SUCCESS; + + if (req->vhost != vhost) { + return ret; + } + + dash->on_unpublish(); + + // Don't start DASH when source is not active. + if (!is_active) { + return ret; + } + + if ((ret = dash->on_publish()) != ERROR_SUCCESS) { + srs_error("DASH start failed, ret=%d", ret); + return ret; + } + + SrsSharedPtrMessage* cache_sh_video = source->meta->vsh(); + SrsSharedPtrMessage* cache_sh_audio = source->meta->ash(); + if (cache_sh_video && (ret = dash->on_video(cache_sh_video, true)) != ERROR_SUCCESS) { + srs_error("DASH consume video failed. ret=%d", ret); + return ret; + } + if (cache_sh_audio && (ret = dash->on_audio(cache_sh_audio)) != ERROR_SUCCESS) { + srs_error("DASH consume audio failed. ret=%d", ret); + return ret; + } + + return ret; +} + int SrsOriginHub::on_reload_vhost_hls(string vhost) { int ret = ERROR_SUCCESS; @@ -1255,17 +1296,38 @@ int SrsOriginHub::on_reload_vhost_hls(string vhost) hls->on_unpublish(); - // Don't start forwarders when source is not active. + // Don't start HLS when source is not active. if (!is_active) { return ret; } - if ((ret = hls->on_publish(true)) != ERROR_SUCCESS) { + if ((ret = hls->on_publish()) != ERROR_SUCCESS) { srs_error("hls publish failed. ret=%d", ret); return ret; } srs_trace("vhost %s hls reload success", vhost.c_str()); + // when publish, don't need to fetch sequence header, which is old and maybe corrupt. + // when reload, we must fetch the sequence header from source cache. + // notice the source to get the cached sequence header. + // when reload to start hls, hls will never get the sequence header in stream, + // use the SrsSource.on_hls_start to push the sequence header to HLS. + SrsSharedPtrMessage* cache_sh_video = source->meta->vsh(); + SrsSharedPtrMessage* cache_sh_audio = source->meta->ash(); + + // feed the hls the metadata/sequence header, + // when reload to start hls, hls will never get the sequence header in stream, + // use the SrsSource.on_hls_start to push the sequence header to HLS. + // TODO: maybe need to decode the metadata? + if (cache_sh_video && (ret = hls->on_video(cache_sh_video, true)) != ERROR_SUCCESS) { + srs_error("hls process video sequence header message failed. ret=%d", ret); + return ret; + } + if (cache_sh_audio && (ret = hls->on_audio(cache_sh_audio)) != ERROR_SUCCESS) { + srs_error("hls process audio sequence header message failed. ret=%d", ret); + return ret; + } + return ret; } @@ -1282,7 +1344,7 @@ int SrsOriginHub::on_reload_vhost_hds(string vhost) #ifdef SRS_AUTO_HDS hds->on_unpublish(); - // Don't start forwarders when source is not active. + // Don't start HDS when source is not active. if (!is_active) { return ret; } @@ -1310,7 +1372,7 @@ int SrsOriginHub::on_reload_vhost_dvr(string vhost) // cleanup dvr dvr->on_unpublish(); - // Don't start forwarders when source is not active. + // Don't start DVR when source is not active. if (!is_active) { return ret; } @@ -1321,11 +1383,15 @@ int SrsOriginHub::on_reload_vhost_dvr(string vhost) } // start to publish by new plan. - if ((ret = dvr->on_publish(true)) != ERROR_SUCCESS) { + if ((ret = dvr->on_publish()) != ERROR_SUCCESS) { srs_error("dvr publish failed. ret=%d", ret); return ret; } + if ((ret = on_dvr_request_sh()) != ERROR_SUCCESS) { + return ret; + } + srs_trace("vhost %s dvr reload success", vhost.c_str()); return ret; @@ -1344,7 +1410,7 @@ int SrsOriginHub::on_reload_vhost_transcode(string vhost) #ifdef SRS_AUTO_TRANSCODE encoder->on_unpublish(); - // Don't start forwarders when source is not active. + // Don't start transcode when source is not active. if (!is_active) { return ret; } @@ -1371,7 +1437,7 @@ int SrsOriginHub::on_reload_vhost_exec(string vhost) ng_exec->on_unpublish(); - // Don't start forwarders when source is not active. + // Don't start exec when source is not active. if (!is_active) { return ret; } @@ -1712,7 +1778,7 @@ SrsSource::SrsSource() publish_edge = new SrsPublishEdge(); gop_cache = new SrsGopCache(); aggregate_stream = new SrsBuffer(); - hub = new SrsOriginHub(this); + hub = new SrsOriginHub(); meta = new SrsMetaCache(); is_monotonically_increase = false; @@ -1790,7 +1856,7 @@ int SrsSource::initialize(SrsRequest* r, ISrsSourceHandler* h) req = r->copy(); atc = _srs_config->get_atc(req->vhost); - if ((ret = hub->initialize(req)) != ERROR_SUCCESS) { + if ((ret = hub->initialize(this, req)) != ERROR_SUCCESS) { return ret; } diff --git a/trunk/src/app/srs_app_source.hpp b/trunk/src/app/srs_app_source.hpp index 573b8e8fa..9ef381db5 100644 --- a/trunk/src/app/srs_app_source.hpp +++ b/trunk/src/app/srs_app_source.hpp @@ -56,6 +56,7 @@ class SrsConnection; class SrsMessageHeader; class SrsHls; class SrsDvr; +class SrsMpegDash; #ifdef SRS_AUTO_TRANSCODE class SrsEncoder; #endif @@ -422,6 +423,8 @@ private: private: // hls handler. SrsHls* hls; + // The DASH encoder. + SrsMpegDash* dash; // dvr handler. SrsDvr* dvr; // transcoding handler. @@ -437,12 +440,12 @@ private: // to forward stream to other servers std::vector forwarders; public: - SrsOriginHub(SrsSource* s); + SrsOriginHub(); virtual ~SrsOriginHub(); public: // Initialize the hub with source and request. // @param r The request object, managed by source. - virtual int initialize(SrsRequest* r); + virtual int initialize(SrsSource* s, SrsRequest* r); // Dispose the hub, release utilities resource, // for example, delete all HLS pieces. virtual void dispose(); @@ -461,17 +464,16 @@ public: virtual int on_publish(); // When stop publish stream. virtual void on_unpublish(); -// for the tools callback +// Internal callback. public: // for the SrsForwarder to callback to request the sequence headers. virtual int on_forwarder_start(SrsForwarder* forwarder); - // for the SrsHls to callback to request the sequence headers. - virtual int on_hls_start(); // for the SrsDvr to callback to request the sequence headers. virtual int on_dvr_request_sh(); // interface ISrsReloadHandler public: virtual int on_reload_vhost_forward(std::string vhost); + virtual int on_reload_vhost_dash(std::string vhost); virtual int on_reload_vhost_hls(std::string vhost); virtual int on_reload_vhost_hds(std::string vhost); virtual int on_reload_vhost_dvr(std::string vhost); diff --git a/trunk/src/main/srs_main_server.cpp b/trunk/src/main/srs_main_server.cpp index e80ad91aa..d2702ecbe 100644 --- a/trunk/src/main/srs_main_server.cpp +++ b/trunk/src/main/srs_main_server.cpp @@ -164,7 +164,10 @@ int main(int argc, char** argv) } #endif - srs_trace(ss.str().c_str()); + string sss = ss.str(); + if (!sss.empty()) { + srs_trace(sss.c_str()); + } } // we check the config when the log initialized. @@ -202,6 +205,7 @@ void show_macro_features() // rch(rtmp complex handshake) ss << ", rch:" << srs_bool2switch(SRS_AUTO_SSL_BOOL); + ss << ", dash:" << "on"; ss << ", hls:" << srs_bool2switch(SRS_AUTO_HLS_BOOL); ss << ", hds:" << srs_bool2switch(SRS_AUTO_HDS_BOOL); // hc(http callback)