OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/mp4/track_run_iterator.h" | 5 #include "media/mp4/track_run_iterator.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "media/base/stream_parser_buffer.h" | 9 #include "media/base/stream_parser_buffer.h" |
10 #include "media/mp4/rcheck.h" | 10 #include "media/mp4/rcheck.h" |
11 | 11 |
12 namespace media { | 12 namespace media { |
13 namespace mp4 { | 13 namespace mp4 { |
14 | 14 |
15 base::TimeDelta TimeDeltaFromFrac(int64 numer, int64 denom) { | 15 struct SampleInfo { |
16 int size; | |
17 int duration; | |
18 int cts_offset; | |
19 bool is_keyframe; | |
20 }; | |
21 | |
22 struct TrackRunInfo { | |
23 uint32 track_id; | |
24 std::vector<SampleInfo> samples; | |
25 int64 timescale; | |
26 int64 start_dts; | |
27 int64 sample_start_offset; | |
28 | |
29 int64 aux_info_start_offset; // Only valid if aux_info_total_size > 0. | |
30 int aux_info_default_size; | |
31 std::vector<uint8> aux_info_sizes; // Present if default_size == 0. | |
ddorwin
2012/07/17 01:14:21
Present => Populated or Non-empty
strobe_
2012/07/19 02:43:35
Done.
| |
32 int aux_info_total_size; | |
33 | |
34 TrackEncryption track_encryption; | |
35 | |
36 TrackRunInfo(); | |
37 ~TrackRunInfo(); | |
38 }; | |
39 | |
40 TrackRunInfo::TrackRunInfo() | |
41 : track_id(0), | |
42 timescale(-1), | |
43 start_dts(-1), | |
44 sample_start_offset(-1), | |
45 aux_info_start_offset(-1), | |
46 aux_info_default_size(-1), | |
47 aux_info_total_size(-1) { | |
48 } | |
49 TrackRunInfo::~TrackRunInfo() {} | |
50 | |
51 TimeDelta TimeDeltaFromFrac(int64 numer, int64 denom) { | |
ddorwin
2012/07/17 01:14:21
Function and var names should usually be complete
ddorwin
2012/07/17 01:14:21
What does "FromFrac" mean? Isn't it really convert
strobe_
2012/07/19 02:43:35
The time base is referred to as the denominator el
| |
16 DCHECK_LT((numer > 0 ? numer : -numer), | 52 DCHECK_LT((numer > 0 ? numer : -numer), |
ddorwin
2012/07/17 01:14:21
use abs()?
strobe_
2012/07/19 02:43:35
Nope, breaks build on cros-tegra2.
| |
17 kint64max / base::Time::kMicrosecondsPerSecond); | 53 kint64max / base::Time::kMicrosecondsPerSecond); |
18 return base::TimeDelta::FromMicroseconds( | 54 return TimeDelta::FromMicroseconds( |
19 base::Time::kMicrosecondsPerSecond * numer / denom); | 55 base::Time::kMicrosecondsPerSecond * numer / denom); |
20 } | 56 } |
21 | 57 |
22 static const uint32 kSampleIsDifferenceSampleFlagMask = 0x10000; | 58 static const uint32 kSampleIsDifferenceSampleFlagMask = 0x10000; |
ddorwin
2012/07/17 01:14:21
file constant should be at the top of the file in
strobe_
2012/07/19 02:43:35
Done.
| |
23 | 59 |
24 TrackRunInfo::TrackRunInfo() | |
25 : track_id(0), | |
26 sample_start_offset(-1), | |
27 is_encrypted(false), | |
28 cenc_start_offset(-1), | |
29 cenc_total_size(-1), | |
30 default_cenc_size(0) {} | |
31 | |
32 TrackRunInfo::~TrackRunInfo() {} | |
33 | 60 |
34 TrackRunIterator::TrackRunIterator() : sample_offset_(0) {} | 61 TrackRunIterator::TrackRunIterator() : sample_offset_(0) {} |
35 TrackRunIterator::~TrackRunIterator() {} | 62 TrackRunIterator::~TrackRunIterator() {} |
36 | 63 |
37 static void PopulateSampleInfo(const Track& trak, | 64 static void PopulateSampleInfo(const TrackExtends& trex, |
38 const TrackExtends& trex, | |
39 const TrackFragmentHeader& tfhd, | 65 const TrackFragmentHeader& tfhd, |
40 const TrackFragmentRun& trun, | 66 const TrackFragmentRun& trun, |
41 const uint32 i, | 67 const uint32 i, |
42 SampleInfo* sample_info) { | 68 SampleInfo* sample_info) { |
43 if (i < trun.sample_sizes.size()) { | 69 if (i < trun.sample_sizes.size()) { |
44 sample_info->size = trun.sample_sizes[i]; | 70 sample_info->size = trun.sample_sizes[i]; |
45 } else if (tfhd.default_sample_size > 0) { | 71 } else if (tfhd.default_sample_size > 0) { |
46 sample_info->size = tfhd.default_sample_size; | 72 sample_info->size = tfhd.default_sample_size; |
47 } else { | 73 } else { |
48 sample_info->size = trex.default_sample_size; | 74 sample_info->size = trex.default_sample_size; |
49 } | 75 } |
50 | 76 |
51 const uint64 timescale = trak.media.header.timescale; | |
52 uint64 duration; | |
53 if (i < trun.sample_durations.size()) { | 77 if (i < trun.sample_durations.size()) { |
54 duration = trun.sample_durations[i]; | 78 sample_info->duration = trun.sample_durations[i]; |
55 } else if (tfhd.default_sample_duration > 0) { | 79 } else if (tfhd.default_sample_duration > 0) { |
56 duration = tfhd.default_sample_duration; | 80 sample_info->duration = tfhd.default_sample_duration; |
57 } else { | 81 } else { |
58 duration = trex.default_sample_duration; | 82 sample_info->duration = trex.default_sample_duration; |
59 } | 83 } |
60 sample_info->duration = TimeDeltaFromFrac(duration, timescale); | |
61 | 84 |
62 if (i < trun.sample_composition_time_offsets.size()) { | 85 if (i < trun.sample_composition_time_offsets.size()) { |
63 sample_info->cts_offset = | 86 sample_info->cts_offset = trun.sample_composition_time_offsets[i]; |
64 TimeDeltaFromFrac(trun.sample_composition_time_offsets[i], timescale); | |
65 } else { | 87 } else { |
66 sample_info->cts_offset = TimeDelta::FromMicroseconds(0); | 88 sample_info->cts_offset = 0; |
67 } | 89 } |
68 | 90 |
69 uint32 flags; | 91 uint32 flags; |
70 if (i < trun.sample_flags.size()) { | 92 if (i < trun.sample_flags.size()) { |
71 flags = trun.sample_flags[i]; | 93 flags = trun.sample_flags[i]; |
72 } else if (tfhd.has_default_sample_flags) { | 94 } else if (tfhd.has_default_sample_flags) { |
73 flags = tfhd.default_sample_flags; | 95 flags = tfhd.default_sample_flags; |
74 } else { | 96 } else { |
75 flags = trex.default_sample_flags; | 97 flags = trex.default_sample_flags; |
76 } | 98 } |
77 sample_info->is_keyframe = !(flags & kSampleIsDifferenceSampleFlagMask); | 99 sample_info->is_keyframe = !(flags & kSampleIsDifferenceSampleFlagMask); |
78 } | 100 } |
79 | 101 |
80 class CompareOffset { | 102 class CompareMinTrackRunDataOffset { |
ddorwin
2012/07/17 01:14:21
What does this do?
strobe_
2012/07/19 02:43:35
Comment added.
| |
81 public: | 103 public: |
82 bool operator()(const TrackRunInfo& a, const TrackRunInfo& b) { | 104 bool operator()(const TrackRunInfo& a, const TrackRunInfo& b) { |
83 int64 a_min = a.sample_start_offset; | 105 int64 a_aux = a.aux_info_total_size ? a.aux_info_start_offset : kint64max; |
84 if (a.is_encrypted && a.cenc_start_offset < a_min) | 106 int64 b_aux = b.aux_info_total_size ? b.aux_info_start_offset : kint64max; |
85 a_min = a.cenc_start_offset; | 107 |
86 int64 b_min = b.sample_start_offset; | 108 int64 a_lesser = std::min(a_aux, a.sample_start_offset); |
87 if (b.is_encrypted && b.cenc_start_offset < b_min) | 109 int64 a_greater = std::max(a_aux, a.sample_start_offset); |
88 b_min = b.cenc_start_offset; | 110 int64 b_lesser = std::min(b_aux, b.sample_start_offset); |
89 return a_min < b_min; | 111 int64 b_greater = std::max(b_aux, b.sample_start_offset); |
112 | |
113 if (a_lesser == b_lesser) return a_greater < b_greater; | |
114 return a_lesser < b_lesser; | |
90 } | 115 } |
91 }; | 116 }; |
92 | 117 |
93 bool TrackRunIterator::Init(const Movie& moov, const MovieFragment& moof) { | 118 bool TrackRunIterator::Init(const Movie& moov, const MovieFragment& moof) { |
94 runs_.clear(); | 119 runs_.clear(); |
95 | 120 |
96 for (size_t i = 0; i < moof.tracks.size(); i++) { | 121 for (size_t i = 0; i < moof.tracks.size(); i++) { |
97 const TrackFragment& traf = moof.tracks[i]; | 122 const TrackFragment& traf = moof.tracks[i]; |
98 | 123 |
99 const Track* trak = NULL; | 124 const Track* trak = NULL; |
100 for (size_t t = 0; t < moov.tracks.size(); t++) { | 125 for (size_t t = 0; t < moov.tracks.size(); t++) { |
101 if (moov.tracks[t].header.track_id == traf.header.track_id) | 126 if (moov.tracks[t].header.track_id == traf.header.track_id) |
102 trak = &moov.tracks[t]; | 127 trak = &moov.tracks[t]; |
103 } | 128 } |
129 RCHECK(trak); | |
104 | 130 |
105 const TrackExtends* trex = NULL; | 131 const TrackExtends* trex = NULL; |
106 for (size_t t = 0; t < moov.extends.tracks.size(); t++) { | 132 for (size_t t = 0; t < moov.extends.tracks.size(); t++) { |
107 if (moov.extends.tracks[t].track_id == traf.header.track_id) | 133 if (moov.extends.tracks[t].track_id == traf.header.track_id) |
108 trex = &moov.extends.tracks[t]; | 134 trex = &moov.extends.tracks[t]; |
109 } | 135 } |
110 RCHECK(trak && trex); | 136 RCHECK(trex); |
111 | 137 |
138 // TODO(strobe): Support multiple sample description entries | |
112 const ProtectionSchemeInfo* sinf = NULL; | 139 const ProtectionSchemeInfo* sinf = NULL; |
113 const SampleDescription& stsd = | 140 const SampleDescription& stsd = |
114 trak->media.information.sample_table.description; | 141 trak->media.information.sample_table.description; |
115 if (stsd.type == kAudio) { | 142 if (stsd.type == kAudio) { |
116 sinf = &stsd.audio_entries[0].sinf; | 143 sinf = &stsd.audio_entries[0].sinf; |
117 } else if (stsd.type == kVideo) { | 144 } else if (stsd.type == kVideo) { |
118 sinf = &stsd.video_entries[0].sinf; | 145 sinf = &stsd.video_entries[0].sinf; |
119 } else { | 146 } else { |
120 DVLOG(1) << "Skipping unhandled track type"; | 147 DVLOG(1) << "Skipping unhandled track type"; |
121 continue; | 148 continue; |
122 } | 149 } |
123 | 150 |
124 if (sinf->info.track_encryption.is_encrypted) { | 151 int64 run_start_dts = traf.decode_time.decode_time; |
125 // TODO(strobe): CENC recovery and testing (http://crbug.com/132351) | |
126 DVLOG(1) << "Encrypted tracks not handled"; | |
127 continue; | |
128 } | |
129 | 152 |
130 for (size_t j = 0; j < traf.runs.size(); j++) { | 153 for (size_t j = 0; j < traf.runs.size(); j++) { |
131 const TrackFragmentRun& trun = traf.runs[j]; | 154 const TrackFragmentRun& trun = traf.runs[j]; |
132 TrackRunInfo tri; | 155 TrackRunInfo tri; |
133 tri.track_id = traf.header.track_id; | 156 tri.track_id = traf.header.track_id; |
134 tri.start_dts = TimeDeltaFromFrac(traf.decode_time.decode_time, | 157 tri.timescale = trak->media.header.timescale; |
135 trak->media.header.timescale); | 158 tri.start_dts = run_start_dts; |
136 tri.sample_start_offset = trun.data_offset; | 159 tri.sample_start_offset = trun.data_offset; |
137 | 160 |
138 tri.is_encrypted = false; | 161 // Collect information from the auxiliary_offset entry with the same index |
139 tri.cenc_start_offset = 0; | 162 // in the 'saiz' container as the current run's index in the 'trun' |
140 tri.cenc_total_size = 0; | 163 // container, if it is present. |
141 tri.default_cenc_size = 0; | 164 if (traf.auxiliary_offset.offsets.size() > j) { |
165 // There should be an auxiliary info entry corresponding to each sample | |
166 // in the auxiliary offset entry's corresponding track run. | |
167 RCHECK(traf.auxiliary_size.sample_count == trun.sample_count); | |
168 tri.aux_info_start_offset = traf.auxiliary_offset.offsets[j]; | |
169 tri.aux_info_default_size = | |
170 traf.auxiliary_size.default_sample_info_size; | |
171 tri.aux_info_sizes = traf.auxiliary_size.sample_info_sizes; | |
172 | |
173 // If the default info size is positive, find the total size of the aux | |
174 // info block from it, otherwise sum over the individual sizes of each | |
175 // aux info entry in the aux_offset entry. | |
176 if (tri.aux_info_default_size) { | |
177 tri.aux_info_total_size = | |
178 tri.aux_info_default_size * trun.sample_count; | |
179 } else { | |
180 tri.aux_info_total_size = 0; | |
181 for (size_t k = 0; k < trun.sample_count; k++) { | |
182 tri.aux_info_total_size += tri.aux_info_sizes[k]; | |
183 } | |
184 } | |
185 } else { | |
186 tri.aux_info_start_offset = -1; | |
187 tri.aux_info_total_size = 0; | |
188 } | |
189 tri.track_encryption = sinf->info.track_encryption; | |
142 | 190 |
143 tri.samples.resize(trun.sample_count); | 191 tri.samples.resize(trun.sample_count); |
144 | |
145 for (size_t k = 0; k < trun.sample_count; k++) { | 192 for (size_t k = 0; k < trun.sample_count; k++) { |
146 PopulateSampleInfo(*trak, *trex, traf.header, trun, k, &tri.samples[k]); | 193 PopulateSampleInfo(*trex, traf.header, trun, k, &tri.samples[k]); |
194 run_start_dts += tri.samples[k].duration; | |
147 } | 195 } |
148 runs_.push_back(tri); | 196 runs_.push_back(tri); |
149 } | 197 } |
150 } | 198 } |
151 | 199 |
152 std::sort(runs_.begin(), runs_.end(), CompareOffset()); | 200 std::sort(runs_.begin(), runs_.end(), CompareMinTrackRunDataOffset()); |
153 run_itr_ = runs_.begin(); | 201 run_itr_ = runs_.begin(); |
154 min_clear_offset_itr_ = min_clear_offsets_.begin(); | |
155 ResetRun(); | 202 ResetRun(); |
156 return true; | 203 return true; |
157 } | 204 } |
158 | 205 |
159 void TrackRunIterator::AdvanceRun() { | 206 void TrackRunIterator::AdvanceRun() { |
160 ++run_itr_; | 207 ++run_itr_; |
161 if (min_clear_offset_itr_ != min_clear_offsets_.end()) | |
162 ++min_clear_offset_itr_; | |
163 ResetRun(); | 208 ResetRun(); |
164 } | 209 } |
165 | 210 |
166 void TrackRunIterator::ResetRun() { | 211 void TrackRunIterator::ResetRun() { |
167 if (!RunValid()) return; | 212 if (!RunIsValid()) return; |
168 sample_dts_ = run_itr_->start_dts; | 213 sample_dts_ = run_itr_->start_dts; |
169 sample_offset_ = run_itr_->sample_start_offset; | 214 sample_offset_ = run_itr_->sample_start_offset; |
170 sample_itr_ = run_itr_->samples.begin(); | 215 sample_itr_ = run_itr_->samples.begin(); |
216 cenc_info_.clear(); | |
171 } | 217 } |
172 | 218 |
173 void TrackRunIterator::AdvanceSample() { | 219 void TrackRunIterator::AdvanceSample() { |
174 DCHECK(SampleValid()); | 220 DCHECK(SampleIsValid()); |
175 sample_dts_ += sample_itr_->duration; | 221 sample_dts_ += sample_itr_->duration; |
176 sample_offset_ += sample_itr_->size; | 222 sample_offset_ += sample_itr_->size; |
177 ++sample_itr_; | 223 ++sample_itr_; |
178 } | 224 } |
179 | 225 |
180 bool TrackRunIterator::NeedsCENC() { | 226 // This implementation only indicates a need for caching if CENC auxiliary |
181 CHECK(!is_encrypted()) << "TODO(strobe): Implement CENC."; | 227 // info is available in the stream. |
182 return is_encrypted(); | 228 bool TrackRunIterator::AuxInfoNeedsToBeCached() { |
183 } | 229 DCHECK(RunIsValid()); |
184 | 230 return is_encrypted() && aux_info_size() > 0 && cenc_info_.size() == 0; |
185 bool TrackRunIterator::CacheCENC(const uint8* buf, int size) { | 231 } |
186 LOG(FATAL) << "Not implemented"; | 232 |
187 return false; | 233 // This implementation currently only caches CENC auxiliary info. |
188 } | 234 bool TrackRunIterator::CacheAuxInfo(const uint8* buf, int buf_size) { |
189 | 235 RCHECK(AuxInfoNeedsToBeCached() && buf_size >= aux_info_size()); |
190 bool TrackRunIterator::RunValid() const { | 236 |
237 cenc_info_.resize(run_itr_->samples.size()); | |
238 int64 pos = 0; | |
239 for (size_t i = 0; i < run_itr_->samples.size(); i++) { | |
240 int info_size = run_itr_->aux_info_default_size; | |
241 if (!info_size) | |
242 info_size = run_itr_->aux_info_sizes[i]; | |
243 | |
244 BufferReader reader(buf + pos, info_size); | |
245 RCHECK(cenc_info_[i].Parse(run_itr_->track_encryption.default_iv_size, | |
246 &reader)); | |
247 pos += info_size; | |
248 } | |
249 | |
250 return true; | |
251 } | |
252 | |
253 bool TrackRunIterator::RunIsValid() const { | |
191 return run_itr_ != runs_.end(); | 254 return run_itr_ != runs_.end(); |
192 } | 255 } |
193 | 256 |
194 bool TrackRunIterator::SampleValid() const { | 257 bool TrackRunIterator::SampleIsValid() const { |
195 return RunValid() && (sample_itr_ != run_itr_->samples.end()); | 258 return RunIsValid() && (sample_itr_ != run_itr_->samples.end()); |
196 } | 259 } |
197 | 260 |
198 int64 TrackRunIterator::GetMaxClearOffset() { | 261 int64 TrackRunIterator::GetMaxClearOffset() { |
199 int64 offset = kint64max; | 262 int64 offset = kint64max; |
ddorwin
2012/07/17 01:14:21
max_offset?
strobe_
2012/07/19 02:43:35
Well, internal to this function, it's really the m
| |
200 | 263 |
201 if (SampleValid()) { | 264 if (SampleIsValid()) { |
202 offset = std::min(offset, sample_offset_); | 265 offset = std::min(offset, sample_offset_); |
203 if (NeedsCENC()) { | 266 if (AuxInfoNeedsToBeCached()) { |
204 offset = std::min(offset, cenc_offset()); | 267 offset = std::min(offset, aux_info_offset()); |
205 } | 268 } |
206 } | 269 } |
207 if (min_clear_offset_itr_ != min_clear_offsets_.end()) { | 270 if (run_itr_ != runs_.end()) { |
208 offset = std::min(offset, *min_clear_offset_itr_); | 271 std::vector<TrackRunInfo>::const_iterator next_run = run_itr_ + 1; |
209 } | 272 if (next_run != runs_.end()) { |
210 if (offset == kint64max) return 0; | 273 offset = std::min(offset, next_run->sample_start_offset); |
274 if (next_run->aux_info_total_size) | |
275 offset = std::min(offset, next_run->aux_info_start_offset); | |
276 } | |
277 } | |
211 return offset; | 278 return offset; |
212 } | 279 } |
213 | 280 |
214 TimeDelta TrackRunIterator::GetMinDecodeTimestamp() { | 281 TimeDelta TrackRunIterator::GetMinDecodeTimestamp() { |
215 TimeDelta dts = kInfiniteDuration(); | 282 TimeDelta dts = kInfiniteDuration(); |
216 for (size_t i = 0; i < runs_.size(); i++) { | 283 for (size_t i = 0; i < runs_.size(); i++) { |
217 if (runs_[i].start_dts < dts) | 284 TimeDelta run_dts = TimeDeltaFromFrac(runs_[i].start_dts, |
218 dts = runs_[i].start_dts; | 285 runs_[i].timescale); |
286 if (run_dts < dts) | |
287 dts = run_dts; | |
ddorwin
2012/07/17 01:14:21
Why?
strobe_
2012/07/19 02:43:35
Addressed by rebase.
| |
219 } | 288 } |
220 return dts; | 289 return dts; |
221 } | 290 } |
222 | 291 |
223 uint32 TrackRunIterator::track_id() const { | 292 uint32 TrackRunIterator::track_id() const { |
224 DCHECK(RunValid()); | 293 DCHECK(RunIsValid()); |
225 return run_itr_->track_id; | 294 return run_itr_->track_id; |
226 } | 295 } |
227 | 296 |
228 bool TrackRunIterator::is_encrypted() const { | 297 bool TrackRunIterator::is_encrypted() const { |
229 DCHECK(RunValid()); | 298 DCHECK(RunIsValid()); |
230 return run_itr_->is_encrypted; | 299 return run_itr_->track_encryption.is_encrypted; |
231 } | 300 } |
232 | 301 |
233 int64 TrackRunIterator::cenc_offset() const { | 302 int64 TrackRunIterator::aux_info_offset() const { |
234 DCHECK(is_encrypted()); | 303 return run_itr_->aux_info_start_offset; |
235 return run_itr_->cenc_start_offset; | 304 } |
236 } | 305 |
237 | 306 int TrackRunIterator::aux_info_size() const { |
238 int TrackRunIterator::cenc_size() const { | 307 return run_itr_->aux_info_total_size; |
239 DCHECK(is_encrypted()); | 308 } |
240 return run_itr_->cenc_total_size; | 309 |
241 } | 310 int64 TrackRunIterator::sample_offset() const { |
242 | 311 DCHECK(SampleIsValid()); |
243 int64 TrackRunIterator::offset() const { | |
244 DCHECK(SampleValid()); | |
245 return sample_offset_; | 312 return sample_offset_; |
246 } | 313 } |
247 | 314 |
248 int TrackRunIterator::size() const { | 315 int TrackRunIterator::sample_size() const { |
249 DCHECK(SampleValid()); | 316 DCHECK(SampleIsValid()); |
250 return sample_itr_->size; | 317 return sample_itr_->size; |
251 } | 318 } |
252 | 319 |
253 TimeDelta TrackRunIterator::dts() const { | 320 TimeDelta TrackRunIterator::dts() const { |
254 DCHECK(SampleValid()); | 321 DCHECK(SampleIsValid()); |
255 return sample_dts_; | 322 return TimeDeltaFromFrac(sample_dts_, run_itr_->timescale); |
256 } | 323 } |
257 | 324 |
258 TimeDelta TrackRunIterator::cts() const { | 325 TimeDelta TrackRunIterator::cts() const { |
259 DCHECK(SampleValid()); | 326 DCHECK(SampleIsValid()); |
260 return sample_dts_ + sample_itr_->cts_offset; | 327 return TimeDeltaFromFrac(sample_dts_ + sample_itr_->cts_offset, |
328 run_itr_->timescale); | |
261 } | 329 } |
262 | 330 |
263 TimeDelta TrackRunIterator::duration() const { | 331 TimeDelta TrackRunIterator::duration() const { |
264 DCHECK(SampleValid()); | 332 DCHECK(SampleIsValid()); |
265 return sample_itr_->duration; | 333 return TimeDeltaFromFrac(sample_itr_->duration, run_itr_->timescale); |
266 } | 334 } |
267 | 335 |
268 bool TrackRunIterator::is_keyframe() const { | 336 bool TrackRunIterator::is_keyframe() const { |
269 DCHECK(SampleValid()); | 337 DCHECK(SampleIsValid()); |
270 return sample_itr_->is_keyframe; | 338 return sample_itr_->is_keyframe; |
271 } | 339 } |
272 | 340 |
273 const FrameCENCInfo& TrackRunIterator::frame_cenc_info() { | 341 scoped_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() { |
274 DCHECK(is_encrypted()); | 342 int sample_idx = sample_itr_ - run_itr_->samples.begin(); |
275 return frame_cenc_info_; | 343 const FrameCENCInfo& cenc_info = cenc_info_[sample_idx]; |
ddorwin
2012/07/17 01:14:21
check size of the vector/array first.
strobe_
2012/07/19 02:43:35
Done.
| |
344 DCHECK(is_encrypted() && !AuxInfoNeedsToBeCached()); | |
345 | |
346 if (!cenc_info.subsamples.empty() && | |
347 (cenc_info.GetTotalSizeOfSubsamples() != | |
348 static_cast<size_t>(sample_size()))) { | |
349 DVLOG(1) << "Incorrect CENC subsample size."; | |
350 return scoped_ptr<DecryptConfig>(); | |
351 } | |
352 | |
353 return scoped_ptr<DecryptConfig>(new DecryptConfig( | |
354 &run_itr_->track_encryption.default_kid[0], | |
355 run_itr_->track_encryption.default_kid.size(), | |
356 std::string(cenc_info.iv, cenc_info.iv + arraysize(cenc_info.iv)), | |
ddorwin
2012/07/17 01:14:21
why not just size as second param?
strobe_
2012/07/19 02:43:35
Would require typecasting.
| |
357 cenc_info.subsamples)); | |
276 } | 358 } |
277 | 359 |
278 } // namespace mp4 | 360 } // namespace mp4 |
279 } // namespace media | 361 } // namespace media |
OLD | NEW |