7 #include "packager/app/packager_util.h"
9 #include <gflags/gflags.h>
12 #include "packager/app/fixed_key_encryption_flags.h"
13 #include "packager/app/mpd_flags.h"
14 #include "packager/app/muxer_flags.h"
15 #include "packager/app/widevine_encryption_flags.h"
16 #include "packager/base/logging.h"
17 #include "packager/base/strings/string_number_conversions.h"
18 #include "packager/media/base/fixed_key_source.h"
19 #include "packager/media/base/media_stream.h"
20 #include "packager/media/base/muxer.h"
21 #include "packager/media/base/muxer_options.h"
22 #include "packager/media/base/request_signer.h"
23 #include "packager/media/base/stream_info.h"
24 #include "packager/media/base/widevine_key_source.h"
25 #include "packager/media/file/file.h"
26 #include "packager/mpd/base/mpd_builder.h"
28 DEFINE_bool(mp4_use_decoding_timestamp_in_timeline,
30 "If set, decoding timestamp instead of presentation timestamp will "
31 "be used when generating media timeline, e.g. timestamps in sidx "
32 "and mpd. This is to workaround a Chromium bug that decoding "
33 "timestamp is used in buffered range, https://crbug.com/398130.");
34 DEFINE_bool(dump_stream_info,
false,
"Dump demuxed stream info.");
39 void DumpStreamInfo(
const std::vector<std::unique_ptr<MediaStream>>& streams) {
40 printf(
"Found %zu stream(s).\n", streams.size());
41 for (
size_t i = 0; i < streams.size(); ++i)
42 printf(
"Stream [%zu] %s\n", i, streams[i]->info()->ToString().c_str());
45 std::unique_ptr<RequestSigner> CreateSigner() {
46 std::unique_ptr<RequestSigner> signer;
48 if (!FLAGS_aes_signing_key.empty()) {
50 FLAGS_signer, FLAGS_aes_signing_key, FLAGS_aes_signing_iv));
52 LOG(ERROR) <<
"Cannot create an AES signer object from '"
53 << FLAGS_aes_signing_key <<
"':'" << FLAGS_aes_signing_iv
55 return std::unique_ptr<RequestSigner>();
57 }
else if (!FLAGS_rsa_signing_key_path.empty()) {
58 std::string rsa_private_key;
61 LOG(ERROR) <<
"Failed to read from '" << FLAGS_rsa_signing_key_path
63 return std::unique_ptr<RequestSigner>();
67 LOG(ERROR) <<
"Cannot create a RSA signer object from '"
68 << FLAGS_rsa_signing_key_path <<
"'.";
69 return std::unique_ptr<RequestSigner>();
75 std::unique_ptr<KeySource> CreateEncryptionKeySource() {
76 std::unique_ptr<KeySource> encryption_key_source;
77 if (FLAGS_enable_widevine_encryption) {
78 std::unique_ptr<WidevineKeySource> widevine_key_source(
79 new WidevineKeySource(FLAGS_key_server_url, FLAGS_include_common_pssh));
80 if (!FLAGS_signer.empty()) {
81 std::unique_ptr<RequestSigner> request_signer(CreateSigner());
83 return std::unique_ptr<KeySource>();
84 widevine_key_source->set_signer(std::move(request_signer));
87 std::vector<uint8_t> content_id;
88 if (!base::HexStringToBytes(FLAGS_content_id, &content_id)) {
89 LOG(ERROR) <<
"Invalid content_id hex string specified.";
90 return std::unique_ptr<KeySource>();
92 Status status = widevine_key_source->FetchKeys(content_id, FLAGS_policy);
94 LOG(ERROR) <<
"Widevine encryption key source failed to fetch keys: "
96 return std::unique_ptr<KeySource>();
98 encryption_key_source = std::move(widevine_key_source);
99 }
else if (FLAGS_enable_fixed_key_encryption) {
101 FLAGS_key_id, FLAGS_key, FLAGS_pssh, FLAGS_iv);
103 return encryption_key_source;
106 std::unique_ptr<KeySource> CreateDecryptionKeySource() {
107 std::unique_ptr<KeySource> decryption_key_source;
108 if (FLAGS_enable_widevine_decryption) {
109 std::unique_ptr<WidevineKeySource> widevine_key_source(
110 new WidevineKeySource(FLAGS_key_server_url, FLAGS_include_common_pssh));
111 if (!FLAGS_signer.empty()) {
112 std::unique_ptr<RequestSigner> request_signer(CreateSigner());
114 return std::unique_ptr<KeySource>();
115 widevine_key_source->set_signer(std::move(request_signer));
118 decryption_key_source = std::move(widevine_key_source);
119 }
else if (FLAGS_enable_fixed_key_decryption) {
120 const char kNoPssh[] =
"";
121 const char kNoIv[] =
"";
123 FLAGS_key_id, FLAGS_key, kNoPssh, kNoIv);
125 return decryption_key_source;
128 bool AssignFlagsFromProfile() {
129 bool single_segment = FLAGS_single_segment;
130 if (FLAGS_profile ==
"on-demand") {
131 single_segment =
true;
132 }
else if (FLAGS_profile ==
"live") {
133 single_segment =
false;
134 }
else if (FLAGS_profile !=
"") {
135 fprintf(stderr,
"ERROR: --profile '%s' is not supported.\n",
136 FLAGS_profile.c_str());
140 if (FLAGS_single_segment != single_segment) {
141 FLAGS_single_segment = single_segment;
142 fprintf(stdout,
"Profile %s: set --single_segment to %s.\n",
143 FLAGS_profile.c_str(), single_segment ?
"true" :
"false");
148 bool GetMuxerOptions(MuxerOptions* muxer_options) {
149 DCHECK(muxer_options);
151 muxer_options->single_segment = FLAGS_single_segment;
152 muxer_options->segment_duration = FLAGS_segment_duration;
153 muxer_options->fragment_duration = FLAGS_fragment_duration;
154 muxer_options->segment_sap_aligned = FLAGS_segment_sap_aligned;
155 muxer_options->fragment_sap_aligned = FLAGS_fragment_sap_aligned;
156 muxer_options->num_subsegments_per_sidx = FLAGS_num_subsegments_per_sidx;
157 muxer_options->webm_subsample_encryption = FLAGS_webm_subsample_encryption;
158 if (FLAGS_mp4_use_decoding_timestamp_in_timeline) {
159 LOG(WARNING) <<
"Flag --mp4_use_decoding_timestamp_in_timeline is set. "
160 "Note that it is a temporary hack to workaround Chromium "
161 "bug https://crbug.com/398130. The flag may be removed "
162 "when the Chromium bug is fixed.";
164 muxer_options->mp4_use_decoding_timestamp_in_timeline =
165 FLAGS_mp4_use_decoding_timestamp_in_timeline;
167 muxer_options->temp_dir = FLAGS_temp_dir;
171 bool GetMpdOptions(MpdOptions* mpd_options) {
174 mpd_options->dash_profile =
175 FLAGS_single_segment ? DashProfile::kOnDemand : DashProfile::kLive;
178 mpd_options->mpd_type =
179 FLAGS_single_segment ? MpdType::kStatic : MpdType::kDynamic;
180 mpd_options->availability_time_offset = FLAGS_availability_time_offset;
181 mpd_options->minimum_update_period = FLAGS_minimum_update_period;
182 mpd_options->min_buffer_time = FLAGS_min_buffer_time;
183 mpd_options->time_shift_buffer_depth = FLAGS_time_shift_buffer_depth;
184 mpd_options->suggested_presentation_delay =
185 FLAGS_suggested_presentation_delay;
186 mpd_options->default_language = FLAGS_default_language;
190 MediaStream* FindFirstStreamOfType(
191 const std::vector<std::unique_ptr<MediaStream>>& streams,
192 StreamType stream_type) {
193 for (
const std::unique_ptr<MediaStream>& stream : streams) {
194 if (stream->info()->stream_type() == stream_type)
199 MediaStream* FindFirstVideoStream(
200 const std::vector<std::unique_ptr<MediaStream>>& streams) {
201 return FindFirstStreamOfType(streams, kStreamVideo);
203 MediaStream* FindFirstAudioStream(
204 const std::vector<std::unique_ptr<MediaStream>>& streams) {
205 return FindFirstStreamOfType(streams, kStreamAudio);
208 bool AddStreamToMuxer(
const std::vector<std::unique_ptr<MediaStream>>& streams,
209 const std::string& stream_selector,
210 const std::string& language_override,
214 MediaStream* stream =
nullptr;
215 if (stream_selector ==
"video") {
216 stream = FindFirstVideoStream(streams);
217 }
else if (stream_selector ==
"audio") {
218 stream = FindFirstAudioStream(streams);
222 if (!base::StringToSizeT(stream_selector, &stream_id) ||
223 stream_id >= streams.size()) {
224 LOG(ERROR) <<
"Invalid argument --stream=" << stream_selector <<
"; "
225 <<
"should be 'audio', 'video', or a number within [0, "
226 << streams.size() - 1 <<
"].";
229 stream = streams[stream_id].get();
236 LOG(ERROR) <<
"No " << stream_selector <<
" stream found in the input.";
240 if (!language_override.empty()) {
241 stream->info()->set_language(language_override);
244 muxer->AddStream(stream);