DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
packager_util.cc
1 // Copyright 2014 Google Inc. 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 "packager/app/packager_util.h"
8 
9 #include <gflags/gflags.h>
10 #include <iostream>
11 
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"
29 
30 DEFINE_bool(mp4_use_decoding_timestamp_in_timeline,
31  false,
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.");
37 
38 namespace shaka {
39 namespace media {
40 
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());
45 }
46 
47 std::unique_ptr<RequestSigner> CreateSigner() {
48  std::unique_ptr<RequestSigner> signer;
49 
50  if (!FLAGS_aes_signing_key.empty()) {
51  signer.reset(AesRequestSigner::CreateSigner(
52  FLAGS_signer, FLAGS_aes_signing_key, FLAGS_aes_signing_iv));
53  if (!signer) {
54  LOG(ERROR) << "Cannot create an AES signer object from '"
55  << FLAGS_aes_signing_key << "':'" << FLAGS_aes_signing_iv
56  << "'.";
57  return std::unique_ptr<RequestSigner>();
58  }
59  } else if (!FLAGS_rsa_signing_key_path.empty()) {
60  std::string rsa_private_key;
61  if (!File::ReadFileToString(FLAGS_rsa_signing_key_path.c_str(),
62  &rsa_private_key)) {
63  LOG(ERROR) << "Failed to read from '" << FLAGS_rsa_signing_key_path
64  << "'.";
65  return std::unique_ptr<RequestSigner>();
66  }
67  signer.reset(RsaRequestSigner::CreateSigner(FLAGS_signer, rsa_private_key));
68  if (!signer) {
69  LOG(ERROR) << "Cannot create a RSA signer object from '"
70  << FLAGS_rsa_signing_key_path << "'.";
71  return std::unique_ptr<RequestSigner>();
72  }
73  }
74  return signer;
75 }
76 
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());
84  if (!request_signer)
85  return std::unique_ptr<KeySource>();
86  widevine_key_source->set_signer(std::move(request_signer));
87  }
88 
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>();
93  }
94  Status status = widevine_key_source->FetchKeys(content_id, FLAGS_policy);
95  if (!status.ok()) {
96  LOG(ERROR) << "Widevine encryption key source failed to fetch keys: "
97  << status.ToString();
98  return std::unique_ptr<KeySource>();
99  }
100  encryption_key_source = std::move(widevine_key_source);
101  } else if (FLAGS_enable_fixed_key_encryption) {
102  encryption_key_source = FixedKeySource::CreateFromHexStrings(
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()) {
106  encryption_key_source = PlayReadyKeySource::CreateFromKeyAndKeyId(
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));
119  } else {
120  playready_key_source.reset(new PlayReadyKeySource(
121  FLAGS_playready_server_url));
122  }
123  if (!FLAGS_ca_file.empty()) {
124  playready_key_source->SetCaFile(FLAGS_ca_file);
125  }
126  playready_key_source->FetchKeysWithProgramIdentifier(FLAGS_program_identifier);
127  encryption_key_source = std::move(playready_key_source);
128  } else {
129  LOG(ERROR) << "Error creating PlayReady key source.";
130  return std::unique_ptr<KeySource>();
131  }
132  }
133  return encryption_key_source;
134 }
135 
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());
143  if (!request_signer)
144  return std::unique_ptr<KeySource>();
145  widevine_key_source->set_signer(std::move(request_signer));
146  }
147 
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[] = "";
152  decryption_key_source = FixedKeySource::CreateFromHexStrings(
153  FLAGS_key_id, FLAGS_key, kNoPssh, kNoIv);
154  }
155  return decryption_key_source;
156 }
157 
158 bool GetMuxerOptions(MuxerOptions* muxer_options) {
159  DCHECK(muxer_options);
160 
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.";
172  }
173  muxer_options->mp4_use_decoding_timestamp_in_timeline =
174  FLAGS_mp4_use_decoding_timestamp_in_timeline;
175 
176  muxer_options->temp_dir = FLAGS_temp_dir;
177  return true;
178 }
179 
180 bool GetMpdOptions(bool on_demand_profile, MpdOptions* mpd_options) {
181  DCHECK(mpd_options);
182 
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)
187  ? MpdType::kStatic
188  : MpdType::kDynamic;
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;
196  return true;
197 }
198 
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)
204  return stream.get();
205  }
206  return nullptr;
207 }
208 MediaStream* FindFirstVideoStream(
209  const std::vector<std::unique_ptr<MediaStream>>& streams) {
210  return FindFirstStreamOfType(streams, kStreamVideo);
211 }
212 MediaStream* FindFirstAudioStream(
213  const std::vector<std::unique_ptr<MediaStream>>& streams) {
214  return FindFirstStreamOfType(streams, kStreamAudio);
215 }
216 
217 bool AddStreamToMuxer(const std::vector<std::unique_ptr<MediaStream>>& streams,
218  const std::string& stream_selector,
219  const std::string& language_override,
220  Muxer* muxer) {
221  DCHECK(muxer);
222 
223  MediaStream* stream = nullptr;
224  if (stream_selector == "video") {
225  stream = FindFirstVideoStream(streams);
226  } else if (stream_selector == "audio") {
227  stream = FindFirstAudioStream(streams);
228  } else {
229  // Expect stream_selector to be a zero based stream id.
230  size_t stream_id;
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 << "].";
236  return false;
237  }
238  stream = streams[stream_id].get();
239  DCHECK(stream);
240  }
241 
242  // This could occur only if stream_selector=audio|video and the corresponding
243  // stream does not exist in the input.
244  if (!stream) {
245  LOG(ERROR) << "No " << stream_selector << " stream found in the input.";
246  return false;
247  }
248 
249  if (!language_override.empty()) {
250  stream->info()->set_language(language_override);
251  }
252 
253  muxer->AddStream(stream);
254  return true;
255 }
256 
257 } // namespace media
258 } // namespace shaka
static RsaRequestSigner * CreateSigner(const std::string &signer_name, const std::string &pkcs1_rsa_key)
static AesRequestSigner * CreateSigner(const std::string &signer_name, const std::string &aes_key_hex, const std::string &iv_hex)
static std::unique_ptr< FixedKeySource > CreateFromHexStrings(const std::string &key_id_hex, const std::string &key_hex, const std::string &pssh_boxes_hex, const std::string &iv_hex)
void SetCaFile(const std::string &ca_file)
Sets the Certificate Authority file for validating self-signed certificates.
static bool ReadFileToString(const char *file_name, std::string *contents)
Definition: file.cc:185
static std::unique_ptr< PlayReadyKeySource > CreateFromKeyAndKeyId(const std::string &key_id_hex, const std::string &key_hex)