From c514a4ceeb700db68c101274e059a5c49cc8883f Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 21 Apr 2015 12:58:54 +0800 Subject: [PATCH 1/4] use atc for ingest hls aac time. --- trunk/src/main/srs_main_ingest_hls.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/trunk/src/main/srs_main_ingest_hls.cpp b/trunk/src/main/srs_main_ingest_hls.cpp index 2d2fd414e..623967816 100644 --- a/trunk/src/main/srs_main_ingest_hls.cpp +++ b/trunk/src/main/srs_main_ingest_hls.cpp @@ -657,7 +657,7 @@ public: SrsIngestSrsOutput(SrsHttpUri* rtmp) { out_rtmp = rtmp; disconnected = false; - raw_aac_dts = 0; + raw_aac_dts = srs_update_system_time_ms(); req = NULL; io = NULL; @@ -807,12 +807,14 @@ int SrsIngestSrsOutput::do_on_aac_frame(SrsStream* avs, double duration) { int ret = ERROR_SUCCESS; + u_int32_t duration_ms = (u_int32_t)(duration * 1000); + // ts tbn to flv tbn. u_int32_t dts = (u_int32_t)raw_aac_dts; - raw_aac_dts += (int64_t)(duration * 1000); + raw_aac_dts += duration_ms; // got the next msg to calc the delta duration for each audio. - u_int32_t max_dts = dts + (u_int32_t)(duration * 1000); + u_int32_t max_dts = dts + duration_ms; // send each frame. while (!avs->empty()) { @@ -852,7 +854,7 @@ int SrsIngestSrsOutput::do_on_aac_frame(SrsStream* avs, double duration) } // calc the delta of dts, when previous frame output. - u_int32_t delta = (duration * 1000) / (avs->size() / frame_size); + u_int32_t delta = duration_ms / (avs->size() / frame_size); dts = (u_int32_t)(srs_min(max_dts, dts + delta)); } From d19dfa528ea102689936b0c4a36769ff69135348 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 21 Apr 2015 14:35:28 +0800 Subject: [PATCH 2/4] abs overflow also plus the deviation, for pure audio hls. --- trunk/src/app/srs_app_hls.cpp | 12 ++++++-- trunk/src/kernel/srs_kernel_ts.cpp | 22 ++++++++++++++ trunk/src/kernel/srs_kernel_ts.hpp | 10 +++++++ trunk/src/main/srs_main_ingest_hls.cpp | 40 +++++++++++++++----------- 4 files changed, 64 insertions(+), 20 deletions(-) diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp index 2a2387b7c..f56b177b9 100644 --- a/trunk/src/app/srs_app_hls.cpp +++ b/trunk/src/app/srs_app_hls.cpp @@ -559,7 +559,13 @@ bool SrsHlsMuxer::is_segment_absolutely_overflow() { // @see https://github.com/winlinvip/simple-rtmp-server/issues/151#issuecomment-83553950 srs_assert(current); - return current->duration >= hls_aof_ratio * hls_fragment; + + // use N% deviation, to smoother. + double deviation = hls_ts_floor? SRS_HLS_FLOOR_REAP_PERCENT * deviation_ts * hls_fragment : 0.0; + srs_info("hls: dur=%.2f, tar=%.2f, dev=%.2fms/%dp, frag=%.2f", + current->duration, hls_fragment + deviation, deviation, deviation_ts, hls_fragment); + + return current->duration >= hls_aof_ratio * hls_fragment + deviation; } int SrsHlsMuxer::update_acodec(SrsCodecAudio ac) @@ -968,7 +974,7 @@ int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t // we use absolutely overflow of segment to make jwplayer/ffplay happy // @see https://github.com/winlinvip/simple-rtmp-server/issues/151#issuecomment-71155184 if (cache->audio && muxer->is_segment_absolutely_overflow()) { - srs_warn("hls: absolute audio reap segment."); + srs_info("hls: absolute audio reap segment."); if ((ret = reap_segment("audio", muxer, cache->audio->pts)) != ERROR_SUCCESS) { return ret; } @@ -991,7 +997,7 @@ int SrsHlsCache::write_video(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t // do reap ts if any of: // a. wait keyframe and got keyframe. // b. always reap when not wait keyframe. - if (!muxer->wait_keyframe() || sample->frame_type == SrsCodecVideoAVCFrameKeyFrame) { + if (!muxer->wait_keyframe()|| sample->frame_type == SrsCodecVideoAVCFrameKeyFrame) { // when wait keyframe, there must exists idr frame in sample. if (!sample->has_idr && muxer->wait_keyframe()) { srs_warn("hls: ts starts without IDR, first nalu=%d, idr=%d", sample->first_nalu_type, sample->has_idr); diff --git a/trunk/src/kernel/srs_kernel_ts.cpp b/trunk/src/kernel/srs_kernel_ts.cpp index 7c4254d55..32e1882ff 100644 --- a/trunk/src/kernel/srs_kernel_ts.cpp +++ b/trunk/src/kernel/srs_kernel_ts.cpp @@ -78,6 +78,7 @@ SrsTsChannel::SrsTsChannel() stream = SrsTsStreamReserved; msg = NULL; continuity_counter = 0; + context = NULL; } SrsTsChannel::~SrsTsChannel() @@ -196,6 +197,7 @@ ISrsTsHandler::~ISrsTsHandler() SrsTsContext::SrsTsContext() { + pure_audio = false; vcodec = SrsCodecVideoReserved; acodec = SrsCodecAudioReserved1; } @@ -210,6 +212,24 @@ SrsTsContext::~SrsTsContext() pids.clear(); } +bool SrsTsContext::is_pure_audio() +{ + return pure_audio; +} + +void SrsTsContext::on_pmt_parsed() +{ + pure_audio = true; + + std::map::iterator it; + for (it = pids.begin(); it != pids.end(); ++it) { + SrsTsChannel* channel = it->second; + if (channel->apply == SrsTsPidApplyVideo) { + pure_audio = false; + } + } +} + void SrsTsContext::reset() { vcodec = SrsCodecVideoReserved; @@ -230,6 +250,7 @@ void SrsTsContext::set(int pid, SrsTsPidApply apply_pid, SrsTsStream stream) if (pids.find(pid) == pids.end()) { channel = new SrsTsChannel(); + channel->context = this; pids[pid] = channel; } else { channel = pids[pid]; @@ -2302,6 +2323,7 @@ int SrsTsPayloadPAT::psi_decode(SrsStream* stream) // update the apply pid table. packet->context->set(packet->pid, SrsTsPidApplyPAT); + packet->context->on_pmt_parsed(); return ret; } diff --git a/trunk/src/kernel/srs_kernel_ts.hpp b/trunk/src/kernel/srs_kernel_ts.hpp index 6b8c9d1a8..f8053f3c2 100644 --- a/trunk/src/kernel/srs_kernel_ts.hpp +++ b/trunk/src/kernel/srs_kernel_ts.hpp @@ -172,6 +172,7 @@ struct SrsTsChannel SrsTsPidApply apply; SrsTsStream stream; SrsTsMessage* msg; + SrsTsContext* context; // for encoder. u_int8_t continuity_counter; @@ -343,6 +344,7 @@ class SrsTsContext // codec private: std::map pids; + bool pure_audio; // encoder private: // when any codec changed, write the PAT/PMT. @@ -352,6 +354,14 @@ public: SrsTsContext(); virtual ~SrsTsContext(); public: + /** + * whether the hls stream is pure audio stream. + */ + virtual bool is_pure_audio(); + /** + * when PMT table parsed, we know some info about stream. + */ + virtual void on_pmt_parsed(); /** * reset the context for a new ts segment start. */ diff --git a/trunk/src/main/srs_main_ingest_hls.cpp b/trunk/src/main/srs_main_ingest_hls.cpp index 623967816..401508067 100644 --- a/trunk/src/main/srs_main_ingest_hls.cpp +++ b/trunk/src/main/srs_main_ingest_hls.cpp @@ -561,7 +561,7 @@ void SrsIngestSrsInput::fetch_all_ts(bool fresh_m3u8) } // only wait for a duration of last piece. - if (i == pieces.size() - 1) { + if (i == (int)pieces.size() - 1) { next_connect_time = srs_update_system_time_ms() + (int)tp->duration * 1000; } } @@ -865,28 +865,34 @@ int SrsIngestSrsOutput::parse_message_queue() { int ret = ERROR_SUCCESS; + if (queue.empty()) { + return ret; + } + + SrsTsMessage* first_ts_msg = queue.begin()->second; + SrsTsContext* context = first_ts_msg->channel->context; + int nb_videos = 0; - int nb_audios = 0; - std::multimap::iterator it; - for (it = queue.begin(); it != queue.end(); ++it) { - SrsTsMessage* msg = it->second; + if (!context->is_pure_audio()) { + std::multimap::iterator it; + for (it = queue.begin(); it != queue.end(); ++it) { + SrsTsMessage* msg = it->second; + + // publish audio or video. + if (msg->channel->stream == SrsTsStreamVideoH264) { + nb_videos++; + } + } - // publish audio or video. - if (msg->channel->stream == SrsTsStreamVideoH264) { - nb_videos++; - } else { - nb_audios++; + // always wait 2+ videos, to left one video in the queue. + // TODO: FIXME: support pure audio hls. + if (nb_videos <= 1) { + return ret; } } - // always wait 2+ videos, to left one video in the queue. - // TODO: FIXME: support pure audio hls. - if (nb_videos <= 1) { - return ret; - } - // parse messages util the last video. - while (nb_videos > 1 && queue.size() > 0) { + while ((nb_videos > 1 || context->is_pure_audio()) && queue.size() > 0) { std::multimap::iterator it = queue.begin(); SrsTsMessage* msg = it->second; From 1d973e2178a214149c02e38d9821bc3e9bebe203 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 21 Apr 2015 16:18:37 +0800 Subject: [PATCH 3/4] refine the overflow algorithm, prevent smaller piece. --- trunk/src/app/srs_app_hls.cpp | 10 ++++++++++ trunk/src/main/srs_main_ingest_hls.cpp | 6 ++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp index f56b177b9..74c2a2e76 100644 --- a/trunk/src/app/srs_app_hls.cpp +++ b/trunk/src/app/srs_app_hls.cpp @@ -542,6 +542,11 @@ bool SrsHlsMuxer::is_segment_overflow() { srs_assert(current); + // to prevent very small segment. + if (current->duration < 2 * SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS) { + return false; + } + // use N% deviation, to smoother. double deviation = hls_ts_floor? SRS_HLS_FLOOR_REAP_PERCENT * deviation_ts * hls_fragment : 0.0; srs_info("hls: dur=%.2f, tar=%.2f, dev=%.2fms/%dp, frag=%.2f", @@ -560,6 +565,11 @@ bool SrsHlsMuxer::is_segment_absolutely_overflow() // @see https://github.com/winlinvip/simple-rtmp-server/issues/151#issuecomment-83553950 srs_assert(current); + // to prevent very small segment. + if (current->duration < 2 * SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS) { + return false; + } + // use N% deviation, to smoother. double deviation = hls_ts_floor? SRS_HLS_FLOOR_REAP_PERCENT * deviation_ts * hls_fragment : 0.0; srs_info("hls: dur=%.2f, tar=%.2f, dev=%.2fms/%dp, frag=%.2f", diff --git a/trunk/src/main/srs_main_ingest_hls.cpp b/trunk/src/main/srs_main_ingest_hls.cpp index 401508067..705fea0ce 100644 --- a/trunk/src/main/srs_main_ingest_hls.cpp +++ b/trunk/src/main/srs_main_ingest_hls.cpp @@ -871,9 +871,10 @@ int SrsIngestSrsOutput::parse_message_queue() SrsTsMessage* first_ts_msg = queue.begin()->second; SrsTsContext* context = first_ts_msg->channel->context; + bool cpa = context->is_pure_audio(); int nb_videos = 0; - if (!context->is_pure_audio()) { + if (!cpa) { std::multimap::iterator it; for (it = queue.begin(); it != queue.end(); ++it) { SrsTsMessage* msg = it->second; @@ -892,7 +893,8 @@ int SrsIngestSrsOutput::parse_message_queue() } // parse messages util the last video. - while ((nb_videos > 1 || context->is_pure_audio()) && queue.size() > 0) { + while ((cpa && queue.size() > 1) || nb_videos > 1) { + srs_assert(!queue.empty()); std::multimap::iterator it = queue.begin(); SrsTsMessage* msg = it->second; From 4e5ddb51e745b8452cd5bdffd9b28e9f9f74463f Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 21 Apr 2015 16:21:22 +0800 Subject: [PATCH 4/4] refine the overflow algorithm, prevent smaller piece. --- trunk/src/app/srs_app_hls.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp index 74c2a2e76..2577d3fc7 100644 --- a/trunk/src/app/srs_app_hls.cpp +++ b/trunk/src/app/srs_app_hls.cpp @@ -543,7 +543,7 @@ bool SrsHlsMuxer::is_segment_overflow() srs_assert(current); // to prevent very small segment. - if (current->duration < 2 * SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS) { + if (current->duration * 1000 < 2 * SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS) { return false; } @@ -566,7 +566,7 @@ bool SrsHlsMuxer::is_segment_absolutely_overflow() srs_assert(current); // to prevent very small segment. - if (current->duration < 2 * SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS) { + if (current->duration * 1000 < 2 * SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS) { return false; }