From 1ca873f453c67c2e554a6a582eee6bdb57de1697 Mon Sep 17 00:00:00 2001 From: sr90 Date: Mon, 24 Feb 2020 23:12:53 -0800 Subject: [PATCH] [DASH] Support signalling of last segment number (#713) Per https://dashif.org/docs/DASH-IF-IOP-v4.3.pdf 4.4.3.6 Signalling the last segment number in Period, there are three ways to signal the last segment number: a. Use the lmsg signalling as defined in clause 4.4.3.5. b. Use the Segment Timeline with @r value greater or equal to 0. c. Add a Supplemental Descriptor with @schemeIdUri set to http://dashif.org/guidelines/last-segment-number with the @value set to the last segment number. We do not support (a). This change adds support for (c) when Segment Timeline (b) is not used, i.e. when Representation has constant duration (could be approximate). Under flag --dash_add_last_segment_number_when_needed (disabled by default). --- packager/mpd/base/xml/xml_node.cc | 15 ++++++++++++ packager/mpd/base/xml/xml_node_unittest.cc | 27 ++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/packager/mpd/base/xml/xml_node.cc b/packager/mpd/base/xml/xml_node.cc index 5143518366..379155d9fd 100644 --- a/packager/mpd/base/xml/xml_node.cc +++ b/packager/mpd/base/xml/xml_node.cc @@ -24,6 +24,12 @@ DEFINE_bool(segment_template_constant_duration, "Generates SegmentTemplate@duration if all segments except the " "last one has the same duration if this flag is set to true."); +DEFINE_bool(dash_add_last_segment_number_when_needed, + false, + "Adds a Supplemental Descriptor with @schemeIdUri " + "set to http://dashif.org/guidelines/last-segment-number with " + "the @value set to the last segment number."); + namespace shaka { using xml::XmlNode; @@ -429,6 +435,15 @@ bool RepresentationXmlNode::AddLiveOnlyInfo( if (IsTimelineConstantDuration(segment_infos, start_number)) { segment_template.SetIntegerAttribute("duration", segment_infos.front().duration); + if (FLAGS_dash_add_last_segment_number_when_needed) { + uint32_t last_segment_number = start_number - 1; + for (const auto& segment_info_element : segment_infos) + last_segment_number += segment_info_element.repeat + 1; + + AddSupplementalProperty( + "http://dashif.org/guidelines/last-segment-number", + std::to_string(last_segment_number)); + } } else { XmlNode segment_timeline("SegmentTimeline"); if (!PopulateSegmentTimeline(segment_infos, &segment_timeline) || diff --git a/packager/mpd/base/xml/xml_node_unittest.cc b/packager/mpd/base/xml/xml_node_unittest.cc index 558284503c..ec2abf83f1 100644 --- a/packager/mpd/base/xml/xml_node_unittest.cc +++ b/packager/mpd/base/xml/xml_node_unittest.cc @@ -18,6 +18,7 @@ #include "packager/mpd/test/xml_compare.h" DECLARE_bool(segment_template_constant_duration); +DECLARE_bool(dash_add_last_segment_number_when_needed); using ::testing::ElementsAre; @@ -397,5 +398,31 @@ TEST_F(LiveSegmentTimelineTest, TwoSegmentInfoWithGap) { "")); } +TEST_F(LiveSegmentTimelineTest, LastSegmentNumberSupplementalProperty) { + const uint32_t kStartNumber = 1; + const uint64_t kStartTime = 0; + const uint64_t kDuration = 100; + const uint64_t kRepeat = 9; + + std::list segment_infos = { + {kStartTime, kDuration, kRepeat}, + }; + RepresentationXmlNode representation; + FLAGS_dash_add_last_segment_number_when_needed = true; + + ASSERT_TRUE( + representation.AddLiveOnlyInfo(media_info_, segment_infos, kStartNumber)); + + EXPECT_THAT( + representation.GetRawPtr(), + XmlNodeEqual("" + "" + " " + "")); + FLAGS_dash_add_last_segment_number_when_needed = false; +} + } // namespace xml } // namespace shaka