5 #include "packager/media/formats/mp4/mp4_media_parser.h"
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/media_sample.h"
20 #include "packager/media/base/video_stream_info.h"
21 #include "packager/media/file/file.h"
22 #include "packager/media/file/file_closer.h"
23 #include "packager/media/filters/avc_decoder_configuration.h"
24 #include "packager/media/filters/hevc_decoder_configuration.h"
25 #include "packager/media/filters/vp_codec_configuration.h"
26 #include "packager/media/formats/mp4/box_definitions.h"
27 #include "packager/media/formats/mp4/box_reader.h"
28 #include "packager/media/formats/mp4/es_descriptor.h"
29 #include "packager/media/formats/mp4/rcheck.h"
30 #include "packager/media/formats/mp4/track_run_iterator.h"
32 namespace edash_packager {
37 uint64_t Rescale(uint64_t time_in_old_scale,
40 return (static_cast<double>(time_in_old_scale) / old_scale) * new_scale;
43 VideoCodec FourCCToCodec(FourCC fourcc) {
58 return kUnknownVideoCodec;
62 const char kWidevineKeySystemId[] =
"edef8ba979d64acea3c827dcd51d21ed";
66 MP4MediaParser::MP4MediaParser()
67 : state_(kWaitingForInit), moof_head_(0), mdat_tail_(0) {}
69 MP4MediaParser::~MP4MediaParser() {
70 STLDeleteValues(&decryptor_map_);
74 const NewSampleCB& new_sample_cb,
76 DCHECK_EQ(state_, kWaitingForInit);
77 DCHECK(init_cb_.is_null());
78 DCHECK(!init_cb.is_null());
79 DCHECK(!new_sample_cb.is_null());
81 ChangeState(kParsingBoxes);
83 new_sample_cb_ = new_sample_cb;
84 decryption_key_source_ = decryption_key_source;
87 void MP4MediaParser::Reset() {
95 DCHECK_NE(state_, kWaitingForInit);
97 ChangeState(kParsingBoxes);
101 DCHECK_NE(state_, kWaitingForInit);
103 if (state_ == kError)
106 queue_.Push(buf, size);
108 bool result, err =
false;
111 if (state_ == kParsingBoxes) {
112 result = ParseBox(&err);
114 DCHECK_EQ(kEmittingSamples, state_);
115 result = EnqueueSample(&err);
117 int64_t max_clear = runs_->GetMaxClearOffset() + moof_head_;
118 err = !ReadAndDiscardMDATsUntil(max_clear);
121 }
while (result && !err);
124 DLOG(ERROR) <<
"Error while parsing MP4";
135 scoped_ptr<File, FileCloser> file(
138 LOG(ERROR) <<
"Unable to open media file '" << file_path <<
"'";
141 if (!file->Seek(0)) {
142 LOG(WARNING) <<
"Filesystem does not support seeking on file '" << file_path
147 uint64_t file_position(0);
148 bool mdat_seen(
false);
150 const uint32_t kBoxHeaderReadSize(16);
151 std::vector<uint8_t> buffer(kBoxHeaderReadSize);
152 int64_t bytes_read = file->Read(&buffer[0], kBoxHeaderReadSize);
153 if (bytes_read == 0) {
154 LOG(ERROR) <<
"Could not find 'moov' box in file '" << file_path <<
"'";
157 if (bytes_read < kBoxHeaderReadSize) {
158 LOG(ERROR) <<
"Error reading media file '" << file_path <<
"'";
166 LOG(ERROR) <<
"Could not start top level box from file '" << file_path
170 if (box_type == FOURCC_MDAT) {
172 }
else if (box_type == FOURCC_MOOV) {
178 if (!
Parse(&buffer[0], bytes_read)) {
179 LOG(ERROR) <<
"Error parsing mp4 file '" << file_path <<
"'";
182 uint64_t bytes_to_read = box_size - bytes_read;
183 buffer.resize(bytes_to_read);
184 while (bytes_to_read > 0) {
185 bytes_read = file->Read(&buffer[0], bytes_to_read);
186 if (bytes_read <= 0) {
187 LOG(ERROR) <<
"Error reading 'moov' contents from file '" << file_path
191 if (!
Parse(&buffer[0], bytes_read)) {
192 LOG(ERROR) <<
"Error parsing mp4 file '" << file_path <<
"'";
195 bytes_to_read -= bytes_read;
201 file_position += box_size;
202 if (!file->Seek(file_position)) {
203 LOG(ERROR) <<
"Error skipping box in mp4 file '" << file_path <<
"'";
210 bool MP4MediaParser::ParseBox(
bool* err) {
213 queue_.Peek(&buf, &size);
218 if (reader.get() == NULL)
221 if (reader->type() == FOURCC_MDAT) {
225 NOTIMPLEMENTED() <<
" Files with MDAT before MOOV is not supported yet.";
231 mdat_tail_ = queue_.
head() + reader->size();
233 if (reader->type() == FOURCC_MOOV) {
234 *err = !ParseMoov(reader.get());
235 }
else if (reader->type() == FOURCC_MOOF) {
236 moof_head_ = queue_.
head();
237 *err = !ParseMoof(reader.get());
245 VLOG(2) <<
"Skipping top-level box: " << FourCCToString(reader->type());
248 queue_.Pop(reader->size());
252 bool MP4MediaParser::ParseMoov(BoxReader* reader) {
256 moov_.reset(
new Movie);
257 RCHECK(moov_->Parse(reader));
260 std::vector<scoped_refptr<StreamInfo> > streams;
262 for (std::vector<Track>::const_iterator track = moov_->tracks.begin();
263 track != moov_->tracks.end(); ++track) {
264 const uint32_t timescale = track->media.header.timescale;
267 uint64_t duration = 0;
268 if (track->media.header.duration > 0) {
269 duration = track->media.header.duration;
270 }
else if (moov_->extends.header.fragment_duration > 0) {
271 DCHECK(moov_->header.timescale != 0);
272 duration = Rescale(moov_->extends.header.fragment_duration,
273 moov_->header.timescale,
275 }
else if (moov_->header.duration > 0 &&
276 moov_->header.duration != std::numeric_limits<uint64_t>::max()) {
277 DCHECK(moov_->header.timescale != 0);
279 Rescale(moov_->header.duration, moov_->header.timescale, timescale);
282 const SampleDescription& samp_descr =
283 track->media.information.sample_table.description;
289 if (moov_->extends.tracks.size() > 0) {
290 for (
size_t t = 0; t < moov_->extends.tracks.size(); t++) {
291 const TrackExtends& trex = moov_->extends.tracks[t];
292 if (trex.track_id == track->header.track_id) {
293 desc_idx = trex.default_sample_description_index;
298 const std::vector<ChunkInfo>& chunk_info =
299 track->media.information.sample_table.sample_to_chunk.chunk_info;
300 RCHECK(chunk_info.size() > 0);
301 desc_idx = chunk_info[0].sample_description_index;
303 RCHECK(desc_idx > 0);
306 if (track->media.handler.type == kAudio) {
307 RCHECK(!samp_descr.audio_entries.empty());
311 if (desc_idx >= samp_descr.audio_entries.size())
313 const AudioSampleEntry& entry = samp_descr.audio_entries[desc_idx];
315 if (!(entry.format == FOURCC_MP4A || entry.format == FOURCC_EAC3 ||
316 (entry.format == FOURCC_ENCA &&
317 entry.sinf.format.format == FOURCC_MP4A))) {
318 LOG(ERROR) <<
"Unsupported audio format 0x"
319 << std::hex << entry.format <<
" in stsd box.";
323 ObjectType audio_type = entry.esds.es_descriptor.object_type();
324 DVLOG(1) <<
"audio_type " << std::hex << audio_type;
325 if (audio_type == kForbidden && entry.format == FOURCC_EAC3) {
329 AudioCodec codec = kUnknownAudioCodec;
330 uint8_t num_channels = 0;
331 uint32_t sampling_frequency = 0;
332 uint8_t audio_object_type = 0;
333 std::vector<uint8_t> extra_data;
336 if (entry.esds.es_descriptor.IsAAC()) {
338 const AACAudioSpecificConfig& aac_audio_specific_config =
339 entry.esds.aac_audio_specific_config;
340 num_channels = aac_audio_specific_config.num_channels();
341 sampling_frequency = aac_audio_specific_config.frequency();
342 audio_object_type = aac_audio_specific_config.audio_object_type();
343 extra_data = entry.esds.es_descriptor.decoder_specific_info();
344 }
else if (audio_type == kEAC3) {
346 num_channels = entry.channelcount;
347 sampling_frequency = entry.samplerate;
349 LOG(ERROR) <<
"Unsupported audio object type 0x"
350 << std::hex << audio_type <<
" in esds.";
354 bool is_encrypted = entry.sinf.info.track_encryption.is_encrypted;
355 DVLOG(1) <<
"is_audio_track_encrypted_: " << is_encrypted;
356 streams.push_back(
new AudioStreamInfo(
357 track->header.track_id,
362 track->media.header.language,
366 extra_data.size() ? &extra_data[0] : NULL,
371 if (track->media.handler.type == kVideo) {
372 RCHECK(!samp_descr.video_entries.empty());
373 if (desc_idx >= samp_descr.video_entries.size())
375 const VideoSampleEntry& entry = samp_descr.video_entries[desc_idx];
377 uint32_t coded_width = entry.width;
378 uint32_t coded_height = entry.height;
379 uint32_t pixel_width = entry.pixel_aspect.h_spacing;
380 uint32_t pixel_height = entry.pixel_aspect.v_spacing;
381 if (pixel_width == 0 && pixel_height == 0) {
385 std::string codec_string;
386 uint8_t nalu_length_size = 0;
388 const FourCC actual_format = entry.GetActualFormat();
389 const VideoCodec video_codec = FourCCToCodec(actual_format);
390 switch (actual_format) {
392 AVCDecoderConfiguration avc_config;
393 if (!avc_config.Parse(entry.codec_config_record.data)) {
394 LOG(ERROR) <<
"Failed to parse avcc.";
397 codec_string = avc_config.GetCodecString();
398 nalu_length_size = avc_config.length_size();
400 if (coded_width != avc_config.coded_width() ||
401 coded_height != avc_config.coded_height()) {
402 LOG(WARNING) <<
"Resolution in VisualSampleEntry (" << coded_width
403 <<
"," << coded_height
404 <<
") does not match with resolution in "
405 "AVCDecoderConfigurationRecord ("
406 << avc_config.coded_width() <<
","
407 << avc_config.coded_height()
408 <<
"). Use AVCDecoderConfigurationRecord.";
409 coded_width = avc_config.coded_width();
410 coded_height = avc_config.coded_height();
413 if (pixel_width != avc_config.pixel_width() ||
414 pixel_height != avc_config.pixel_height()) {
415 LOG_IF(WARNING, pixel_width != 1 || pixel_height != 1)
416 <<
"Pixel aspect ratio in PASP box (" << pixel_width <<
","
418 <<
") does not match with SAR in AVCDecoderConfigurationRecord "
420 << avc_config.pixel_width() <<
"," << avc_config.pixel_height()
421 <<
"). Use AVCDecoderConfigurationRecord.";
422 pixel_width = avc_config.pixel_width();
423 pixel_height = avc_config.pixel_height();
429 HEVCDecoderConfiguration hevc_config;
430 if (!hevc_config.Parse(entry.codec_config_record.data)) {
431 LOG(ERROR) <<
"Failed to parse hevc.";
434 codec_string = hevc_config.GetCodecString(video_codec);
435 nalu_length_size = hevc_config.length_size();
441 VPCodecConfiguration vp_config;
442 if (!vp_config.Parse(entry.codec_config_record.data)) {
443 LOG(ERROR) <<
"Failed to parse vpcc.";
446 codec_string = vp_config.GetCodecString(video_codec);
450 LOG(ERROR) <<
"Unsupported video format "
451 << FourCCToString(actual_format) <<
" in stsd box.";
455 bool is_encrypted = entry.sinf.info.track_encryption.is_encrypted;
456 DVLOG(1) <<
"is_video_track_encrypted_: " << is_encrypted;
457 streams.push_back(
new VideoStreamInfo(
458 track->header.track_id, timescale, duration, video_codec,
459 codec_string, track->media.header.language, coded_width, coded_height,
460 pixel_width, pixel_height,
462 nalu_length_size, vector_as_array(&entry.codec_config_record.data),
463 entry.codec_config_record.data.size(), is_encrypted));
467 init_cb_.Run(streams);
468 if (!FetchKeysIfNecessary(moov_->pssh))
470 runs_.reset(
new TrackRunIterator(moov_.get()));
471 RCHECK(runs_->Init());
472 ChangeState(kEmittingSamples);
476 bool MP4MediaParser::ParseMoof(BoxReader* reader) {
480 RCHECK(moof.Parse(reader));
482 runs_.reset(
new TrackRunIterator(moov_.get()));
483 RCHECK(runs_->Init(moof));
484 if (!FetchKeysIfNecessary(moof.pssh))
486 ChangeState(kEmittingSamples);
490 bool MP4MediaParser::FetchKeysIfNecessary(
491 const std::vector<ProtectionSystemSpecificHeader>& headers) {
496 if (!decryption_key_source_)
501 std::vector<uint8_t> widevine_system_id;
502 base::HexStringToBytes(kWidevineKeySystemId, &widevine_system_id);
503 for (std::vector<ProtectionSystemSpecificHeader>::const_iterator iter =
504 headers.begin(); iter != headers.end(); ++iter) {
505 if (iter->system_id == widevine_system_id) {
506 Status status = decryption_key_source_->
FetchKeys(iter->data);
508 LOG(ERROR) <<
"Error fetching decryption keys: " << status;
515 LOG(ERROR) <<
"No viable 'pssh' box found for content decryption.";
519 bool MP4MediaParser::EnqueueSample(
bool* err) {
520 if (!runs_->IsRunValid()) {
523 if (!queue_.
Trim(mdat_tail_))
526 ChangeState(kParsingBoxes);
530 if (!runs_->IsSampleValid()) {
539 queue_.Peek(&buf, &buf_size);
544 if (!runs_->is_audio() && !runs_->is_video())
554 if (runs_->AuxInfoNeedsToBeCached()) {
555 queue_.
PeekAt(runs_->aux_info_offset() + moof_head_, &buf, &buf_size);
556 if (buf_size < runs_->aux_info_size())
558 *err = !runs_->CacheAuxInfo(buf, buf_size);
562 int64_t sample_offset = runs_->sample_offset() + moof_head_;
563 queue_.
PeekAt(sample_offset, &buf, &buf_size);
564 if (buf_size < runs_->sample_size()) {
565 if (sample_offset < queue_.
head()) {
566 LOG(ERROR) <<
"Incorrect sample offset " << sample_offset
567 <<
" < " << queue_.
head();
574 buf, runs_->sample_size(), runs_->is_keyframe()));
575 if (runs_->is_encrypted()) {
576 scoped_ptr<DecryptConfig> decrypt_config = runs_->GetDecryptConfig();
577 if (!decrypt_config ||
578 !DecryptSampleBuffer(decrypt_config.get(),
579 stream_sample->writable_data(),
580 stream_sample->data_size())) {
582 LOG(ERROR) <<
"Cannot decrypt samples.";
587 stream_sample->set_dts(runs_->dts());
588 stream_sample->set_pts(runs_->cts());
589 stream_sample->set_duration(runs_->duration());
591 DVLOG(3) <<
"Pushing frame: "
592 <<
", key=" << runs_->is_keyframe()
593 <<
", dur=" << runs_->duration()
594 <<
", dts=" << runs_->dts()
595 <<
", cts=" << runs_->cts()
596 <<
", size=" << runs_->sample_size();
598 if (!new_sample_cb_.Run(runs_->track_id(), stream_sample)) {
600 LOG(ERROR) <<
"Failed to process the sample.";
604 runs_->AdvanceSample();
608 bool MP4MediaParser::DecryptSampleBuffer(
const DecryptConfig* decrypt_config,
610 size_t buffer_size) {
611 DCHECK(decrypt_config);
614 if (!decryption_key_source_) {
615 LOG(ERROR) <<
"Encrypted media sample encountered, but decryption is not "
621 AesCtrEncryptor* encryptor;
622 DecryptorMap::iterator found = decryptor_map_.find(decrypt_config->key_id());
623 if (found == decryptor_map_.end()) {
626 Status status(decryption_key_source_->
GetKey(decrypt_config->key_id(),
629 LOG(ERROR) <<
"Error retrieving decryption key: " << status;
632 scoped_ptr<AesCtrEncryptor> new_encryptor(
new AesCtrEncryptor);
633 if (!new_encryptor->InitializeWithIv(key.key, decrypt_config->iv())) {
634 LOG(ERROR) <<
"Failed to initialize AesCtrEncryptor for decryption.";
637 encryptor = new_encryptor.release();
638 decryptor_map_[decrypt_config->key_id()] = encryptor;
640 encryptor = found->second;
642 if (!encryptor->SetIv(decrypt_config->iv())) {
643 LOG(ERROR) <<
"Invalid initialization vector.";
647 if (decrypt_config->subsamples().empty()) {
649 if (!encryptor->Decrypt(buffer, buffer_size, buffer)) {
650 LOG(ERROR) <<
"Error during bulk sample decryption.";
657 const std::vector<SubsampleEntry>& subsamples = decrypt_config->subsamples();
658 uint8_t* current_ptr = buffer;
659 const uint8_t* buffer_end = buffer + buffer_size;
660 current_ptr += decrypt_config->data_offset();
661 if (current_ptr > buffer_end) {
662 LOG(ERROR) <<
"Subsample data_offset too large.";
665 for (std::vector<SubsampleEntry>::const_iterator iter = subsamples.begin();
666 iter != subsamples.end();
668 if ((current_ptr + iter->clear_bytes + iter->cipher_bytes) > buffer_end) {
669 LOG(ERROR) <<
"Subsamples overflow sample buffer.";
672 current_ptr += iter->clear_bytes;
673 if (!encryptor->Decrypt(current_ptr, iter->cipher_bytes, current_ptr)) {
674 LOG(ERROR) <<
"Error decrypting subsample buffer.";
677 current_ptr += iter->cipher_bytes;
682 bool MP4MediaParser::ReadAndDiscardMDATsUntil(
const int64_t offset) {
684 while (mdat_tail_ < offset) {
687 queue_.
PeekAt(mdat_tail_, &buf, &size);
694 mdat_tail_ += box_sz;
696 queue_.
Trim(std::min(mdat_tail_, offset));
700 void MP4MediaParser::ChangeState(State new_state) {
701 DVLOG(2) <<
"Changing state: " << new_state;