Support UTCTiming
UTCTiming schemeIdUri and value pairs can be provided to packager using --utc_timings flag. It should be comma separated list of schemeIdUri=value pairs. Note that urn:mpeg:dash:utc:direct:2014 scheme is not supported as it requires the MPD to be dynamically generated on the fly when MPD is served to client. Fixes #311. Change-Id: Ibc07af8a6d8b2b6261ba3ecd2c02f23809f96614
This commit is contained in:
parent
634ee65663
commit
222737d5b5
|
@ -9,36 +9,41 @@ DASH options
|
|||
that if segment_template is not specified, shaka-packager always generates
|
||||
static mpd regardless of the value of this flag.
|
||||
|
||||
--mpd_output <file_path>
|
||||
--mpd_output {file_path}
|
||||
|
||||
MPD output file name.
|
||||
|
||||
--base_urls <comma separated url>
|
||||
--base_urls {url}[,{url}]...
|
||||
|
||||
Comma separated BaseURLs for the MPD. The values will be added as <BaseURL>
|
||||
element(s) immediately under the <MPD> element.
|
||||
|
||||
--min_buffer_time <seconds>
|
||||
--min_buffer_time {seconds}
|
||||
|
||||
Specifies, in seconds, a common duration used in the definition of the MPD
|
||||
Representation data rate.
|
||||
|
||||
--minimum_update_period <seconds>
|
||||
--minimum_update_period {seconds}
|
||||
|
||||
Indicates to the player how often to refresh the media presentation
|
||||
description in seconds. This value is used for dynamic MPD only.
|
||||
|
||||
--suggested_presentation_delay <seconds>
|
||||
--suggested_presentation_delay {seconds}
|
||||
|
||||
Specifies a delay, in seconds, to be added to the media presentation time.
|
||||
This value is used for dynamic MPD only.
|
||||
|
||||
--time_shift_buffer_depth <seconds>
|
||||
--time_shift_buffer_depth {seconds}
|
||||
|
||||
Guaranteed duration of the time shifting buffer for dynamic media
|
||||
presentations, in seconds.
|
||||
|
||||
--default_language <language>
|
||||
--utc_timing {scheme_id_uri}={value}[,{scheme_id_uri}={value}]...
|
||||
|
||||
Comma separated UTCTiming schemeIdUri and value pairs for the MPD.
|
||||
This value is used for dynamic MPD only.
|
||||
|
||||
--default_language {language}
|
||||
|
||||
Any audio/text tracks tagged with this language will have
|
||||
<Role ... value=\"main\" /> in the manifest. This allows the player to
|
||||
|
|
|
@ -43,6 +43,10 @@ DEFINE_double(suggested_presentation_delay,
|
|||
0.0,
|
||||
"Specifies a delay, in seconds, to be added to the media "
|
||||
"presentation time. This value is used for dynamic MPD only.");
|
||||
DEFINE_string(utc_timings,
|
||||
"",
|
||||
"Comma separated UTCTiming schemeIdUri and value pairs for the "
|
||||
"MPD. This value is used for dynamic MPD only.");
|
||||
DEFINE_bool(generate_dash_if_iop_compliant_mpd,
|
||||
true,
|
||||
"Try to generate DASH-IF IOP compliant MPD. This is best effort "
|
||||
|
|
|
@ -18,6 +18,7 @@ DECLARE_string(base_urls);
|
|||
DECLARE_double(minimum_update_period);
|
||||
DECLARE_double(min_buffer_time);
|
||||
DECLARE_double(suggested_presentation_delay);
|
||||
DECLARE_string(utc_timings);
|
||||
DECLARE_bool(generate_dash_if_iop_compliant_mpd);
|
||||
|
||||
#endif // APP_MPD_FLAGS_H_
|
||||
|
|
|
@ -396,17 +396,30 @@ base::Optional<PackagingParams> GetPackagingParams() {
|
|||
packaging_params.output_media_info = FLAGS_output_media_info;
|
||||
|
||||
MpdParams& mpd_params = packaging_params.mpd_params;
|
||||
mpd_params.generate_static_live_mpd = FLAGS_generate_static_mpd;
|
||||
mpd_params.mpd_output = FLAGS_mpd_output;
|
||||
mpd_params.base_urls = base::SplitString(
|
||||
FLAGS_base_urls, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
||||
FLAGS_base_urls, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
||||
mpd_params.min_buffer_time = FLAGS_min_buffer_time;
|
||||
mpd_params.minimum_update_period = FLAGS_minimum_update_period;
|
||||
mpd_params.suggested_presentation_delay = FLAGS_suggested_presentation_delay;
|
||||
mpd_params.time_shift_buffer_depth = FLAGS_time_shift_buffer_depth;
|
||||
|
||||
if (!FLAGS_utc_timings.empty()) {
|
||||
base::StringPairs pairs;
|
||||
if (!base::SplitStringIntoKeyValuePairs(FLAGS_utc_timings, '=', ',',
|
||||
&pairs)) {
|
||||
LOG(ERROR) << "Invalid --utc_timings scheme_id_uri/value pairs.";
|
||||
return base::nullopt;
|
||||
}
|
||||
for (const auto& string_pair : pairs) {
|
||||
mpd_params.utc_timings.push_back({string_pair.first, string_pair.second});
|
||||
}
|
||||
}
|
||||
|
||||
mpd_params.default_language = FLAGS_default_language;
|
||||
mpd_params.generate_static_live_mpd = FLAGS_generate_static_mpd;
|
||||
mpd_params.generate_dash_if_iop_compliant_mpd =
|
||||
FLAGS_generate_dash_if_iop_compliant_mpd;
|
||||
mpd_params.minimum_update_period = FLAGS_minimum_update_period;
|
||||
mpd_params.min_buffer_time = FLAGS_min_buffer_time;
|
||||
mpd_params.time_shift_buffer_depth = FLAGS_time_shift_buffer_depth;
|
||||
mpd_params.suggested_presentation_delay = FLAGS_suggested_presentation_delay;
|
||||
mpd_params.default_language = FLAGS_default_language;
|
||||
|
||||
HlsParams& hls_params = packaging_params.hls_params;
|
||||
if (!GetHlsPlaylistType(FLAGS_hls_playlist_type, &hls_params.playlist_type)) {
|
||||
|
|
|
@ -273,6 +273,7 @@ class PackagerAppTest(unittest.TestCase):
|
|||
output_hls=False,
|
||||
hls_playlist_type=None,
|
||||
time_shift_buffer_depth=0.0,
|
||||
utc_timings=None,
|
||||
generate_static_mpd=False,
|
||||
ad_cues=None,
|
||||
use_fake_clock=True):
|
||||
|
@ -341,6 +342,9 @@ class PackagerAppTest(unittest.TestCase):
|
|||
else:
|
||||
flags += ['--mpd_output', self.mpd_output]
|
||||
|
||||
if utc_timings:
|
||||
flags += ['--utc_timings', utc_timings]
|
||||
|
||||
if generate_static_mpd:
|
||||
flags += ['--generate_static_mpd']
|
||||
|
||||
|
@ -384,7 +388,7 @@ class PackagerAppTest(unittest.TestCase):
|
|||
else:
|
||||
match = filecmp.cmp(test_output, golden_file)
|
||||
if not match:
|
||||
output, error = self._GitDiff(test_output, golden_file)
|
||||
output, error = self._GitDiff(golden_file, test_output)
|
||||
command_line = self.packager.GetCommandLine()
|
||||
failure_message = '\n'.join([
|
||||
output,
|
||||
|
@ -471,7 +475,7 @@ class PackagerAppTest(unittest.TestCase):
|
|||
actual_file = os.path.join(out_dir, diff_file)
|
||||
expected_file = os.path.join(gold_dir, diff_file)
|
||||
|
||||
output, error = self._GitDiff(actual_file, expected_file)
|
||||
output, error = self._GitDiff(expected_file, actual_file)
|
||||
|
||||
if output:
|
||||
failure_messages += [output]
|
||||
|
@ -1126,7 +1130,13 @@ class PackagerFunctionalTest(PackagerAppTest):
|
|||
|
||||
def testPackageLiveProfile(self):
|
||||
self.assertPackageSuccess(
|
||||
self._GetStreams(['audio', 'video'], segmented=True), self._GetFlags())
|
||||
self._GetStreams(['audio', 'video'], segmented=True),
|
||||
self._GetFlags(
|
||||
utc_timings=
|
||||
'urn:mpeg:dash:utc:http-xsdate:2014='
|
||||
'http://foo.bar/my_body_is_the_current_date_and_time,'
|
||||
'urn:mpeg:dash:utc:http-head:2014='
|
||||
'http://foo.bar/check_me_for_the_date_header'))
|
||||
self._CheckTestResults('live-profile')
|
||||
|
||||
def testPackageLiveStaticProfile(self):
|
||||
|
|
|
@ -25,4 +25,6 @@
|
|||
</Representation>
|
||||
</AdaptationSet>
|
||||
</Period>
|
||||
<UTCTiming schemeIdUri="urn:mpeg:dash:utc:http-xsdate:2014" value="http://foo.bar/my_body_is_the_current_date_and_time"/>
|
||||
<UTCTiming schemeIdUri="urn:mpeg:dash:utc:http-head:2014" value="http://foo.bar/check_me_for_the_date_header"/>
|
||||
</MPD>
|
||||
|
|
|
@ -215,6 +215,8 @@ xmlDocPtr MpdBuilder::GenerateMpd() {
|
|||
break;
|
||||
case MpdType::kDynamic:
|
||||
AddDynamicMpdInfo(&mpd);
|
||||
// Must be after Period element.
|
||||
AddUtcTiming(&mpd);
|
||||
break;
|
||||
default:
|
||||
NOTREACHED() << "Unknown MPD type: "
|
||||
|
@ -302,6 +304,19 @@ void MpdBuilder::AddDynamicMpdInfo(XmlNode* mpd_node) {
|
|||
mpd_options_.mpd_params.suggested_presentation_delay, mpd_node);
|
||||
}
|
||||
|
||||
void MpdBuilder::AddUtcTiming(XmlNode* mpd_node) {
|
||||
DCHECK(mpd_node);
|
||||
DCHECK_EQ(MpdType::kDynamic, mpd_options_.mpd_type);
|
||||
|
||||
for (const MpdParams::UtcTiming& utc_timing :
|
||||
mpd_options_.mpd_params.utc_timings) {
|
||||
XmlNode utc_timing_node("UTCTiming");
|
||||
utc_timing_node.SetStringAttribute("schemeIdUri", utc_timing.scheme_id_uri);
|
||||
utc_timing_node.SetStringAttribute("value", utc_timing.value);
|
||||
mpd_node->AddChild(utc_timing_node.PassScopedPtr());
|
||||
}
|
||||
}
|
||||
|
||||
float MpdBuilder::GetStaticMpdDuration() {
|
||||
DCHECK_EQ(MpdType::kStatic, mpd_options_.mpd_type);
|
||||
|
||||
|
|
|
@ -100,6 +100,9 @@ class MpdBuilder {
|
|||
// Same as AddStaticMpdInfo() but for 'dynamic' MPDs.
|
||||
void AddDynamicMpdInfo(xml::XmlNode* mpd_node);
|
||||
|
||||
// Add UTCTiming element if utc timing is provided.
|
||||
void AddUtcTiming(xml::XmlNode* mpd_node);
|
||||
|
||||
float GetStaticMpdDuration();
|
||||
|
||||
// Set MPD attributes for dynamic profile MPD. Uses non-zero |mpd_options_| as
|
||||
|
|
|
@ -272,11 +272,21 @@ TEST_F(LiveMpdBuilderTest, DynamicCheckMpdAttributes) {
|
|||
" type=\"dynamic\""
|
||||
" publishTime=\"2016-01-11T15:10:24Z\""
|
||||
" availabilityStartTime=\"2011-12-25T12:30:00\""
|
||||
" minimumUpdatePeriod=\"PT2S\"/>\n";
|
||||
" minimumUpdatePeriod=\"PT2S\">\n"
|
||||
" <UTCTiming schemeIdUri=\"urn:mpeg:dash:utc:http-xsdate:2014\" "
|
||||
"value=\"http://foo.bar/my_body_is_the_current_date_and_time\"/>\n"
|
||||
" <UTCTiming schemeIdUri=\"urn:mpeg:dash:utc:http-head:2014\" "
|
||||
"value=\"http://foo.bar/check_me_for_the_date_header\"/>\n"
|
||||
"</MPD>\n";
|
||||
|
||||
std::string mpd_doc;
|
||||
mutable_mpd_options()->mpd_type = MpdType::kDynamic;
|
||||
mutable_mpd_options()->mpd_params.minimum_update_period = 2;
|
||||
mutable_mpd_options()->mpd_params.utc_timings = {
|
||||
{"urn:mpeg:dash:utc:http-xsdate:2014",
|
||||
"http://foo.bar/my_body_is_the_current_date_and_time"},
|
||||
{"urn:mpeg:dash:utc:http-head:2014",
|
||||
"http://foo.bar/check_me_for_the_date_header"}};
|
||||
ASSERT_TRUE(mpd_.ToString(&mpd_doc));
|
||||
ASSERT_EQ(kExpectedOutput, mpd_doc);
|
||||
}
|
||||
|
@ -298,6 +308,15 @@ TEST_F(LiveMpdBuilderTest, StaticCheckMpdAttributes) {
|
|||
|
||||
std::string mpd_doc;
|
||||
mutable_mpd_options()->mpd_type = MpdType::kStatic;
|
||||
|
||||
// Ignored in static MPD.
|
||||
mutable_mpd_options()->mpd_params.minimum_update_period = 2;
|
||||
mutable_mpd_options()->mpd_params.utc_timings = {
|
||||
{"urn:mpeg:dash:utc:http-xsdate:2014",
|
||||
"http://foo.bar/my_body_is_the_current_date_and_time"},
|
||||
{"urn:mpeg:dash:utc:http-head:2014",
|
||||
"http://foo.bar/check_me_for_the_date_header"}};
|
||||
|
||||
ASSERT_TRUE(mpd_.ToString(&mpd_doc));
|
||||
ASSERT_EQ(kExpectedOutput, mpd_doc);
|
||||
}
|
||||
|
|
|
@ -25,25 +25,31 @@ struct MpdParams {
|
|||
/// providing playout begins at min_buffer_time after the first bit is
|
||||
/// received.
|
||||
double min_buffer_time = 2.0;
|
||||
/// Generate static MPD for live profile. Note that this flag has no effect
|
||||
/// for on-demand profile, in which case static MPD is always used.
|
||||
bool generate_static_live_mpd = false;
|
||||
/// Set MPD@timeShiftBufferDepth attribute, which is the guaranteed duration
|
||||
/// of the time shifting buffer for 'dynamic' media presentations, in seconds.
|
||||
double time_shift_buffer_depth = 0;
|
||||
/// Set MPD@minimumUpdatePeriod attribute, which indicates to the player how
|
||||
/// often to refresh the MPD in seconds. For dynamic MPD only.
|
||||
double minimum_update_period = 0;
|
||||
/// Set MPD@suggestedPresentationDelay attribute. For 'dynamic' media
|
||||
/// presentations, it specifies a delay, in seconds, to be added to the media
|
||||
/// presentation time. The attribute is not set if the value is 0; the client
|
||||
/// is expected to choose a suitable value in this case.
|
||||
static constexpr double kSuggestedPresentationDelayNotSet = 0;
|
||||
double suggested_presentation_delay = kSuggestedPresentationDelayNotSet;
|
||||
/// Set MPD@minimumUpdatePeriod attribute, which indicates to the player how
|
||||
/// often to refresh the MPD in seconds. For dynamic MPD only.
|
||||
double minimum_update_period = 0;
|
||||
/// Set MPD@timeShiftBufferDepth attribute, which is the guaranteed duration
|
||||
/// of the time shifting buffer for 'dynamic' media presentations, in seconds.
|
||||
double time_shift_buffer_depth = 0;
|
||||
/// UTCTimings. For dynamic MPD only.
|
||||
struct UtcTiming {
|
||||
std::string scheme_id_uri;
|
||||
std::string value;
|
||||
};
|
||||
std::vector<UtcTiming> utc_timings;
|
||||
/// The tracks tagged with this language will have <Role ... value=\"main\" />
|
||||
/// in the manifest. This allows the player to choose the correct default
|
||||
/// language for the content.
|
||||
std::string default_language;
|
||||
/// Generate static MPD for live profile. Note that this flag has no effect
|
||||
/// for on-demand profile, in which case static MPD is always used.
|
||||
bool generate_static_live_mpd = false;
|
||||
/// Try to generate DASH-IF IOP compliant MPD.
|
||||
bool generate_dash_if_iop_compliant_mpd = true;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue