DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations 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 <algorithm>
8 #include <limits>
9 
10 #include "packager/base/callback.h"
11 #include "packager/base/callback_helpers.h"
12 #include "packager/base/logging.h"
13 #include "packager/base/strings/string_number_conversions.h"
14 #include "packager/media/base/audio_stream_info.h"
15 #include "packager/media/base/buffer_reader.h"
16 #include "packager/media/base/decrypt_config.h"
17 #include "packager/media/base/key_source.h"
18 #include "packager/media/base/macros.h"
19 #include "packager/media/base/media_sample.h"
20 #include "packager/media/base/rcheck.h"
21 #include "packager/media/base/video_stream_info.h"
22 #include "packager/media/codecs/avc_decoder_configuration_record.h"
23 #include "packager/media/codecs/es_descriptor.h"
24 #include "packager/media/codecs/hevc_decoder_configuration_record.h"
25 #include "packager/media/codecs/vp_codec_configuration_record.h"
26 #include "packager/media/file/file.h"
27 #include "packager/media/file/file_closer.h"
28 #include "packager/media/formats/mp4/box_definitions.h"
29 #include "packager/media/formats/mp4/box_reader.h"
30 #include "packager/media/formats/mp4/track_run_iterator.h"
31 
32 namespace shaka {
33 namespace media {
34 namespace mp4 {
35 namespace {
36 
37 uint64_t Rescale(uint64_t time_in_old_scale,
38  uint32_t old_scale,
39  uint32_t new_scale) {
40  return (static_cast<double>(time_in_old_scale) / old_scale) * new_scale;
41 }
42 
43 Codec FourCCToCodec(FourCC fourcc) {
44  switch (fourcc) {
45  case FOURCC_avc1:
46  return kCodecH264;
47  case FOURCC_hev1:
48  return kCodecHEV1;
49  case FOURCC_hvc1:
50  return kCodecHVC1;
51  case FOURCC_vp08:
52  return kCodecVP8;
53  case FOURCC_vp09:
54  return kCodecVP9;
55  case FOURCC_vp10:
56  return kCodecVP10;
57  case FOURCC_Opus:
58  return kCodecOpus;
59  case FOURCC_dtsc:
60  return kCodecDTSC;
61  case FOURCC_dtsh:
62  return kCodecDTSH;
63  case FOURCC_dtsl:
64  return kCodecDTSL;
65  case FOURCC_dtse:
66  return kCodecDTSE;
67  case FOURCC_dtsp:
68  return kCodecDTSP;
69  case FOURCC_dtsm:
70  return kCodecDTSM;
71  case FOURCC_ac_3:
72  return kCodecAC3;
73  case FOURCC_ec_3:
74  return kCodecEAC3;
75  default:
76  return kUnknownCodec;
77  }
78 }
79 
80 // Default DTS audio number of channels for 5.1 channel layout.
81 const uint8_t kDtsAudioNumChannels = 6;
82 const uint64_t kNanosecondsPerSecond = 1000000000ull;
83 
84 } // namespace
85 
86 MP4MediaParser::MP4MediaParser()
87  : state_(kWaitingForInit),
88  decryption_key_source_(NULL),
89  moof_head_(0),
90  mdat_tail_(0) {}
91 
92 MP4MediaParser::~MP4MediaParser() {}
93 
94 void MP4MediaParser::Init(const InitCB& init_cb,
95  const NewSampleCB& new_sample_cb,
96  KeySource* decryption_key_source) {
97  DCHECK_EQ(state_, kWaitingForInit);
98  DCHECK(init_cb_.is_null());
99  DCHECK(!init_cb.is_null());
100  DCHECK(!new_sample_cb.is_null());
101 
102  ChangeState(kParsingBoxes);
103  init_cb_ = init_cb;
104  new_sample_cb_ = new_sample_cb;
105  decryption_key_source_ = decryption_key_source;
106  if (decryption_key_source)
107  decryptor_source_.reset(new DecryptorSource(decryption_key_source));
108 }
109 
110 void MP4MediaParser::Reset() {
111  queue_.Reset();
112  runs_.reset();
113  moof_head_ = 0;
114  mdat_tail_ = 0;
115 }
116 
118  DCHECK_NE(state_, kWaitingForInit);
119  Reset();
120  ChangeState(kParsingBoxes);
121  return true;
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  std::unique_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::StartBox(&buffer[0], kBoxHeaderReadSize, &box_type,
189  &box_size, &err)) {
190  LOG(ERROR) << "Could not start box from file '" << file_path << "'";
191  return false;
192  }
193  if (box_type == FOURCC_mdat) {
194  mdat_seen = true;
195  } else if (box_type == FOURCC_moov) {
196  if (!mdat_seen) {
197  // 'moov' is before 'mdat'. Nothing to do.
198  break;
199  }
200  // 'mdat' before 'moov'. Read and parse 'moov'.
201  if (!Parse(&buffer[0], bytes_read)) {
202  LOG(ERROR) << "Error parsing mp4 file '" << file_path << "'";
203  return false;
204  }
205  uint64_t bytes_to_read = box_size - bytes_read;
206  buffer.resize(bytes_to_read);
207  while (bytes_to_read > 0) {
208  bytes_read = file->Read(&buffer[0], bytes_to_read);
209  if (bytes_read <= 0) {
210  LOG(ERROR) << "Error reading 'moov' contents from file '" << file_path
211  << "'";
212  return false;
213  }
214  if (!Parse(&buffer[0], bytes_read)) {
215  LOG(ERROR) << "Error parsing mp4 file '" << file_path << "'";
216  return false;
217  }
218  bytes_to_read -= bytes_read;
219  }
220  queue_.Reset(); // So that we don't need to adjust data offsets.
221  mdat_tail_ = 0; // So it will skip boxes until mdat.
222  break; // Done.
223  }
224  file_position += box_size;
225  if (!file->Seek(file_position)) {
226  LOG(ERROR) << "Error skipping box in mp4 file '" << file_path << "'";
227  return false;
228  }
229  }
230  return true;
231 }
232 
233 bool MP4MediaParser::ParseBox(bool* err) {
234  const uint8_t* buf;
235  int size;
236  queue_.Peek(&buf, &size);
237  if (!size)
238  return false;
239 
240  std::unique_ptr<BoxReader> reader(BoxReader::ReadBox(buf, size, err));
241  if (reader.get() == NULL)
242  return false;
243 
244  if (reader->type() == FOURCC_mdat) {
245  // The code ends up here only if a MOOV box is not yet seen.
246  DCHECK(!moov_);
247 
248  NOTIMPLEMENTED() << " Files with MDAT before MOOV is not supported yet.";
249  *err = true;
250  return false;
251  }
252 
253  // Set up mdat offset for ReadMDATsUntil().
254  mdat_tail_ = queue_.head() + reader->size();
255 
256  if (reader->type() == FOURCC_moov) {
257  *err = !ParseMoov(reader.get());
258  } else if (reader->type() == FOURCC_moof) {
259  moof_head_ = queue_.head();
260  *err = !ParseMoof(reader.get());
261 
262  // Return early to avoid evicting 'moof' data from queue. Auxiliary info may
263  // be located anywhere in the file, including inside the 'moof' itself.
264  // (Since 'default-base-is-moof' is mandated, no data references can come
265  // before the head of the 'moof', so keeping this box around is sufficient.)
266  return !(*err);
267  } else {
268  VLOG(2) << "Skipping top-level box: " << FourCCToString(reader->type());
269  }
270 
271  queue_.Pop(static_cast<int>(reader->size()));
272  return !(*err);
273 }
274 
275 bool MP4MediaParser::ParseMoov(BoxReader* reader) {
276  if (moov_)
277  return true; // Already parsed the 'moov' box.
278 
279  moov_.reset(new Movie);
280  RCHECK(moov_->Parse(reader));
281  runs_.reset();
282 
283  std::vector<std::shared_ptr<StreamInfo>> streams;
284 
285  for (std::vector<Track>::const_iterator track = moov_->tracks.begin();
286  track != moov_->tracks.end(); ++track) {
287  const uint32_t timescale = track->media.header.timescale;
288 
289  // Calculate duration (based on timescale).
290  uint64_t duration = 0;
291  if (track->media.header.duration > 0) {
292  duration = track->media.header.duration;
293  } else if (moov_->extends.header.fragment_duration > 0) {
294  DCHECK(moov_->header.timescale != 0);
295  duration = Rescale(moov_->extends.header.fragment_duration,
296  moov_->header.timescale,
297  timescale);
298  } else if (moov_->header.duration > 0 &&
299  moov_->header.duration != std::numeric_limits<uint64_t>::max()) {
300  DCHECK(moov_->header.timescale != 0);
301  duration =
302  Rescale(moov_->header.duration, moov_->header.timescale, timescale);
303  }
304 
305  const SampleDescription& samp_descr =
306  track->media.information.sample_table.description;
307 
308  size_t desc_idx = 0;
309 
310  // Read sample description index from mvex if it exists otherwise read
311  // from the first entry in Sample To Chunk box.
312  if (moov_->extends.tracks.size() > 0) {
313  for (size_t t = 0; t < moov_->extends.tracks.size(); t++) {
314  const TrackExtends& trex = moov_->extends.tracks[t];
315  if (trex.track_id == track->header.track_id) {
316  desc_idx = trex.default_sample_description_index;
317  break;
318  }
319  }
320  } else {
321  const std::vector<ChunkInfo>& chunk_info =
322  track->media.information.sample_table.sample_to_chunk.chunk_info;
323  RCHECK(chunk_info.size() > 0);
324  desc_idx = chunk_info[0].sample_description_index;
325  }
326  RCHECK(desc_idx > 0);
327  desc_idx -= 1; // BMFF descriptor index is one-based
328 
329  if (samp_descr.type == kAudio) {
330  RCHECK(!samp_descr.audio_entries.empty());
331 
332  // It is not uncommon to find otherwise-valid files with incorrect sample
333  // description indices, so we fail gracefully in that case.
334  if (desc_idx >= samp_descr.audio_entries.size())
335  desc_idx = 0;
336 
337  const AudioSampleEntry& entry = samp_descr.audio_entries[desc_idx];
338  const FourCC actual_format = entry.GetActualFormat();
339  Codec codec = FourCCToCodec(actual_format);
340  uint8_t num_channels = 0;
341  uint32_t sampling_frequency = 0;
342  uint64_t codec_delay_ns = 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> codec_config;
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  codec_config = 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  codec_config = 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_ac_3:
414  codec_config = entry.dac3.data;
415  num_channels = entry.channelcount;
416  sampling_frequency = entry.samplerate;
417  break;
418  case FOURCC_ec_3:
419  codec_config = entry.dec3.data;
420  num_channels = entry.channelcount;
421  sampling_frequency = entry.samplerate;
422  break;
423  case FOURCC_Opus:
424  codec_config = entry.dops.opus_identification_header;
425  num_channels = entry.channelcount;
426  sampling_frequency = entry.samplerate;
427  RCHECK(sampling_frequency != 0);
428  codec_delay_ns =
429  entry.dops.preskip * kNanosecondsPerSecond / sampling_frequency;
430  break;
431  default:
432  LOG(ERROR) << "Unsupported audio format 0x" << std::hex
433  << actual_format << " in stsd box.";
434  return false;
435  }
436 
437  // Extract possible seek preroll.
438  uint64_t seek_preroll_ns = 0;
439  for (const auto& sample_group_description :
440  track->media.information.sample_table.sample_group_descriptions) {
441  if (sample_group_description.grouping_type != FOURCC_roll)
442  continue;
443  const auto& audio_roll_recovery_entries =
444  sample_group_description.audio_roll_recovery_entries;
445  if (audio_roll_recovery_entries.size() != 1) {
446  LOG(WARNING) << "Unexpected number of entries in "
447  "SampleGroupDescription table with grouping type "
448  "'roll'.";
449  break;
450  }
451  const int16_t roll_distance_in_samples =
452  audio_roll_recovery_entries[0].roll_distance;
453  if (roll_distance_in_samples < 0) {
454  RCHECK(sampling_frequency != 0);
455  seek_preroll_ns = kNanosecondsPerSecond *
456  (-roll_distance_in_samples) / sampling_frequency;
457  } else {
458  LOG(WARNING)
459  << "Roll distance is supposed to be negative, but seeing "
460  << roll_distance_in_samples;
461  }
462  break;
463  }
464 
465  // The stream will be decrypted if a |decryptor_source_| is available.
466  const bool is_encrypted =
467  decryptor_source_
468  ? false
469  : entry.sinf.info.track_encryption.default_is_protected == 1;
470  DVLOG(1) << "is_audio_track_encrypted_: " << is_encrypted;
471  streams.emplace_back(new AudioStreamInfo(
472  track->header.track_id, timescale, duration, codec,
473  AudioStreamInfo::GetCodecString(codec, audio_object_type),
474  codec_config.data(), codec_config.size(), entry.samplesize,
475  num_channels, sampling_frequency, seek_preroll_ns, codec_delay_ns,
476  max_bitrate, avg_bitrate, track->media.header.language.code,
477  is_encrypted));
478  }
479 
480  if (samp_descr.type == kVideo) {
481  RCHECK(!samp_descr.video_entries.empty());
482  if (desc_idx >= samp_descr.video_entries.size())
483  desc_idx = 0;
484  const VideoSampleEntry& entry = samp_descr.video_entries[desc_idx];
485 
486  uint32_t coded_width = entry.width;
487  uint32_t coded_height = entry.height;
488  uint32_t pixel_width = entry.pixel_aspect.h_spacing;
489  uint32_t pixel_height = entry.pixel_aspect.v_spacing;
490  if (pixel_width == 0 && pixel_height == 0) {
491  pixel_width = 1;
492  pixel_height = 1;
493  }
494  std::string codec_string;
495  uint8_t nalu_length_size = 0;
496 
497  const FourCC actual_format = entry.GetActualFormat();
498  const Codec video_codec = FourCCToCodec(actual_format);
499  switch (actual_format) {
500  case FOURCC_avc1: {
501  AVCDecoderConfigurationRecord avc_config;
502  if (!avc_config.Parse(entry.codec_configuration.data)) {
503  LOG(ERROR) << "Failed to parse avcc.";
504  return false;
505  }
506  codec_string = avc_config.GetCodecString();
507  nalu_length_size = avc_config.nalu_length_size();
508 
509  if (coded_width != avc_config.coded_width() ||
510  coded_height != avc_config.coded_height()) {
511  LOG(WARNING) << "Resolution in VisualSampleEntry (" << coded_width
512  << "," << coded_height
513  << ") does not match with resolution in "
514  "AVCDecoderConfigurationRecord ("
515  << avc_config.coded_width() << ","
516  << avc_config.coded_height()
517  << "). Use AVCDecoderConfigurationRecord.";
518  coded_width = avc_config.coded_width();
519  coded_height = avc_config.coded_height();
520  }
521 
522  if (pixel_width != avc_config.pixel_width() ||
523  pixel_height != avc_config.pixel_height()) {
524  LOG_IF(WARNING, pixel_width != 1 || pixel_height != 1)
525  << "Pixel aspect ratio in PASP box (" << pixel_width << ","
526  << pixel_height
527  << ") does not match with SAR in AVCDecoderConfigurationRecord "
528  "("
529  << avc_config.pixel_width() << "," << avc_config.pixel_height()
530  << "). Use AVCDecoderConfigurationRecord.";
531  pixel_width = avc_config.pixel_width();
532  pixel_height = avc_config.pixel_height();
533  }
534  break;
535  }
536  case FOURCC_hev1:
537  case FOURCC_hvc1: {
538  HEVCDecoderConfigurationRecord hevc_config;
539  if (!hevc_config.Parse(entry.codec_configuration.data)) {
540  LOG(ERROR) << "Failed to parse hevc.";
541  return false;
542  }
543  codec_string = hevc_config.GetCodecString(video_codec);
544  nalu_length_size = hevc_config.nalu_length_size();
545  break;
546  }
547  case FOURCC_vp08:
548  case FOURCC_vp09:
549  case FOURCC_vp10: {
550  VPCodecConfigurationRecord vp_config;
551  if (!vp_config.ParseMP4(entry.codec_configuration.data)) {
552  LOG(ERROR) << "Failed to parse vpcc.";
553  return false;
554  }
555  codec_string = vp_config.GetCodecString(video_codec);
556  break;
557  }
558  default:
559  LOG(ERROR) << "Unsupported video format "
560  << FourCCToString(actual_format) << " in stsd box.";
561  return false;
562  }
563 
564  // The stream will be decrypted if a |decryptor_source_| is available.
565  const bool is_encrypted =
566  decryptor_source_
567  ? false
568  : entry.sinf.info.track_encryption.default_is_protected == 1;
569  DVLOG(1) << "is_video_track_encrypted_: " << is_encrypted;
570  std::shared_ptr<VideoStreamInfo> video_stream_info(new VideoStreamInfo(
571  track->header.track_id, timescale, duration, video_codec,
572  codec_string, entry.codec_configuration.data.data(),
573  entry.codec_configuration.data.size(), coded_width, coded_height,
574  pixel_width, pixel_height,
575  0, // trick_play_rate
576  nalu_length_size, track->media.header.language.code, is_encrypted));
577 
578  // Set pssh raw data if it has.
579  if (moov_->pssh.size() > 0) {
580  std::vector<uint8_t> pssh_raw_data;
581  for (const auto& pssh : moov_->pssh) {
582  pssh_raw_data.insert(pssh_raw_data.end(), pssh.raw_box.begin(),
583  pssh.raw_box.end());
584  }
585  video_stream_info->set_eme_init_data(pssh_raw_data.data(),
586  pssh_raw_data.size());
587  }
588 
589  streams.push_back(video_stream_info);
590  }
591  }
592 
593  init_cb_.Run(streams);
594  if (!FetchKeysIfNecessary(moov_->pssh))
595  return false;
596  runs_.reset(new TrackRunIterator(moov_.get()));
597  RCHECK(runs_->Init());
598  ChangeState(kEmittingSamples);
599  return true;
600 }
601 
602 bool MP4MediaParser::ParseMoof(BoxReader* reader) {
603  // Must already have initialization segment.
604  RCHECK(moov_.get());
605  MovieFragment moof;
606  RCHECK(moof.Parse(reader));
607  if (!runs_)
608  runs_.reset(new TrackRunIterator(moov_.get()));
609  RCHECK(runs_->Init(moof));
610  if (!FetchKeysIfNecessary(moof.pssh))
611  return false;
612  ChangeState(kEmittingSamples);
613  return true;
614 }
615 
616 bool MP4MediaParser::FetchKeysIfNecessary(
617  const std::vector<ProtectionSystemSpecificHeader>& headers) {
618  if (headers.empty())
619  return true;
620 
621  // An error will be returned later if the samples need to be decrypted.
622  if (!decryption_key_source_)
623  return true;
624 
625  Status status;
626  for (std::vector<ProtectionSystemSpecificHeader>::const_iterator iter =
627  headers.begin(); iter != headers.end(); ++iter) {
628  status = decryption_key_source_->FetchKeys(iter->raw_box);
629  if (!status.ok()) {
630  // If there is an error, try using the next PSSH box and report if none
631  // work.
632  VLOG(1) << "Unable to fetch decryption keys: " << status
633  << ", trying the next PSSH box";
634  continue;
635  }
636  return true;
637  }
638 
639  if (!status.ok()) {
640  LOG(ERROR) << "Error fetching decryption keys: " << status;
641  return false;
642  }
643 
644  LOG(ERROR) << "No viable 'pssh' box found for content decryption.";
645  return false;
646 }
647 
648 bool MP4MediaParser::EnqueueSample(bool* err) {
649  if (!runs_->IsRunValid()) {
650  // Remain in kEnqueueingSamples state, discarding data, until the end of
651  // the current 'mdat' box has been appended to the queue.
652  if (!queue_.Trim(mdat_tail_))
653  return false;
654 
655  ChangeState(kParsingBoxes);
656  return true;
657  }
658 
659  if (!runs_->IsSampleValid()) {
660  runs_->AdvanceRun();
661  return true;
662  }
663 
664  DCHECK(!(*err));
665 
666  const uint8_t* buf;
667  int buf_size;
668  queue_.Peek(&buf, &buf_size);
669  if (!buf_size)
670  return false;
671 
672  // Skip this entire track if it is not audio nor video.
673  if (!runs_->is_audio() && !runs_->is_video())
674  runs_->AdvanceRun();
675 
676  // Attempt to cache the auxiliary information first. Aux info is usually
677  // placed in a contiguous block before the sample data, rather than being
678  // interleaved. If we didn't cache it, this would require that we retain the
679  // start of the segment buffer while reading samples. Aux info is typically
680  // quite small compared to sample data, so this pattern is useful on
681  // memory-constrained devices where the source buffer consumes a substantial
682  // portion of the total system memory.
683  if (runs_->AuxInfoNeedsToBeCached()) {
684  queue_.PeekAt(runs_->aux_info_offset() + moof_head_, &buf, &buf_size);
685  if (buf_size < runs_->aux_info_size())
686  return false;
687  *err = !runs_->CacheAuxInfo(buf, buf_size);
688  return !*err;
689  }
690 
691  int64_t sample_offset = runs_->sample_offset() + moof_head_;
692  queue_.PeekAt(sample_offset, &buf, &buf_size);
693  if (buf_size < runs_->sample_size()) {
694  if (sample_offset < queue_.head()) {
695  LOG(ERROR) << "Incorrect sample offset " << sample_offset
696  << " < " << queue_.head();
697  *err = true;
698  }
699  return false;
700  }
701 
702  std::shared_ptr<MediaSample> stream_sample(
703  MediaSample::CopyFrom(buf, runs_->sample_size(), runs_->is_keyframe()));
704  if (runs_->is_encrypted()) {
705  std::unique_ptr<DecryptConfig> decrypt_config = runs_->GetDecryptConfig();
706  if (!decrypt_config) {
707  *err = true;
708  LOG(ERROR) << "Missing decrypt config.";
709  return false;
710  }
711 
712  if (!decryptor_source_) {
713  // If the demuxer does not have the decryptor_source_, store
714  // decrypt_config so that the demuxed sample can be decrypted later.
715  stream_sample->set_decrypt_config(std::move(decrypt_config));
716  stream_sample->set_is_encrypted(true);
717  } else if (!decryptor_source_->DecryptSampleBuffer(
718  decrypt_config.get(), stream_sample->writable_data(),
719  stream_sample->data_size())) {
720  *err = true;
721  LOG(ERROR) << "Cannot decrypt samples.";
722  return false;
723  }
724  }
725 
726  stream_sample->set_dts(runs_->dts());
727  stream_sample->set_pts(runs_->cts());
728  stream_sample->set_duration(runs_->duration());
729 
730  DVLOG(3) << "Pushing frame: "
731  << ", key=" << runs_->is_keyframe()
732  << ", dur=" << runs_->duration()
733  << ", dts=" << runs_->dts()
734  << ", cts=" << runs_->cts()
735  << ", size=" << runs_->sample_size();
736 
737  if (!new_sample_cb_.Run(runs_->track_id(), stream_sample)) {
738  *err = true;
739  LOG(ERROR) << "Failed to process the sample.";
740  return false;
741  }
742 
743  runs_->AdvanceSample();
744  return true;
745 }
746 
747 bool MP4MediaParser::ReadAndDiscardMDATsUntil(const int64_t offset) {
748  bool err = false;
749  while (mdat_tail_ < offset) {
750  const uint8_t* buf;
751  int size;
752  queue_.PeekAt(mdat_tail_, &buf, &size);
753 
754  FourCC type;
755  uint64_t box_sz;
756  if (!BoxReader::StartBox(buf, size, &type, &box_sz, &err))
757  break;
758 
759  mdat_tail_ += box_sz;
760  }
761  queue_.Trim(std::min(mdat_tail_, offset));
762  return !err;
763 }
764 
765 void MP4MediaParser::ChangeState(State new_state) {
766  DVLOG(2) << "Changing state: " << new_state;
767  state_ = new_state;
768 }
769 
770 } // namespace mp4
771 } // namespace media
772 } // namespace shaka
void PeekAt(int64_t offset, const uint8_t **buf, int *size)
static File * OpenWithNoBuffering(const char *file_name, const char *mode)
Definition: file.cc:152
bool Flush() override WARN_UNUSED_RESULT
bool Trim(int64_t max_offset)
bool Parse(const uint8_t *buf, int size) override WARN_UNUSED_RESULT
virtual Status FetchKeys(const std::vector< uint8_t > &pssh_box)=0
static std::string GetCodecString(Codec codec, uint8_t audio_object_type)
bool LoadMoov(const std::string &file_path)
static std::shared_ptr< MediaSample > CopyFrom(const uint8_t *data, size_t size, bool is_key_frame)
Definition: media_sample.cc:45
KeySource is responsible for encryption key acquisition.
Definition: key_source.h:30
void Init(const InitCB &init_cb, const NewSampleCB &new_sample_cb, KeySource *decryption_key_source) override
DecryptorSource wraps KeySource and is responsible for decryptor management.
static bool StartBox(const uint8_t *buf, const size_t buf_size, FourCC *type, uint64_t *box_size, bool *err) WARN_UNUSED_RESULT
Definition: box_reader.cc:54
static BoxReader * ReadBox(const uint8_t *buf, const size_t buf_size, bool *err)
Definition: box_reader.cc:36