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 | |
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 to, see mov_read_trun). | |
wolenetz
2015/08/27 03:01:30
nit: s/to/too/
chcunningham
2015/08/27 18:59:39
Done.
| |
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; | |
wolenetz
2015/08/27 03:01:30
Hmm. This patch drops the automatic compiler check
chcunningham
2015/08/27 18:59:39
I don't think this is more fragile. There are just
wolenetz
2015/08/28 18:23:37
Acknowledged.
| |
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; |
wolenetz
2015/08/27 03:01:30
Do we catch non-keyframe audio buffers in parser,
chcunningham
2015/08/27 18:59:39
We used to (https://b.corp.google.com/issues/12218
wolenetz
2015/08/28 18:23:37
I'll take a look at this (audio frames potentially
| |
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 |