Shaka Packager SDK
packager_main.cc
1 // Copyright 2014 Google LLC. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file or at
5 // https://developers.google.com/open-source/licenses/bsd
6 
7 #include <iostream>
8 #include <optional>
9 
10 #if defined(OS_WIN)
11 #include <codecvt>
12 #include <functional>
13 #endif // defined(OS_WIN)
14 
15 #include <absl/flags/flag.h>
16 #include <absl/flags/parse.h>
17 #include <absl/flags/usage.h>
18 #include <absl/flags/usage_config.h>
19 #include <absl/log/globals.h>
20 #include <absl/log/initialize.h>
21 #include <absl/log/log.h>
22 #include <absl/strings/numbers.h>
23 #include <absl/strings/str_format.h>
24 #include <absl/strings/str_split.h>
25 
26 #include <packager/app/ad_cue_generator_flags.h>
27 #include <packager/app/crypto_flags.h>
28 #include <packager/app/hls_flags.h>
29 #include <packager/app/manifest_flags.h>
30 #include <packager/app/mpd_flags.h>
31 #include <packager/app/muxer_flags.h>
32 #include <packager/app/playready_key_encryption_flags.h>
33 #include <packager/app/protection_system_flags.h>
34 #include <packager/app/raw_key_encryption_flags.h>
35 #include <packager/app/retired_flags.h>
36 #include <packager/app/stream_descriptor.h>
37 #include <packager/app/widevine_encryption_flags.h>
38 #include <packager/file.h>
39 #include <packager/kv_pairs/kv_pairs.h>
40 #include <packager/tools/license_notice.h>
41 #include <packager/utils/string_trim_split.h>
42 
43 ABSL_FLAG(bool, dump_stream_info, false, "Dump demuxed stream info.");
44 ABSL_FLAG(bool, licenses, false, "Dump licenses.");
45 ABSL_FLAG(bool, quiet, false, "When enabled, LOG(INFO) output is suppressed.");
46 ABSL_FLAG(bool,
47  use_fake_clock_for_muxer,
48  false,
49  "Set to true to use a fake clock for muxer. With this flag set, "
50  "creation time and modification time in outputs are set to 0. "
51  "Should only be used for testing.");
52 ABSL_FLAG(std::string,
53  test_packager_version,
54  "",
55  "Packager version for testing. Should be used for testing only.");
56 ABSL_FLAG(bool,
57  single_threaded,
58  false,
59  "If enabled, only use one thread when generating content.");
60 
61 // From absl/log:
62 ABSL_DECLARE_FLAG(int, stderrthreshold);
63 
64 namespace shaka {
65 namespace {
66 
67 const char kUsage[] =
68  "%s [flags] <stream_descriptor> ...\n\n"
69  " stream_descriptor consists of comma separated field_name/value pairs:\n"
70  " field_name=value,[field_name=value,]...\n"
71  " Supported field names are as follows (names in parenthesis are alias):\n"
72  " - input (in): Required input/source media file path or network stream\n"
73  " URL.\n"
74  " - stream_selector (stream): Required field with value 'audio',\n"
75  " 'video', 'text', or stream number (zero based).\n"
76  " - output (out,init_segment): Required output file (single file) or\n"
77  " initialization file path (multiple file).\n"
78  " - segment_template (segment): Optional value which specifies the\n"
79  " naming pattern for the segment files, and that the stream should be\n"
80  " split into multiple files. Its presence should be consistent across\n"
81  " streams.\n"
82  " - bandwidth (bw): Optional value which contains a user-specified\n"
83  " maximum bit rate for the stream, in bits/sec. If specified, this\n"
84  " value is propagated to (HLS) EXT-X-STREAM-INF:BANDWIDTH or (DASH)\n"
85  " Representation@bandwidth and the $Bandwidth$ template parameter for\n"
86  " segment names. If not specified, the bandwidth value is estimated\n"
87  " from content bitrate. Note that it only affects the generated\n"
88  " manifests/playlists; it has no effect on the media content itself.\n"
89  " - language (lang): Optional value which contains a user-specified\n"
90  " language tag. If specified, this value overrides any language\n"
91  " metadata in the input stream.\n"
92  " - output_format (format): Optional value which specifies the format\n"
93  " of the output files (MP4 or WebM). If not specified, it will be\n"
94  " derived from the file extension of the output file.\n"
95  " - input_format (format): Optional value which specifies the format\n"
96  " of the input files or streams. If not specified, it will be\n"
97  " autodetected, which in some cases (such as live UDP webvtt) may\n"
98  " fail.\n"
99  " - skip_encryption=0|1: Optional. Defaults to 0 if not specified. If\n"
100  " it is set to 1, no encryption of the stream will be made.\n"
101  " - drm_label: Optional value for custom DRM label, which defines the\n"
102  " encryption key applied to the stream. Typical values include AUDIO,\n"
103  " SD, HD, UHD1, UHD2. For raw key, it should be a label defined in\n"
104  " --keys. If not provided, the DRM label is derived from stream type\n"
105  " (video, audio), resolution, etc.\n"
106  " Note that it is case sensitive.\n"
107  " - trick_play_factor (tpf): Optional value which specifies the trick\n"
108  " play, a.k.a. trick mode, stream sampling rate among key frames.\n"
109  " If specified, the output is a trick play stream.\n"
110  " - hls_name: Used for HLS audio to set the NAME attribute for\n"
111  " EXT-X-MEDIA. Defaults to the base of the playlist name.\n"
112  " - hls_group_id: Used for HLS audio to set the GROUP-ID attribute for\n"
113  " EXT-X-MEDIA. Defaults to 'audio' if not specified.\n"
114  " - playlist_name: The HLS playlist file to create. Usually ends with\n"
115  " '.m3u8', and is relative to --hls_master_playlist_output. If\n"
116  " unspecified, defaults to something of the form 'stream_0.m3u8',\n"
117  " 'stream_1.m3u8', 'stream_2.m3u8', etc.\n"
118  " - iframe_playlist_name: The optional HLS I-Frames only playlist file\n"
119  " to create. Usually ends with '.m3u8', and is relative to\n"
120  " hls_master_playlist_output. Should only be set for video streams. If\n"
121  " unspecified, no I-Frames only playlist is created.\n"
122  " - hls_characteristics (charcs): Optional colon/semicolon separated\n"
123  " list of values for the CHARACTERISTICS attribute for EXT-X-MEDIA.\n"
124  " See CHARACTERISTICS attribute in http://bit.ly/2OOUkdB for details.\n"
125  " - dash_accessibilities (accessibilities): Optional semicolon separated\n"
126  " list of values for DASH Accessibility elements. The value should be\n"
127  " in the format: scheme_id_uri=value.\n"
128  " - dash_roles (roles): Optional semicolon separated list of values for\n"
129  " DASH Role elements. The value should be one of: caption, subtitle, \n"
130  " main, alternate, supplementary, commentary, dub, description, sign, \n"
131  " metadata, enhanced-audio- intelligibility, emergency, \n"
132  " forced-subtitle, easyreader, and karaoke. See DASH\n"
133  " (ISO/IEC 23009-1) specification for details.\n"
134  " - forced_subtitle: Optional boolean value (0|1). If set to 1 \n"
135  " indicates that this stream is a Forced Narrative subtitle that \n"
136  " should be displayed when subtitles are otherwise off, for example \n"
137  " used to caption short portions of the audio that might be in a \n"
138  " foreign language. For DASH this will set role to forced_subtitle, \n"
139  " for HLS it will set FORCED=YES and AUTOSELECT=YES. \n"
140  " Only valid for subtitles.\n";
141 
142 // Labels for parameters in RawKey key info.
143 const char kDrmLabelLabel[] = "label";
144 const char kKeyIdLabel[] = "key_id";
145 const char kKeyLabel[] = "key";
146 const char kKeyIvLabel[] = "iv";
147 
148 enum ExitStatus {
149  kSuccess = 0,
150  kArgumentValidationFailed,
151  kPackagingFailed,
152  kInternalError,
153 };
154 
155 bool GetWidevineSigner(WidevineSigner* signer) {
156  signer->signer_name = absl::GetFlag(FLAGS_signer);
157  if (!absl::GetFlag(FLAGS_aes_signing_key).bytes.empty()) {
158  signer->signing_key_type = WidevineSigner::SigningKeyType::kAes;
159  signer->aes.key = absl::GetFlag(FLAGS_aes_signing_key).bytes;
160  signer->aes.iv = absl::GetFlag(FLAGS_aes_signing_iv).bytes;
161  } else if (!absl::GetFlag(FLAGS_rsa_signing_key_path).empty()) {
162  signer->signing_key_type = WidevineSigner::SigningKeyType::kRsa;
163  if (!File::ReadFileToString(
164  absl::GetFlag(FLAGS_rsa_signing_key_path).c_str(),
165  &signer->rsa.key)) {
166  LOG(ERROR) << "Failed to read from '"
167  << absl::GetFlag(FLAGS_rsa_signing_key_path) << "'.";
168  return false;
169  }
170  }
171  return true;
172 }
173 
174 bool GetHlsPlaylistType(const std::string& playlist_type,
175  HlsPlaylistType* playlist_type_enum) {
176  if (absl::AsciiStrToUpper(playlist_type) == "VOD") {
177  *playlist_type_enum = HlsPlaylistType::kVod;
178  } else if (absl::AsciiStrToUpper(playlist_type) == "LIVE") {
179  *playlist_type_enum = HlsPlaylistType::kLive;
180  } else if (absl::AsciiStrToUpper(playlist_type) == "EVENT") {
181  *playlist_type_enum = HlsPlaylistType::kEvent;
182  } else {
183  LOG(ERROR) << "Unrecognized playlist type " << playlist_type;
184  return false;
185  }
186  return true;
187 }
188 
189 bool GetProtectionScheme(uint32_t* protection_scheme) {
190  if (absl::GetFlag(FLAGS_protection_scheme) == "cenc") {
191  *protection_scheme = EncryptionParams::kProtectionSchemeCenc;
192  return true;
193  }
194  if (absl::GetFlag(FLAGS_protection_scheme) == "cbc1") {
195  *protection_scheme = EncryptionParams::kProtectionSchemeCbc1;
196  return true;
197  }
198  if (absl::GetFlag(FLAGS_protection_scheme) == "cbcs") {
199  *protection_scheme = EncryptionParams::kProtectionSchemeCbcs;
200  return true;
201  }
202  if (absl::GetFlag(FLAGS_protection_scheme) == "cens") {
203  *protection_scheme = EncryptionParams::kProtectionSchemeCens;
204  return true;
205  }
206  LOG(ERROR) << "Unrecognized protection_scheme "
207  << absl::GetFlag(FLAGS_protection_scheme);
208  return false;
209 }
210 
211 bool ParseKeys(const std::string& keys, RawKeyParams* raw_key) {
212  std::vector<std::string> keys_data = SplitAndTrimSkipEmpty(keys, ',');
213 
214  for (const std::string& key_data : keys_data) {
215  std::vector<KVPair> string_pairs =
216  SplitStringIntoKeyValuePairs(key_data, '=', ':');
217 
218  std::map<std::string, std::string> value_map;
219  for (const auto& string_pair : string_pairs)
220  value_map[string_pair.first] = string_pair.second;
221  const std::string drm_label = value_map[kDrmLabelLabel];
222  if (raw_key->key_map.find(drm_label) != raw_key->key_map.end()) {
223  LOG(ERROR) << "Seeing duplicated DRM label '" << drm_label << "'.";
224  return false;
225  }
226  auto& key_info = raw_key->key_map[drm_label];
227  if (value_map[kKeyIdLabel].empty() ||
228  !shaka::ValidHexStringToBytes(value_map[kKeyIdLabel],
229  &key_info.key_id)) {
230  LOG(ERROR) << "Empty key id or invalid hex string for key id: "
231  << value_map[kKeyIdLabel];
232  return false;
233  }
234  if (value_map[kKeyLabel].empty() ||
235  !shaka::ValidHexStringToBytes(value_map[kKeyLabel], &key_info.key)) {
236  LOG(ERROR) << "Empty key or invalid hex string for key: "
237  << value_map[kKeyLabel];
238  return false;
239  }
240  if (!value_map[kKeyIvLabel].empty()) {
241  if (!raw_key->iv.empty()) {
242  LOG(ERROR) << "IV already specified with --iv";
243  return false;
244  }
245  if (!shaka::ValidHexStringToBytes(value_map[kKeyIvLabel], &key_info.iv)) {
246  LOG(ERROR) << "Empty IV or invalid hex string for IV: "
247  << value_map[kKeyIvLabel];
248  return false;
249  }
250  }
251  }
252  return true;
253 }
254 
255 bool GetRawKeyParams(RawKeyParams* raw_key) {
256  raw_key->iv = absl::GetFlag(FLAGS_iv).bytes;
257  raw_key->pssh = absl::GetFlag(FLAGS_pssh).bytes;
258  if (!absl::GetFlag(FLAGS_keys).empty()) {
259  if (!ParseKeys(absl::GetFlag(FLAGS_keys), raw_key)) {
260  LOG(ERROR) << "Failed to parse --keys " << absl::GetFlag(FLAGS_keys);
261  return false;
262  }
263  } else {
264  // An empty StreamLabel specifies the default key info.
265  RawKeyParams::KeyInfo& key_info = raw_key->key_map[""];
266  key_info.key_id = absl::GetFlag(FLAGS_key_id).bytes;
267  key_info.key = absl::GetFlag(FLAGS_key).bytes;
268  }
269  return true;
270 }
271 
272 bool ParseAdCues(const std::string& ad_cues, std::vector<Cuepoint>* cuepoints) {
273  // Track if optional field is supplied consistently across all cue points.
274  size_t duration_count = 0;
275  std::vector<std::string> ad_cues_vec = SplitAndTrimSkipEmpty(ad_cues, ';');
276 
277  for (const std::string& ad_cue : ad_cues_vec) {
278  Cuepoint cuepoint;
279  std::vector<std::string> split_ad_cue = SplitAndTrimSkipEmpty(ad_cue, ',');
280 
281  if (split_ad_cue.size() > 2) {
282  LOG(ERROR) << "Failed to parse --ad_cues " << ad_cues
283  << " Each ad cue must contain no more than 2 components.";
284  }
285  if (!absl::SimpleAtod(split_ad_cue.front(),
286  &cuepoint.start_time_in_seconds)) {
287  LOG(ERROR) << "Failed to parse --ad_cues " << ad_cues
288  << " Start time component must be of type double.";
289  return false;
290  }
291  if (split_ad_cue.size() > 1) {
292  duration_count++;
293  if (!absl::SimpleAtod(split_ad_cue[1], &cuepoint.duration_in_seconds)) {
294  LOG(ERROR) << "Failed to parse --ad_cues " << ad_cues
295  << " Duration component must be of type double.";
296  return false;
297  }
298  }
299  cuepoints->push_back(cuepoint);
300  }
301 
302  if (duration_count > 0 && duration_count != cuepoints->size()) {
303  LOG(ERROR) << "Failed to parse --ad_cues " << ad_cues
304  << " Duration component is optional. However if it is supplied,"
305  << " it must be supplied consistently across all cuepoints.";
306  return false;
307  }
308  return true;
309 }
310 
311 bool ParseProtectionSystems(const std::string& protection_systems_str,
312  ProtectionSystem* protection_systems) {
313  *protection_systems = ProtectionSystem::kNone;
314 
315  std::map<std::string, ProtectionSystem> mapping = {
316  {"common", ProtectionSystem::kCommon},
317  {"commonsystem", ProtectionSystem::kCommon},
318  {"fairplay", ProtectionSystem::kFairPlay},
319  {"marlin", ProtectionSystem::kMarlin},
320  {"playready", ProtectionSystem::kPlayReady},
321  {"widevine", ProtectionSystem::kWidevine},
322  };
323 
324  std::vector<std::string> protection_systems_vec =
325  SplitAndTrimSkipEmpty(absl::AsciiStrToLower(protection_systems_str), ',');
326 
327  for (const std::string& protection_system : protection_systems_vec) {
328  auto iter = mapping.find(protection_system);
329  if (iter == mapping.end()) {
330  LOG(ERROR) << "Seeing unrecognized protection system: "
331  << protection_system;
332  return false;
333  }
334  *protection_systems |= iter->second;
335  }
336  return true;
337 }
338 
339 std::optional<PackagingParams> GetPackagingParams() {
340  PackagingParams packaging_params;
341 
342  packaging_params.temp_dir = absl::GetFlag(FLAGS_temp_dir);
343  packaging_params.single_threaded = absl::GetFlag(FLAGS_single_threaded);
344 
345  AdCueGeneratorParams& ad_cue_generator_params =
346  packaging_params.ad_cue_generator_params;
347  if (!ParseAdCues(absl::GetFlag(FLAGS_ad_cues),
348  &ad_cue_generator_params.cue_points)) {
349  return std::nullopt;
350  }
351 
352  ChunkingParams& chunking_params = packaging_params.chunking_params;
353  chunking_params.segment_duration_in_seconds =
354  absl::GetFlag(FLAGS_segment_duration);
355  chunking_params.subsegment_duration_in_seconds =
356  absl::GetFlag(FLAGS_fragment_duration);
357  chunking_params.low_latency_dash_mode =
358  absl::GetFlag(FLAGS_low_latency_dash_mode);
359  chunking_params.segment_sap_aligned =
360  absl::GetFlag(FLAGS_segment_sap_aligned);
361  chunking_params.subsegment_sap_aligned =
362  absl::GetFlag(FLAGS_fragment_sap_aligned);
363  chunking_params.start_segment_number =
364  absl::GetFlag(FLAGS_start_segment_number);
365 
366  int num_key_providers = 0;
367  EncryptionParams& encryption_params = packaging_params.encryption_params;
368  if (absl::GetFlag(FLAGS_enable_widevine_encryption)) {
369  encryption_params.key_provider = KeyProvider::kWidevine;
370  ++num_key_providers;
371  }
372  if (absl::GetFlag(FLAGS_enable_playready_encryption)) {
373  encryption_params.key_provider = KeyProvider::kPlayReady;
374  ++num_key_providers;
375  }
376  if (absl::GetFlag(FLAGS_enable_raw_key_encryption)) {
377  encryption_params.key_provider = KeyProvider::kRawKey;
378  ++num_key_providers;
379  }
380  if (num_key_providers > 1) {
381  LOG(ERROR) << "Only one of --enable_widevine_encryption, "
382  "--enable_playready_encryption, "
383  "--enable_raw_key_encryption can be enabled.";
384  return std::nullopt;
385  }
386 
387  if (!ParseProtectionSystems(absl::GetFlag(FLAGS_protection_systems),
388  &encryption_params.protection_systems)) {
389  return std::nullopt;
390  }
391 
392  if (encryption_params.key_provider != KeyProvider::kNone) {
393  encryption_params.clear_lead_in_seconds = absl::GetFlag(FLAGS_clear_lead);
394  if (!GetProtectionScheme(&encryption_params.protection_scheme))
395  return std::nullopt;
396  encryption_params.crypt_byte_block = absl::GetFlag(FLAGS_crypt_byte_block);
397  encryption_params.skip_byte_block = absl::GetFlag(FLAGS_skip_byte_block);
398 
399  encryption_params.crypto_period_duration_in_seconds =
400  absl::GetFlag(FLAGS_crypto_period_duration);
401  encryption_params.vp9_subsample_encryption =
402  absl::GetFlag(FLAGS_vp9_subsample_encryption);
403  encryption_params.stream_label_func = std::bind(
404  &Packager::DefaultStreamLabelFunction,
405  absl::GetFlag(FLAGS_max_sd_pixels), absl::GetFlag(FLAGS_max_hd_pixels),
406  absl::GetFlag(FLAGS_max_uhd1_pixels), std::placeholders::_1);
407  encryption_params.playready_extra_header_data =
408  absl::GetFlag(FLAGS_playready_extra_header_data);
409  }
410  switch (encryption_params.key_provider) {
411  case KeyProvider::kWidevine: {
412  WidevineEncryptionParams& widevine = encryption_params.widevine;
413  widevine.key_server_url = absl::GetFlag(FLAGS_key_server_url);
414 
415  widevine.content_id = absl::GetFlag(FLAGS_content_id).bytes;
416  widevine.policy = absl::GetFlag(FLAGS_policy);
417  widevine.group_id = absl::GetFlag(FLAGS_group_id).bytes;
418  widevine.enable_entitlement_license =
419  absl::GetFlag(FLAGS_enable_entitlement_license);
420  if (!GetWidevineSigner(&widevine.signer))
421  return std::nullopt;
422  break;
423  }
424  case KeyProvider::kPlayReady: {
425  PlayReadyEncryptionParams& playready = encryption_params.playready;
426  playready.key_server_url = absl::GetFlag(FLAGS_playready_server_url);
427  playready.program_identifier = absl::GetFlag(FLAGS_program_identifier);
428  break;
429  }
430  case KeyProvider::kRawKey: {
431  if (!GetRawKeyParams(&encryption_params.raw_key))
432  return std::nullopt;
433  break;
434  }
435  case KeyProvider::kNone:
436  break;
437  }
438 
439  num_key_providers = 0;
440  DecryptionParams& decryption_params = packaging_params.decryption_params;
441  if (absl::GetFlag(FLAGS_enable_widevine_decryption)) {
442  decryption_params.key_provider = KeyProvider::kWidevine;
443  ++num_key_providers;
444  }
445  if (absl::GetFlag(FLAGS_enable_raw_key_decryption)) {
446  decryption_params.key_provider = KeyProvider::kRawKey;
447  ++num_key_providers;
448  }
449  if (num_key_providers > 1) {
450  LOG(ERROR) << "Only one of --enable_widevine_decryption, "
451  "--enable_raw_key_decryption can be enabled.";
452  return std::nullopt;
453  }
454  switch (decryption_params.key_provider) {
455  case KeyProvider::kWidevine: {
456  WidevineDecryptionParams& widevine = decryption_params.widevine;
457  widevine.key_server_url = absl::GetFlag(FLAGS_key_server_url);
458  if (!GetWidevineSigner(&widevine.signer))
459  return std::nullopt;
460  break;
461  }
462  case KeyProvider::kRawKey: {
463  if (!GetRawKeyParams(&decryption_params.raw_key))
464  return std::nullopt;
465  break;
466  }
467  case KeyProvider::kPlayReady:
468  case KeyProvider::kNone:
469  break;
470  }
471 
472  Mp4OutputParams& mp4_params = packaging_params.mp4_output_params;
473  mp4_params.generate_sidx_in_media_segments =
474  absl::GetFlag(FLAGS_generate_sidx_in_media_segments);
475  mp4_params.include_pssh_in_stream =
476  absl::GetFlag(FLAGS_mp4_include_pssh_in_stream);
477  mp4_params.low_latency_dash_mode = absl::GetFlag(FLAGS_low_latency_dash_mode);
478 
479  packaging_params.transport_stream_timestamp_offset_ms =
480  absl::GetFlag(FLAGS_transport_stream_timestamp_offset_ms);
481  packaging_params.default_text_zero_bias_ms =
482  absl::GetFlag(FLAGS_default_text_zero_bias_ms);
483 
484  packaging_params.output_media_info = absl::GetFlag(FLAGS_output_media_info);
485 
486  MpdParams& mpd_params = packaging_params.mpd_params;
487  mpd_params.mpd_output = absl::GetFlag(FLAGS_mpd_output);
488 
489  std::vector<std::string> base_urls =
490  SplitAndTrimSkipEmpty(absl::GetFlag(FLAGS_base_urls), ',');
491 
492  mpd_params.base_urls = base_urls;
493  mpd_params.min_buffer_time = absl::GetFlag(FLAGS_min_buffer_time);
494  mpd_params.minimum_update_period = absl::GetFlag(FLAGS_minimum_update_period);
495  mpd_params.suggested_presentation_delay =
496  absl::GetFlag(FLAGS_suggested_presentation_delay);
497  mpd_params.time_shift_buffer_depth =
498  absl::GetFlag(FLAGS_time_shift_buffer_depth);
499  mpd_params.preserved_segments_outside_live_window =
500  absl::GetFlag(FLAGS_preserved_segments_outside_live_window);
501  mpd_params.use_segment_list = absl::GetFlag(FLAGS_dash_force_segment_list);
502 
503  if (!absl::GetFlag(FLAGS_utc_timings).empty()) {
504  std::vector<KVPair> pairs = SplitStringIntoKeyValuePairs(
505  absl::GetFlag(FLAGS_utc_timings), '=', ',');
506  if (pairs.empty()) {
507  LOG(ERROR) << "Invalid --utc_timings scheme_id_uri/value pairs.";
508  return std::nullopt;
509  }
510  for (const auto& string_pair : pairs) {
511  mpd_params.utc_timings.push_back({string_pair.first, string_pair.second});
512  }
513  }
514 
515  mpd_params.default_language = absl::GetFlag(FLAGS_default_language);
516  mpd_params.default_text_language = absl::GetFlag(FLAGS_default_text_language);
517  mpd_params.generate_static_live_mpd =
518  absl::GetFlag(FLAGS_generate_static_live_mpd);
519  mpd_params.generate_dash_if_iop_compliant_mpd =
520  absl::GetFlag(FLAGS_generate_dash_if_iop_compliant_mpd);
521  mpd_params.allow_approximate_segment_timeline =
522  absl::GetFlag(FLAGS_allow_approximate_segment_timeline);
523  mpd_params.allow_codec_switching = absl::GetFlag(FLAGS_allow_codec_switching);
524  mpd_params.include_mspr_pro =
525  absl::GetFlag(FLAGS_include_mspr_pro_for_playready);
526  mpd_params.low_latency_dash_mode = absl::GetFlag(FLAGS_low_latency_dash_mode);
527 
528  HlsParams& hls_params = packaging_params.hls_params;
529  if (!GetHlsPlaylistType(absl::GetFlag(FLAGS_hls_playlist_type),
530  &hls_params.playlist_type)) {
531  return std::nullopt;
532  }
533  hls_params.master_playlist_output =
534  absl::GetFlag(FLAGS_hls_master_playlist_output);
535  hls_params.base_url = absl::GetFlag(FLAGS_hls_base_url);
536  hls_params.key_uri = absl::GetFlag(FLAGS_hls_key_uri);
537  hls_params.time_shift_buffer_depth =
538  absl::GetFlag(FLAGS_time_shift_buffer_depth);
539  hls_params.preserved_segments_outside_live_window =
540  absl::GetFlag(FLAGS_preserved_segments_outside_live_window);
541  hls_params.default_language = absl::GetFlag(FLAGS_default_language);
542  hls_params.default_text_language = absl::GetFlag(FLAGS_default_text_language);
543  hls_params.media_sequence_number =
544  absl::GetFlag(FLAGS_hls_media_sequence_number);
545  hls_params.start_time_offset = absl::GetFlag(FLAGS_hls_start_time_offset);
546  hls_params.create_session_keys = absl::GetFlag(FLAGS_create_session_keys);
547 
548  TestParams& test_params = packaging_params.test_params;
549  test_params.dump_stream_info = absl::GetFlag(FLAGS_dump_stream_info);
550  test_params.inject_fake_clock = absl::GetFlag(FLAGS_use_fake_clock_for_muxer);
551  if (!absl::GetFlag(FLAGS_test_packager_version).empty())
552  test_params.injected_library_version =
553  absl::GetFlag(FLAGS_test_packager_version);
554 
555  return packaging_params;
556 }
557 
558 int PackagerMain(int argc, char** argv) {
559  absl::FlagsUsageConfig flag_config;
560  flag_config.version_string = []() -> std::string {
561  return "packager version " + shaka::Packager::GetLibraryVersion() + "\n";
562  };
563  flag_config.contains_help_flags =
564  [](absl::string_view flag_file_name) -> bool { return true; };
565  absl::SetFlagsUsageConfig(flag_config);
566 
567  auto usage = absl::StrFormat(kUsage, argv[0]);
568  absl::SetProgramUsageMessage(usage);
569 
570  // Before parsing the command line, change the default value of some flags
571  // provided by libraries.
572 
573  // Always log to stderr. Log levels are still controlled by --minloglevel.
574  absl::SetFlag(&FLAGS_stderrthreshold, 0);
575 
576  auto remaining_args = absl::ParseCommandLine(argc, argv);
577  if (absl::GetFlag(FLAGS_licenses)) {
578  for (const char* line : kLicenseNotice)
579  std::cout << line << std::endl;
580  return kSuccess;
581  }
582 
583  if (remaining_args.size() < 2) {
584  std::cerr << "Usage: " << absl::ProgramUsageMessage();
585  return kSuccess;
586  }
587 
588  if (absl::GetFlag(FLAGS_quiet)) {
589  absl::SetMinLogLevel(absl::LogSeverityAtLeast::kWarning);
590  }
591 
592  absl::InitializeLog();
593 
595  !ValidatePRCryptoFlags() || !ValidateCryptoFlags() ||
596  !ValidateRetiredFlags()) {
597  return kArgumentValidationFailed;
598  }
599 
600  std::optional<PackagingParams> packaging_params = GetPackagingParams();
601  if (!packaging_params)
602  return kArgumentValidationFailed;
603 
604  std::vector<StreamDescriptor> stream_descriptors;
605  for (size_t i = 1; i < remaining_args.size(); ++i) {
606  std::optional<StreamDescriptor> stream_descriptor =
607  ParseStreamDescriptor(remaining_args[i]);
608  if (!stream_descriptor)
609  return kArgumentValidationFailed;
610  stream_descriptors.push_back(stream_descriptor.value());
611  }
612 
613  if (absl::GetFlag(FLAGS_force_cl_index)) {
614  int index = 0;
615  for (auto& descriptor : stream_descriptors) {
616  descriptor.index = index++;
617  }
618  }
619 
620  Packager packager;
621  Status status =
622  packager.Initialize(packaging_params.value(), stream_descriptors);
623  if (!status.ok()) {
624  LOG(ERROR) << "Failed to initialize packager: " << status.ToString();
625  return kArgumentValidationFailed;
626  }
627  status = packager.Run();
628  if (!status.ok()) {
629  LOG(ERROR) << "Packaging Error: " << status.ToString();
630  return kPackagingFailed;
631  }
632  if (!absl::GetFlag(FLAGS_quiet))
633  printf("Packaging completed successfully.\n");
634  return kSuccess;
635 }
636 
637 } // namespace
638 } // namespace shaka
639 
640 #if defined(OS_WIN)
641 // Windows wmain, which converts wide character arguments to UTF-8.
642 int wmain(int argc, wchar_t* argv[], wchar_t* envp[]) {
643  std::unique_ptr<char*[], std::function<void(char**)>> utf8_argv(
644  new char*[argc], [argc](char** utf8_args) {
645  // TODO(tinskip): This leaks, but if this code is enabled, it crashes.
646  // Figure out why. I suspect gflags does something funny with the
647  // argument array.
648  // for (int idx = 0; idx < argc; ++idx)
649  // delete[] utf8_args[idx];
650  delete[] utf8_args;
651  });
652  std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
653 
654  for (int idx = 0; idx < argc; ++idx) {
655  std::string utf8_arg(converter.to_bytes(argv[idx]));
656  utf8_arg += '\0';
657  utf8_argv[idx] = new char[utf8_arg.size()];
658  memcpy(utf8_argv[idx], &utf8_arg[0], utf8_arg.size());
659  }
660 
661  // Because we just converted wide character args into UTF8, and because
662  // std::filesystem::u8path is used to interpret all std::string paths as
663  // UTF8, we should set the locale to UTF8 as well, for the transition point
664  // to C library functions like fopen to work correctly with non-ASCII paths.
665  std::setlocale(LC_ALL, ".UTF8");
666 
667  return shaka::PackagerMain(argc, utf8_argv.get());
668 }
669 #else
670 int main(int argc, char** argv) {
671  return shaka::PackagerMain(argc, argv);
672 }
673 #endif // defined(OS_WIN)
All the methods that are virtual are virtual for mocking.
Definition: crypto_flags.cc:66
std::optional< StreamDescriptor > ParseStreamDescriptor(const std::string &descriptor_string)
bool ValidateRawKeyCryptoFlags()
bool ValidateWidevineCryptoFlags()