5#include <packager/media/formats/mp4/mp4_media_parser.h>
11#include <absl/log/check.h>
12#include <absl/log/log.h>
13#include <absl/strings/numbers.h>
15#include <packager/file.h>
16#include <packager/file/file_closer.h>
17#include <packager/macros/compiler.h>
18#include <packager/macros/logging.h>
19#include <packager/media/base/audio_stream_info.h>
20#include <packager/media/base/buffer_reader.h>
21#include <packager/media/base/decrypt_config.h>
22#include <packager/media/base/key_source.h>
23#include <packager/media/base/media_sample.h>
24#include <packager/media/base/rcheck.h>
25#include <packager/media/base/video_stream_info.h>
26#include <packager/media/base/video_util.h>
27#include <packager/media/codecs/ac3_audio_util.h>
28#include <packager/media/codecs/ac4_audio_util.h>
29#include <packager/media/codecs/av1_codec_configuration_record.h>
30#include <packager/media/codecs/avc_decoder_configuration_record.h>
31#include <packager/media/codecs/dovi_decoder_configuration_record.h>
32#include <packager/media/codecs/ec3_audio_util.h>
33#include <packager/media/codecs/es_descriptor.h>
34#include <packager/media/codecs/hevc_decoder_configuration_record.h>
35#include <packager/media/codecs/iamf_audio_util.h>
36#include <packager/media/codecs/vp_codec_configuration_record.h>
37#include <packager/media/formats/mp4/box_definitions.h>
38#include <packager/media/formats/mp4/box_reader.h>
39#include <packager/media/formats/mp4/track_run_iterator.h>
42 use_dovi_supplemental_codecs,
44 "Set to true to signal DolbyVision using the modern supplemental "
45 "codecs approach instead of the legacy "
46 "duplicate representations approach");
53int64_t Rescale(int64_t time_in_old_scale,
56 return (
static_cast<double>(time_in_old_scale) / old_scale) * new_scale;
59H26xStreamFormat GetH26xStreamFormat(FourCC fourcc) {
64 return H26xStreamFormat::kNalUnitStreamWithoutParameterSetNalus;
68 return H26xStreamFormat::kNalUnitStreamWithParameterSetNalus;
70 return H26xStreamFormat::kUnSpecified;
74Codec FourCCToCodec(FourCC fourcc) {
83 return kCodecH265DolbyVision;
126 return kUnknownCodec;
130Codec ObjectTypeToCodec(ObjectType object_type) {
131 switch (object_type) {
132 case ObjectType::kISO_14496_3:
133 case ObjectType::kISO_13818_7_AAC_LC:
135 case ObjectType::kDTSC:
137 case ObjectType::kDTSE:
139 case ObjectType::kDTSH:
141 case ObjectType::kDTSL:
144 return kUnknownCodec;
148std::vector<uint8_t> GetDOVIDecoderConfig(
149 const std::vector<CodecConfiguration>& configs) {
150 for (
const CodecConfiguration& config : configs) {
151 if (config.box_type == FOURCC_dvcC || config.box_type == FOURCC_dvvC) {
155 return std::vector<uint8_t>();
158std::vector<uint8_t> GetLHEVCDecoderConfig(
159 const std::vector<CodecConfiguration>& configs) {
160 for (
const CodecConfiguration& config : configs) {
161 if (config.box_type == FOURCC_lhvC) {
165 return std::vector<uint8_t>();
168bool UpdateCodecStringForDolbyVision(
169 FourCC actual_format,
170 const std::vector<CodecConfiguration>& configs,
171 std::string* codec_string) {
172 DOVIDecoderConfigurationRecord dovi_config;
173 if (!dovi_config.Parse(GetDOVIDecoderConfig(configs))) {
174 LOG(ERROR) <<
"Failed to parse Dolby Vision decoder "
175 "configuration record.";
178 switch (actual_format) {
184 *codec_string = dovi_config.GetCodecString(actual_format);
189 *codec_string +=
";" + dovi_config.GetCodecString(FOURCC_dvhe);
193 *codec_string +=
";" + dovi_config.GetCodecString(FOURCC_dvh1);
196 *codec_string +=
";" + dovi_config.GetCodecString(FOURCC_dav1);
199 LOG(ERROR) <<
"Unsupported format with extra codec "
200 << FourCCToString(actual_format);
206bool UpdateDolbyVisionInfo(FourCC actual_format,
207 const std::vector<CodecConfiguration>& configs,
208 uint8_t transfer_characteristics,
209 std::string* codec_string,
210 std::string* dovi_supplemental_codec_string,
211 FourCC* dovi_compatible_brand) {
212 DOVIDecoderConfigurationRecord dovi_config;
213 if (!dovi_config.Parse(GetDOVIDecoderConfig(configs))) {
214 LOG(ERROR) <<
"Failed to parse Dolby Vision decoder "
215 "configuration record.";
218 switch (actual_format) {
224 *codec_string = dovi_config.GetCodecString(actual_format);
229 *dovi_supplemental_codec_string = dovi_config.GetCodecString(FOURCC_dvhe);
233 *dovi_supplemental_codec_string = dovi_config.GetCodecString(FOURCC_dvh1);
236 *dovi_supplemental_codec_string = dovi_config.GetCodecString(FOURCC_dav1);
239 LOG(ERROR) <<
"Unsupported format with extra codec "
240 << FourCCToString(actual_format);
243 *dovi_compatible_brand =
244 dovi_config.GetDoViCompatibleBrand(transfer_characteristics);
248bool UpdateLHEVCInfo(FourCC actual_format,
249 HEVCDecoderConfigurationRecord& hevc_config,
250 const std::vector<CodecConfiguration>& configs,
251 std::string* codec_string) {
252 if (!hevc_config.ParseLHEVCConfig(GetLHEVCDecoderConfig(configs))) {
253 LOG(ERROR) <<
"Failed to parse L-HEVC decoder "
254 "configuration record.";
257 *codec_string = hevc_config.GetCodecString(actual_format);
261const uint64_t kNanosecondsPerSecond = 1000000000ull;
265MP4MediaParser::MP4MediaParser()
266 : state_(kWaitingForInit),
267 decryption_key_source_(NULL),
271MP4MediaParser::~MP4MediaParser() {}
273void MP4MediaParser::Init(
const InitCB& init_cb,
277 DCHECK_EQ(state_, kWaitingForInit);
278 DCHECK(init_cb_ ==
nullptr);
279 DCHECK(init_cb !=
nullptr);
280 DCHECK(new_media_sample_cb !=
nullptr);
282 ChangeState(kParsingBoxes);
284 new_sample_cb_ = new_media_sample_cb;
285 decryption_key_source_ = decryption_key_source;
286 if (decryption_key_source)
290void MP4MediaParser::Reset() {
297bool MP4MediaParser::Flush() {
298 DCHECK_NE(state_, kWaitingForInit);
300 ChangeState(kParsingBoxes);
304bool MP4MediaParser::Parse(
const uint8_t* buf,
int size) {
305 DCHECK_NE(state_, kWaitingForInit);
307 if (state_ == kError)
310 queue_.Push(buf, size);
312 bool result, err =
false;
315 if (state_ == kParsingBoxes) {
316 result = ParseBox(&err);
318 DCHECK_EQ(kEmittingSamples, state_);
319 result = EnqueueSample(&err);
321 int64_t max_clear = runs_->GetMaxClearOffset() + moof_head_;
322 err = !ReadAndDiscardMDATsUntil(max_clear);
325 }
while (result && !err);
328 DLOG(ERROR) <<
"Error while parsing MP4";
338bool MP4MediaParser::LoadMoov(
const std::string& file_path) {
339 std::unique_ptr<File, FileCloser> file(
340 File::OpenWithNoBuffering(file_path.c_str(),
"r"));
342 LOG(ERROR) <<
"Unable to open media file '" << file_path <<
"'";
345 if (!file->Seek(0)) {
346 LOG(WARNING) <<
"Filesystem does not support seeking on file '" << file_path
351 uint64_t file_position(0);
352 bool mdat_seen(
false);
354 const uint32_t kBoxHeaderReadSize(16);
355 std::vector<uint8_t> buffer(kBoxHeaderReadSize);
356 int64_t bytes_read = file->Read(&buffer[0], kBoxHeaderReadSize);
357 if (bytes_read == 0) {
358 LOG(ERROR) <<
"Could not find 'moov' box in file '" << file_path <<
"'";
361 if (bytes_read < kBoxHeaderReadSize) {
362 LOG(ERROR) <<
"Error reading media file '" << file_path <<
"'";
368 if (!BoxReader::StartBox(&buffer[0], kBoxHeaderReadSize, &box_type,
370 LOG(ERROR) <<
"Could not start box from file '" << file_path <<
"'";
373 if (box_type == FOURCC_mdat) {
375 }
else if (box_type == FOURCC_moov) {
381 if (!Parse(&buffer[0], bytes_read)) {
382 LOG(ERROR) <<
"Error parsing mp4 file '" << file_path <<
"'";
385 uint64_t bytes_to_read = box_size - bytes_read;
386 buffer.resize(bytes_to_read);
387 while (bytes_to_read > 0) {
388 bytes_read = file->Read(&buffer[0], bytes_to_read);
389 if (bytes_read <= 0) {
390 LOG(ERROR) <<
"Error reading 'moov' contents from file '" << file_path
394 if (!Parse(&buffer[0], bytes_read)) {
395 LOG(ERROR) <<
"Error parsing mp4 file '" << file_path <<
"'";
398 bytes_to_read -= bytes_read;
404 file_position += box_size;
405 if (!file->Seek(file_position)) {
406 LOG(ERROR) <<
"Error skipping box in mp4 file '" << file_path <<
"'";
413bool MP4MediaParser::ParseBox(
bool* err) {
416 queue_.Peek(&buf, &size);
420 std::unique_ptr<BoxReader> reader(BoxReader::ReadBox(buf, size, err));
421 if (reader.get() == NULL)
424 if (reader->type() == FOURCC_mdat) {
430 NOTIMPLEMENTED() <<
" Non-seekable Files with 'mdat' box before 'moov' "
431 "box is not supported.";
438 <<
"Ignore unused 'mdat' box - this could be as a result of extra "
439 "not usable 'mdat' or 'mdat' associated with unrecognized track.";
444 mdat_tail_ = queue_.head() + reader->size();
446 if (reader->type() == FOURCC_moov) {
447 *err = !ParseMoov(reader.get());
448 }
else if (reader->type() == FOURCC_moof) {
449 moof_head_ = queue_.head();
450 *err = !ParseMoof(reader.get());
458 VLOG(2) <<
"Skipping top-level box: " << FourCCToString(reader->type());
461 queue_.Pop(
static_cast<int>(reader->size()));
465bool MP4MediaParser::ParseMoov(BoxReader* reader) {
469 moov_.reset(
new Movie);
470 RCHECK(moov_->Parse(reader));
473 std::vector<std::shared_ptr<StreamInfo>> streams;
475 bool use_dovi_supplemental =
476 absl::GetFlag(FLAGS_use_dovi_supplemental_codecs);
478 for (std::vector<Track>::const_iterator track = moov_->tracks.begin();
479 track != moov_->tracks.end(); ++track) {
480 const int32_t timescale = track->media.header.timescale;
483 int64_t duration = 0;
484 if (track->media.header.duration > 0) {
485 duration = track->media.header.duration;
486 }
else if (moov_->extends.header.fragment_duration > 0) {
487 DCHECK(moov_->header.timescale != 0);
488 duration = Rescale(moov_->extends.header.fragment_duration,
489 moov_->header.timescale, timescale);
490 }
else if (moov_->header.duration > 0 &&
491 moov_->header.duration != std::numeric_limits<uint64_t>::max()) {
492 DCHECK(moov_->header.timescale != 0);
494 Rescale(moov_->header.duration, moov_->header.timescale, timescale);
497 const SampleDescription& samp_descr =
498 track->media.information.sample_table.description;
504 if (moov_->extends.tracks.size() > 0) {
505 for (
size_t t = 0; t < moov_->extends.tracks.size(); t++) {
506 const TrackExtends& trex = moov_->extends.tracks[t];
507 if (trex.track_id == track->header.track_id) {
508 desc_idx = trex.default_sample_description_index;
513 const std::vector<ChunkInfo>& chunk_info =
514 track->media.information.sample_table.sample_to_chunk.chunk_info;
515 RCHECK(chunk_info.size() > 0);
516 desc_idx = chunk_info[0].sample_description_index;
518 RCHECK(desc_idx > 0);
521 if (samp_descr.type == kAudio) {
522 RCHECK(!samp_descr.audio_entries.empty());
526 if (desc_idx >= samp_descr.audio_entries.size())
529 const AudioSampleEntry& entry = samp_descr.audio_entries[desc_idx];
530 const FourCC actual_format = entry.GetActualFormat();
531 Codec codec = FourCCToCodec(actual_format);
532 uint8_t num_channels = entry.channelcount;
533 uint32_t sampling_frequency = entry.samplerate;
534 uint64_t codec_delay_ns = 0;
535 uint8_t audio_object_type = 0;
536 uint32_t max_bitrate = 0;
537 uint32_t avg_bitrate = 0;
538 std::vector<uint8_t> codec_config;
540 switch (actual_format) {
542 const DecoderConfigDescriptor& decoder_config =
543 entry.esds.es_descriptor.decoder_config_descriptor();
544 max_bitrate = decoder_config.max_bitrate();
545 avg_bitrate = decoder_config.avg_bitrate();
547 codec = ObjectTypeToCodec(decoder_config.object_type());
548 if (codec == kCodecAAC) {
549 const AACAudioSpecificConfig& aac_audio_specific_config =
550 entry.esds.aac_audio_specific_config;
551 num_channels = aac_audio_specific_config.GetNumChannels();
553 aac_audio_specific_config.GetSamplesPerSecond();
554 audio_object_type = aac_audio_specific_config.GetAudioObjectType();
556 decoder_config.decoder_specific_info_descriptor().data();
557 }
else if (codec == kUnknownCodec) {
562 LOG(WARNING) <<
"Unsupported audio object type "
563 <<
static_cast<int>(decoder_config.object_type())
564 <<
" in stsd.es_desriptor.";
569 FALLTHROUGH_INTENDED;
571 FALLTHROUGH_INTENDED;
573 FALLTHROUGH_INTENDED;
575 FALLTHROUGH_INTENDED;
577 codec_config = entry.ddts.extra_data;
578 max_bitrate = entry.ddts.max_bitrate;
579 avg_bitrate = entry.ddts.avg_bitrate;
582 codec_config = entry.udts.data;
585 codec_config = entry.dac3.data;
586 num_channels =
static_cast<uint8_t
>(GetAc3NumChannels(codec_config));
589 codec_config = entry.dec3.data;
590 num_channels =
static_cast<uint8_t
>(GetEc3NumChannels(codec_config));
593 codec_config = entry.dac4.data;
597 if (!GetAc4CodecInfo(codec_config, &audio_object_type)) {
598 LOG(ERROR) <<
"Failed to parse dac4.";
603 codec_config = entry.alac.data;
606 codec_config = entry.dfla.data;
609 codec_config = entry.dops.opus_identification_header;
611 entry.dops.preskip * kNanosecondsPerSecond / sampling_frequency;
614 codec_config = entry.iacb.data;
615 if (!GetIamfCodecStringInfo(codec_config, audio_object_type)) {
616 LOG(ERROR) <<
"Failed to parse iamf.";
622 codec_config = entry.mhac.data;
623 audio_object_type = entry.mhac.mpeg_h_3da_profile_level_indication;
631 LOG(WARNING) <<
"Unsupported audio format '"
632 << FourCCToString(actual_format) <<
"' in stsd box.";
637 uint64_t seek_preroll_ns = 0;
638 for (
const auto& sample_group_description :
639 track->media.information.sample_table.sample_group_descriptions) {
640 if (sample_group_description.grouping_type != FOURCC_roll)
642 const auto& audio_roll_recovery_entries =
643 sample_group_description.audio_roll_recovery_entries;
644 if (audio_roll_recovery_entries.size() != 1) {
645 LOG(WARNING) <<
"Unexpected number of entries in "
646 "SampleGroupDescription table with grouping type "
650 const int16_t roll_distance_in_samples =
651 audio_roll_recovery_entries[0].roll_distance;
652 if (roll_distance_in_samples < 0) {
655 if (actual_format == FOURCC_iamf)
658 RCHECK((sampling_frequency != 0));
659 seek_preroll_ns = kNanosecondsPerSecond *
660 (-roll_distance_in_samples) / sampling_frequency;
663 <<
"Roll distance is supposed to be negative, but seeing "
664 << roll_distance_in_samples;
670 const bool is_encrypted =
673 : entry.sinf.info.track_encryption.default_is_protected == 1;
674 DVLOG(1) <<
"is_audio_track_encrypted_: " << is_encrypted;
675 streams.emplace_back(
new AudioStreamInfo(
676 track->header.track_id, timescale, duration, codec,
677 AudioStreamInfo::GetCodecString(codec, audio_object_type),
678 codec_config.data(), codec_config.size(), entry.samplesize,
679 num_channels, sampling_frequency, seek_preroll_ns, codec_delay_ns,
680 max_bitrate, avg_bitrate, track->media.header.language.code,
684 if (samp_descr.type == kVideo) {
685 RCHECK(!samp_descr.video_entries.empty());
686 if (desc_idx >= samp_descr.video_entries.size())
688 const VideoSampleEntry& entry = samp_descr.video_entries[desc_idx];
689 std::vector<uint8_t> codec_configuration_data =
690 entry.codec_configuration.data;
692 uint32_t coded_width = entry.width;
693 uint32_t coded_height = entry.height;
694 uint32_t pixel_width = entry.pixel_aspect.h_spacing;
695 uint32_t pixel_height = entry.pixel_aspect.v_spacing;
696 if (pixel_width == 0 && pixel_height == 0) {
697 DerivePixelWidthHeight(coded_width, coded_height, track->header.width,
698 track->header.height, &pixel_width,
701 std::string codec_string;
702 std::string dovi_supplemental_codec_string(
"");
703 FourCC dovi_compatible_brand = FOURCC_NULL;
704 uint8_t nalu_length_size = 0;
705 uint8_t transfer_characteristics = 0;
706 uint8_t color_primaries = 0;
707 uint8_t matrix_coefficients = 0;
709 const FourCC actual_format = entry.GetActualFormat();
710 const Codec video_codec = FourCCToCodec(actual_format);
711 switch (actual_format) {
713 AV1CodecConfigurationRecord av1_config;
714 if (!av1_config.Parse(codec_configuration_data)) {
715 LOG(ERROR) <<
"Failed to parse av1c.";
719 if (entry.colr.color_parameter_type != FOURCC_NULL) {
720 transfer_characteristics = entry.colr.transfer_characteristics;
721 color_primaries = entry.colr.color_primaries;
722 matrix_coefficients = entry.colr.matrix_coefficients;
723 codec_string = av1_config.GetCodecString(
724 color_primaries, transfer_characteristics, matrix_coefficients,
725 entry.colr.video_full_range_flag);
727 codec_string = av1_config.GetCodecString();
730 if (!entry.extra_codec_configs.empty()) {
732 if (use_dovi_supplemental) {
733 if (!UpdateDolbyVisionInfo(
734 actual_format, entry.extra_codec_configs,
735 transfer_characteristics, &codec_string,
736 &dovi_supplemental_codec_string,
737 &dovi_compatible_brand)) {
741 if (!UpdateCodecStringForDolbyVision(actual_format,
742 entry.extra_codec_configs,
752 AVCDecoderConfigurationRecord avc_config;
753 if (!avc_config.Parse(codec_configuration_data)) {
754 LOG(ERROR) <<
"Failed to parse avcc.";
757 codec_string = avc_config.GetCodecString(actual_format);
758 nalu_length_size = avc_config.nalu_length_size();
759 transfer_characteristics = avc_config.transfer_characteristics();
760 color_primaries = avc_config.color_primaries();
761 matrix_coefficients = avc_config.matrix_coefficients();
764 if (avc_config.coded_width() != 0) {
765 DCHECK_NE(avc_config.coded_height(), 0u);
766 if (coded_width != avc_config.coded_width() ||
767 coded_height != avc_config.coded_height()) {
768 LOG(WARNING) <<
"Resolution in VisualSampleEntry (" << coded_width
769 <<
"," << coded_height
770 <<
") does not match with resolution in "
771 "AVCDecoderConfigurationRecord ("
772 << avc_config.coded_width() <<
","
773 << avc_config.coded_height()
774 <<
"). Use AVCDecoderConfigurationRecord.";
775 coded_width = avc_config.coded_width();
776 coded_height = avc_config.coded_height();
779 DCHECK_NE(avc_config.pixel_width(), 0u);
780 DCHECK_NE(avc_config.pixel_height(), 0u);
781 if (pixel_width != avc_config.pixel_width() ||
782 pixel_height != avc_config.pixel_height()) {
783 LOG_IF(WARNING, pixel_width != 1 || pixel_height != 1)
784 <<
"Pixel aspect ratio in PASP box (" << pixel_width <<
","
786 <<
") does not match with SAR in "
787 "AVCDecoderConfigurationRecord "
789 << avc_config.pixel_width() <<
","
790 << avc_config.pixel_height()
791 <<
"). Use AVCDecoderConfigurationRecord.";
792 pixel_width = avc_config.pixel_width();
793 pixel_height = avc_config.pixel_height();
802 HEVCDecoderConfigurationRecord hevc_config;
803 if (!hevc_config.Parse(codec_configuration_data)) {
804 LOG(ERROR) <<
"Failed to parse hevc.";
807 codec_string = hevc_config.GetCodecString(actual_format);
808 nalu_length_size = hevc_config.nalu_length_size();
809 transfer_characteristics = hevc_config.transfer_characteristics();
810 color_primaries = hevc_config.color_primaries();
811 matrix_coefficients = hevc_config.matrix_coefficients();
813 if (!entry.extra_codec_configs.empty()) {
816 if (entry.HaveDolbyVisionConfig()) {
817 if (use_dovi_supplemental) {
818 if (!UpdateDolbyVisionInfo(
819 actual_format, entry.extra_codec_configs,
820 transfer_characteristics, &codec_string,
821 &dovi_supplemental_codec_string,
822 &dovi_compatible_brand)) {
826 if (!UpdateCodecStringForDolbyVision(actual_format,
827 entry.extra_codec_configs,
833 if (entry.HaveLHEVCConfig()) {
834 if (!UpdateLHEVCInfo(actual_format, hevc_config,
835 entry.extra_codec_configs, &codec_string)) {
844 VPCodecConfigurationRecord vp_config;
845 if (!vp_config.ParseMP4(codec_configuration_data)) {
846 LOG(ERROR) <<
"Failed to parse vpcc.";
849 if (actual_format == FOURCC_vp09 &&
850 (!vp_config.is_level_set() || vp_config.level() == 0)) {
851 const double kUnknownSampleDuration = 0.0;
852 vp_config.SetVP9Level(coded_width, coded_height,
853 kUnknownSampleDuration);
854 vp_config.WriteMP4(&codec_configuration_data);
856 codec_string = vp_config.GetCodecString(video_codec);
865 LOG(WARNING) <<
"Unsupported video format '"
866 << FourCCToString(actual_format) <<
"' in stsd box.";
871 const bool is_encrypted =
874 : entry.sinf.info.track_encryption.default_is_protected == 1;
875 DVLOG(1) <<
"is_video_track_encrypted_: " << is_encrypted;
876 std::shared_ptr<VideoStreamInfo> video_stream_info(
new VideoStreamInfo(
877 track->header.track_id, timescale, duration, video_codec,
878 GetH26xStreamFormat(actual_format), codec_string,
879 codec_configuration_data.data(), codec_configuration_data.size(),
880 coded_width, coded_height, pixel_width, pixel_height, color_primaries,
881 matrix_coefficients, transfer_characteristics,
883 nalu_length_size, track->media.header.language.code, is_encrypted));
885 if (use_dovi_supplemental) {
886 video_stream_info->set_supplemental_codec(
887 dovi_supplemental_codec_string);
888 video_stream_info->set_compatible_brand(dovi_compatible_brand);
890 video_stream_info->set_layered_codec_config(
891 GetLHEVCDecoderConfig(entry.extra_codec_configs));
892 video_stream_info->set_extra_config(entry.ExtraCodecConfigsAsVector());
893 video_stream_info->set_colr_data((entry.colr.raw_box).data(),
894 (entry.colr.raw_box).size());
897 if (moov_->pssh.size() > 0) {
898 std::vector<uint8_t> pssh_raw_data;
899 for (
const auto& pssh : moov_->pssh) {
900 pssh_raw_data.insert(pssh_raw_data.end(), pssh.raw_box.begin(),
903 video_stream_info->set_eme_init_data(pssh_raw_data.data(),
904 pssh_raw_data.size());
907 streams.push_back(video_stream_info);
912 if (!FetchKeysIfNecessary(moov_->pssh))
914 runs_.reset(
new TrackRunIterator(moov_.get()));
915 RCHECK(runs_->Init());
916 ChangeState(kEmittingSamples);
920bool MP4MediaParser::ParseMoof(BoxReader* reader) {
924 RCHECK(moof.Parse(reader));
926 runs_.reset(
new TrackRunIterator(moov_.get()));
927 RCHECK(runs_->Init(moof));
928 if (!FetchKeysIfNecessary(moof.pssh))
930 ChangeState(kEmittingSamples);
934bool MP4MediaParser::FetchKeysIfNecessary(
935 const std::vector<ProtectionSystemSpecificHeader>& headers) {
940 if (!decryption_key_source_)
943 std::vector<uint8_t> pssh_raw_data;
944 for (
const auto& header : headers) {
945 pssh_raw_data.insert(pssh_raw_data.end(), header.raw_box.begin(),
946 header.raw_box.end());
949 decryption_key_source_->FetchKeys(EmeInitDataType::CENC, pssh_raw_data);
951 LOG(ERROR) <<
"Error fetching decryption keys: " << status;
957bool MP4MediaParser::EnqueueSample(
bool* err) {
958 if (!runs_->IsRunValid()) {
961 if (!queue_.Trim(mdat_tail_))
964 ChangeState(kParsingBoxes);
968 if (!runs_->IsSampleValid()) {
977 queue_.Peek(&buf, &buf_size);
982 if (!runs_->is_audio() && !runs_->is_video())
992 if (runs_->AuxInfoNeedsToBeCached()) {
993 queue_.PeekAt(runs_->aux_info_offset() + moof_head_, &buf, &buf_size);
994 if (buf_size < runs_->aux_info_size())
996 *err = !runs_->CacheAuxInfo(buf, buf_size);
1000 int64_t sample_offset = runs_->sample_offset() + moof_head_;
1001 queue_.PeekAt(sample_offset, &buf, &buf_size);
1002 if (buf_size < runs_->sample_size()) {
1003 if (sample_offset < queue_.head()) {
1004 LOG(ERROR) <<
"Incorrect sample offset " << sample_offset <<
" < "
1011 const uint8_t* media_data = buf;
1012 const size_t media_data_size = runs_->sample_size();
1015 const size_t kDummyDataSize = 0;
1016 std::shared_ptr<MediaSample> stream_sample(
1017 MediaSample::CopyFrom(media_data, kDummyDataSize, runs_->is_keyframe()));
1019 if (runs_->is_encrypted()) {
1020 std::shared_ptr<uint8_t> decrypted_media_data(
1021 new uint8_t[media_data_size], std::default_delete<uint8_t[]>());
1022 std::unique_ptr<DecryptConfig> decrypt_config = runs_->GetDecryptConfig();
1023 if (!decrypt_config) {
1025 LOG(ERROR) <<
"Missing decrypt config.";
1029 if (!decryptor_source_) {
1030 stream_sample->SetData(media_data, media_data_size);
1033 stream_sample->set_decrypt_config(std::move(decrypt_config));
1034 stream_sample->set_is_encrypted(
true);
1036 if (!decryptor_source_->DecryptSampleBuffer(decrypt_config.get(),
1037 media_data, media_data_size,
1038 decrypted_media_data.get())) {
1040 LOG(ERROR) <<
"Cannot decrypt samples.";
1043 stream_sample->TransferData(std::move(decrypted_media_data),
1047 stream_sample->SetData(media_data, media_data_size);
1050 stream_sample->set_dts(runs_->dts());
1051 stream_sample->set_pts(runs_->cts());
1052 stream_sample->set_duration(runs_->duration());
1054 DVLOG(3) <<
"Pushing frame: "
1055 <<
", key=" << runs_->is_keyframe() <<
", dur=" << runs_->duration()
1056 <<
", dts=" << runs_->dts() <<
", cts=" << runs_->cts()
1057 <<
", size=" << runs_->sample_size();
1059 if (!new_sample_cb_(runs_->track_id(), stream_sample)) {
1061 LOG(ERROR) <<
"Failed to process the sample.";
1065 runs_->AdvanceSample();
1069bool MP4MediaParser::ReadAndDiscardMDATsUntil(
const int64_t offset) {
1071 while (mdat_tail_ < offset) {
1074 queue_.PeekAt(mdat_tail_, &buf, &size);
1078 if (!BoxReader::StartBox(buf, size, &type, &box_sz, &err))
1081 mdat_tail_ += box_sz;
1083 queue_.Trim(std::min(mdat_tail_, offset));
1087void MP4MediaParser::ChangeState(State new_state) {
1088 DVLOG(2) <<
"Changing state: " << new_state;
All the methods that are virtual are virtual for mocking.