New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding support for hls EXT_X_PROGRAM_DATE_TIME #840
Conversation
…HLS playlists, with fixed UTC timezone Add a new hls option: --hls_ext_x_program_date_time <time_offset_ms> When turned on this option will insert EXT_X_PROGRAM_DATE_TIME in media playlists. Date time is computed from local time adjusted by time_offset_ms.
931fabb
to
c6bc81f
Compare
@r0ro Thanks for the PR. A bit busy right now. I'll try to review it later this week. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@r0ro Sorry for the delay in the review. Super busy these days :(.
The general idea looks good to me. Thanks for working on it. I left some comments. Let me know if you need clarifications.
@@ -76,6 +76,13 @@ HLS options | |||
The EXT-X-MEDIA-SEQUENCE documentation can be read here: | |||
https://tools.ietf.org/html/rfc8216#section-4.3.3.2. | |||
|
|||
|
|||
--hls_ext_x_program_date_time <time_offset_ms> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have a definitive answer myself right now. I am thinking whether it is a good idea to reuse --suggested_presentation_delay from DASH for the offset in HLS instead having another offset here.
@@ -490,6 +490,11 @@ base::Optional<PackagingParams> GetPackagingParams() { | |||
hls_params.default_text_language = FLAGS_default_text_language; | |||
hls_params.media_sequence_number = FLAGS_hls_media_sequence_number; | |||
|
|||
if (FLAGS_hls_ext_x_program_date_time != INT32_MIN) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the reason not to use 0 as default?
@@ -170,7 +172,8 @@ class SegmentInfoEntry : public HlsEntry { | |||
bool use_byte_range, | |||
uint64_t start_byte_offset, | |||
uint64_t segment_file_size, | |||
uint64_t previous_segment_end_offset); | |||
uint64_t previous_segment_end_offset, | |||
const base::Time wall_time); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pass by const reference to avoid copying, i.e. const base::Time& wall_time
.
@@ -179,6 +182,10 @@ class SegmentInfoEntry : public HlsEntry { | |||
duration_seconds_ = duration_seconds; | |||
} | |||
|
|||
const base::Time wall_time() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Return a const reference to avoid copying, i.e.
const base::Time& wall_time() const { return wall_time_; }
@@ -408,7 +418,8 @@ void MediaPlaylist::AddSegment(const std::string& file_name, | |||
int64_t start_time, | |||
int64_t duration, | |||
uint64_t start_byte_offset, | |||
uint64_t size) { | |||
uint64_t size, | |||
const base::Time reference_time) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it only changes on discontinuity, it is probably a good idea to provide it in a separate function instead of in AddSegment.
case HlsEntry::EntryType::kExtInf: | ||
if (need_ext_date_time) { | ||
SegmentInfoEntry* segment_info = | ||
reinterpret_cast<SegmentInfoEntry*>(entry.get()); | ||
base::Time::Exploded time; | ||
segment_info->wall_time().UTCExplode(&time); | ||
base::StringAppendF(&content, | ||
"#EXT-X-PROGRAM-DATE-TIME:" | ||
"%4d-%02d-%02dT%02d:%02d:%02d.%03dZ\n", | ||
time.year, time.month, time.day_of_month, | ||
time.hour, time.minute, time.second, | ||
time.millisecond); | ||
need_ext_date_time = false; | ||
} | ||
break; | ||
case HlsEntry::EntryType::kExtDiscontinuity: | ||
// we need to add a new program data time after a discontinuity | ||
need_ext_date_time = hls_params_.add_ext_x_program_date_time; | ||
break; | ||
default: | ||
break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indent by two extra characters.
<< start_time << "."; | ||
entries_.emplace_back(new DiscontinuityEntry()); | ||
} | ||
const base::Time wall_time = reference_time + base::TimeDelta::FromSeconds(start_time / time_scale_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can defer the wall_time computation to MediaPlaylist::WriteToFile
when writing the EXT-X-PROGRAM-DATE-TIME
, then SegmentInfoEntry
constructor does not need to be changed.
base::Time adjusted_time = base::Time::Now() | ||
+ base::TimeDelta::FromMilliseconds(hls_params().packaging_time_offset_ms); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's assuming packaging_time_offset_ms
to be 0 for now to simplify the illustration below.
I think we want to map Now()
to the current segment which media timestamp start_time
.
So the reference time should be: Now() - start_time
. (If we set the reference time to Now()
, the segment with start_time
is mapped to Now() + start_time
as start_time
is added later)
There could be an offset, so the reference time or adjusted time is:
base::Time::Now() + base::TimeDelta::FromMilliseconds(hls_params().packaging_time_offset_ms) - base::TimeDelta::FromSeconds(start_time / media_playlist->timescale());
// Check if we need to set reference_time_ | ||
// This need to be adjusted on discontinuity | ||
if (hls_params().add_ext_x_program_date_time) { | ||
if (reference_time_.is_null() || start_time < media_playlist->LastSegmentStartTime()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of resetting the reference time when there are discontinuities!
There is a minor problem here though. Let's assume that there are two streams. The reference time will be reset twice for every discontinuity as the discontinuity exists in both streams.
Can you we always use one stream as reference (except for the initial case)?
The code can be structured as something like:
if (hls_params().add_ext_x_program_date_time) {
if (reference_time_.is_null()) {
reference_time_ = CalculateReferenceTime(start_time);
reference_stream_id_ = stream_id;
} else if (stream_id == reference_stream_id_ && media_playlist->IsDiscontinuity(start_time)) {
reference_time_ = CalculateReferenceTime(start_time);
}
media_playlist->SetReferenceTime(reference_time_);
}
IsDiscontinuity(start_time)
is a MediaPlaylist function which wraps start_time < media_playlist->LastSegmentStartTime()
, as it is easier to understand and also easier to maintain in the future.
Are there any advances on this topic, by chance? |
Is this merge going to happen? |
Hi @r0ro thank you for initiating this PR, are you still following up this PR? Currently i have a use case that is needing this feature, i hope this can be merged soon, thanks! |
I'm not sorry. |
Going to close this for now since nobody is actively working on it, if someone else wants to pick it up please open a new PR on top of the current |
Rework from #814
Adding support for generation of the EXT_X_PROGRAM_DATE_TIME tag for HLS playlists, with fixed UTC timezone
Add a new hls option: --hls_ext_x_program_date_time <time_offset_ms>
When turned on this option will insert EXT_X_PROGRAM_DATE_TIME in media playlists.
Date time is computed from local time adjusted by time_offset_ms.
ex playlist:
stream_0.m3u8
stream_1.m3u8