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