7 #include <gflags/gflags.h>
10 #include "packager/app/crypto_flags.h"
11 #include "packager/app/fixed_key_encryption_flags.h"
12 #include "packager/app/hls_flags.h"
13 #include "packager/app/mpd_flags.h"
14 #include "packager/app/muxer_flags.h"
15 #include "packager/app/packager_util.h"
16 #include "packager/app/playready_key_encryption_flags.h"
17 #include "packager/app/stream_descriptor.h"
18 #include "packager/app/vlog_flags.h"
19 #include "packager/app/widevine_encryption_flags.h"
20 #include "packager/base/command_line.h"
21 #include "packager/base/logging.h"
22 #include "packager/base/optional.h"
23 #include "packager/base/strings/string_number_conversions.h"
24 #include "packager/base/strings/string_split.h"
25 #include "packager/base/strings/stringprintf.h"
26 #include "packager/media/file/file.h"
27 #include "packager/packager.h"
33 #endif // defined(OS_WIN)
35 DEFINE_bool(dump_stream_info,
false,
"Dump demuxed stream info.");
36 DEFINE_bool(use_fake_clock_for_muxer,
38 "Set to true to use a fake clock for muxer. With this flag set, "
39 "creation time and modification time in outputs are set to 0. "
40 "Should only be used for testing.");
41 DEFINE_bool(override_version,
43 "Override packager version in the generated outputs with "
44 "--test_version if it is set to true. Should be used for "
46 DEFINE_string(test_version,
48 "Packager version for testing. Ignored if --override_version is "
49 "false. Should be used for testing only.");
55 "%s [flags] <stream_descriptor> ...\n\n"
56 " stream_descriptor consists of comma separated field_name/value pairs:\n"
57 " field_name=value,[field_name=value,]...\n"
58 " Supported field names are as follows (names in parenthesis are alias):\n"
59 " - input (in): Required input/source media file path or network stream\n"
61 " - stream_selector (stream): Required field with value 'audio',\n"
62 " 'video', 'text', or stream number (zero based).\n"
63 " - output (out,init_segment): Required output file (single file) or\n"
64 " initialization file path (multiple file).\n"
65 " - segment_template (segment): Optional value which specifies the\n"
66 " naming pattern for the segment files, and that the stream should be\n"
67 " split into multiple files. Its presence should be consistent across\n"
69 " - bandwidth (bw): Optional value which contains a user-specified\n"
70 " content bit rate for the stream, in bits/sec. If specified, this\n"
71 " value is propagated to the $Bandwidth$ template parameter for\n"
72 " segment names. If not specified, its value may be estimated.\n"
73 " - language (lang): Optional value which contains a user-specified\n"
74 " language tag. If specified, this value overrides any language\n"
75 " metadata in the input stream.\n"
76 " - output_format (format): Optional value which specifies the format\n"
77 " of the output files (MP4 or WebM). If not specified, it will be\n"
78 " derived from the file extension of the output file.\n"
79 " - skip_encryption=0|1: Optional. Defaults to 0 if not specified. If\n"
80 " it is set to 1, no encryption of the stream will be made.\n"
81 " - trick_play_factor (tpf): Optional value which specifies the trick\n"
82 " play, a.k.a. trick mode, stream sampling rate among key frames.\n"
83 " If specified, the output is a trick play stream.\n"
84 " - hls_name: Required for audio when outputting HLS.\n"
85 " name of the output stream. This is not (necessarily) the same as\n"
86 " output. This is used as the NAME attribute for EXT-X-MEDIA\n"
87 " - hls_group_id: Required for audio when outputting HLS.\n"
88 " The group ID for the output stream. This is used as the GROUP-ID\n"
89 " attribute for EXT-X-MEDIA.\n"
90 " - playlist_name: Required for HLS output.\n"
91 " Name of the playlist for the stream. Usually ends with '.m3u8'.\n";
95 kArgumentValidationFailed,
100 base::Optional<PackagingParams> GetPackagingParams() {
101 PackagingParams packaging_params;
103 ChunkingParams& chunking_params = packaging_params.chunking_params;
104 chunking_params.segment_duration_in_seconds = FLAGS_segment_duration;
105 chunking_params.subsegment_duration_in_seconds = FLAGS_fragment_duration;
106 chunking_params.segment_sap_aligned = FLAGS_segment_sap_aligned;
107 chunking_params.subsegment_sap_aligned = FLAGS_fragment_sap_aligned;
109 int num_key_providers = 0;
110 EncryptionParams& encryption_params = packaging_params.encryption_params;
111 if (FLAGS_enable_widevine_encryption) {
112 encryption_params.key_provider = KeyProvider::kWidevine;
115 if (FLAGS_enable_playready_encryption) {
116 encryption_params.key_provider = KeyProvider::kPlayready;
119 if (FLAGS_enable_fixed_key_encryption) {
120 encryption_params.key_provider = KeyProvider::kRawKey;
123 if (num_key_providers > 1) {
124 LOG(ERROR) <<
"Only one of --enable_widevine_encryption, "
125 "--enable_playready_encryption, "
126 "--enable_fixed_key_encryption can be enabled.";
127 return base::nullopt;
130 if (encryption_params.key_provider != KeyProvider::kNone) {
131 encryption_params.clear_lead_in_seconds = FLAGS_clear_lead;
132 encryption_params.protection_scheme = FLAGS_protection_scheme;
133 encryption_params.crypto_period_duration_in_seconds =
134 FLAGS_crypto_period_duration;
135 encryption_params.vp9_subsample_encryption = FLAGS_vp9_subsample_encryption;
136 encryption_params.stream_label_func = std::bind(
137 &EncryptionParams::DefaultStreamLabelFunction, FLAGS_max_sd_pixels,
138 FLAGS_max_hd_pixels, FLAGS_max_uhd1_pixels, std::placeholders::_1);
140 switch (encryption_params.key_provider) {
141 case KeyProvider::kWidevine: {
142 WidevineEncryptionParams& widevine = encryption_params.widevine;
143 widevine.key_server_url = FLAGS_key_server_url;
144 widevine.include_common_pssh = FLAGS_include_common_pssh;
146 if (!base::HexStringToBytes(FLAGS_content_id, &widevine.content_id)) {
147 LOG(ERROR) <<
"Invalid content_id hex string specified.";
148 return base::nullopt;
150 widevine.policy = FLAGS_policy;
151 widevine.signer.signer_name = FLAGS_signer;
152 if (!FLAGS_aes_signing_key.empty() && !FLAGS_rsa_signing_key_path.empty()) {
153 LOG(ERROR) <<
"Only one of --aes_signing_key and "
154 "--rsa_signing_key_path is needed.";
155 return base::nullopt;
157 WidevineSigner& signer = widevine.signer;
158 if (!FLAGS_aes_signing_key.empty()) {
160 signer.signing_key_type = WidevineSigner::SigningKeyType::kAes;
161 signer.aes.key = FLAGS_aes_signing_key;
162 signer.aes.iv = FLAGS_aes_signing_iv;
164 if (!FLAGS_rsa_signing_key_path.empty()) {
165 signer.signing_key_type = WidevineSigner::SigningKeyType::kRsa;
168 LOG(ERROR) <<
"Failed to read from '" << FLAGS_rsa_signing_key_path
170 return base::nullopt;
175 case KeyProvider::kPlayready: {
176 PlayreadyEncryptionParams& playready = encryption_params.playready;
177 playready.key_server_url = FLAGS_playready_server_url;
178 playready.program_identifier = FLAGS_program_identifier;
179 playready.ca_file = FLAGS_ca_file;
180 playready.client_cert_file = FLAGS_client_cert_file;
181 playready.client_cert_private_key_file =
182 FLAGS_client_cert_private_key_file;
183 playready.client_cert_private_key_password =
184 FLAGS_client_cert_private_key_password;
185 playready.key_id = FLAGS_playready_key_id;
186 playready.key = FLAGS_playready_key;
189 case KeyProvider::kRawKey: {
190 RawKeyEncryptionParams& raw_key = encryption_params.raw_key;
191 raw_key.iv = FLAGS_iv;
192 raw_key.pssh = FLAGS_pssh;
194 RawKeyEncryptionParams::KeyPair& key_pair = raw_key.key_map[
""];
196 key_pair.key_id = FLAGS_key_id;
197 key_pair.key = FLAGS_key;
200 case KeyProvider::kNone:
204 num_key_providers = 0;
205 DecryptionParams& decryption_params = packaging_params.decryption_params;
206 if (FLAGS_enable_widevine_decryption) {
207 decryption_params.key_provider = KeyProvider::kWidevine;
210 if (FLAGS_enable_fixed_key_decryption) {
211 decryption_params.key_provider = KeyProvider::kRawKey;
214 if (num_key_providers > 1) {
215 LOG(ERROR) <<
"Only one of --enable_widevine_decryption, "
216 "--enable_fixed_key_decryption can be enabled.";
217 return base::nullopt;
219 switch (decryption_params.key_provider) {
220 case KeyProvider::kWidevine: {
221 WidevineDecryptionParams& widevine = decryption_params.widevine;
222 widevine.key_server_url = FLAGS_key_server_url;
224 widevine.signer.signer_name = FLAGS_signer;
225 if (!FLAGS_aes_signing_key.empty() && !FLAGS_rsa_signing_key_path.empty()) {
226 LOG(ERROR) <<
"Only one of --aes_signing_key and "
227 "--rsa_signing_key_path is needed.";
228 return base::nullopt;
230 WidevineSigner& signer = widevine.signer;
231 if (!FLAGS_aes_signing_key.empty()) {
233 signer.signing_key_type = WidevineSigner::SigningKeyType::kAes;
234 signer.aes.key = FLAGS_aes_signing_key;
235 signer.aes.iv = FLAGS_aes_signing_iv;
237 if (!FLAGS_rsa_signing_key_path.empty()) {
238 signer.signing_key_type = WidevineSigner::SigningKeyType::kRsa;
241 LOG(ERROR) <<
"Failed to read from '" << FLAGS_rsa_signing_key_path
243 return base::nullopt;
248 case KeyProvider::kRawKey: {
249 RawKeyDecryptionParams& raw_key = decryption_params.raw_key;
251 RawKeyDecryptionParams::KeyPair& key_pair = raw_key.key_map[
""];
253 key_pair.key_id = FLAGS_key_id;
254 key_pair.key = FLAGS_key;
257 case KeyProvider::kNone:
258 case KeyProvider::kPlayready:
262 Mp4OutputParams& mp4_params = packaging_params.mp4_output_params;
263 mp4_params.num_subsegments_per_sidx = FLAGS_num_subsegments_per_sidx;
264 if (FLAGS_mp4_use_decoding_timestamp_in_timeline) {
265 LOG(WARNING) <<
"Flag --mp4_use_decoding_timestamp_in_timeline is set. "
266 "Note that it is a temporary hack to workaround Chromium "
267 "bug https://crbug.com/398130. The flag may be removed "
268 "when the Chromium bug is fixed.";
270 mp4_params.use_decoding_timestamp_in_timeline =
271 FLAGS_mp4_use_decoding_timestamp_in_timeline;
272 mp4_params.include_pssh_in_stream = FLAGS_mp4_include_pssh_in_stream;
274 packaging_params.output_media_info = FLAGS_output_media_info;
276 MpdParams& mpd_params = packaging_params.mpd_params;
277 mpd_params.generate_static_live_mpd = FLAGS_generate_static_mpd;
278 mpd_params.mpd_output = FLAGS_mpd_output;
279 mpd_params.base_urls = base::SplitString(
280 FLAGS_base_urls,
",", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
281 mpd_params.generate_dash_if_iop_compliant_mpd =
282 FLAGS_generate_dash_if_iop_compliant_mpd;
283 mpd_params.minimum_update_period = FLAGS_minimum_update_period;
284 mpd_params.min_buffer_time = FLAGS_min_buffer_time;
285 mpd_params.time_shift_buffer_depth = FLAGS_time_shift_buffer_depth;
286 mpd_params.suggested_presentation_delay = FLAGS_suggested_presentation_delay;
287 mpd_params.default_language = FLAGS_default_language;
289 HlsParams& hls_params = packaging_params.hls_params;
290 hls_params.master_playlist_output = FLAGS_hls_master_playlist_output;
291 hls_params.base_url = FLAGS_hls_base_url;
293 TestParams& test_params = packaging_params.test_params;
294 test_params.dump_stream_info = FLAGS_dump_stream_info;
295 test_params.inject_fake_clock = FLAGS_use_fake_clock_for_muxer;
296 if (FLAGS_override_version)
297 test_params.injected_library_version = FLAGS_test_version;
299 return packaging_params;
302 int PackagerMain(
int argc,
char** argv) {
304 base::CommandLine::Init(argc, argv);
307 logging::LoggingSettings log_settings;
308 log_settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
309 CHECK(logging::InitLogging(log_settings));
311 google::SetVersionString(shaka::Packager::GetLibraryVersion());
312 google::SetUsageMessage(base::StringPrintf(kUsage, argv[0]));
313 google::ParseCommandLineFlags(&argc, &argv,
true);
315 google::ShowUsageWithFlags(
"Usage");
321 return kArgumentValidationFailed;
324 base::Optional<PackagingParams> packaging_params = GetPackagingParams();
325 if (!packaging_params)
326 return kArgumentValidationFailed;
328 std::vector<StreamDescriptor> stream_descriptors;
329 for (
int i = 1; i < argc; ++i) {
330 base::Optional<StreamDescriptor> stream_descriptor =
332 if (!stream_descriptor)
333 return kArgumentValidationFailed;
334 stream_descriptors.push_back(stream_descriptor.value());
337 media::Status status =
338 packager.Initialize(packaging_params.value(), stream_descriptors);
340 LOG(ERROR) <<
"Failed to initialize packager: " << status.ToString();
341 return kArgumentValidationFailed;
343 status = packager.Run();
345 LOG(ERROR) <<
"Packaging Error: " << status.ToString();
346 return kPackagingFailed;
348 printf(
"Packaging completed successfully.\n");
357 int wmain(
int argc,
wchar_t* argv[],
wchar_t* envp[]) {
358 std::unique_ptr<char* [], std::function<void(char**)>> utf8_argv(
359 new char*[argc], [argc](
char** utf8_args) {
367 std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
368 for (
int idx = 0; idx < argc; ++idx) {
369 std::string utf8_arg(converter.to_bytes(argv[idx]));
371 utf8_argv[idx] =
new char[utf8_arg.size()];
372 memcpy(utf8_argv[idx], &utf8_arg[0], utf8_arg.size());
374 return shaka::PackagerMain(argc, utf8_argv.get());
377 int main(
int argc,
char** argv) {
378 return shaka::PackagerMain(argc, argv);
380 #endif // defined(OS_WIN)
base::Optional< StreamDescriptor > ParseStreamDescriptor(const std::string &descriptor_string)
bool ValidateWidevineCryptoFlags()
bool ValidateFixedCryptoFlags()
bool ValidatePRCryptoFlags()