Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/formats/mp4/track_run_iterator.h" | 5 #include "media/formats/mp4/track_run_iterator.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <iomanip> | |
| 8 | 9 |
| 9 #include "media/base/buffers.h" | 10 #include "media/base/buffers.h" |
| 10 #include "media/formats/mp4/rcheck.h" | 11 #include "media/formats/mp4/rcheck.h" |
| 11 #include "media/formats/mp4/sample_to_group_iterator.h" | 12 #include "media/formats/mp4/sample_to_group_iterator.h" |
| 12 | 13 |
| 13 namespace media { | 14 namespace media { |
| 14 namespace mp4 { | 15 namespace mp4 { |
| 15 | 16 |
| 16 struct SampleInfo { | 17 struct SampleInfo { |
| 17 int size; | 18 int size; |
| 18 int duration; | 19 int duration; |
| 19 int cts_offset; | 20 int cts_offset; |
| 20 bool is_keyframe; | 21 bool is_keyframe; |
| 21 bool is_random_access_point; | |
| 22 uint32 cenc_group_description_index; | 22 uint32 cenc_group_description_index; |
| 23 }; | 23 }; |
| 24 | 24 |
| 25 struct TrackRunInfo { | 25 struct TrackRunInfo { |
| 26 uint32 track_id; | 26 uint32 track_id; |
| 27 std::vector<SampleInfo> samples; | 27 std::vector<SampleInfo> samples; |
| 28 int64 timescale; | 28 int64 timescale; |
| 29 int64 start_dts; | 29 int64 start_dts; |
| 30 int64 sample_start_offset; | 30 int64 sample_start_offset; |
| 31 | 31 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 82 } | 82 } |
| 83 | 83 |
| 84 TrackRunIterator::TrackRunIterator(const Movie* moov, | 84 TrackRunIterator::TrackRunIterator(const Movie* moov, |
| 85 const scoped_refptr<MediaLog>& media_log) | 85 const scoped_refptr<MediaLog>& media_log) |
| 86 : moov_(moov), media_log_(media_log), sample_offset_(0) { | 86 : moov_(moov), media_log_(media_log), sample_offset_(0) { |
| 87 CHECK(moov); | 87 CHECK(moov); |
| 88 } | 88 } |
| 89 | 89 |
| 90 TrackRunIterator::~TrackRunIterator() {} | 90 TrackRunIterator::~TrackRunIterator() {} |
| 91 | 91 |
| 92 static std::string HexFlags(uint32 flags) { | |
| 93 std::stringstream stream; | |
| 94 stream << std::setfill('0') << std::setw(sizeof(uint32)*2) << std::hex | |
|
acolwell GONE FROM CHROMIUM
2015/08/28 15:39:01
nit:sizeof(flags) just in case its size changes at
chcunningham
2015/08/28 20:34:47
Done.
| |
| 95 << flags; | |
| 96 return stream.str(); | |
| 97 } | |
| 98 | |
| 92 static bool PopulateSampleInfo(const TrackExtends& trex, | 99 static bool PopulateSampleInfo(const TrackExtends& trex, |
| 93 const TrackFragmentHeader& tfhd, | 100 const TrackFragmentHeader& tfhd, |
| 94 const TrackFragmentRun& trun, | 101 const TrackFragmentRun& trun, |
| 95 const int64 edit_list_offset, | 102 const int64 edit_list_offset, |
| 96 const uint32 i, | 103 const uint32 i, |
| 97 SampleInfo* sample_info, | 104 SampleInfo* sample_info, |
| 98 const SampleDependsOn sdtp_sample_depends_on, | 105 const SampleDependsOn sdtp_sample_depends_on, |
| 106 bool is_audio, | |
| 99 const scoped_refptr<MediaLog>& media_log) { | 107 const scoped_refptr<MediaLog>& media_log) { |
| 100 if (i < trun.sample_sizes.size()) { | 108 if (i < trun.sample_sizes.size()) { |
| 101 sample_info->size = trun.sample_sizes[i]; | 109 sample_info->size = trun.sample_sizes[i]; |
| 102 } else if (tfhd.default_sample_size > 0) { | 110 } else if (tfhd.default_sample_size > 0) { |
| 103 sample_info->size = tfhd.default_sample_size; | 111 sample_info->size = tfhd.default_sample_size; |
| 104 } else { | 112 } else { |
| 105 sample_info->size = trex.default_sample_size; | 113 sample_info->size = trex.default_sample_size; |
| 106 } | 114 } |
| 107 | 115 |
| 108 if (i < trun.sample_durations.size()) { | 116 if (i < trun.sample_durations.size()) { |
| 109 sample_info->duration = trun.sample_durations[i]; | 117 sample_info->duration = trun.sample_durations[i]; |
| 110 } else if (tfhd.default_sample_duration > 0) { | 118 } else if (tfhd.default_sample_duration > 0) { |
| 111 sample_info->duration = tfhd.default_sample_duration; | 119 sample_info->duration = tfhd.default_sample_duration; |
| 112 } else { | 120 } else { |
| 113 sample_info->duration = trex.default_sample_duration; | 121 sample_info->duration = trex.default_sample_duration; |
| 114 } | 122 } |
| 115 | 123 |
| 116 if (i < trun.sample_composition_time_offsets.size()) { | 124 if (i < trun.sample_composition_time_offsets.size()) { |
| 117 sample_info->cts_offset = trun.sample_composition_time_offsets[i]; | 125 sample_info->cts_offset = trun.sample_composition_time_offsets[i]; |
| 118 } else { | 126 } else { |
| 119 sample_info->cts_offset = 0; | 127 sample_info->cts_offset = 0; |
| 120 } | 128 } |
| 121 sample_info->cts_offset += edit_list_offset; | 129 sample_info->cts_offset += edit_list_offset; |
| 122 | 130 |
| 123 uint32 flags; | 131 uint32 flags; |
| 124 if (i < trun.sample_flags.size()) { | 132 if (i < trun.sample_flags.size()) { |
| 125 flags = trun.sample_flags[i]; | 133 flags = trun.sample_flags[i]; |
| 134 DVLOG(4) << __FUNCTION__ << " trun sample flags " << HexFlags(flags); | |
| 126 } else if (tfhd.has_default_sample_flags) { | 135 } else if (tfhd.has_default_sample_flags) { |
| 127 flags = tfhd.default_sample_flags; | 136 flags = tfhd.default_sample_flags; |
| 137 DVLOG(4) << __FUNCTION__ << " tfhd sample flags " << HexFlags(flags); | |
| 128 } else { | 138 } else { |
| 129 flags = trex.default_sample_flags; | 139 flags = trex.default_sample_flags; |
| 140 DVLOG(4) << __FUNCTION__ << " trex sample flags " << HexFlags(flags); | |
| 130 } | 141 } |
| 131 | 142 |
| 132 SampleDependsOn sample_depends_on = | 143 SampleDependsOn sample_depends_on = |
| 133 static_cast<SampleDependsOn>((flags >> 24) & 0x3); | 144 static_cast<SampleDependsOn>((flags >> 24) & 0x3); |
| 145 if (sample_depends_on == kSampleDependsOnUnknown) { | |
| 146 sample_depends_on = sdtp_sample_depends_on; | |
| 147 } | |
| 148 DVLOG(4) << __FUNCTION__ << " sample_depends_on " << sample_depends_on; | |
| 149 if (sample_depends_on == kSampleDependsOnReserved) { | |
| 150 MEDIA_LOG(ERROR, media_log) << "Reserved value used in sample dependency" | |
| 151 " info."; | |
| 152 return false; | |
| 153 } | |
| 134 | 154 |
| 135 if (sample_depends_on == kSampleDependsOnUnknown) | 155 // Per spec (ISO 14496-12:2012), the definition for a "sync sample" is |
| 136 sample_depends_on = sdtp_sample_depends_on; | 156 // equivalent to the downstream code's "is keyframe" concept. But media exists |
| 157 // that marks non-key video frames as sync samples (http://crbug.com/507916 | |
| 158 // and http://crbug.com/310712). Hence, for video we additionally check that | |
| 159 // the sample does not depend on others (FFmpeg does too, see mov_read_trun). | |
| 160 // Sample dependency is not ignored for audio because encoded audio samples | |
| 161 // can depend on other samples and still be used for random access. Generally | |
| 162 // all audio samples are expected to be sync samples, but we prefer to check | |
| 163 // the flags to catch badly muxed audio (for now anyway ;P). History of | |
| 164 // attempts to get this right discussed in http://crrev.com/1319813002 | |
| 165 bool sample_is_sync_sample = !(flags & kSampleIsNonSyncSample); | |
| 166 bool sample_depends_on_others = sample_depends_on == kSampleDependsOnOthers; | |
| 167 sample_info->is_keyframe = sample_is_sync_sample && | |
| 168 (!sample_depends_on_others || is_audio); | |
| 137 | 169 |
| 138 // ISO/IEC 14496-12 Section 8.8.3.1 : The negation of |sample_is_sync_sample| | 170 DVLOG(4) << __FUNCTION__ << " is_kf:" << sample_info->is_keyframe |
| 139 // provides the same information as the sync sample table [8.6.2]. When | 171 << " is_sync:" << sample_is_sync_sample |
| 140 // |sample_is_sync_sample| is true for a sample, it is the same as if the | 172 << " deps:" << sample_depends_on_others |
| 141 // sample were not in a movie fragment and marked with an entry in the sync | 173 << " audio:" << is_audio; |
| 142 // sample table (or, if all samples are sync samples, the sync sample table | |
| 143 // were absent). | |
| 144 bool sample_is_sync_sample = !(flags & kSampleIsNonSyncSample); | |
| 145 sample_info->is_random_access_point = sample_is_sync_sample; | |
| 146 | 174 |
| 147 switch (sample_depends_on) { | |
| 148 case kSampleDependsOnUnknown: | |
| 149 sample_info->is_keyframe = sample_is_sync_sample; | |
| 150 break; | |
| 151 | |
| 152 case kSampleDependsOnOthers: | |
| 153 sample_info->is_keyframe = false; | |
| 154 break; | |
| 155 | |
| 156 case kSampleDependsOnNoOther: | |
| 157 sample_info->is_keyframe = true; | |
| 158 break; | |
| 159 | |
| 160 case kSampleDependsOnReserved: | |
| 161 MEDIA_LOG(ERROR, media_log) << "Reserved value used in sample dependency" | |
| 162 " info."; | |
| 163 return false; | |
| 164 } | |
| 165 return true; | 175 return true; |
| 166 } | 176 } |
| 167 | 177 |
| 168 static const CencSampleEncryptionInfoEntry* GetSampleEncryptionInfoEntry( | 178 static const CencSampleEncryptionInfoEntry* GetSampleEncryptionInfoEntry( |
| 169 const TrackRunInfo& run_info, | 179 const TrackRunInfo& run_info, |
| 170 uint32 group_description_index) { | 180 uint32 group_description_index) { |
| 171 const std::vector<CencSampleEncryptionInfoEntry>* entries = nullptr; | 181 const std::vector<CencSampleEncryptionInfoEntry>* entries = nullptr; |
| 172 | 182 |
| 173 // ISO-14496-12 Section 8.9.2.3 and 8.9.4 : group description index | 183 // ISO-14496-12 Section 8.9.2.3 and 8.9.4 : group description index |
| 174 // (1) ranges from 1 to the number of sample group entries in the track | 184 // (1) ranges from 1 to the number of sample group entries in the track |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 335 } | 345 } |
| 336 } else { | 346 } else { |
| 337 tri.aux_info_start_offset = -1; | 347 tri.aux_info_start_offset = -1; |
| 338 tri.aux_info_total_size = 0; | 348 tri.aux_info_total_size = 0; |
| 339 } | 349 } |
| 340 | 350 |
| 341 tri.samples.resize(trun.sample_count); | 351 tri.samples.resize(trun.sample_count); |
| 342 for (size_t k = 0; k < trun.sample_count; k++) { | 352 for (size_t k = 0; k < trun.sample_count; k++) { |
| 343 if (!PopulateSampleInfo(*trex, traf.header, trun, edit_list_offset, k, | 353 if (!PopulateSampleInfo(*trex, traf.header, trun, edit_list_offset, k, |
| 344 &tri.samples[k], traf.sdtp.sample_depends_on(k), | 354 &tri.samples[k], traf.sdtp.sample_depends_on(k), |
| 345 media_log_)) { | 355 tri.is_audio, media_log_)) { |
| 346 return false; | 356 return false; |
| 347 } | 357 } |
| 348 | 358 |
| 349 run_start_dts += tri.samples[k].duration; | 359 run_start_dts += tri.samples[k].duration; |
| 350 | 360 |
| 351 if (!is_sample_to_group_valid) { | 361 if (!is_sample_to_group_valid) { |
| 352 // Set group description index to 0 to read encryption information | 362 // Set group description index to 0 to read encryption information |
| 353 // from TrackEncryption Box. | 363 // from TrackEncryption Box. |
| 354 tri.samples[k].cenc_group_description_index = 0; | 364 tri.samples[k].cenc_group_description_index = 0; |
| 355 continue; | 365 continue; |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 516 base::TimeDelta TrackRunIterator::duration() const { | 526 base::TimeDelta TrackRunIterator::duration() const { |
| 517 DCHECK(IsSampleValid()); | 527 DCHECK(IsSampleValid()); |
| 518 return TimeDeltaFromRational(sample_itr_->duration, run_itr_->timescale); | 528 return TimeDeltaFromRational(sample_itr_->duration, run_itr_->timescale); |
| 519 } | 529 } |
| 520 | 530 |
| 521 bool TrackRunIterator::is_keyframe() const { | 531 bool TrackRunIterator::is_keyframe() const { |
| 522 DCHECK(IsSampleValid()); | 532 DCHECK(IsSampleValid()); |
| 523 return sample_itr_->is_keyframe; | 533 return sample_itr_->is_keyframe; |
| 524 } | 534 } |
| 525 | 535 |
| 526 bool TrackRunIterator::is_random_access_point() const { | |
| 527 DCHECK(IsSampleValid()); | |
| 528 return sample_itr_->is_random_access_point; | |
| 529 } | |
| 530 | |
| 531 const TrackEncryption& TrackRunIterator::track_encryption() const { | 536 const TrackEncryption& TrackRunIterator::track_encryption() const { |
| 532 if (is_audio()) | 537 if (is_audio()) |
| 533 return audio_description().sinf.info.track_encryption; | 538 return audio_description().sinf.info.track_encryption; |
| 534 return video_description().sinf.info.track_encryption; | 539 return video_description().sinf.info.track_encryption; |
| 535 } | 540 } |
| 536 | 541 |
| 537 scoped_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() { | 542 scoped_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() { |
| 538 DCHECK(is_encrypted()); | 543 DCHECK(is_encrypted()); |
| 539 | 544 |
| 540 if (cenc_info_.empty()) { | 545 if (cenc_info_.empty()) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 584 } | 589 } |
| 585 | 590 |
| 586 uint8 TrackRunIterator::GetIvSize(size_t sample_index) const { | 591 uint8 TrackRunIterator::GetIvSize(size_t sample_index) const { |
| 587 uint32 index = GetGroupDescriptionIndex(sample_index); | 592 uint32 index = GetGroupDescriptionIndex(sample_index); |
| 588 return (index == 0) ? track_encryption().default_iv_size | 593 return (index == 0) ? track_encryption().default_iv_size |
| 589 : GetSampleEncryptionInfoEntry(*run_itr_, index)->iv_size; | 594 : GetSampleEncryptionInfoEntry(*run_itr_, index)->iv_size; |
| 590 } | 595 } |
| 591 | 596 |
| 592 } // namespace mp4 | 597 } // namespace mp4 |
| 593 } // namespace media | 598 } // namespace media |
| OLD | NEW |