Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(70)

Side by Side Diff: media/formats/mp4/track_run_iterator.cc

Issue 1319813002: Fix mp4 keyframe parsing, removing unused stss parsing. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Typo Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « media/formats/mp4/track_run_iterator.h ('k') | media/formats/mp4/track_run_iterator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698