diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index cfd4259c6eb..de5b8c2dd56 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -1780,8 +1780,8 @@ vhost hls.srs.com { # EXT-X-TARGETDURATION = hls_td_ratio * hls_fragment // init # EXT-X-TARGETDURATION = max(ts_duration, EXT-X-TARGETDURATION) // for each ts # Overwrite by env SRS_VHOST_HLS_HLS_TD_RATIO for all vhosts. - # default: 1.5 - hls_td_ratio 1.5; + # default: 1.0 + hls_td_ratio 1.0; # the audio overflow ratio. # for pure audio, the duration to reap the segment. # for example, the hls_fragment is 10s, hls_aof_ratio is 2.0, diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 176f7f8fd53..1507b028384 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -6973,7 +6973,7 @@ double SrsConfig::get_hls_td_ratio(string vhost) { SRS_OVERWRITE_BY_ENV_FLOAT("srs.vhost.hls.hls_td_ratio"); // SRS_VHOST_HLS_HLS_TD_RATIO - static double DEFAULT = 1.5; + static double DEFAULT = 1.0; SrsConfDirective* conf = get_hls(vhost); if (!conf) { diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp index 15ec9cd457e..547ebcb567c 100644 --- a/trunk/src/app/srs_app_hls.cpp +++ b/trunk/src/app/srs_app_hls.cpp @@ -542,9 +542,12 @@ bool SrsHlsMuxer::is_segment_overflow() return false; } - // use N% deviation, to smoother. + // Use N% deviation, to smoother. srs_utime_t deviation = hls_ts_floor? SRS_HLS_FLOOR_REAP_PERCENT * deviation_ts * hls_fragment : 0; - return current->duration() >= hls_fragment + deviation; + + // Keep in mind that we use max_td for the base duration, not the hls_fragment. To calculate + // max_td, multiply hls_fragment by hls_td_ratio. + return current->duration() >= max_td + deviation; } bool SrsHlsMuxer::wait_keyframe() @@ -627,6 +630,11 @@ srs_error_t SrsHlsMuxer::flush_video(SrsTsMessageCache* cache) return err; } +void SrsHlsMuxer::update_duration(uint64_t dts) +{ + current->append(dts / 90); +} + srs_error_t SrsHlsMuxer::segment_close() { srs_error_t err = do_segment_close(); @@ -920,8 +928,9 @@ srs_error_t SrsHlsController::on_publish(SrsRequest* req) std::string vhost = req->vhost; std::string stream = req->stream; std::string app = req->app; - + srs_utime_t hls_fragment = _srs_config->get_hls_fragment(vhost); + double hls_td_ratio = _srs_config->get_hls_td_ratio(vhost); srs_utime_t hls_window = _srs_config->get_hls_window(vhost); // get the hls m3u8 ts list entry prefix config @@ -965,9 +974,9 @@ srs_error_t SrsHlsController::on_publish(SrsRequest* req) // This config item is used in SrsHls, we just log its value here. bool hls_dts_directly = _srs_config->get_vhost_hls_dts_directly(req->vhost); - srs_trace("hls: win=%dms, frag=%dms, prefix=%s, path=%s, m3u8=%s, ts=%s, aof=%.2f, floor=%d, clean=%d, waitk=%d, dispose=%dms, dts_directly=%d", + srs_trace("hls: win=%dms, frag=%dms, prefix=%s, path=%s, m3u8=%s, ts=%s, tdr=%.2f, aof=%.2f, floor=%d, clean=%d, waitk=%d, dispose=%dms, dts_directly=%d", srsu2msi(hls_window), srsu2msi(hls_fragment), entry_prefix.c_str(), path.c_str(), m3u8_file.c_str(), ts_file.c_str(), - hls_aof_ratio, ts_floor, cleanup, wait_keyframe, srsu2msi(hls_dispose), hls_dts_directly); + hls_td_ratio, hls_aof_ratio, ts_floor, cleanup, wait_keyframe, srsu2msi(hls_dispose), hls_dts_directly); return err; } @@ -1017,6 +1026,10 @@ srs_error_t SrsHlsController::write_audio(SrsAudioFrame* frame, int64_t pts) if ((err = tsmc->cache_audio(frame, pts)) != srs_success) { return srs_error_wrap(err, "hls: cache audio"); } + + // First, update the duration of the segment, as we might collect the segment. The duration should + // cover from the first frame to the last frame. + muxer->update_duration(tsmc->audio->dts); // reap when current source is pure audio. // it maybe changed when stream info changed, @@ -1064,6 +1077,10 @@ srs_error_t SrsHlsController::write_video(SrsVideoFrame* frame, int64_t dts) if ((err = tsmc->cache_video(frame, dts)) != srs_success) { return srs_error_wrap(err, "hls: cache video"); } + + // First, update the duration of the segment, as we might collect the segment. The duration should + // cover from the first frame to the last frame. + muxer->update_duration(tsmc->video->dts); // when segment overflow, reap if possible. if (muxer->is_segment_overflow()) { diff --git a/trunk/src/app/srs_app_hls.hpp b/trunk/src/app/srs_app_hls.hpp index e111b68b695..8b74f48db14 100644 --- a/trunk/src/app/srs_app_hls.hpp +++ b/trunk/src/app/srs_app_hls.hpp @@ -204,6 +204,10 @@ class SrsHlsMuxer virtual bool pure_audio(); virtual srs_error_t flush_audio(SrsTsMessageCache* cache); virtual srs_error_t flush_video(SrsTsMessageCache* cache); + // When flushing video or audio, we update the duration. But, we should also update the + // duration before closing the segment. Keep in mind that it's fine to update the duration + // several times using the same dts timestamp. + void update_duration(uint64_t dts); // Close segment(ts). virtual srs_error_t segment_close(); private: