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/playready_key_encryption_flags.h"
14 #include "packager/app/mpd_flags.h"
15 #include "packager/app/muxer_flags.h"
16 #include "packager/app/widevine_encryption_flags.h"
17 #include "packager/base/logging.h"
18 #include "packager/base/strings/string_number_conversions.h"
19 #include "packager/media/base/fixed_key_source.h"
20 #include "packager/media/base/media_stream.h"
21 #include "packager/media/base/muxer.h"
22 #include "packager/media/base/muxer_options.h"
23 #include "packager/media/base/playready_key_source.h"
24 #include "packager/media/base/request_signer.h"
25 #include "packager/media/base/stream_info.h"
26 #include "packager/media/base/widevine_key_source.h"
27 #include "packager/media/file/file.h"
28 #include "packager/mpd/base/mpd_builder.h"
30 DEFINE_bool(mp4_use_decoding_timestamp_in_timeline,
32 "If set, decoding timestamp instead of presentation timestamp will "
33 "be used when generating media timeline, e.g. timestamps in sidx "
34 "and mpd. This is to workaround a Chromium bug that decoding "
35 "timestamp is used in buffered range, https://crbug.com/398130.");
36 DEFINE_bool(dump_stream_info,
false,
"Dump demuxed stream info.");
41 void DumpStreamInfo(
const std::vector<std::unique_ptr<MediaStream>>& streams) {
42 printf(
"Found %zu stream(s).\n", streams.size());
43 for (
size_t i = 0; i < streams.size(); ++i)
44 printf(
"Stream [%zu] %s\n", i, streams[i]->info()->ToString().c_str());
47 std::unique_ptr<RequestSigner> CreateSigner() {
48 std::unique_ptr<RequestSigner> signer;
50 if (!FLAGS_aes_signing_key.empty()) {
52 FLAGS_signer, FLAGS_aes_signing_key, FLAGS_aes_signing_iv));
54 LOG(ERROR) <<
"Cannot create an AES signer object from '"
55 << FLAGS_aes_signing_key <<
"':'" << FLAGS_aes_signing_iv
57 return std::unique_ptr<RequestSigner>();
59 }
else if (!FLAGS_rsa_signing_key_path.empty()) {
60 std::string rsa_private_key;
63 LOG(ERROR) <<
"Failed to read from '" << FLAGS_rsa_signing_key_path
65 return std::unique_ptr<RequestSigner>();
69 LOG(ERROR) <<
"Cannot create a RSA signer object from '"
70 << FLAGS_rsa_signing_key_path <<
"'.";
71 return std::unique_ptr<RequestSigner>();
77 std::unique_ptr<KeySource> CreateEncryptionKeySource() {
78 std::unique_ptr<KeySource> encryption_key_source;
79 if (FLAGS_enable_widevine_encryption) {
80 std::unique_ptr<WidevineKeySource> widevine_key_source(
81 new WidevineKeySource(FLAGS_key_server_url, FLAGS_include_common_pssh));
82 if (!FLAGS_signer.empty()) {
83 std::unique_ptr<RequestSigner> request_signer(CreateSigner());
85 return std::unique_ptr<KeySource>();
86 widevine_key_source->set_signer(std::move(request_signer));
89 std::vector<uint8_t> content_id;
90 if (!base::HexStringToBytes(FLAGS_content_id, &content_id)) {
91 LOG(ERROR) <<
"Invalid content_id hex string specified.";
92 return std::unique_ptr<KeySource>();
94 Status status = widevine_key_source->FetchKeys(content_id, FLAGS_policy);
96 LOG(ERROR) <<
"Widevine encryption key source failed to fetch keys: "
98 return std::unique_ptr<KeySource>();
100 encryption_key_source = std::move(widevine_key_source);
101 }
else if (FLAGS_enable_fixed_key_encryption) {
103 FLAGS_key_id, FLAGS_key, FLAGS_pssh, FLAGS_iv);
104 }
else if (FLAGS_enable_playready_encryption) {
105 if (!FLAGS_playready_key_id.empty() && !FLAGS_playready_key.empty()) {
107 FLAGS_playready_key_id, FLAGS_playready_key);
108 }
else if (!FLAGS_playready_server_url.empty() &&
109 !FLAGS_program_identifier.empty()) {
110 std::unique_ptr<PlayReadyKeySource> playready_key_source;
111 if (!FLAGS_client_cert_file.empty() &&
112 !FLAGS_client_cert_private_key_file.empty() &&
113 !FLAGS_client_cert_private_key_password.empty()) {
114 playready_key_source.reset(
new PlayReadyKeySource(
115 FLAGS_playready_server_url,
116 FLAGS_client_cert_file,
117 FLAGS_client_cert_private_key_file,
118 FLAGS_client_cert_private_key_password));
120 playready_key_source.reset(
new PlayReadyKeySource(
121 FLAGS_playready_server_url));
123 if (!FLAGS_ca_file.empty()) {
124 playready_key_source->
SetCaFile(FLAGS_ca_file);
126 playready_key_source->FetchKeysWithProgramIdentifier(FLAGS_program_identifier);
127 encryption_key_source = std::move(playready_key_source);
129 LOG(ERROR) <<
"Error creating PlayReady key source.";
130 return std::unique_ptr<KeySource>();
133 return encryption_key_source;
136 std::unique_ptr<KeySource> CreateDecryptionKeySource() {
137 std::unique_ptr<KeySource> decryption_key_source;
138 if (FLAGS_enable_widevine_decryption) {
139 std::unique_ptr<WidevineKeySource> widevine_key_source(
140 new WidevineKeySource(FLAGS_key_server_url, FLAGS_include_common_pssh));
141 if (!FLAGS_signer.empty()) {
142 std::unique_ptr<RequestSigner> request_signer(CreateSigner());
144 return std::unique_ptr<KeySource>();
145 widevine_key_source->set_signer(std::move(request_signer));
148 decryption_key_source = std::move(widevine_key_source);
149 }
else if (FLAGS_enable_fixed_key_decryption) {
150 const char kNoPssh[] =
"";
151 const char kNoIv[] =
"";
153 FLAGS_key_id, FLAGS_key, kNoPssh, kNoIv);
155 return decryption_key_source;
158 bool GetMuxerOptions(MuxerOptions* muxer_options) {
159 DCHECK(muxer_options);
161 muxer_options->segment_duration = FLAGS_segment_duration;
162 muxer_options->fragment_duration = FLAGS_fragment_duration;
163 muxer_options->segment_sap_aligned = FLAGS_segment_sap_aligned;
164 muxer_options->fragment_sap_aligned = FLAGS_fragment_sap_aligned;
165 muxer_options->num_subsegments_per_sidx = FLAGS_num_subsegments_per_sidx;
166 muxer_options->webm_subsample_encryption = FLAGS_webm_subsample_encryption;
167 if (FLAGS_mp4_use_decoding_timestamp_in_timeline) {
168 LOG(WARNING) <<
"Flag --mp4_use_decoding_timestamp_in_timeline is set. "
169 "Note that it is a temporary hack to workaround Chromium "
170 "bug https://crbug.com/398130. The flag may be removed "
171 "when the Chromium bug is fixed.";
173 muxer_options->mp4_use_decoding_timestamp_in_timeline =
174 FLAGS_mp4_use_decoding_timestamp_in_timeline;
176 muxer_options->temp_dir = FLAGS_temp_dir;
180 bool GetMpdOptions(
bool on_demand_profile, MpdOptions* mpd_options) {
183 mpd_options->dash_profile =
184 on_demand_profile ? DashProfile::kOnDemand : DashProfile::kLive;
185 mpd_options->mpd_type =
186 (on_demand_profile || FLAGS_generate_static_mpd)
189 mpd_options->availability_time_offset = FLAGS_availability_time_offset;
190 mpd_options->minimum_update_period = FLAGS_minimum_update_period;
191 mpd_options->min_buffer_time = FLAGS_min_buffer_time;
192 mpd_options->time_shift_buffer_depth = FLAGS_time_shift_buffer_depth;
193 mpd_options->suggested_presentation_delay =
194 FLAGS_suggested_presentation_delay;
195 mpd_options->default_language = FLAGS_default_language;
199 MediaStream* FindFirstStreamOfType(
200 const std::vector<std::unique_ptr<MediaStream>>& streams,
201 StreamType stream_type) {
202 for (
const std::unique_ptr<MediaStream>& stream : streams) {
203 if (stream->info()->stream_type() == stream_type)
208 MediaStream* FindFirstVideoStream(
209 const std::vector<std::unique_ptr<MediaStream>>& streams) {
210 return FindFirstStreamOfType(streams, kStreamVideo);
212 MediaStream* FindFirstAudioStream(
213 const std::vector<std::unique_ptr<MediaStream>>& streams) {
214 return FindFirstStreamOfType(streams, kStreamAudio);
217 bool AddStreamToMuxer(
const std::vector<std::unique_ptr<MediaStream>>& streams,
218 const std::string& stream_selector,
219 const std::string& language_override,
223 MediaStream* stream =
nullptr;
224 if (stream_selector ==
"video") {
225 stream = FindFirstVideoStream(streams);
226 }
else if (stream_selector ==
"audio") {
227 stream = FindFirstAudioStream(streams);
231 if (!base::StringToSizeT(stream_selector, &stream_id) ||
232 stream_id >= streams.size()) {
233 LOG(ERROR) <<
"Invalid argument --stream=" << stream_selector <<
"; "
234 <<
"should be 'audio', 'video', or a number within [0, "
235 << streams.size() - 1 <<
"].";
238 stream = streams[stream_id].get();
245 LOG(ERROR) <<
"No " << stream_selector <<
" stream found in the input.";
249 if (!language_override.empty()) {
250 stream->info()->set_language(language_override);
253 muxer->AddStream(stream);