diff --git a/README.md b/README.md index 2d186565c..d2c68b891 100755 --- a/README.md +++ b/README.md @@ -342,6 +342,7 @@ Remark: ## History +* v2.0, 2015-08-14, use reduce_sequence_header for stream control. * v2.0, 2015-08-14, use send_min_interval for stream control. 2.0.183 * v2.0, 2015-08-12, enable the SRS_PERF_TCP_NODELAY and add config tcp_nodelay. 2.0.182 * v2.0, 2015-08-11, for [#442](https://github.com/simple-rtmp-server/srs/issues/442) support kickoff connected client. 2.0.181 diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 0a2127bff..f81ba989e 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -876,7 +876,12 @@ vhost stream.control.com { # @remark 0 to disable the minimal interval. # @remark >0 to make the srs to send message one by one. # default: 0 - send_min_interval 10; + send_min_interval 10; + # whether reduce the sequence header, + # for some client which cannot got duplicated sequence header, + # while the sequence header is not changed yet. + # default: off + reduce_sequence_header on; } # the vhost for antisuck. diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 33c2db42d..0d1796186 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -1761,7 +1761,8 @@ int SrsConfig::check_config() && n != "time_jitter" && n != "mix_correct" && n != "atc" && n != "atc_auto" && n != "debug_srs_upnode" - && n != "mr" && n != "mw_latency" && n != "min_latency" && n != "tcp_nodelay" && n != "send_min_interval" + && n != "mr" && n != "mw_latency" && n != "min_latency" + && n != "tcp_nodelay" && n != "send_min_interval" && n != "reduce_sequence_header" && n != "security" && n != "http_remux" && n != "http" && n != "http_static" && n != "hds" @@ -2534,6 +2535,23 @@ int SrsConfig::get_send_min_interval(string vhost) return ::atoi(conf->arg0().c_str()); } +bool SrsConfig::get_reduce_sequence_header(string vhost) +{ + static bool DEFAULT = false; + + SrsConfDirective* conf = get_vhost(vhost); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("reduce_sequence_header"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return SRS_CONF_PERFER_FALSE(conf->arg0()); +} + int SrsConfig::get_global_chunk_size() { SrsConfDirective* conf = root->get("chunk_size"); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index ad695d166..efc805a3a 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -530,6 +530,10 @@ public: * the minimal send interval in ms. */ virtual int get_send_min_interval(std::string vhost); + /** + * whether reduce the sequence header. + */ + virtual bool get_reduce_sequence_header(std::string vhost); private: /** * get the global chunk size. diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index 02a9457eb..dbe47f689 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -1535,6 +1535,8 @@ int SrsSource::on_audio_imp(SrsSharedPtrMessage* msg) int ret = ERROR_SUCCESS; srs_info("Audio dts=%"PRId64", size=%d", msg->timestamp, msg->size); + bool is_aac_sequence_header = SrsFlvCodec::audio_is_sequence_header(msg->payload, msg->size); + bool is_sequence_header = is_aac_sequence_header; #ifdef SRS_AUTO_HLS if ((ret = hls->on_audio(msg)) != ERROR_SUCCESS) { @@ -1589,11 +1591,16 @@ int SrsSource::on_audio_imp(SrsSharedPtrMessage* msg) #endif // copy to all consumer - int nb_consumers = (int)consumers.size(); - if (nb_consumers > 0) { - SrsConsumer** pconsumer = consumers.data(); - for (int i = 0; i < nb_consumers; i++) { - SrsConsumer* consumer = pconsumer[i]; + bool drop_for_reduce = false; + if (is_sequence_header && cache_sh_audio && _srs_config->get_reduce_sequence_header(_req->vhost)) { + if (cache_sh_audio->size == msg->size) { + drop_for_reduce = srs_bytes_equals(cache_sh_audio->payload, msg->payload, msg->size); + srs_warn("drop for reduce sh audio, size=%d", msg->size); + } + } + if (!drop_for_reduce) { + for (int i = 0; i < (int)consumers.size(); i++) { + SrsConsumer* consumer = consumers.at(i); if ((ret = consumer->enqueue(msg, atc, jitter_algorithm)) != ERROR_SUCCESS) { srs_error("dispatch the audio failed. ret=%d", ret); return ret; @@ -1617,7 +1624,6 @@ int SrsSource::on_audio_imp(SrsSharedPtrMessage* msg) // cache the sequence header of aac, or first packet of mp3. // for example, the mp3 is used for hls to write the "right" audio codec. // TODO: FIXME: to refine the stream info system. - bool is_aac_sequence_header = SrsFlvCodec::audio_is_sequence_header(msg->payload, msg->size); if (is_aac_sequence_header || !cache_sh_audio) { srs_freep(cache_sh_audio); cache_sh_audio = msg->copy(); @@ -1740,6 +1746,8 @@ int SrsSource::on_video_imp(SrsSharedPtrMessage* msg) srs_info("Video dts=%"PRId64", size=%d", msg->timestamp, msg->size); + bool is_sequence_header = SrsFlvCodec::video_is_sequence_header(msg->payload, msg->size); + #ifdef SRS_AUTO_HLS if ((ret = hls->on_video(msg)) != ERROR_SUCCESS) { // apply the error strategy for hls. @@ -1793,7 +1801,14 @@ int SrsSource::on_video_imp(SrsSharedPtrMessage* msg) #endif // copy to all consumer - if (true) { + bool drop_for_reduce = false; + if (is_sequence_header && cache_sh_video && _srs_config->get_reduce_sequence_header(_req->vhost)) { + if (cache_sh_video->size == msg->size) { + drop_for_reduce = srs_bytes_equals(cache_sh_video->payload, msg->payload, msg->size); + srs_warn("drop for reduce sh video, size=%d", msg->size); + } + } + if (!drop_for_reduce) { for (int i = 0; i < (int)consumers.size(); i++) { SrsConsumer* consumer = consumers.at(i); if ((ret = consumer->enqueue(msg, atc, jitter_algorithm)) != ERROR_SUCCESS) { @@ -1818,7 +1833,7 @@ int SrsSource::on_video_imp(SrsSharedPtrMessage* msg) // cache the sequence header if h264 // donot cache the sequence header to gop_cache, return here. - if (SrsFlvCodec::video_is_sequence_header(msg->payload, msg->size)) { + if (is_sequence_header) { srs_freep(cache_sh_video); cache_sh_video = msg->copy(); @@ -2062,13 +2077,12 @@ void SrsSource::on_unpublish() hds->on_unpublish(); #endif + // only clear the gop cache metadata, + // donot clear the sequence header, for it maybe not changed. gop_cache->clear(); - srs_freep(cache_metadata); - srs_freep(cache_sh_video); - srs_freep(cache_sh_audio); - srs_info("clear cache/metadata/sequence-headers when unpublish."); + srs_info("clear cache/metadata when unpublish."); srs_trace("cleanup when unpublish"); _can_publish = true;