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/h264_parser.h"
24 #include "packager/media/formats/mp4/box_definitions.h"
25 #include "packager/media/formats/mp4/box_reader.h"
26 #include "packager/media/formats/mp4/es_descriptor.h"
27 #include "packager/media/formats/mp4/rcheck.h"
28 #include "packager/media/formats/mp4/track_run_iterator.h"
32 uint64_t Rescale(uint64_t time_in_old_scale,
35 return (static_cast<double>(time_in_old_scale) / old_scale) * new_scale;
39 const char kWidevineKeySystemId[] =
"edef8ba979d64acea3c827dcd51d21ed";
43 namespace edash_packager {
47 MP4MediaParser::MP4MediaParser()
48 : state_(kWaitingForInit), moof_head_(0), mdat_tail_(0) {}
50 MP4MediaParser::~MP4MediaParser() {
51 STLDeleteValues(&decryptor_map_);
55 const NewSampleCB& new_sample_cb,
57 DCHECK_EQ(state_, kWaitingForInit);
58 DCHECK(init_cb_.is_null());
59 DCHECK(!init_cb.is_null());
60 DCHECK(!new_sample_cb.is_null());
62 ChangeState(kParsingBoxes);
64 new_sample_cb_ = new_sample_cb;
65 decryption_key_source_ = decryption_key_source;
68 void MP4MediaParser::Reset() {
76 DCHECK_NE(state_, kWaitingForInit);
78 ChangeState(kParsingBoxes);
82 DCHECK_NE(state_, kWaitingForInit);
87 queue_.Push(buf, size);
89 bool result, err =
false;
92 if (state_ == kParsingBoxes) {
93 result = ParseBox(&err);
95 DCHECK_EQ(kEmittingSamples, state_);
96 result = EnqueueSample(&err);
98 int64_t max_clear = runs_->GetMaxClearOffset() + moof_head_;
99 err = !ReadAndDiscardMDATsUntil(max_clear);
102 }
while (result && !err);
105 DLOG(ERROR) <<
"Error while parsing MP4";
116 scoped_ptr<File, FileCloser> file(
119 LOG(ERROR) <<
"Unable to open media file '" << file_path <<
"'";
122 if (!file->Seek(0)) {
123 LOG(WARNING) <<
"Filesystem does not support seeking on file '" << file_path
128 uint64_t file_position(0);
129 bool mdat_seen(
false);
131 const uint32_t kBoxHeaderReadSize(16);
132 std::vector<uint8_t> buffer(kBoxHeaderReadSize);
133 int64_t bytes_read = file->Read(&buffer[0], kBoxHeaderReadSize);
134 if (bytes_read == 0) {
135 LOG(ERROR) <<
"Could not find 'moov' box in file '" << file_path <<
"'";
138 if (bytes_read < kBoxHeaderReadSize) {
139 LOG(ERROR) <<
"Error reading media file '" << file_path <<
"'";
147 LOG(ERROR) <<
"Could not start top level box from file '" << file_path
151 if (box_type == FOURCC_MDAT) {
153 }
else if (box_type == FOURCC_MOOV) {
159 if (!
Parse(&buffer[0], bytes_read)) {
160 LOG(ERROR) <<
"Error parsing mp4 file '" << file_path <<
"'";
163 uint64_t bytes_to_read = box_size - bytes_read;
164 buffer.resize(bytes_to_read);
165 while (bytes_to_read > 0) {
166 bytes_read = file->Read(&buffer[0], bytes_to_read);
167 if (bytes_read <= 0) {
168 LOG(ERROR) <<
"Error reading 'moov' contents from file '" << file_path
172 if (!
Parse(&buffer[0], bytes_read)) {
173 LOG(ERROR) <<
"Error parsing mp4 file '" << file_path <<
"'";
176 bytes_to_read -= bytes_read;
182 file_position += box_size;
183 if (!file->Seek(file_position)) {
184 LOG(ERROR) <<
"Error skipping box in mp4 file '" << file_path <<
"'";
191 bool MP4MediaParser::ParseBox(
bool* err) {
194 queue_.Peek(&buf, &size);
199 if (reader.get() == NULL)
202 if (reader->type() == FOURCC_MDAT) {
206 NOTIMPLEMENTED() <<
" Files with MDAT before MOOV is not supported yet.";
212 mdat_tail_ = queue_.
head() + reader->size();
214 if (reader->type() == FOURCC_MOOV) {
215 *err = !ParseMoov(reader.get());
216 }
else if (reader->type() == FOURCC_MOOF) {
217 moof_head_ = queue_.
head();
218 *err = !ParseMoof(reader.get());
226 VLOG(2) <<
"Skipping top-level box: " << FourCCToString(reader->type());
229 queue_.Pop(reader->size());
233 bool MP4MediaParser::ParseMoov(BoxReader* reader) {
237 moov_.reset(
new Movie);
238 RCHECK(moov_->Parse(reader));
241 std::vector<scoped_refptr<StreamInfo> > streams;
243 for (std::vector<Track>::const_iterator track = moov_->tracks.begin();
244 track != moov_->tracks.end(); ++track) {
245 const uint32_t timescale = track->media.header.timescale;
248 uint64_t duration = 0;
249 if (track->media.header.duration > 0) {
250 duration = track->media.header.duration;
251 }
else if (moov_->extends.header.fragment_duration > 0) {
252 DCHECK(moov_->header.timescale != 0);
253 duration = Rescale(moov_->extends.header.fragment_duration,
254 moov_->header.timescale,
256 }
else if (moov_->header.duration > 0 &&
257 moov_->header.duration != std::numeric_limits<uint64_t>::max()) {
258 DCHECK(moov_->header.timescale != 0);
260 Rescale(moov_->header.duration, moov_->header.timescale, timescale);
263 const SampleDescription& samp_descr =
264 track->media.information.sample_table.description;
270 if (moov_->extends.tracks.size() > 0) {
271 for (
size_t t = 0; t < moov_->extends.tracks.size(); t++) {
272 const TrackExtends& trex = moov_->extends.tracks[t];
273 if (trex.track_id == track->header.track_id) {
274 desc_idx = trex.default_sample_description_index;
279 const std::vector<ChunkInfo>& chunk_info =
280 track->media.information.sample_table.sample_to_chunk.chunk_info;
281 RCHECK(chunk_info.size() > 0);
282 desc_idx = chunk_info[0].sample_description_index;
284 RCHECK(desc_idx > 0);
287 if (track->media.handler.type == kAudio) {
288 RCHECK(!samp_descr.audio_entries.empty());
292 if (desc_idx >= samp_descr.audio_entries.size())
294 const AudioSampleEntry& entry = samp_descr.audio_entries[desc_idx];
296 if (!(entry.format == FOURCC_MP4A || entry.format == FOURCC_EAC3 ||
297 (entry.format == FOURCC_ENCA &&
298 entry.sinf.format.format == FOURCC_MP4A))) {
299 LOG(ERROR) <<
"Unsupported audio format 0x"
300 << std::hex << entry.format <<
" in stsd box.";
304 ObjectType audio_type = entry.esds.es_descriptor.object_type();
305 DVLOG(1) <<
"audio_type " << std::hex << audio_type;
306 if (audio_type == kForbidden && entry.format == FOURCC_EAC3) {
310 AudioCodec codec = kUnknownAudioCodec;
311 uint8_t num_channels = 0;
312 uint32_t sampling_frequency = 0;
313 uint8_t audio_object_type = 0;
314 std::vector<uint8_t> extra_data;
317 if (entry.esds.es_descriptor.IsAAC()) {
319 const AACAudioSpecificConfig& aac_audio_specific_config =
320 entry.esds.aac_audio_specific_config;
321 num_channels = aac_audio_specific_config.num_channels();
322 sampling_frequency = aac_audio_specific_config.frequency();
323 audio_object_type = aac_audio_specific_config.audio_object_type();
324 extra_data = entry.esds.es_descriptor.decoder_specific_info();
325 }
else if (audio_type == kEAC3) {
327 num_channels = entry.channelcount;
328 sampling_frequency = entry.samplerate;
330 LOG(ERROR) <<
"Unsupported audio object type 0x"
331 << std::hex << audio_type <<
" in esds.";
335 bool is_encrypted = entry.sinf.info.track_encryption.is_encrypted;
336 DVLOG(1) <<
"is_audio_track_encrypted_: " << is_encrypted;
337 streams.push_back(
new AudioStreamInfo(
338 track->header.track_id,
343 track->media.header.language,
347 extra_data.size() ? &extra_data[0] : NULL,
352 if (track->media.handler.type == kVideo) {
353 RCHECK(!samp_descr.video_entries.empty());
354 if (desc_idx >= samp_descr.video_entries.size())
356 const VideoSampleEntry& entry = samp_descr.video_entries[desc_idx];
358 if (!(entry.format == FOURCC_AVC1 ||
359 (entry.format == FOURCC_ENCV &&
360 entry.sinf.format.format == FOURCC_AVC1))) {
361 LOG(ERROR) <<
"Unsupported video format 0x"
362 << std::hex << entry.format <<
" in stsd box.";
366 const std::string codec_string =
368 entry.avcc.profile_indication,
369 entry.avcc.profile_compatibility,
370 entry.avcc.avc_level);
372 uint32_t coded_width = 0;
373 uint32_t coded_height = 0;
374 uint32_t pixel_width = 0;
375 uint32_t pixel_height = 0;
377 if (entry.avcc.sps_list.empty()) {
378 LOG(ERROR) <<
"Cannot find sps in avc decoder configuration record.";
381 const std::vector<uint8_t>& sps = entry.avcc.sps_list[0];
382 if (!ExtractResolutionFromSpsData(&sps[0], sps.size(), &coded_width,
383 &coded_height, &pixel_width,
385 LOG(ERROR) <<
"Failed to parse SPS.";
390 entry.width != coded_width || entry.height != coded_height)
391 <<
"Resolution in VisualSampleEntry (" << entry.width <<
","
392 << entry.height <<
") does not match with resolution in "
393 "AVCDecoderConfigurationRecord ("
394 << coded_width <<
"," << coded_height
395 <<
"). Use AVCDecoderConfigurationRecord.";
397 if (entry.pixel_aspect.h_spacing != 0 || entry.pixel_aspect.v_spacing != 0) {
398 LOG_IF(WARNING, entry.pixel_aspect.h_spacing != pixel_width ||
399 entry.pixel_aspect.v_spacing != pixel_height)
400 <<
"Pixel aspect ratio in PASP box ("
401 << entry.pixel_aspect.h_spacing <<
","
402 << entry.pixel_aspect.v_spacing
403 <<
") does not match with SAR in AVCDecoderConfigurationRecord ("
404 << pixel_width <<
"," << pixel_height
405 <<
"). Use AVCDecoderConfigurationRecord.";
408 bool is_encrypted = entry.sinf.info.track_encryption.is_encrypted;
409 DVLOG(1) <<
"is_video_track_encrypted_: " << is_encrypted;
410 streams.push_back(
new VideoStreamInfo(track->header.track_id,
415 track->media.header.language,
421 entry.avcc.length_size,
423 entry.avcc.data.size(),
428 init_cb_.Run(streams);
429 if (!FetchKeysIfNecessary(moov_->pssh))
431 runs_.reset(
new TrackRunIterator(moov_.get()));
432 RCHECK(runs_->Init());
433 ChangeState(kEmittingSamples);
437 bool MP4MediaParser::ParseMoof(BoxReader* reader) {
441 RCHECK(moof.Parse(reader));
443 runs_.reset(
new TrackRunIterator(moov_.get()));
444 RCHECK(runs_->Init(moof));
445 if (!FetchKeysIfNecessary(moof.pssh))
447 ChangeState(kEmittingSamples);
451 bool MP4MediaParser::FetchKeysIfNecessary(
452 const std::vector<ProtectionSystemSpecificHeader>& headers) {
457 if (!decryption_key_source_)
462 std::vector<uint8_t> widevine_system_id;
463 base::HexStringToBytes(kWidevineKeySystemId, &widevine_system_id);
464 for (std::vector<ProtectionSystemSpecificHeader>::const_iterator iter =
465 headers.begin(); iter != headers.end(); ++iter) {
466 if (iter->system_id == widevine_system_id) {
467 Status status = decryption_key_source_->
FetchKeys(iter->data);
469 LOG(ERROR) <<
"Error fetching decryption keys: " << status;
476 LOG(ERROR) <<
"No viable 'pssh' box found for content decryption.";
480 bool MP4MediaParser::EnqueueSample(
bool* err) {
481 if (!runs_->IsRunValid()) {
484 if (!queue_.
Trim(mdat_tail_))
487 ChangeState(kParsingBoxes);
491 if (!runs_->IsSampleValid()) {
500 queue_.Peek(&buf, &buf_size);
505 if (!runs_->is_audio() && !runs_->is_video())
515 if (runs_->AuxInfoNeedsToBeCached()) {
516 queue_.
PeekAt(runs_->aux_info_offset() + moof_head_, &buf, &buf_size);
517 if (buf_size < runs_->aux_info_size())
519 *err = !runs_->CacheAuxInfo(buf, buf_size);
523 int64_t sample_offset = runs_->sample_offset() + moof_head_;
524 queue_.
PeekAt(sample_offset, &buf, &buf_size);
525 if (buf_size < runs_->sample_size()) {
526 if (sample_offset < queue_.
head()) {
527 LOG(ERROR) <<
"Incorrect sample offset " << sample_offset
528 <<
" < " << queue_.
head();
535 buf, runs_->sample_size(), runs_->is_keyframe()));
536 if (runs_->is_encrypted()) {
537 scoped_ptr<DecryptConfig> decrypt_config = runs_->GetDecryptConfig();
538 if (!decrypt_config ||
539 !DecryptSampleBuffer(decrypt_config.get(),
540 stream_sample->writable_data(),
541 stream_sample->data_size())) {
543 LOG(ERROR) <<
"Cannot decrypt samples.";
548 stream_sample->set_dts(runs_->dts());
549 stream_sample->set_pts(runs_->cts());
550 stream_sample->set_duration(runs_->duration());
552 DVLOG(3) <<
"Pushing frame: "
553 <<
", key=" << runs_->is_keyframe()
554 <<
", dur=" << runs_->duration()
555 <<
", dts=" << runs_->dts()
556 <<
", cts=" << runs_->cts()
557 <<
", size=" << runs_->sample_size();
559 if (!new_sample_cb_.Run(runs_->track_id(), stream_sample)) {
561 LOG(ERROR) <<
"Failed to process the sample.";
565 runs_->AdvanceSample();
569 bool MP4MediaParser::DecryptSampleBuffer(
const DecryptConfig* decrypt_config,
571 size_t buffer_size) {
572 DCHECK(decrypt_config);
575 if (!decryption_key_source_) {
576 LOG(ERROR) <<
"Encrypted media sample encountered, but decryption is not "
582 AesCtrEncryptor* encryptor;
583 DecryptorMap::iterator found = decryptor_map_.find(decrypt_config->key_id());
584 if (found == decryptor_map_.end()) {
587 Status status(decryption_key_source_->
GetKey(decrypt_config->key_id(),
590 LOG(ERROR) <<
"Error retrieving decryption key: " << status;
593 scoped_ptr<AesCtrEncryptor> new_encryptor(
new AesCtrEncryptor);
594 if (!new_encryptor->InitializeWithIv(key.key, decrypt_config->iv())) {
595 LOG(ERROR) <<
"Failed to initialize AesCtrEncryptor for decryption.";
598 encryptor = new_encryptor.release();
599 decryptor_map_[decrypt_config->key_id()] = encryptor;
601 encryptor = found->second;
603 if (!encryptor->SetIv(decrypt_config->iv())) {
604 LOG(ERROR) <<
"Invalid initialization vector.";
608 if (decrypt_config->subsamples().empty()) {
610 if (!encryptor->Decrypt(buffer, buffer_size, buffer)) {
611 LOG(ERROR) <<
"Error during bulk sample decryption.";
618 const std::vector<SubsampleEntry>& subsamples = decrypt_config->subsamples();
619 uint8_t* current_ptr = buffer;
620 const uint8_t* buffer_end = buffer + buffer_size;
621 current_ptr += decrypt_config->data_offset();
622 if (current_ptr > buffer_end) {
623 LOG(ERROR) <<
"Subsample data_offset too large.";
626 for (std::vector<SubsampleEntry>::const_iterator iter = subsamples.begin();
627 iter != subsamples.end();
629 if ((current_ptr + iter->clear_bytes + iter->cipher_bytes) > buffer_end) {
630 LOG(ERROR) <<
"Subsamples overflow sample buffer.";
633 current_ptr += iter->clear_bytes;
634 if (!encryptor->Decrypt(current_ptr, iter->cipher_bytes, current_ptr)) {
635 LOG(ERROR) <<
"Error decrypting subsample buffer.";
638 current_ptr += iter->cipher_bytes;
643 bool MP4MediaParser::ReadAndDiscardMDATsUntil(
const int64_t offset) {
645 while (mdat_tail_ < offset) {
648 queue_.
PeekAt(mdat_tail_, &buf, &size);
655 mdat_tail_ += box_sz;
657 queue_.
Trim(std::min(mdat_tail_, offset));
661 void MP4MediaParser::ChangeState(State new_state) {
662 DVLOG(2) <<
"Changing state: " << new_state;