From a994191ddccf409a737b4f99a5fabac22f1157f2 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 14 Sep 2015 15:10:34 +0800 Subject: [PATCH 1/9] for #474, always release publish for source. --- README.md | 2 ++ trunk/src/app/srs_app_rtmp_conn.cpp | 10 ++++++++-- trunk/src/app/srs_app_source.cpp | 1 + trunk/src/app/srs_app_thread.cpp | 2 ++ 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ae0c46e3a..b00951bfe 100755 --- a/README.md +++ b/README.md @@ -343,6 +343,7 @@ Remark: ## History +* v2.0, 2015-09-14, for [#474][bug #474] always release publish for source. * v2.0, 2015-09-14, for [#458][bug #458] http hooks use source thread cid. 2.0.188 * v2.0, 2015-09-14, for [#475][bug #475] fix http hooks crash for st context switch. 2.0.187 * v2.0, 2015-09-09, support reload utc_time. 2.0.186 @@ -1026,6 +1027,7 @@ Winlin [bug #133]: https://github.com/simple-rtmp-server/srs/issues/133 [bug #92]: https://github.com/simple-rtmp-server/srs/issues/92 [bug #380]: https://github.com/simple-rtmp-server/srs/issues/380 +[bug #474]: https://github.com/simple-rtmp-server/srs/issues/474 [bug #475]: https://github.com/simple-rtmp-server/srs/issues/475 [bug #458]: https://github.com/simple-rtmp-server/srs/issues/458 [bug #454]: https://github.com/simple-rtmp-server/srs/issues/454 diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index 51fb46d84..8a8321034 100755 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -834,9 +834,13 @@ int SrsRtmpConn::publishing(SrsSource* source) // stop isolate recv thread trd.stop(); - - release_publish(source, vhost_is_edge); } + + // whatever the acquire publish, always release publish. + // when the acquire error in the midlle-way, the publish state changed, + // but failed, so we must cleanup it. + // @see https://github.com/simple-rtmp-server/srs/issues/474 + release_publish(source, vhost_is_edge); http_hooks_on_unpublish(); @@ -944,10 +948,12 @@ int SrsRtmpConn::acquire_publish(SrsSource* source, bool is_edge) if (is_edge) { if ((ret = source->on_edge_start_publish()) != ERROR_SUCCESS) { srs_error("notice edge start publish stream failed. ret=%d", ret); + return ret; } } else { if ((ret = source->on_publish()) != ERROR_SUCCESS) { srs_error("notify publish failed. ret=%d", ret); + return ret; } } diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index ec00978cc..4f08e774a 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -2066,6 +2066,7 @@ int SrsSource::on_publish() } SrsStatistic* stat = SrsStatistic::instance(); stat->on_stream_publish(_req, _source_id); + return ret; } diff --git a/trunk/src/app/srs_app_thread.cpp b/trunk/src/app/srs_app_thread.cpp index 097758563..d56624cd9 100644 --- a/trunk/src/app/srs_app_thread.cpp +++ b/trunk/src/app/srs_app_thread.cpp @@ -217,6 +217,8 @@ namespace internal { handler->on_thread_stop(); srs_info("thread %s cycle finished", _name); + + // TODO: FIXME: when thread terminated normally, set the tid to NULL. } void* SrsThread::thread_fun(void* arg) From 3da25f3aee654f9da83a5d9e182ff6e9d3527305 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 14 Sep 2015 15:11:49 +0800 Subject: [PATCH 2/9] when thread terminated normally, set the tid to NULL. --- trunk/src/app/srs_app_thread.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trunk/src/app/srs_app_thread.cpp b/trunk/src/app/srs_app_thread.cpp index d56624cd9..180446a8b 100644 --- a/trunk/src/app/srs_app_thread.cpp +++ b/trunk/src/app/srs_app_thread.cpp @@ -218,7 +218,8 @@ namespace internal { handler->on_thread_stop(); srs_info("thread %s cycle finished", _name); - // TODO: FIXME: when thread terminated normally, set the tid to NULL. + // when thread terminated normally, set the tid to NULL. + tid = NULL; } void* SrsThread::thread_fun(void* arg) From 8be3c875af90aa785069d7ddcc8cc36ac73d67ce Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 14 Sep 2015 15:17:59 +0800 Subject: [PATCH 3/9] donot release stream when busy --- trunk/src/app/srs_app_rtmp_conn.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index 8a8321034..c09364ce0 100755 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -840,7 +840,10 @@ int SrsRtmpConn::publishing(SrsSource* source) // when the acquire error in the midlle-way, the publish state changed, // but failed, so we must cleanup it. // @see https://github.com/simple-rtmp-server/srs/issues/474 - release_publish(source, vhost_is_edge); + // @remark when stream is busy, should never release it. + if (ret != ERROR_SYSTEM_STREAM_BUSY) { + release_publish(source, vhost_is_edge); + } http_hooks_on_unpublish(); From 704624c9ec08eef08a80b4f9bd4b8aa9635b56c6 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 14 Sep 2015 15:19:49 +0800 Subject: [PATCH 4/9] clear the queue when edge republish. --- trunk/src/app/srs_app_edge.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/trunk/src/app/srs_app_edge.cpp b/trunk/src/app/srs_app_edge.cpp index cd4a2fdcb..f60bc7e6b 100644 --- a/trunk/src/app/srs_app_edge.cpp +++ b/trunk/src/app/srs_app_edge.cpp @@ -476,6 +476,8 @@ void SrsEdgeForwarder::stop() close_underlayer_socket(); + queue->clear(); + srs_freep(client); srs_freep(io); kbps->set_io(NULL, NULL); From 07ef8160a3aa1d1ca64e12e01781cc725486c404 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 14 Sep 2015 15:25:01 +0800 Subject: [PATCH 5/9] clear the queue when edge republish. --- trunk/src/app/srs_app_source.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/trunk/src/app/srs_app_source.hpp b/trunk/src/app/srs_app_source.hpp index 7c626b7eb..fe82f6332 100755 --- a/trunk/src/app/srs_app_source.hpp +++ b/trunk/src/app/srs_app_source.hpp @@ -190,6 +190,10 @@ private: * if no iframe found, clear it. */ virtual void shrink(); +public: + /** + * clear all messages in queue. + */ virtual void clear(); }; From 44bcb4045f54322edf5b0da843793edb96213091 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 14 Sep 2015 15:32:09 +0800 Subject: [PATCH 6/9] for #474, decode the sequence header before hls. --- trunk/src/app/srs_app_source.cpp | 150 ++++++++++++++++--------------- 1 file changed, 76 insertions(+), 74 deletions(-) diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index 4f08e774a..409f55fd5 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -1551,6 +1551,45 @@ int SrsSource::on_audio_imp(SrsSharedPtrMessage* msg) bool is_aac_sequence_header = SrsFlvCodec::audio_is_sequence_header(msg->payload, msg->size); bool is_sequence_header = is_aac_sequence_header; + // whether consumer should drop for the duplicated sequence header. + 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); + } + } + + // cache the sequence header if aac + // donot cache the sequence header to gop_cache, return here. + if (is_aac_sequence_header) { + // parse detail audio codec + SrsAvcAacCodec codec; + SrsCodecSample sample; + if ((ret = codec.audio_aac_demux(msg->payload, msg->size, &sample)) != ERROR_SUCCESS) { + srs_error("source codec demux audio failed. ret=%d", ret); + return ret; + } + + static int flv_sample_sizes[] = {8, 16, 0}; + static int flv_sound_types[] = {1, 2, 0}; + + // when got audio stream info. + SrsStatistic* stat = SrsStatistic::instance(); + if ((ret = stat->on_audio_info(_req, SrsCodecAudioAAC, sample.sound_rate, sample.sound_type, codec.aac_object)) != ERROR_SUCCESS) { + return ret; + } + + srs_trace("%dB audio sh, codec(%d, profile=%s, %dchannels, %dkbps, %dHZ), " + "flv(%dbits, %dchannels, %dHZ)", + msg->size, codec.audio_codec_id, + srs_codec_aac_object2str(codec.aac_object).c_str(), codec.aac_channels, + codec.audio_data_rate / 1000, aac_sample_rates[codec.aac_sample_rate], + flv_sample_sizes[sample.sound_size], flv_sound_types[sample.sound_type], + flv_sample_rates[sample.sound_rate]); + return ret; + } + #ifdef SRS_AUTO_HLS if ((ret = hls->on_audio(msg)) != ERROR_SUCCESS) { // apply the error strategy for hls. @@ -1604,13 +1643,6 @@ int SrsSource::on_audio_imp(SrsSharedPtrMessage* msg) #endif // copy to all consumer - 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); @@ -1641,37 +1673,6 @@ int SrsSource::on_audio_imp(SrsSharedPtrMessage* msg) srs_freep(cache_sh_audio); cache_sh_audio = msg->copy(); } - - // cache the sequence header if aac - // donot cache the sequence header to gop_cache, return here. - if (is_aac_sequence_header) { - // parse detail audio codec - SrsAvcAacCodec codec; - SrsCodecSample sample; - if ((ret = codec.audio_aac_demux(msg->payload, msg->size, &sample)) != ERROR_SUCCESS) { - srs_error("source codec demux audio failed. ret=%d", ret); - return ret; - } - - static int flv_sample_sizes[] = {8, 16, 0}; - static int flv_sound_types[] = {1, 2, 0}; - - // when got audio stream info. - SrsStatistic* stat = SrsStatistic::instance(); - if ((ret = stat->on_audio_info(_req, SrsCodecAudioAAC, sample.sound_rate, sample.sound_type, codec.aac_object)) != ERROR_SUCCESS) { - return ret; - } - - srs_trace("%dB audio sh, " - "codec(%d, profile=%s, %dchannels, %dkbps, %dHZ), " - "flv(%dbits, %dchannels, %dHZ)", - msg->size, codec.audio_codec_id, - srs_codec_aac_object2str(codec.aac_object).c_str(), codec.aac_channels, - codec.audio_data_rate / 1000, aac_sample_rates[codec.aac_sample_rate], - flv_sample_sizes[sample.sound_size], flv_sound_types[sample.sound_type], - flv_sample_rates[sample.sound_rate]); - return ret; - } // cache the last gop packets if ((ret = gop_cache->cache(msg)) != ERROR_SUCCESS) { @@ -1761,6 +1762,43 @@ int SrsSource::on_video_imp(SrsSharedPtrMessage* msg) bool is_sequence_header = SrsFlvCodec::video_is_sequence_header(msg->payload, msg->size); + // whether consumer should drop for the duplicated sequence header. + 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); + } + } + + // cache the sequence header if h264 + // donot cache the sequence header to gop_cache, return here. + if (is_sequence_header) { + srs_freep(cache_sh_video); + cache_sh_video = msg->copy(); + + // parse detail audio codec + SrsAvcAacCodec codec; + SrsCodecSample sample; + if ((ret = codec.video_avc_demux(msg->payload, msg->size, &sample)) != ERROR_SUCCESS) { + srs_error("source codec demux video failed. ret=%d", ret); + return ret; + } + + // when got video stream info. + SrsStatistic* stat = SrsStatistic::instance(); + if ((ret = stat->on_video_info(_req, SrsCodecVideoAVC, codec.avc_profile, codec.avc_level)) != ERROR_SUCCESS) { + return ret; + } + + srs_trace("%dB video sh, codec(%d, profile=%s, level=%s, %dx%d, %dkbps, %dfps, %ds)", + msg->size, codec.video_codec_id, + srs_codec_avc_profile2str(codec.avc_profile).c_str(), + srs_codec_avc_level2str(codec.avc_level).c_str(), codec.width, codec.height, + codec.video_data_rate / 1000, codec.frame_rate, codec.duration); + return ret; + } + #ifdef SRS_AUTO_HLS if ((ret = hls->on_video(msg)) != ERROR_SUCCESS) { // apply the error strategy for hls. @@ -1814,13 +1852,6 @@ int SrsSource::on_video_imp(SrsSharedPtrMessage* msg) #endif // copy to all consumer - 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); @@ -1844,35 +1875,6 @@ int SrsSource::on_video_imp(SrsSharedPtrMessage* msg) } } - // cache the sequence header if h264 - // donot cache the sequence header to gop_cache, return here. - if (is_sequence_header) { - srs_freep(cache_sh_video); - cache_sh_video = msg->copy(); - - // parse detail audio codec - SrsAvcAacCodec codec; - SrsCodecSample sample; - if ((ret = codec.video_avc_demux(msg->payload, msg->size, &sample)) != ERROR_SUCCESS) { - srs_error("source codec demux video failed. ret=%d", ret); - return ret; - } - - // when got video stream info. - SrsStatistic* stat = SrsStatistic::instance(); - if ((ret = stat->on_video_info(_req, SrsCodecVideoAVC, codec.avc_profile, codec.avc_level)) != ERROR_SUCCESS) { - return ret; - } - - srs_trace("%dB video sh, " - "codec(%d, profile=%s, level=%s, %dx%d, %dkbps, %dfps, %ds)", - msg->size, codec.video_codec_id, - srs_codec_avc_profile2str(codec.avc_profile).c_str(), - srs_codec_avc_level2str(codec.avc_level).c_str(), codec.width, codec.height, - codec.video_data_rate / 1000, codec.frame_rate, codec.duration); - return ret; - } - // cache the last gop packets if ((ret = gop_cache->cache(msg)) != ERROR_SUCCESS) { srs_error("gop cache msg failed. ret=%d", ret); From 83a9ff9f5dfe3f5fb933838cd5a147e2e5273916 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 14 Sep 2015 15:49:25 +0800 Subject: [PATCH 7/9] for #474, refine the hls publish, donot fetch from source when publish --- trunk/src/app/srs_app_hls.cpp | 18 +++++++++++------- trunk/src/app/srs_app_hls.hpp | 9 +++++---- trunk/src/app/srs_app_source.cpp | 4 ++-- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp index d8437bae3..fe73551ee 100644 --- a/trunk/src/app/srs_app_hls.cpp +++ b/trunk/src/app/srs_app_hls.cpp @@ -1252,7 +1252,7 @@ int SrsHls::initialize(SrsSource* s, ISrsHlsHandler* h) return ret; } -int SrsHls::on_publish(SrsRequest* req) +int SrsHls::on_publish(SrsRequest* req, bool fetch_sequence_header) { int ret = ERROR_SUCCESS; @@ -1282,12 +1282,16 @@ int SrsHls::on_publish(SrsRequest* req) // ok, the hls can be dispose, or need to be dispose. hls_can_dispose = true; - // 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 = source->on_hls_start()) != ERROR_SUCCESS) { - srs_error("callback source hls start failed. ret=%d", ret); - return ret; + // 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 = source->on_hls_start()) != ERROR_SUCCESS) { + srs_error("callback source hls start failed. ret=%d", ret); + return ret; + } } return ret; diff --git a/trunk/src/app/srs_app_hls.hpp b/trunk/src/app/srs_app_hls.hpp index dd9f8953c..0ffdf5b74 100644 --- a/trunk/src/app/srs_app_hls.hpp +++ b/trunk/src/app/srs_app_hls.hpp @@ -424,10 +424,11 @@ public: */ virtual int initialize(SrsSource* s, ISrsHlsHandler* h); /** - * publish stream event, continue to write the m3u8, - * for the muxer object not destroyed. - */ - virtual int on_publish(SrsRequest* req); + * publish stream event, continue to write the m3u8, + * for the muxer object not destroyed. + * @param fetch_sequence_header whether fetch sequence from source. + */ + virtual int on_publish(SrsRequest* req, bool fetch_sequence_header); /** * 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_source.cpp b/trunk/src/app/srs_app_source.cpp index 409f55fd5..fa3596034 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -1180,7 +1180,7 @@ int SrsSource::on_reload_vhost_hls(string vhost) #ifdef SRS_AUTO_HLS hls->on_unpublish(); - if ((ret = hls->on_publish(_req)) != ERROR_SUCCESS) { + if ((ret = hls->on_publish(_req, true)) != ERROR_SUCCESS) { srs_error("hls publish failed. ret=%d", ret); return ret; } @@ -2039,7 +2039,7 @@ int SrsSource::on_publish() // TODO: FIXME: use initialize to set req. #ifdef SRS_AUTO_HLS - if ((ret = hls->on_publish(_req)) != ERROR_SUCCESS) { + if ((ret = hls->on_publish(_req, false)) != ERROR_SUCCESS) { srs_error("start hls failed. ret=%d", ret); return ret; } From eb578b4a39080b1889296691c8888768306c6dd9 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 14 Sep 2015 17:17:38 +0800 Subject: [PATCH 8/9] refine the thread, set to disposed when terminate normally --- trunk/src/app/srs_app_thread.cpp | 80 +++++++++++++---------- trunk/src/app/srs_app_thread.hpp | 2 + trunk/src/protocol/srs_rtmp_handshake.cpp | 2 +- 3 files changed, 50 insertions(+), 34 deletions(-) diff --git a/trunk/src/app/srs_app_thread.cpp b/trunk/src/app/srs_app_thread.cpp index 180446a8b..274c16f6b 100644 --- a/trunk/src/app/srs_app_thread.cpp +++ b/trunk/src/app/srs_app_thread.cpp @@ -66,6 +66,7 @@ namespace internal { really_terminated = true; _cid = -1; _joinable = joinable; + disposed = false; // in start(), the thread cycle method maybe stop and remove the thread itself, // and the thread start() is waiting for the _cid, and segment fault then. @@ -115,38 +116,15 @@ namespace internal { void SrsThread::stop() { - if (tid) { - loop = false; - - // the interrupt will cause the socket to read/write error, - // which will terminate the cycle thread. - st_thread_interrupt(tid); - - // when joinable, wait util quit. - if (_joinable) { - // wait the thread to exit. - int ret = st_thread_join(tid, NULL); - if (ret) { - srs_warn("core: ignore join thread failed."); - } - } - - // wait the thread actually terminated. - // sometimes the thread join return -1, for example, - // when thread use st_recvfrom, the thread join return -1. - // so here, we use a variable to ensure the thread stopped. - // @remark even the thread not joinable, we must ensure the thread stopped when stop. - while (!really_terminated) { - st_usleep(10 * 1000); - - if (really_terminated) { - break; - } - srs_warn("core: wait thread to actually terminated"); - } - - tid = NULL; + if (!tid) { + return; } + + loop = false; + + dispose(); + + tid = NULL; } bool SrsThread::can_loop() @@ -159,6 +137,42 @@ namespace internal { loop = false; } + void SrsThread::dispose() + { + if (disposed) { + return; + } + + // the interrupt will cause the socket to read/write error, + // which will terminate the cycle thread. + st_thread_interrupt(tid); + + // when joinable, wait util quit. + if (_joinable) { + // wait the thread to exit. + int ret = st_thread_join(tid, NULL); + if (ret) { + srs_warn("core: ignore join thread failed."); + } + } + + // wait the thread actually terminated. + // sometimes the thread join return -1, for example, + // when thread use st_recvfrom, the thread join return -1. + // so here, we use a variable to ensure the thread stopped. + // @remark even the thread not joinable, we must ensure the thread stopped when stop. + while (!really_terminated) { + st_usleep(10 * 1000); + + if (really_terminated) { + break; + } + srs_warn("core: wait thread to actually terminated"); + } + + disposed = true; + } + void SrsThread::thread_cycle() { int ret = ERROR_SUCCESS; @@ -218,8 +232,8 @@ namespace internal { handler->on_thread_stop(); srs_info("thread %s cycle finished", _name); - // when thread terminated normally, set the tid to NULL. - tid = NULL; + // when thread terminated normally, also disposed. + disposed = true; } void* SrsThread::thread_fun(void* arg) diff --git a/trunk/src/app/srs_app_thread.hpp b/trunk/src/app/srs_app_thread.hpp index 1974cff22..8eb65dc0d 100644 --- a/trunk/src/app/srs_app_thread.hpp +++ b/trunk/src/app/srs_app_thread.hpp @@ -100,6 +100,7 @@ namespace internal { bool really_terminated; bool _joinable; const char* _name; + bool disposed; private: ISrsThreadHandler* handler; int64_t cycle_interval_us; @@ -154,6 +155,7 @@ namespace internal { */ virtual void stop_loop(); private: + virtual void dispose(); virtual void thread_cycle(); static void* thread_fun(void* arg); }; diff --git a/trunk/src/protocol/srs_rtmp_handshake.cpp b/trunk/src/protocol/srs_rtmp_handshake.cpp index f32bc1d5e..d4fbae69b 100644 --- a/trunk/src/protocol/srs_rtmp_handshake.cpp +++ b/trunk/src/protocol/srs_rtmp_handshake.cpp @@ -905,7 +905,7 @@ namespace _srs_internal } // client c1 time and version - time = ::time(NULL); + time = (int32_t)::time(NULL); version = 0x80000702; // client c1 version // generate signature by schema From 511627ababc2e759cfcfbfcd808614f179cc380c Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 14 Sep 2015 18:36:44 +0800 Subject: [PATCH 9/9] fix #474, config to donot parse width/height from sps. 2.0.189 --- README.md | 1 + trunk/conf/full.conf | 11 ++++++++ trunk/src/app/srs_app_config.cpp | 38 ++++++++++++++++++++++++++- trunk/src/app/srs_app_config.hpp | 4 +++ trunk/src/app/srs_app_hls.cpp | 8 +++++- trunk/src/app/srs_app_hls.hpp | 9 ++++--- trunk/src/app/srs_app_source.cpp | 21 ++++++++++++--- trunk/src/core/srs_core.hpp | 2 +- trunk/src/kernel/srs_kernel_codec.cpp | 8 ++++++ trunk/src/kernel/srs_kernel_codec.hpp | 3 +++ 10 files changed, 94 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index b00951bfe..1860b9ba6 100755 --- a/README.md +++ b/README.md @@ -343,6 +343,7 @@ Remark: ## History +* v2.0, 2015-09-14, fix [#474][bug #474] config to donot parse width/height from sps. 2.0.189 * v2.0, 2015-09-14, for [#474][bug #474] always release publish for source. * v2.0, 2015-09-14, for [#458][bug #458] http hooks use source thread cid. 2.0.188 * v2.0, 2015-09-14, for [#475][bug #475] fix http hooks crash for st context switch. 2.0.187 diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 340ae4626..623a4d298 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -858,6 +858,17 @@ vhost min.delay.com { tcp_nodelay on; } +# whether disable the sps parse, for the resolution of video. +vhost no.parse.sps.com { + publish { + # whether parse the sps when publish stream. + # we can got the resolution of video for stat api. + # but we may failed to cause publish failed. + # default: on + parse_sps on; + } +} + # the vhost to control the stream delivery feature vhost stream.control.com { # @see vhost mrw.srs.com for detail. diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 8a945cc25..92e364043 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -618,6 +618,9 @@ int SrsConfig::reload_vhost(SrsConfDirective* old_root) srs_error("reload never supports mode changed. ret=%d", ret); return ret; } + + // the auto reload configs: + // publish.parse_sps // ENABLED => ENABLED (modified) if (get_vhost_enabled(new_vhost) && get_vhost_enabled(old_vhost)) { @@ -1806,7 +1809,7 @@ 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 != "mr" && n != "mw_latency" && n != "min_latency" && n != "publish" && n != "tcp_nodelay" && n != "send_min_interval" && n != "reduce_sequence_header" && n != "publish_1stpkt_timeout" && n != "publish_normal_timeout" && n != "security" && n != "http_remux" @@ -1839,6 +1842,16 @@ int SrsConfig::check_config() return ret; } } + } else if (n == "publish") { + for (int j = 0; j < (int)conf->directives.size(); j++) { + string m = conf->at(j)->name.c_str(); + if (m != "parse_sps" + ) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("unsupported vhost publish directive %s, ret=%d", m.c_str(), ret); + return ret; + } + } } else if (n == "ingest") { for (int j = 0; j < (int)conf->directives.size(); j++) { string m = conf->at(j)->name.c_str(); @@ -2473,6 +2486,29 @@ int SrsConfig::get_chunk_size(string vhost) return ::atoi(conf->arg0().c_str()); } +bool SrsConfig::get_parse_sps(string vhost) +{ + static bool DEFAULT = true; + + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return DEFAULT; + } + + conf = conf->get("publish"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("parse_sps"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return SRS_CONF_PERFER_TRUE(conf->arg0()); +} + bool SrsConfig::get_mr_enabled(string vhost) { SrsConfDirective* conf = get_vhost(vhost); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 4dd83c044..f15a5ab89 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -499,6 +499,10 @@ public: * @remark, default 60000. */ virtual int get_chunk_size(std::string vhost); + /** + * whether parse the sps when publish stream to SRS. + */ + virtual bool get_parse_sps(std::string vhost); /** * whether mr is enabled for vhost. * @param vhost, the vhost to get the mr. diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp index fe73551ee..8b36ab7f9 100644 --- a/trunk/src/app/srs_app_hls.cpp +++ b/trunk/src/app/srs_app_hls.cpp @@ -1395,7 +1395,7 @@ int SrsHls::on_audio(SrsSharedPtrMessage* shared_audio) return ret; } -int SrsHls::on_video(SrsSharedPtrMessage* shared_video) +int SrsHls::on_video(SrsSharedPtrMessage* shared_video, bool is_sps_pps) { int ret = ERROR_SUCCESS; @@ -1409,6 +1409,12 @@ int SrsHls::on_video(SrsSharedPtrMessage* shared_video) SrsSharedPtrMessage* video = shared_video->copy(); SrsAutoFree(SrsSharedPtrMessage, video); + // user can disable the sps parse to workaround when parse sps failed. + // @see https://github.com/simple-rtmp-server/srs/issues/474 + if (is_sps_pps) { + codec->avc_parse_sps = _srs_config->get_parse_sps(_req->vhost); + } + sample->clear(); if ((ret = codec->video_avc_demux(video->payload, video->size, sample)) != ERROR_SUCCESS) { srs_error("hls codec demux video failed. ret=%d", ret); diff --git a/trunk/src/app/srs_app_hls.hpp b/trunk/src/app/srs_app_hls.hpp index 0ffdf5b74..62abd660f 100644 --- a/trunk/src/app/srs_app_hls.hpp +++ b/trunk/src/app/srs_app_hls.hpp @@ -444,10 +444,11 @@ public: */ virtual int on_audio(SrsSharedPtrMessage* shared_audio); /** - * mux the video packets to ts. - * @param shared_video, directly ptr, copy it if need to save it. - */ - virtual int on_video(SrsSharedPtrMessage* shared_video); + * mux the video packets to ts. + * @param shared_video, directly ptr, copy it if need to save it. + * @param is_sps_pps whether the video is h.264 sps/pps. + */ + virtual int on_video(SrsSharedPtrMessage* shared_video, bool is_sps_pps); private: virtual void hls_show_mux_log(); }; diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index fa3596034..158acd16b 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -1290,7 +1290,7 @@ int SrsSource::on_hls_start() // 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)) != ERROR_SUCCESS) { + 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; } @@ -1587,7 +1587,6 @@ int SrsSource::on_audio_imp(SrsSharedPtrMessage* msg) codec.audio_data_rate / 1000, aac_sample_rates[codec.aac_sample_rate], flv_sample_sizes[sample.sound_size], flv_sound_types[sample.sound_type], flv_sample_rates[sample.sound_rate]); - return ret; } #ifdef SRS_AUTO_HLS @@ -1674,6 +1673,11 @@ int SrsSource::on_audio_imp(SrsSharedPtrMessage* msg) cache_sh_audio = msg->copy(); } + // when sequence header, donot push to gop cache and adjust the timestamp. + if (is_sequence_header) { + return ret; + } + // cache the last gop packets if ((ret = gop_cache->cache(msg)) != ERROR_SUCCESS) { srs_error("shrink gop cache failed. ret=%d", ret); @@ -1779,6 +1783,11 @@ int SrsSource::on_video_imp(SrsSharedPtrMessage* msg) // parse detail audio codec SrsAvcAacCodec codec; + + // user can disable the sps parse to workaround when parse sps failed. + // @see https://github.com/simple-rtmp-server/srs/issues/474 + codec.avc_parse_sps = _srs_config->get_parse_sps(_req->vhost); + SrsCodecSample sample; if ((ret = codec.video_avc_demux(msg->payload, msg->size, &sample)) != ERROR_SUCCESS) { srs_error("source codec demux video failed. ret=%d", ret); @@ -1796,11 +1805,10 @@ int SrsSource::on_video_imp(SrsSharedPtrMessage* msg) srs_codec_avc_profile2str(codec.avc_profile).c_str(), srs_codec_avc_level2str(codec.avc_level).c_str(), codec.width, codec.height, codec.video_data_rate / 1000, codec.frame_rate, codec.duration); - return ret; } #ifdef SRS_AUTO_HLS - if ((ret = hls->on_video(msg)) != ERROR_SUCCESS) { + if ((ret = hls->on_video(msg, is_sequence_header)) != ERROR_SUCCESS) { // apply the error strategy for hls. // @see https://github.com/simple-rtmp-server/srs/issues/264 std::string hls_error_strategy = _srs_config->get_hls_on_error(_req->vhost); @@ -1874,6 +1882,11 @@ int SrsSource::on_video_imp(SrsSharedPtrMessage* msg) } } } + + // when sequence header, donot push to gop cache and adjust the timestamp. + if (is_sequence_header) { + return ret; + } // cache the last gop packets if ((ret = gop_cache->cache(msg)) != ERROR_SUCCESS) { diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index 940b7e81d..ebe87801d 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // current release version #define VERSION_MAJOR 2 #define VERSION_MINOR 0 -#define VERSION_REVISION 188 +#define VERSION_REVISION 189 // server info. #define RTMP_SIG_SRS_KEY "SRS" diff --git a/trunk/src/kernel/srs_kernel_codec.cpp b/trunk/src/kernel/srs_kernel_codec.cpp index a0d0843f5..fddd112df 100644 --- a/trunk/src/kernel/srs_kernel_codec.cpp +++ b/trunk/src/kernel/srs_kernel_codec.cpp @@ -382,6 +382,8 @@ int SrsCodecSample::add_sample_unit(char* bytes, int size) SrsAvcAacCodec::SrsAvcAacCodec() { + avc_parse_sps = true; + width = 0; height = 0; duration = 0; @@ -939,6 +941,12 @@ int SrsAvcAacCodec::avc_demux_sps_rbsp(char* rbsp, int nb_rbsp) { int ret = ERROR_SUCCESS; + // we donot parse the detail of sps. + // @see https://github.com/simple-rtmp-server/srs/issues/474 + if (!avc_parse_sps) { + return ret; + } + // reparse the rbsp. SrsStream stream; if ((ret = stream.initialize(rbsp, nb_rbsp)) != ERROR_SUCCESS) { diff --git a/trunk/src/kernel/srs_kernel_codec.hpp b/trunk/src/kernel/srs_kernel_codec.hpp index 204673882..3b1c7845b 100644 --- a/trunk/src/kernel/srs_kernel_codec.hpp +++ b/trunk/src/kernel/srs_kernel_codec.hpp @@ -605,6 +605,9 @@ public: */ int aac_extra_size; char* aac_extra_data; +public: + // for sequence header, whether parse the h.264 sps. + bool avc_parse_sps; public: SrsAvcAacCodec(); virtual ~SrsAvcAacCodec();