DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs 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/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/media_stream.h"
19 #include "packager/media/base/muxer.h"
20 #include "packager/media/base/muxer_options.h"
21 #include "packager/media/base/request_signer.h"
22 #include "packager/media/base/stream_info.h"
23 #include "packager/media/base/widevine_key_source.h"
24 #include "packager/media/file/file.h"
25 #include "packager/mpd/base/mpd_builder.h"
26 
27 DEFINE_bool(dump_stream_info, false, "Dump demuxed stream info.");
28 DEFINE_bool(override_version_string,
29  false,
30  "Override packager version string in the generated outputs with "
31  "--test_version_string if it is set to true. Should be used for "
32  "testing only.");
33 DEFINE_string(test_version_string,
34  "",
35  "Packager version string for testing. Ignored if "
36  "--override_version_string is false. Should be used for testing "
37  "only.");
38 
39 namespace edash_packager {
40 namespace media {
41 
42 void DumpStreamInfo(const std::vector<MediaStream*>& streams) {
43  printf("Found %zu stream(s).\n", streams.size());
44  for (size_t i = 0; i < streams.size(); ++i)
45  printf("Stream [%zu] %s\n", i, streams[i]->info()->ToString().c_str());
46 }
47 
48 scoped_ptr<RequestSigner> CreateSigner() {
49  scoped_ptr<RequestSigner> signer;
50 
51  if (!FLAGS_aes_signing_key.empty()) {
52  signer.reset(AesRequestSigner::CreateSigner(
53  FLAGS_signer, FLAGS_aes_signing_key, FLAGS_aes_signing_iv));
54  if (!signer) {
55  LOG(ERROR) << "Cannot create an AES signer object from '"
56  << FLAGS_aes_signing_key << "':'" << FLAGS_aes_signing_iv
57  << "'.";
58  return scoped_ptr<RequestSigner>();
59  }
60  } else if (!FLAGS_rsa_signing_key_path.empty()) {
61  std::string rsa_private_key;
62  if (!File::ReadFileToString(FLAGS_rsa_signing_key_path.c_str(),
63  &rsa_private_key)) {
64  LOG(ERROR) << "Failed to read from '" << FLAGS_rsa_signing_key_path
65  << "'.";
66  return scoped_ptr<RequestSigner>();
67  }
68  signer.reset(RsaRequestSigner::CreateSigner(FLAGS_signer, rsa_private_key));
69  if (!signer) {
70  LOG(ERROR) << "Cannot create a RSA signer object from '"
71  << FLAGS_rsa_signing_key_path << "'.";
72  return scoped_ptr<RequestSigner>();
73  }
74  }
75  return signer.Pass();
76 }
77 
78 scoped_ptr<KeySource> CreateEncryptionKeySource() {
79  scoped_ptr<KeySource> encryption_key_source;
80  if (FLAGS_enable_widevine_encryption) {
81  scoped_ptr<WidevineKeySource> widevine_key_source(
82  new WidevineKeySource(FLAGS_key_server_url));
83  if (!FLAGS_signer.empty()) {
84  scoped_ptr<RequestSigner> request_signer(CreateSigner());
85  if (!request_signer)
86  return scoped_ptr<KeySource>();
87  widevine_key_source->set_signer(request_signer.Pass());
88  }
89 
90  std::vector<uint8_t> content_id;
91  if (!base::HexStringToBytes(FLAGS_content_id, &content_id)) {
92  LOG(ERROR) << "Invalid content_id hex string specified.";
93  return scoped_ptr<KeySource>();
94  }
95  Status status = widevine_key_source->FetchKeys(content_id, FLAGS_policy);
96  if (!status.ok()) {
97  LOG(ERROR) << "Widevine encryption key source failed to fetch keys: "
98  << status.ToString();
99  return scoped_ptr<KeySource>();
100  }
101  encryption_key_source = widevine_key_source.Pass();
102  } else if (FLAGS_enable_fixed_key_encryption) {
103  encryption_key_source = KeySource::CreateFromHexStrings(
104  FLAGS_key_id, FLAGS_key, FLAGS_pssh, FLAGS_iv);
105  }
106  return encryption_key_source.Pass();
107 }
108 
109 scoped_ptr<KeySource> CreateDecryptionKeySource() {
110  scoped_ptr<KeySource> decryption_key_source;
111  if (FLAGS_enable_widevine_decryption) {
112  scoped_ptr<WidevineKeySource> widevine_key_source(
113  new WidevineKeySource(FLAGS_key_server_url));
114  if (!FLAGS_signer.empty()) {
115  scoped_ptr<RequestSigner> request_signer(CreateSigner());
116  if (!request_signer)
117  return scoped_ptr<KeySource>();
118  widevine_key_source->set_signer(request_signer.Pass());
119  }
120 
121  decryption_key_source = widevine_key_source.Pass();
122  } else if (FLAGS_enable_fixed_key_decryption) {
123  decryption_key_source =
124  KeySource::CreateFromHexStrings(FLAGS_key_id, FLAGS_key, "", "");
125  }
126  return decryption_key_source.Pass();
127 }
128 
129 bool AssignFlagsFromProfile() {
130  bool single_segment = FLAGS_single_segment;
131  if (FLAGS_profile == "on-demand") {
132  single_segment = true;
133  } else if (FLAGS_profile == "live") {
134  single_segment = false;
135  } else if (FLAGS_profile != "") {
136  fprintf(stderr, "ERROR: --profile '%s' is not supported.\n",
137  FLAGS_profile.c_str());
138  return false;
139  }
140 
141  if (FLAGS_single_segment != single_segment) {
142  FLAGS_single_segment = single_segment;
143  fprintf(stdout, "Profile %s: set --single_segment to %s.\n",
144  FLAGS_profile.c_str(), single_segment ? "true" : "false");
145  }
146  return true;
147 }
148 
149 bool GetMuxerOptions(MuxerOptions* muxer_options) {
150  DCHECK(muxer_options);
151 
152  muxer_options->single_segment = FLAGS_single_segment;
153  muxer_options->segment_duration = FLAGS_segment_duration;
154  muxer_options->fragment_duration = FLAGS_fragment_duration;
155  muxer_options->segment_sap_aligned = FLAGS_segment_sap_aligned;
156  muxer_options->fragment_sap_aligned = FLAGS_fragment_sap_aligned;
157  muxer_options->num_subsegments_per_sidx = FLAGS_num_subsegments_per_sidx;
158  muxer_options->temp_dir = FLAGS_temp_dir;
159  if (FLAGS_override_version_string)
160  muxer_options->packager_version_string = FLAGS_test_version_string;
161  return true;
162 }
163 
164 bool GetMpdOptions(MpdOptions* mpd_options) {
165  DCHECK(mpd_options);
166 
167  mpd_options->availability_time_offset = FLAGS_availability_time_offset;
168  mpd_options->minimum_update_period = FLAGS_minimum_update_period;
169  mpd_options->min_buffer_time = FLAGS_min_buffer_time;
170  mpd_options->time_shift_buffer_depth = FLAGS_time_shift_buffer_depth;
171  mpd_options->suggested_presentation_delay =
172  FLAGS_suggested_presentation_delay;
173  if (FLAGS_override_version_string)
174  mpd_options->packager_version_string = FLAGS_test_version_string;
175  return true;
176 }
177 
178 MediaStream* FindFirstStreamOfType(const std::vector<MediaStream*>& streams,
179  StreamType stream_type) {
180  typedef std::vector<MediaStream*>::const_iterator StreamIterator;
181  for (StreamIterator it = streams.begin(); it != streams.end(); ++it) {
182  if ((*it)->info()->stream_type() == stream_type)
183  return *it;
184  }
185  return NULL;
186 }
187 MediaStream* FindFirstVideoStream(const std::vector<MediaStream*>& streams) {
188  return FindFirstStreamOfType(streams, kStreamVideo);
189 }
190 MediaStream* FindFirstAudioStream(const std::vector<MediaStream*>& streams) {
191  return FindFirstStreamOfType(streams, kStreamAudio);
192 }
193 
194 bool AddStreamToMuxer(const std::vector<MediaStream*>& streams,
195  const std::string& stream_selector,
196  const std::string& language_override,
197  Muxer* muxer) {
198  DCHECK(muxer);
199 
200  MediaStream* stream = NULL;
201  if (stream_selector == "video") {
202  stream = FindFirstVideoStream(streams);
203  } else if (stream_selector == "audio") {
204  stream = FindFirstAudioStream(streams);
205  } else {
206  // Expect stream_selector to be a zero based stream id.
207  size_t stream_id;
208  if (!base::StringToSizeT(stream_selector, &stream_id) ||
209  stream_id >= streams.size()) {
210  LOG(ERROR) << "Invalid argument --stream=" << stream_selector << "; "
211  << "should be 'audio', 'video', or a number within [0, "
212  << streams.size() - 1 << "].";
213  return false;
214  }
215  stream = streams[stream_id];
216  DCHECK(stream);
217  }
218 
219  // This could occur only if stream_selector=audio|video and the corresponding
220  // stream does not exist in the input.
221  if (!stream) {
222  LOG(ERROR) << "No " << stream_selector << " stream found in the input.";
223  return false;
224  }
225 
226  if (!language_override.empty()) {
227  stream->info()->set_language(language_override);
228  }
229 
230  muxer->AddStream(stream);
231  return true;
232 }
233 
234 } // namespace media
235 } // namespace edash_packager
static bool ReadFileToString(const char *file_name, std::string *contents)
Definition: file.cc:184
static AesRequestSigner * CreateSigner(const std::string &signer_name, const std::string &aes_key_hex, const std::string &iv_hex)
static RsaRequestSigner * CreateSigner(const std::string &signer_name, const std::string &pkcs1_rsa_key)
static scoped_ptr< KeySource > CreateFromHexStrings(const std::string &key_id_hex, const std::string &key_hex, const std::string &pssh_data_hex, const std::string &iv_hex)
Definition: key_source.cc:100