DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerator
mp4_media_parser.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "packager/media/formats/mp4/mp4_media_parser.h"
6 
7 #include <limits>
8 
9 #include "packager/base/callback.h"
10 #include "packager/base/callback_helpers.h"
11 #include "packager/base/logging.h"
12 #include "packager/base/memory/ref_counted.h"
13 #include "packager/base/strings/string_number_conversions.h"
14 #include "packager/media/base/aes_encryptor.h"
15 #include "packager/media/base/audio_stream_info.h"
16 #include "packager/media/base/buffer_reader.h"
17 #include "packager/media/base/decrypt_config.h"
18 #include "packager/media/base/key_source.h"
19 #include "packager/media/base/macros.h"
20 #include "packager/media/base/media_sample.h"
21 #include "packager/media/base/video_stream_info.h"
22 #include "packager/media/file/file.h"
23 #include "packager/media/file/file_closer.h"
24 #include "packager/media/filters/avc_decoder_configuration.h"
25 #include "packager/media/filters/hevc_decoder_configuration.h"
26 #include "packager/media/filters/vp_codec_configuration.h"
27 #include "packager/media/formats/mp4/box_definitions.h"
28 #include "packager/media/formats/mp4/box_reader.h"
29 #include "packager/media/formats/mp4/es_descriptor.h"
30 #include "packager/media/formats/mp4/rcheck.h"
31 #include "packager/media/formats/mp4/track_run_iterator.h"
32 
33 namespace edash_packager {
34 namespace media {
35 namespace mp4 {
36 namespace {
37 
38 uint64_t Rescale(uint64_t time_in_old_scale,
39  uint32_t old_scale,
40  uint32_t new_scale) {
41  return (static_cast<double>(time_in_old_scale) / old_scale) * new_scale;
42 }
43 
44 VideoCodec FourCCToVideoCodec(FourCC fourcc) {
45  switch (fourcc) {
46  case FOURCC_AVC1:
47  return kCodecH264;
48  case FOURCC_HEV1:
49  return kCodecHEV1;
50  case FOURCC_HVC1:
51  return kCodecHVC1;
52  case FOURCC_VP08:
53  return kCodecVP8;
54  case FOURCC_VP09:
55  return kCodecVP9;
56  case FOURCC_VP10:
57  return kCodecVP10;
58  default:
59  return kUnknownVideoCodec;
60  }
61 }
62 
63 AudioCodec FourCCToAudioCodec(FourCC fourcc) {
64  switch(fourcc) {
65  case FOURCC_DTSC:
66  return kCodecDTSC;
67  case FOURCC_DTSH:
68  return kCodecDTSH;
69  case FOURCC_DTSL:
70  return kCodecDTSL;
71  case FOURCC_DTSE:
72  return kCodecDTSE;
73  case FOURCC_DTSP:
74  return kCodecDTSP;
75  case FOURCC_DTSM:
76  return kCodecDTSM;
77  case FOURCC_AC3:
78  return kCodecAC3;
79  case FOURCC_EAC3:
80  return kCodecEAC3;
81  default:
82  return kUnknownAudioCodec;
83  }
84 }
85 
86 const char kWidevineKeySystemId[] = "edef8ba979d64acea3c827dcd51d21ed";
87 // Default DTS audio number of channels for 5.1 channel layout.
88 const uint8_t kDtsAudioNumChannels = 6;
89 
90 } // namespace
91 
92 MP4MediaParser::MP4MediaParser()
93  : state_(kWaitingForInit), moof_head_(0), mdat_tail_(0) {}
94 
95 MP4MediaParser::~MP4MediaParser() {
96  STLDeleteValues(&decryptor_map_);
97 }
98 
99 void MP4MediaParser::Init(const InitCB& init_cb,
100  const NewSampleCB& new_sample_cb,
101  KeySource* decryption_key_source) {
102  DCHECK_EQ(state_, kWaitingForInit);
103  DCHECK(init_cb_.is_null());
104  DCHECK(!init_cb.is_null());
105  DCHECK(!new_sample_cb.is_null());
106 
107  ChangeState(kParsingBoxes);
108  init_cb_ = init_cb;
109  new_sample_cb_ = new_sample_cb;
110  decryption_key_source_ = decryption_key_source;
111 }
112 
113 void MP4MediaParser::Reset() {
114  queue_.Reset();
115  runs_.reset();
116  moof_head_ = 0;
117  mdat_tail_ = 0;
118 }
119 
121  DCHECK_NE(state_, kWaitingForInit);
122  Reset();
123  ChangeState(kParsingBoxes);
124 }
125 
126 bool MP4MediaParser::Parse(const uint8_t* buf, int size) {
127  DCHECK_NE(state_, kWaitingForInit);
128 
129  if (state_ == kError)
130  return false;
131 
132  queue_.Push(buf, size);
133 
134  bool result, err = false;
135 
136  do {
137  if (state_ == kParsingBoxes) {
138  result = ParseBox(&err);
139  } else {
140  DCHECK_EQ(kEmittingSamples, state_);
141  result = EnqueueSample(&err);
142  if (result) {
143  int64_t max_clear = runs_->GetMaxClearOffset() + moof_head_;
144  err = !ReadAndDiscardMDATsUntil(max_clear);
145  }
146  }
147  } while (result && !err);
148 
149  if (err) {
150  DLOG(ERROR) << "Error while parsing MP4";
151  moov_.reset();
152  Reset();
153  ChangeState(kError);
154  return false;
155  }
156 
157  return true;
158 }
159 
160 bool MP4MediaParser::LoadMoov(const std::string& file_path) {
161  scoped_ptr<File, FileCloser> file(
162  File::OpenWithNoBuffering(file_path.c_str(), "r"));
163  if (!file) {
164  LOG(ERROR) << "Unable to open media file '" << file_path << "'";
165  return false;
166  }
167  if (!file->Seek(0)) {
168  LOG(WARNING) << "Filesystem does not support seeking on file '" << file_path
169  << "'";
170  return false;
171  }
172 
173  uint64_t file_position(0);
174  bool mdat_seen(false);
175  while (true) {
176  const uint32_t kBoxHeaderReadSize(16);
177  std::vector<uint8_t> buffer(kBoxHeaderReadSize);
178  int64_t bytes_read = file->Read(&buffer[0], kBoxHeaderReadSize);
179  if (bytes_read == 0) {
180  LOG(ERROR) << "Could not find 'moov' box in file '" << file_path << "'";
181  return false;
182  }
183  if (bytes_read < kBoxHeaderReadSize) {
184  LOG(ERROR) << "Error reading media file '" << file_path << "'";
185  return false;
186  }
187  uint64_t box_size;
188  FourCC box_type;
189  bool err;
190  if (!BoxReader::StartTopLevelBox(&buffer[0], kBoxHeaderReadSize, &box_type,
191  &box_size, &err)) {
192  LOG(ERROR) << "Could not start top level box from file '" << file_path
193  << "'";
194  return false;
195  }
196  if (box_type == FOURCC_MDAT) {
197  mdat_seen = true;
198  } else if (box_type == FOURCC_MOOV) {
199  if (!mdat_seen) {
200  // 'moov' is before 'mdat'. Nothing to do.
201  break;
202  }
203  // 'mdat' before 'moov'. Read and parse 'moov'.
204  if (!Parse(&buffer[0], bytes_read)) {
205  LOG(ERROR) << "Error parsing mp4 file '" << file_path << "'";
206  return false;
207  }
208  uint64_t bytes_to_read = box_size - bytes_read;
209  buffer.resize(bytes_to_read);
210  while (bytes_to_read > 0) {
211  bytes_read = file->Read(&buffer[0], bytes_to_read);
212  if (bytes_read <= 0) {
213  LOG(ERROR) << "Error reading 'moov' contents from file '" << file_path
214  << "'";
215  return false;
216  }
217  if (!Parse(&buffer[0], bytes_read)) {
218  LOG(ERROR) << "Error parsing mp4 file '" << file_path << "'";
219  return false;
220  }
221  bytes_to_read -= bytes_read;
222  }
223  queue_.Reset(); // So that we don't need to adjust data offsets.
224  mdat_tail_ = 0; // So it will skip boxes until mdat.
225  break; // Done.
226  }
227  file_position += box_size;
228  if (!file->Seek(file_position)) {
229  LOG(ERROR) << "Error skipping box in mp4 file '" << file_path << "'";
230  return false;
231  }
232  }
233  return true;
234 }
235 
236 bool MP4MediaParser::ParseBox(bool* err) {
237  const uint8_t* buf;
238  int size;
239  queue_.Peek(&buf, &size);
240  if (!size)
241  return false;
242 
243  scoped_ptr<BoxReader> reader(BoxReader::ReadTopLevelBox(buf, size, err));
244  if (reader.get() == NULL)
245  return false;
246 
247  if (reader->type() == FOURCC_MDAT) {
248  // The code ends up here only if a MOOV box is not yet seen.
249  DCHECK(!moov_);
250 
251  NOTIMPLEMENTED() << " Files with MDAT before MOOV is not supported yet.";
252  *err = true;
253  return false;
254  }
255 
256  // Set up mdat offset for ReadMDATsUntil().
257  mdat_tail_ = queue_.head() + reader->size();
258 
259  if (reader->type() == FOURCC_MOOV) {
260  *err = !ParseMoov(reader.get());
261  } else if (reader->type() == FOURCC_MOOF) {
262  moof_head_ = queue_.head();
263  *err = !ParseMoof(reader.get());
264 
265  // Return early to avoid evicting 'moof' data from queue. Auxiliary info may
266  // be located anywhere in the file, including inside the 'moof' itself.
267  // (Since 'default-base-is-moof' is mandated, no data references can come
268  // before the head of the 'moof', so keeping this box around is sufficient.)
269  return !(*err);
270  } else {
271  VLOG(2) << "Skipping top-level box: " << FourCCToString(reader->type());
272  }
273 
274  queue_.Pop(reader->size());
275  return !(*err);
276 }
277 
278 bool MP4MediaParser::ParseMoov(BoxReader* reader) {
279  if (moov_)
280  return true; // Already parsed the 'moov' box.
281 
282  moov_.reset(new Movie);
283  RCHECK(moov_->Parse(reader));
284  runs_.reset();
285 
286  std::vector<scoped_refptr<StreamInfo> > streams;
287 
288  for (std::vector<Track>::const_iterator track = moov_->tracks.begin();
289  track != moov_->tracks.end(); ++track) {
290  const uint32_t timescale = track->media.header.timescale;
291 
292  // Calculate duration (based on timescale).
293  uint64_t duration = 0;
294  if (track->media.header.duration > 0) {
295  duration = track->media.header.duration;
296  } else if (moov_->extends.header.fragment_duration > 0) {
297  DCHECK(moov_->header.timescale != 0);
298  duration = Rescale(moov_->extends.header.fragment_duration,
299  moov_->header.timescale,
300  timescale);
301  } else if (moov_->header.duration > 0 &&
302  moov_->header.duration != std::numeric_limits<uint64_t>::max()) {
303  DCHECK(moov_->header.timescale != 0);
304  duration =
305  Rescale(moov_->header.duration, moov_->header.timescale, timescale);
306  }
307 
308  const SampleDescription& samp_descr =
309  track->media.information.sample_table.description;
310 
311  size_t desc_idx = 0;
312 
313  // Read sample description index from mvex if it exists otherwise read
314  // from the first entry in Sample To Chunk box.
315  if (moov_->extends.tracks.size() > 0) {
316  for (size_t t = 0; t < moov_->extends.tracks.size(); t++) {
317  const TrackExtends& trex = moov_->extends.tracks[t];
318  if (trex.track_id == track->header.track_id) {
319  desc_idx = trex.default_sample_description_index;
320  break;
321  }
322  }
323  } else {
324  const std::vector<ChunkInfo>& chunk_info =
325  track->media.information.sample_table.sample_to_chunk.chunk_info;
326  RCHECK(chunk_info.size() > 0);
327  desc_idx = chunk_info[0].sample_description_index;
328  }
329  RCHECK(desc_idx > 0);
330  desc_idx -= 1; // BMFF descriptor index is one-based
331 
332  if (samp_descr.type == kAudio) {
333  RCHECK(!samp_descr.audio_entries.empty());
334 
335  // It is not uncommon to find otherwise-valid files with incorrect sample
336  // description indices, so we fail gracefully in that case.
337  if (desc_idx >= samp_descr.audio_entries.size())
338  desc_idx = 0;
339 
340  const AudioSampleEntry& entry = samp_descr.audio_entries[desc_idx];
341  const FourCC actual_format = entry.GetActualFormat();
342  AudioCodec codec = FourCCToAudioCodec(actual_format);
343  uint8_t num_channels = 0;
344  uint32_t sampling_frequency = 0;
345  uint8_t audio_object_type = 0;
346  uint32_t max_bitrate = 0;
347  uint32_t avg_bitrate = 0;
348  std::vector<uint8_t> extra_data;
349 
350  switch (actual_format) {
351  case FOURCC_MP4A:
352  // Check if it is MPEG4 AAC defined in ISO 14496 Part 3 or
353  // supported MPEG2 AAC variants.
354  if (entry.esds.es_descriptor.IsAAC()) {
355  codec = kCodecAAC;
356  const AACAudioSpecificConfig& aac_audio_specific_config =
357  entry.esds.aac_audio_specific_config;
358  num_channels = aac_audio_specific_config.num_channels();
359  sampling_frequency = aac_audio_specific_config.frequency();
360  audio_object_type = aac_audio_specific_config.audio_object_type();
361  extra_data = entry.esds.es_descriptor.decoder_specific_info();
362  break;
363  } else if (entry.esds.es_descriptor.IsDTS()) {
364  ObjectType audio_type = entry.esds.es_descriptor.object_type();
365  switch (audio_type) {
366  case kDTSC:
367  codec = kCodecDTSC;
368  break;
369  case kDTSE:
370  codec = kCodecDTSE;
371  break;
372  case kDTSH:
373  codec = kCodecDTSH;
374  break;
375  case kDTSL:
376  codec = kCodecDTSL;
377  break;
378  default:
379  LOG(ERROR) << "Unsupported audio type " << audio_type
380  << " in stsd box.";
381  return false;
382  }
383  num_channels = entry.esds.aac_audio_specific_config.num_channels();
384  // For dts audio in esds, current supported number of channels is 6
385  // as the only supported channel layout is 5.1.
386  if (num_channels != kDtsAudioNumChannels) {
387  LOG(ERROR) << "Unsupported channel count " << num_channels
388  << " for audio type " << audio_type << ".";
389  return false;
390  }
391  sampling_frequency = entry.samplerate;
392  max_bitrate = entry.esds.es_descriptor.max_bitrate();
393  avg_bitrate = entry.esds.es_descriptor.avg_bitrate();
394  } else {
395  LOG(ERROR) << "Unsupported audio format 0x" << std::hex
396  << actual_format << " in stsd box.";
397  return false;
398  }
399  break;
400  case FOURCC_DTSC:
401  FALLTHROUGH_INTENDED;
402  case FOURCC_DTSH:
403  FALLTHROUGH_INTENDED;
404  case FOURCC_DTSL:
405  FALLTHROUGH_INTENDED;
406  case FOURCC_DTSE:
407  FALLTHROUGH_INTENDED;
408  case FOURCC_DTSM:
409  extra_data = entry.ddts.extra_data;
410  max_bitrate = entry.ddts.max_bitrate;
411  avg_bitrate = entry.ddts.avg_bitrate;
412  num_channels = entry.channelcount;
413  sampling_frequency = entry.samplerate;
414  break;
415  case FOURCC_AC3:
416  extra_data = entry.dac3.data;
417  num_channels = entry.channelcount;
418  sampling_frequency = entry.samplerate;
419  break;
420  case FOURCC_EAC3:
421  extra_data = entry.dec3.data;
422  num_channels = entry.channelcount;
423  sampling_frequency = entry.samplerate;
424  break;
425  default:
426  LOG(ERROR) << "Unsupported audio format 0x" << std::hex
427  << actual_format << " in stsd box.";
428  return false;
429  }
430 
431  bool is_encrypted = entry.sinf.info.track_encryption.is_encrypted;
432  DVLOG(1) << "is_audio_track_encrypted_: " << is_encrypted;
433  streams.push_back(new AudioStreamInfo(
434  track->header.track_id,
435  timescale,
436  duration,
437  codec,
438  AudioStreamInfo::GetCodecString(codec, audio_object_type),
439  track->media.header.language.code,
440  entry.samplesize,
441  num_channels,
442  sampling_frequency,
443  max_bitrate,
444  avg_bitrate,
445  vector_as_array(&extra_data),
446  extra_data.size(),
447  is_encrypted));
448  }
449 
450  if (samp_descr.type == kVideo) {
451  RCHECK(!samp_descr.video_entries.empty());
452  if (desc_idx >= samp_descr.video_entries.size())
453  desc_idx = 0;
454  const VideoSampleEntry& entry = samp_descr.video_entries[desc_idx];
455 
456  uint32_t coded_width = entry.width;
457  uint32_t coded_height = entry.height;
458  uint32_t pixel_width = entry.pixel_aspect.h_spacing;
459  uint32_t pixel_height = entry.pixel_aspect.v_spacing;
460  if (pixel_width == 0 && pixel_height == 0) {
461  pixel_width = 1;
462  pixel_height = 1;
463  }
464  std::string codec_string;
465  uint8_t nalu_length_size = 0;
466 
467  const FourCC actual_format = entry.GetActualFormat();
468  const VideoCodec video_codec = FourCCToVideoCodec(actual_format);
469  switch (actual_format) {
470  case FOURCC_AVC1: {
471  AVCDecoderConfiguration avc_config;
472  if (!avc_config.Parse(entry.codec_config_record.data)) {
473  LOG(ERROR) << "Failed to parse avcc.";
474  return false;
475  }
476  codec_string = avc_config.GetCodecString();
477  nalu_length_size = avc_config.length_size();
478 
479  if (coded_width != avc_config.coded_width() ||
480  coded_height != avc_config.coded_height()) {
481  LOG(WARNING) << "Resolution in VisualSampleEntry (" << coded_width
482  << "," << coded_height
483  << ") does not match with resolution in "
484  "AVCDecoderConfigurationRecord ("
485  << avc_config.coded_width() << ","
486  << avc_config.coded_height()
487  << "). Use AVCDecoderConfigurationRecord.";
488  coded_width = avc_config.coded_width();
489  coded_height = avc_config.coded_height();
490  }
491 
492  if (pixel_width != avc_config.pixel_width() ||
493  pixel_height != avc_config.pixel_height()) {
494  LOG_IF(WARNING, pixel_width != 1 || pixel_height != 1)
495  << "Pixel aspect ratio in PASP box (" << pixel_width << ","
496  << pixel_height
497  << ") does not match with SAR in AVCDecoderConfigurationRecord "
498  "("
499  << avc_config.pixel_width() << "," << avc_config.pixel_height()
500  << "). Use AVCDecoderConfigurationRecord.";
501  pixel_width = avc_config.pixel_width();
502  pixel_height = avc_config.pixel_height();
503  }
504  break;
505  }
506  case FOURCC_HEV1:
507  case FOURCC_HVC1: {
508  HEVCDecoderConfiguration hevc_config;
509  if (!hevc_config.Parse(entry.codec_config_record.data)) {
510  LOG(ERROR) << "Failed to parse hevc.";
511  return false;
512  }
513  codec_string = hevc_config.GetCodecString(video_codec);
514  nalu_length_size = hevc_config.length_size();
515  break;
516  }
517  case FOURCC_VP08:
518  case FOURCC_VP09:
519  case FOURCC_VP10: {
520  VPCodecConfiguration vp_config;
521  if (!vp_config.Parse(entry.codec_config_record.data)) {
522  LOG(ERROR) << "Failed to parse vpcc.";
523  return false;
524  }
525  codec_string = vp_config.GetCodecString(video_codec);
526  break;
527  }
528  default:
529  LOG(ERROR) << "Unsupported video format "
530  << FourCCToString(actual_format) << " in stsd box.";
531  return false;
532  }
533 
534  bool is_encrypted = entry.sinf.info.track_encryption.is_encrypted;
535  DVLOG(1) << "is_video_track_encrypted_: " << is_encrypted;
536  streams.push_back(new VideoStreamInfo(
537  track->header.track_id, timescale, duration, video_codec,
538  codec_string, track->media.header.language.code, coded_width,
539  coded_height, pixel_width, pixel_height,
540  0, // trick_play_rate
541  nalu_length_size, vector_as_array(&entry.codec_config_record.data),
542  entry.codec_config_record.data.size(), is_encrypted));
543  }
544  }
545 
546  init_cb_.Run(streams);
547  if (!FetchKeysIfNecessary(moov_->pssh))
548  return false;
549  runs_.reset(new TrackRunIterator(moov_.get()));
550  RCHECK(runs_->Init());
551  ChangeState(kEmittingSamples);
552  return true;
553 }
554 
555 bool MP4MediaParser::ParseMoof(BoxReader* reader) {
556  // Must already have initialization segment.
557  RCHECK(moov_.get());
558  MovieFragment moof;
559  RCHECK(moof.Parse(reader));
560  if (!runs_)
561  runs_.reset(new TrackRunIterator(moov_.get()));
562  RCHECK(runs_->Init(moof));
563  if (!FetchKeysIfNecessary(moof.pssh))
564  return false;
565  ChangeState(kEmittingSamples);
566  return true;
567 }
568 
569 bool MP4MediaParser::FetchKeysIfNecessary(
570  const std::vector<ProtectionSystemSpecificHeader>& headers) {
571  if (headers.empty())
572  return true;
573 
574  // An error will be returned later if the samples need to be decrypted.
575  if (!decryption_key_source_)
576  return true;
577 
578  // TODO(tinskip): Pass in raw 'pssh' boxes to FetchKeys. This will allow
579  // supporting multiple keysystems. Move this to KeySource.
580  std::vector<uint8_t> widevine_system_id;
581  base::HexStringToBytes(kWidevineKeySystemId, &widevine_system_id);
582  for (std::vector<ProtectionSystemSpecificHeader>::const_iterator iter =
583  headers.begin(); iter != headers.end(); ++iter) {
584  if (iter->system_id == widevine_system_id) {
585  Status status = decryption_key_source_->FetchKeys(iter->data);
586  if (!status.ok()) {
587  LOG(ERROR) << "Error fetching decryption keys: " << status;
588  return false;
589  }
590  return true;
591  }
592  }
593 
594  LOG(ERROR) << "No viable 'pssh' box found for content decryption.";
595  return false;
596 }
597 
598 bool MP4MediaParser::EnqueueSample(bool* err) {
599  if (!runs_->IsRunValid()) {
600  // Remain in kEnqueueingSamples state, discarding data, until the end of
601  // the current 'mdat' box has been appended to the queue.
602  if (!queue_.Trim(mdat_tail_))
603  return false;
604 
605  ChangeState(kParsingBoxes);
606  return true;
607  }
608 
609  if (!runs_->IsSampleValid()) {
610  runs_->AdvanceRun();
611  return true;
612  }
613 
614  DCHECK(!(*err));
615 
616  const uint8_t* buf;
617  int buf_size;
618  queue_.Peek(&buf, &buf_size);
619  if (!buf_size)
620  return false;
621 
622  // Skip this entire track if it is not audio nor video.
623  if (!runs_->is_audio() && !runs_->is_video())
624  runs_->AdvanceRun();
625 
626  // Attempt to cache the auxiliary information first. Aux info is usually
627  // placed in a contiguous block before the sample data, rather than being
628  // interleaved. If we didn't cache it, this would require that we retain the
629  // start of the segment buffer while reading samples. Aux info is typically
630  // quite small compared to sample data, so this pattern is useful on
631  // memory-constrained devices where the source buffer consumes a substantial
632  // portion of the total system memory.
633  if (runs_->AuxInfoNeedsToBeCached()) {
634  queue_.PeekAt(runs_->aux_info_offset() + moof_head_, &buf, &buf_size);
635  if (buf_size < runs_->aux_info_size())
636  return false;
637  *err = !runs_->CacheAuxInfo(buf, buf_size);
638  return !*err;
639  }
640 
641  int64_t sample_offset = runs_->sample_offset() + moof_head_;
642  queue_.PeekAt(sample_offset, &buf, &buf_size);
643  if (buf_size < runs_->sample_size()) {
644  if (sample_offset < queue_.head()) {
645  LOG(ERROR) << "Incorrect sample offset " << sample_offset
646  << " < " << queue_.head();
647  *err = true;
648  }
649  return false;
650  }
651 
652  scoped_refptr<MediaSample> stream_sample(MediaSample::CopyFrom(
653  buf, runs_->sample_size(), runs_->is_keyframe()));
654  if (runs_->is_encrypted()) {
655  scoped_ptr<DecryptConfig> decrypt_config = runs_->GetDecryptConfig();
656  if (!decrypt_config ||
657  !DecryptSampleBuffer(decrypt_config.get(),
658  stream_sample->writable_data(),
659  stream_sample->data_size())) {
660  *err = true;
661  LOG(ERROR) << "Cannot decrypt samples.";
662  return false;
663  }
664  }
665 
666  stream_sample->set_dts(runs_->dts());
667  stream_sample->set_pts(runs_->cts());
668  stream_sample->set_duration(runs_->duration());
669 
670  DVLOG(3) << "Pushing frame: "
671  << ", key=" << runs_->is_keyframe()
672  << ", dur=" << runs_->duration()
673  << ", dts=" << runs_->dts()
674  << ", cts=" << runs_->cts()
675  << ", size=" << runs_->sample_size();
676 
677  if (!new_sample_cb_.Run(runs_->track_id(), stream_sample)) {
678  *err = true;
679  LOG(ERROR) << "Failed to process the sample.";
680  return false;
681  }
682 
683  runs_->AdvanceSample();
684  return true;
685 }
686 
687 bool MP4MediaParser::DecryptSampleBuffer(const DecryptConfig* decrypt_config,
688  uint8_t* buffer,
689  size_t buffer_size) {
690  DCHECK(decrypt_config);
691  DCHECK(buffer);
692 
693  if (!decryption_key_source_) {
694  LOG(ERROR) << "Encrypted media sample encountered, but decryption is not "
695  "enabled";
696  return false;
697  }
698 
699  // Get the encryptor object.
700  AesCtrEncryptor* encryptor;
701  DecryptorMap::iterator found = decryptor_map_.find(decrypt_config->key_id());
702  if (found == decryptor_map_.end()) {
703  // Create new AesCtrEncryptor
704  EncryptionKey key;
705  Status status(decryption_key_source_->GetKey(decrypt_config->key_id(),
706  &key));
707  if (!status.ok()) {
708  LOG(ERROR) << "Error retrieving decryption key: " << status;
709  return false;
710  }
711  scoped_ptr<AesCtrEncryptor> new_encryptor(new AesCtrEncryptor);
712  if (!new_encryptor->InitializeWithIv(key.key, decrypt_config->iv())) {
713  LOG(ERROR) << "Failed to initialize AesCtrEncryptor for decryption.";
714  return false;
715  }
716  encryptor = new_encryptor.release();
717  decryptor_map_[decrypt_config->key_id()] = encryptor;
718  } else {
719  encryptor = found->second;
720  }
721  if (!encryptor->SetIv(decrypt_config->iv())) {
722  LOG(ERROR) << "Invalid initialization vector.";
723  return false;
724  }
725 
726  if (decrypt_config->subsamples().empty()) {
727  // Sample not encrypted using subsample encryption. Decrypt whole.
728  if (!encryptor->Decrypt(buffer, buffer_size, buffer)) {
729  LOG(ERROR) << "Error during bulk sample decryption.";
730  return false;
731  }
732  return true;
733  }
734 
735  // Subsample decryption.
736  const std::vector<SubsampleEntry>& subsamples = decrypt_config->subsamples();
737  uint8_t* current_ptr = buffer;
738  const uint8_t* buffer_end = buffer + buffer_size;
739  current_ptr += decrypt_config->data_offset();
740  if (current_ptr > buffer_end) {
741  LOG(ERROR) << "Subsample data_offset too large.";
742  return false;
743  }
744  for (std::vector<SubsampleEntry>::const_iterator iter = subsamples.begin();
745  iter != subsamples.end();
746  ++iter) {
747  if ((current_ptr + iter->clear_bytes + iter->cipher_bytes) > buffer_end) {
748  LOG(ERROR) << "Subsamples overflow sample buffer.";
749  return false;
750  }
751  current_ptr += iter->clear_bytes;
752  if (!encryptor->Decrypt(current_ptr, iter->cipher_bytes, current_ptr)) {
753  LOG(ERROR) << "Error decrypting subsample buffer.";
754  return false;
755  }
756  current_ptr += iter->cipher_bytes;
757  }
758  return true;
759 }
760 
761 bool MP4MediaParser::ReadAndDiscardMDATsUntil(const int64_t offset) {
762  bool err = false;
763  while (mdat_tail_ < offset) {
764  const uint8_t* buf;
765  int size;
766  queue_.PeekAt(mdat_tail_, &buf, &size);
767 
768  FourCC type;
769  uint64_t box_sz;
770  if (!BoxReader::StartTopLevelBox(buf, size, &type, &box_sz, &err))
771  break;
772 
773  mdat_tail_ += box_sz;
774  }
775  queue_.Trim(std::min(mdat_tail_, offset));
776  return !err;
777 }
778 
779 void MP4MediaParser::ChangeState(State new_state) {
780  DVLOG(2) << "Changing state: " << new_state;
781  state_ = new_state;
782 }
783 
784 } // namespace mp4
785 } // namespace media
786 } // namespace edash_packager
static BoxReader * ReadTopLevelBox(const uint8_t *buf, const size_t buf_size, bool *err)
Definition: box_reader.cc:37
virtual Status GetKey(TrackType track_type, EncryptionKey *key)
Definition: key_source.cc:46
bool Parse(const uint8_t *buf, int size) override
static scoped_refptr< MediaSample > CopyFrom(const uint8_t *data, size_t size, bool is_key_frame)
Definition: media_sample.cc:45
void PeekAt(int64_t offset, const uint8_t **buf, int *size)
bool LoadMoov(const std::string &file_path)
virtual Status FetchKeys(const std::vector< uint8_t > &content_id, const std::string &policy)
Definition: key_source.cc:30
KeySource is responsible for encryption key acquisition.
Definition: key_source.h:29
static bool StartTopLevelBox(const uint8_t *buf, const size_t buf_size, FourCC *type, uint64_t *box_size, bool *err) WARN_UNUSED_RESULT
Definition: box_reader.cc:60
void Init(const InitCB &init_cb, const NewSampleCB &new_sample_cb, KeySource *decryption_key_source) override
static File * OpenWithNoBuffering(const char *file_name, const char *mode)
Definition: file.cc:151
static std::string GetCodecString(AudioCodec codec, uint8_t audio_object_type)