Skip to content

Commit

Permalink
Update cmd flags to support static mpd with live profile
Browse files Browse the repository at this point in the history
- Deprecated command line flags --profile and --single_segment.
  'segment_template' in stream descriptors implies live profile
  and non-single segment.
- Added flag --generate_static_mpd_for_live_profile to generate
  static mpd for live profile; if not set, dynamic mpd will be
  generated.

Close #142

Change-Id: I78879297ed118f0f246c4753a16ad125bd6b5e4f
  • Loading branch information
kqyang committed Jan 13, 2017
1 parent 5aaae30 commit 80c54a5
Show file tree
Hide file tree
Showing 24 changed files with 137 additions and 134 deletions.
25 changes: 14 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ host operating systems.
# VOD: mp4 --> dash
packager input=/media/example.mp4,stream=audio,output=audio.mp4 \
input=/media/example.mp4,stream=video,output=video.mp4 \
--profile on-demand --mpd_output example.mpd
--mpd_output example.mpd

# Leave the container.
exit
Expand Down Expand Up @@ -231,13 +231,11 @@ Demux audio from the input and generate a fragmented mp4:
packager input=sintel.mp4,stream=audio,output=fragmented_sintel.mp4
```

Demux streams from the input and generates a mpd with on-demand profile along
with fragmented mp4:
Demux streams from the input and generates a mpd with fragmented mp4:
```Shell
packager \
input=sintel.mp4,stream=audio,output=sintel_audio.mp4 \
input=sintel.mp4,stream=video,output=sintel_video.mp4 \
--profile on-demand \
--mpd_output sintel_vod.mpd
```

Expand All @@ -247,19 +245,17 @@ packager \
input=sintel.mp4,stream=audio,output=sintel_audio.mp4 \
input=sintel.mp4,stream=video,output=sintel_video.mp4 \
input=sintel_english_input.vtt,stream=text,output=sintel_english.vtt \
--profile on-demand \
--mpd_output sintel_vod.mpd
```


You may also generate mpd with live profile. Here is an example with IPTV input
streams:
You may also generate mpd with live profile by specifying segment_template in
stream descriptors. Here is an example with IPTV input streams:
```Shell
packager \
'input=udp://224.1.1.5:5003,stream=audio,init_segment=live-audio.mp4,segment_template=live-audio-$Number$.mp4,bandwidth=130000' \
'input=udp://224.1.1.5:5003,stream=video,init_segment=live-video-sd.mp4,segment_template=live-video-sd-$Number$.mp4,bandwidth=2000000' \
'input=udp://224.1.1.5:5002,stream=video,init_segment=live-video-hd.mp4,segment_template=live-video-hd-$Number$.mp4,bandwidth=5000000' \
--profile live \
--mpd_output live.mpd
```

Expand All @@ -274,6 +270,16 @@ Three options are supported right now:
- timeout=microseconds
Timeout in microseconds. Default to unlimited.

To generate static mpd with live profile. An additional flag needs to be
specified:
```Shell
packager \
'input=sintel.mp4,stream=audio,init_segment=audio.mp4,segment_template=audio-$Number$.mp4' \
'input=sintel.mp4,stream=video,init_segment=video.mp4,segment_template=video-$Number$.mp4' \
--mpd_output live_static.mpd \
--generate_static_mpd
```

Demux video from the input and generate an encrypted fragmented mp4 using
Widevine encryption with RSA signing key file *widevine_test_private.der*:
```Shell
Expand All @@ -292,7 +298,6 @@ packager \
'input=udp://224.1.1.5:5003,stream=audio,init_segment=live-audio.mp4,segment_template=live-audio-$Number$.mp4,bandwidth=130000' \
'input=udp://224.1.1.5:5003,stream=video,init_segment=live-video-sd.mp4,segment_template=live-video-sd-$Number$.mp4,bandwidth=2000000' \
'input=udp://224.1.1.5:5002,stream=video,init_segment=live-video-hd.mp4,segment_template=live-video-hd-$Number$.mp4,bandwidth=5000000' \
--profile live \
--mpd_output live.mpd \
--enable_widevine_encryption \
--key_server_url "https://license.uat.widevine.com/cenc/getcontentkey/widevine_test" \
Expand Down Expand Up @@ -343,7 +348,6 @@ generated TS segments.
```Shell
packager \
'input=bear-1280x720.mp4,stream=video,segment_template=bear$Number$.ts,playlist_name=playlist.m3u8' \
--single_segment=false \
--hls_master_playlist_output="master.m3u8" \
--hls_base_url="http://localhost:10000/"
```
Expand All @@ -354,7 +358,6 @@ specified.
packager \
'input=input.mp4,stream=video,segment_template=output$Number$.ts,playlist_name=video_playlist.m3u8' \
'input=input.mp4,stream=audio,segment_template=output_audio$Number$.ts,playlist_name=audio_playlist.m3u8,hls_group_id=audio,hls_name=ENGLISH' \
--single_segment=false \
--hls_master_playlist_output="master_playlist.m3u8" \
--hls_base_url="http://localhost:10000/"
```
8 changes: 8 additions & 0 deletions packager/app/mpd_flags.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@

#include "packager/app/mpd_flags.h"

DEFINE_bool(generate_static_mpd,
false,
"Set to true to generate static mpd. If segment_template is "
"specified in stream descriptors, shaka-packager generates dynamic "
"mpd by default; if this flag is enabled, shaka-packager generates "
"static mpd instead. Note that if segment_template is not "
"specified, shaka-packager always generates static mpd regardless "
"of the value of this flag.");
// TODO(rkuroiwa, kqyang): Remove the 'Exclusive' statements once
// --output_media_info can work together with --mpd_output.
DEFINE_bool(output_media_info,
Expand Down
1 change: 1 addition & 0 deletions packager/app/mpd_flags.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <gflags/gflags.h>

DECLARE_bool(generate_static_mpd);
DECLARE_bool(output_media_info);
DECLARE_string(mpd_output);
DECLARE_string(base_urls);
Expand Down
9 changes: 0 additions & 9 deletions packager/app/muxer_flags.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,9 @@

#include "packager/app/muxer_flags.h"

DEFINE_string(profile,
"",
"Specify the target DASH profile: on-demand or live. This will "
"set proper option values to ensure conformance to the desired "
"profile.");
DEFINE_double(clear_lead,
10.0f,
"Clear lead in seconds if encryption is enabled.");
DEFINE_bool(single_segment,
true,
"Generate a single segment for the media presentation. This option "
"should be set for on demand profile.");
DEFINE_double(segment_duration,
10.0f,
"Segment duration in seconds. If single_segment is specified, "
Expand Down
2 changes: 0 additions & 2 deletions packager/app/muxer_flags.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@

#include <gflags/gflags.h>

DECLARE_string(profile);
DECLARE_double(clear_lead);
DECLARE_bool(single_segment);
DECLARE_double(segment_duration);
DECLARE_bool(segment_sap_aligned);
DECLARE_double(fragment_duration);
Expand Down
36 changes: 21 additions & 15 deletions packager/app/packager_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,6 @@ bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors,
return false;
}
stream_muxer_options.segment_template = stream_iter->segment_template;
if (stream_muxer_options.single_segment) {
LOG(WARNING) << "Segment template and single segment are incompatible, "
"setting single segment to false.";
stream_muxer_options.single_segment = false;
}
}
stream_muxer_options.bandwidth = stream_iter->bandwidth;

Expand Down Expand Up @@ -419,20 +414,11 @@ bool RunPackager(const StreamDescriptorList& stream_descriptors) {
if (protection_scheme == FOURCC_NULL)
return false;

if (!AssignFlagsFromProfile())
return false;

if (FLAGS_output_media_info && !FLAGS_mpd_output.empty()) {
NOTIMPLEMENTED() << "ERROR: --output_media_info and --mpd_output do not "
"work together.";
return false;
}
if (FLAGS_output_media_info && !FLAGS_single_segment) {
// TODO(rkuroiwa, kqyang): Support partial media info dump for live.
NOTIMPLEMENTED() << "ERROR: --output_media_info is only supported if "
"--single_segment is true.";
return false;
}

// Since there isn't a muxer listener that can output both MPD and HLS,
// disallow specifying both MPD and HLS flags.
Expand All @@ -446,8 +432,28 @@ bool RunPackager(const StreamDescriptorList& stream_descriptors) {
if (!GetMuxerOptions(&muxer_options))
return false;

DCHECK(!stream_descriptors.empty());
// On demand profile generates single file segment while live profile
// generates multiple segments specified using segment template.
const bool on_demand_dash_profile =
stream_descriptors.begin()->segment_template.empty();
for (const auto& stream_descriptor : stream_descriptors) {
if (on_demand_dash_profile != stream_descriptor.segment_template.empty()) {
LOG(ERROR) << "Inconsistent stream descriptor specification: "
"segment_template should be specified for none or all "
"stream descriptors.";
return false;
}
}
if (FLAGS_output_media_info && !on_demand_dash_profile) {
// TODO(rkuroiwa, kqyang): Support partial media info dump for live.
NOTIMPLEMENTED() << "ERROR: --output_media_info is only supported for "
"on-demand profile (not using segment_template).";
return false;
}

MpdOptions mpd_options;
if (!GetMpdOptions(&mpd_options))
if (!GetMpdOptions(on_demand_dash_profile, &mpd_options))
return false;

// Create encryption key source if needed.
Expand Down
31 changes: 5 additions & 26 deletions packager/app/packager_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -125,30 +125,9 @@ std::unique_ptr<KeySource> CreateDecryptionKeySource() {
return decryption_key_source;
}

bool AssignFlagsFromProfile() {
bool single_segment = FLAGS_single_segment;
if (FLAGS_profile == "on-demand") {
single_segment = true;
} else if (FLAGS_profile == "live") {
single_segment = false;
} else if (FLAGS_profile != "") {
fprintf(stderr, "ERROR: --profile '%s' is not supported.\n",
FLAGS_profile.c_str());
return false;
}

if (FLAGS_single_segment != single_segment) {
FLAGS_single_segment = single_segment;
fprintf(stdout, "Profile %s: set --single_segment to %s.\n",
FLAGS_profile.c_str(), single_segment ? "true" : "false");
}
return true;
}

bool GetMuxerOptions(MuxerOptions* muxer_options) {
DCHECK(muxer_options);

muxer_options->single_segment = FLAGS_single_segment;
muxer_options->segment_duration = FLAGS_segment_duration;
muxer_options->fragment_duration = FLAGS_fragment_duration;
muxer_options->segment_sap_aligned = FLAGS_segment_sap_aligned;
Expand All @@ -168,15 +147,15 @@ bool GetMuxerOptions(MuxerOptions* muxer_options) {
return true;
}

bool GetMpdOptions(MpdOptions* mpd_options) {
bool GetMpdOptions(bool on_demand_profile, MpdOptions* mpd_options) {
DCHECK(mpd_options);

mpd_options->dash_profile =
FLAGS_single_segment ? DashProfile::kOnDemand : DashProfile::kLive;
// Single segment does not always mean static mpd.
// TODO(kqyang): Add a new flag for mpd type and update the code.
on_demand_profile ? DashProfile::kOnDemand : DashProfile::kLive;
mpd_options->mpd_type =
FLAGS_single_segment ? MpdType::kStatic : MpdType::kDynamic;
(on_demand_profile || FLAGS_generate_static_mpd)
? MpdType::kStatic
: MpdType::kDynamic;
mpd_options->availability_time_offset = FLAGS_availability_time_offset;
mpd_options->minimum_update_period = FLAGS_minimum_update_period;
mpd_options->min_buffer_time = FLAGS_min_buffer_time;
Expand Down
5 changes: 1 addition & 4 deletions packager/app/packager_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,11 @@ std::unique_ptr<KeySource> CreateEncryptionKeySource();
/// decryption is not required.
std::unique_ptr<KeySource> CreateDecryptionKeySource();

/// Set flags according to profile.
bool AssignFlagsFromProfile();

/// Fill MuxerOptions members using provided command line options.
bool GetMuxerOptions(MuxerOptions* muxer_options);

/// Fill MpdOptions members using provided command line options.
bool GetMpdOptions(MpdOptions* mpd_options);
bool GetMpdOptions(bool on_demand_profile, MpdOptions* mpd_options);

/// Select and add a stream from a provided set to a muxer.
/// @param streams contains the set of MediaStreams from which to select.
Expand Down
34 changes: 34 additions & 0 deletions packager/app/retired_flags.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2017 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
//
// Defines retired / deprecated flags. These flags will be removed in later
// versions.

#include "packager/app/retired_flags.h"

#include <stdio.h>

DEFINE_string(profile, "", "This flag is deprecated. Do not use.");
DEFINE_bool(single_segment, true, "This flag is deprecated. Do not use.");

// The current gflags library does not provide a way to check whether a flag is
// set in command line. If a flag has a different value to its default value,
// the flag must have been set. It is possible that the flag is set to the same
// value as its default value though.
bool InformRetiredStringFlag(const char* flagname, const std::string& value) {
if (!value.empty())
fprintf(stderr, "WARNING: %s is deprecated and ignored.\n", flagname);
return true;
}

bool InformRetiredDefaultTrueFlag(const char* flagname, bool value) {
if (!value)
fprintf(stderr, "WARNING: %s is deprecated and ignored.\n", flagname);
return true;
}

DEFINE_validator(profile, &InformRetiredStringFlag);
DEFINE_validator(single_segment, &InformRetiredDefaultTrueFlag);
10 changes: 10 additions & 0 deletions packager/app/retired_flags.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright 2017 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd

#include <gflags/gflags.h>

DECLARE_string(profile);
DECLARE_bool(single_segment);

0 comments on commit 80c54a5

Please sign in to comment.