mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
Solve the problem of inaccurate HLS TS duration. v5.0.187 (#3824)
This commit is contained in:
parent
8b80566f78
commit
75c9c5a849
10 changed files with 84 additions and 62 deletions
|
|
@ -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) {
|
||||
|
|
@ -6992,7 +6992,7 @@ double SrsConfig::get_hls_aof_ratio(string vhost)
|
|||
{
|
||||
SRS_OVERWRITE_BY_ENV_FLOAT("srs.vhost.hls.hls_aof_ratio"); // SRS_VHOST_HLS_HLS_AOF_RATIO
|
||||
|
||||
static double DEFAULT = 2.0;
|
||||
static double DEFAULT = 1.2;
|
||||
|
||||
SrsConfDirective* conf = get_hls(vhost);
|
||||
if (!conf) {
|
||||
|
|
@ -7183,7 +7183,7 @@ srs_utime_t SrsConfig::get_hls_dispose(string vhost)
|
|||
{
|
||||
SRS_OVERWRITE_BY_ENV_SECONDS("srs.vhost.hls.hls_dispose"); // SRS_VHOST_HLS_HLS_DISPOSE
|
||||
|
||||
static srs_utime_t DEFAULT = 0;
|
||||
static srs_utime_t DEFAULT = 120 * SRS_UTIME_SECONDS;
|
||||
|
||||
SrsConfDirective* conf = get_hls(vhost);
|
||||
if (!conf) {
|
||||
|
|
|
|||
|
|
@ -519,9 +519,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()
|
||||
|
|
@ -564,8 +567,8 @@ srs_error_t SrsHlsMuxer::flush_audio(SrsTsMessageCache* cache)
|
|||
}
|
||||
|
||||
// update the duration of segment.
|
||||
current->append(cache->audio->pts / 90);
|
||||
|
||||
update_duration(cache->audio->dts);
|
||||
|
||||
if ((err = current->tscw->write_audio(cache->audio)) != srs_success) {
|
||||
return srs_error_wrap(err, "hls: write audio");
|
||||
}
|
||||
|
|
@ -593,8 +596,8 @@ srs_error_t SrsHlsMuxer::flush_video(SrsTsMessageCache* cache)
|
|||
srs_assert(current);
|
||||
|
||||
// update the duration of segment.
|
||||
current->append(cache->video->dts / 90);
|
||||
|
||||
update_duration(cache->video->dts);
|
||||
|
||||
if ((err = current->tscw->write_video(cache->video)) != srs_success) {
|
||||
return srs_error_wrap(err, "hls: write video");
|
||||
}
|
||||
|
|
@ -605,6 +608,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();
|
||||
|
|
@ -635,9 +643,9 @@ srs_error_t SrsHlsMuxer::do_segment_close()
|
|||
// valid, add to segments if segment duration is ok
|
||||
// when too small, it maybe not enough data to play.
|
||||
// when too large, it maybe timestamp corrupt.
|
||||
// make the segment more acceptable, when in [min, max_td * 2], it's ok.
|
||||
// make the segment more acceptable, when in [min, max_td * 3], it's ok.
|
||||
bool matchMinDuration = current->duration() >= SRS_HLS_SEGMENT_MIN_DURATION;
|
||||
bool matchMaxDuration = current->duration() <= max_td * 2 * 1000;
|
||||
bool matchMaxDuration = current->duration() <= max_td * 3 * 1000;
|
||||
if (matchMinDuration && matchMaxDuration) {
|
||||
// rename from tmp to real path
|
||||
if ((err = current->rename()) != srs_success) {
|
||||
|
|
@ -899,8 +907,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
|
||||
|
|
@ -944,9 +953,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;
|
||||
}
|
||||
|
|
@ -996,6 +1005,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 reap 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,
|
||||
|
|
@ -1038,6 +1051,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 reap 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()) {
|
||||
|
|
|
|||
|
|
@ -200,6 +200,10 @@ public:
|
|||
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:
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@
|
|||
|
||||
#define VERSION_MAJOR 5
|
||||
#define VERSION_MINOR 0
|
||||
#define VERSION_REVISION 186
|
||||
#define VERSION_REVISION 187
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2085,7 +2085,7 @@ VOID TEST(ConfigUnitTest, CheckDefaultValuesVhost)
|
|||
|
||||
if (true) {
|
||||
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF));
|
||||
EXPECT_EQ(0, (int)conf.get_hls_dispose(""));
|
||||
EXPECT_EQ(120 * SRS_UTIME_SECONDS, (int)conf.get_hls_dispose(""));
|
||||
EXPECT_EQ(10 * SRS_UTIME_SECONDS, conf.get_hls_fragment(""));
|
||||
EXPECT_EQ(60 * SRS_UTIME_SECONDS, conf.get_hls_window(""));
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue