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 { | |
13 static const uint32 kSampleIsDifferenceSampleFlagMask = 0x10000; | |
14 } | |
15 | |
12 namespace media { | 16 namespace media { |
13 namespace mp4 { | 17 namespace mp4 { |
14 | 18 |
15 struct SampleInfo { | 19 struct SampleInfo { |
16 int size; | 20 int size; |
17 int duration; | 21 int duration; |
18 int cts_offset; | 22 int cts_offset; |
19 bool is_keyframe; | 23 bool is_keyframe; |
20 }; | 24 }; |
21 | 25 |
22 struct TrackRunInfo { | 26 struct TrackRunInfo { |
23 uint32 track_id; | 27 uint32 track_id; |
24 std::vector<SampleInfo> samples; | 28 std::vector<SampleInfo> samples; |
25 int64 timescale; | 29 int64 timescale; |
26 int64 start_dts; | 30 int64 start_dts; |
27 int64 sample_start_offset; | 31 int64 sample_start_offset; |
28 | 32 |
29 bool is_audio; | 33 bool is_audio; |
30 const AudioSampleEntry* audio_description; | 34 const AudioSampleEntry* audio_description; |
31 const VideoSampleEntry* video_description; | 35 const VideoSampleEntry* video_description; |
32 | 36 |
37 int64 aux_info_start_offset; // Only valid if aux_info_total_size > 0. | |
38 int aux_info_default_size; | |
39 std::vector<uint8> aux_info_sizes; // Populated if default_size == 0. | |
40 int aux_info_total_size; | |
41 | |
33 TrackRunInfo(); | 42 TrackRunInfo(); |
34 ~TrackRunInfo(); | 43 ~TrackRunInfo(); |
35 }; | 44 }; |
36 | 45 |
37 TrackRunInfo::TrackRunInfo() | 46 TrackRunInfo::TrackRunInfo() |
38 : track_id(0), | 47 : track_id(0), |
39 timescale(-1), | 48 timescale(-1), |
40 start_dts(-1), | 49 start_dts(-1), |
41 sample_start_offset(-1), | 50 sample_start_offset(-1), |
42 is_audio(false) { | 51 is_audio(false), |
52 aux_info_start_offset(-1), | |
53 aux_info_default_size(-1), | |
54 aux_info_total_size(-1) { | |
43 } | 55 } |
44 TrackRunInfo::~TrackRunInfo() {} | 56 TrackRunInfo::~TrackRunInfo() {} |
45 | 57 |
46 TimeDelta TimeDeltaFromFrac(int64 numer, int64 denom) { | 58 TimeDelta TimeDeltaFromRational(int64 numer, int64 denom) { |
47 DCHECK_LT((numer > 0 ? numer : -numer), | 59 DCHECK_LT((numer > 0 ? numer : -numer), |
48 kint64max / base::Time::kMicrosecondsPerSecond); | 60 kint64max / base::Time::kMicrosecondsPerSecond); |
49 return TimeDelta::FromMicroseconds( | 61 return TimeDelta::FromMicroseconds( |
50 base::Time::kMicrosecondsPerSecond * numer / denom); | 62 base::Time::kMicrosecondsPerSecond * numer / denom); |
51 } | 63 } |
52 | 64 |
53 static const uint32 kSampleIsDifferenceSampleFlagMask = 0x10000; | |
54 | |
55 | |
56 TrackRunIterator::TrackRunIterator(const Movie* moov) | 65 TrackRunIterator::TrackRunIterator(const Movie* moov) |
57 : moov_(moov), sample_offset_(0) { | 66 : moov_(moov), sample_offset_(0) { |
58 CHECK(moov); | 67 CHECK(moov); |
59 } | 68 } |
60 TrackRunIterator::~TrackRunIterator() {} | 69 TrackRunIterator::~TrackRunIterator() {} |
61 | 70 |
62 static void PopulateSampleInfo(const TrackExtends& trex, | 71 static void PopulateSampleInfo(const TrackExtends& trex, |
63 const TrackFragmentHeader& tfhd, | 72 const TrackFragmentHeader& tfhd, |
64 const TrackFragmentRun& trun, | 73 const TrackFragmentRun& trun, |
65 const uint32 i, | 74 const uint32 i, |
(...skipping 24 matching lines...) Expand all Loading... | |
90 if (i < trun.sample_flags.size()) { | 99 if (i < trun.sample_flags.size()) { |
91 flags = trun.sample_flags[i]; | 100 flags = trun.sample_flags[i]; |
92 } else if (tfhd.has_default_sample_flags) { | 101 } else if (tfhd.has_default_sample_flags) { |
93 flags = tfhd.default_sample_flags; | 102 flags = tfhd.default_sample_flags; |
94 } else { | 103 } else { |
95 flags = trex.default_sample_flags; | 104 flags = trex.default_sample_flags; |
96 } | 105 } |
97 sample_info->is_keyframe = !(flags & kSampleIsDifferenceSampleFlagMask); | 106 sample_info->is_keyframe = !(flags & kSampleIsDifferenceSampleFlagMask); |
98 } | 107 } |
99 | 108 |
109 // In well-structured encrypted media, each track run will be immediately | |
110 // preceded by its auxiliary information; this is the only optimal storage | |
111 // pattern in terms of minimum number of bytes from a serial stream needed to | |
112 // begin playback. It also allows us to optimize caching on memory-constrained | |
113 // architectures, because we can cache the relatively small auxiliary | |
114 // information for an entire run and then discard data from the input stream, | |
115 // instead of retaining the entire 'mdat' box. | |
116 // | |
117 // We optimize for this situation (with no loss of generality) by sorting track | |
118 // runs during iteration in order of their first data offset (either sample data | |
119 // or auxiliary data). | |
100 class CompareMinTrackRunDataOffset { | 120 class CompareMinTrackRunDataOffset { |
101 public: | 121 public: |
102 bool operator()(const TrackRunInfo& a, const TrackRunInfo& b) { | 122 bool operator()(const TrackRunInfo& a, const TrackRunInfo& b) { |
103 return a.sample_start_offset < b.sample_start_offset; | 123 int64 a_aux = a.aux_info_total_size ? a.aux_info_start_offset : kint64max; |
124 int64 b_aux = b.aux_info_total_size ? b.aux_info_start_offset : kint64max; | |
125 | |
126 int64 a_lesser = std::min(a_aux, a.sample_start_offset); | |
127 int64 a_greater = std::max(a_aux, a.sample_start_offset); | |
128 int64 b_lesser = std::min(b_aux, b.sample_start_offset); | |
129 int64 b_greater = std::max(b_aux, b.sample_start_offset); | |
130 | |
131 if (a_lesser == b_lesser) return a_greater < b_greater; | |
132 return a_lesser < b_lesser; | |
104 } | 133 } |
105 }; | 134 }; |
106 | 135 |
107 bool TrackRunIterator::Init(const MovieFragment& moof) { | 136 bool TrackRunIterator::Init(const MovieFragment& moof) { |
108 runs_.clear(); | 137 runs_.clear(); |
109 | 138 |
110 for (size_t i = 0; i < moof.tracks.size(); i++) { | 139 for (size_t i = 0; i < moof.tracks.size(); i++) { |
111 const TrackFragment& traf = moof.tracks[i]; | 140 const TrackFragment& traf = moof.tracks[i]; |
112 | 141 |
113 const Track* trak = NULL; | 142 const Track* trak = NULL; |
114 for (size_t t = 0; t < moov_->tracks.size(); t++) { | 143 for (size_t t = 0; t < moov_->tracks.size(); t++) { |
115 if (moov_->tracks[t].header.track_id == traf.header.track_id) | 144 if (moov_->tracks[t].header.track_id == traf.header.track_id) |
116 trak = &moov_->tracks[t]; | 145 trak = &moov_->tracks[t]; |
117 } | 146 } |
118 RCHECK(trak); | 147 RCHECK(trak); |
119 | 148 |
120 const TrackExtends* trex = NULL; | 149 const TrackExtends* trex = NULL; |
121 for (size_t t = 0; t < moov_->extends.tracks.size(); t++) { | 150 for (size_t t = 0; t < moov_->extends.tracks.size(); t++) { |
122 if (moov_->extends.tracks[t].track_id == traf.header.track_id) | 151 if (moov_->extends.tracks[t].track_id == traf.header.track_id) |
123 trex = &moov_->extends.tracks[t]; | 152 trex = &moov_->extends.tracks[t]; |
124 } | 153 } |
125 RCHECK(trex); | 154 RCHECK(trex); |
126 | 155 |
127 const SampleDescription& stsd = | 156 const SampleDescription& stsd = |
128 trak->media.information.sample_table.description; | 157 trak->media.information.sample_table.description; |
129 if (stsd.type != kAudio && stsd.type != kVideo) { | 158 if (stsd.type != kAudio && stsd.type != kVideo) { |
130 DVLOG(1) << "Skipping unhandled track type"; | 159 DVLOG(1) << "Skipping unhandled track type"; |
131 continue; | 160 continue; |
132 } | 161 } |
133 int desc_idx = traf.header.sample_description_index; | 162 size_t desc_idx = traf.header.sample_description_index; |
134 if (!desc_idx) desc_idx = trex->default_sample_description_index; | 163 if (!desc_idx) desc_idx = trex->default_sample_description_index; |
135 desc_idx--; // Descriptions are one-indexed in the file | 164 RCHECK(desc_idx > 0); // Descriptions are one-indexed in the file |
165 desc_idx -= 1; | |
136 | 166 |
137 int64 run_start_dts = traf.decode_time.decode_time; | 167 int64 run_start_dts = traf.decode_time.decode_time; |
168 int sample_count_sum = 0; | |
138 | 169 |
139 for (size_t j = 0; j < traf.runs.size(); j++) { | 170 for (size_t j = 0; j < traf.runs.size(); j++) { |
140 const TrackFragmentRun& trun = traf.runs[j]; | 171 const TrackFragmentRun& trun = traf.runs[j]; |
141 TrackRunInfo tri; | 172 TrackRunInfo tri; |
142 tri.track_id = traf.header.track_id; | 173 tri.track_id = traf.header.track_id; |
143 tri.timescale = trak->media.header.timescale; | 174 tri.timescale = trak->media.header.timescale; |
144 tri.start_dts = run_start_dts; | 175 tri.start_dts = run_start_dts; |
145 tri.sample_start_offset = trun.data_offset; | 176 tri.sample_start_offset = trun.data_offset; |
146 | 177 |
147 tri.is_audio = (stsd.type == kAudio); | 178 tri.is_audio = (stsd.type == kAudio); |
148 if (tri.is_audio) { | 179 if (tri.is_audio) { |
180 RCHECK(!stsd.audio_entries.empty()); | |
181 if (desc_idx > stsd.audio_entries.size()) | |
182 desc_idx = 0; | |
149 tri.audio_description = &stsd.audio_entries[desc_idx]; | 183 tri.audio_description = &stsd.audio_entries[desc_idx]; |
150 } else { | 184 } else { |
185 RCHECK(!stsd.video_entries.empty()); | |
186 if (desc_idx > stsd.video_entries.size()) | |
187 desc_idx = 0; | |
151 tri.video_description = &stsd.video_entries[desc_idx]; | 188 tri.video_description = &stsd.video_entries[desc_idx]; |
152 } | 189 } |
153 | 190 |
191 // Collect information from the auxiliary_offset entry with the same index | |
192 // in the 'saiz' container as the current run's index in the 'trun' | |
193 // container, if it is present. | |
194 if (traf.auxiliary_offset.offsets.size() > j) { | |
195 // There should be an auxiliary info entry corresponding to each sample | |
196 // in the auxiliary offset entry's corresponding track run. | |
197 RCHECK(traf.auxiliary_size.sample_count >= | |
198 sample_count_sum + trun.sample_count); | |
199 tri.aux_info_start_offset = traf.auxiliary_offset.offsets[j]; | |
200 tri.aux_info_default_size = | |
201 traf.auxiliary_size.default_sample_info_size; | |
202 if (tri.aux_info_default_size == 0) { | |
203 const std::vector<uint8>& sizes = | |
204 traf.auxiliary_size.sample_info_sizes; | |
205 tri.aux_info_sizes.insert(tri.aux_info_sizes.begin(), | |
206 sizes.begin() + sample_count_sum, | |
207 sizes.begin() + sample_count_sum + trun.sample_count); | |
208 } | |
209 | |
210 // If the default info size is positive, find the total size of the aux | |
211 // info block from it, otherwise sum over the individual sizes of each | |
212 // aux info entry in the aux_offset entry. | |
213 if (tri.aux_info_default_size) { | |
214 tri.aux_info_total_size = | |
215 tri.aux_info_default_size * trun.sample_count; | |
216 } else { | |
217 tri.aux_info_total_size = 0; | |
218 for (size_t k = 0; k < trun.sample_count; k++) { | |
219 tri.aux_info_total_size += tri.aux_info_sizes[k]; | |
220 } | |
221 } | |
222 } else { | |
223 tri.aux_info_start_offset = -1; | |
224 tri.aux_info_total_size = 0; | |
225 } | |
226 | |
154 tri.samples.resize(trun.sample_count); | 227 tri.samples.resize(trun.sample_count); |
155 for (size_t k = 0; k < trun.sample_count; k++) { | 228 for (size_t k = 0; k < trun.sample_count; k++) { |
156 PopulateSampleInfo(*trex, traf.header, trun, k, &tri.samples[k]); | 229 PopulateSampleInfo(*trex, traf.header, trun, k, &tri.samples[k]); |
157 run_start_dts += tri.samples[k].duration; | 230 run_start_dts += tri.samples[k].duration; |
158 } | 231 } |
159 runs_.push_back(tri); | 232 runs_.push_back(tri); |
233 sample_count_sum += trun.sample_count; | |
160 } | 234 } |
161 } | 235 } |
162 | 236 |
163 std::sort(runs_.begin(), runs_.end(), CompareMinTrackRunDataOffset()); | 237 std::sort(runs_.begin(), runs_.end(), CompareMinTrackRunDataOffset()); |
164 run_itr_ = runs_.begin(); | 238 run_itr_ = runs_.begin(); |
165 ResetRun(); | 239 ResetRun(); |
166 return true; | 240 return true; |
167 } | 241 } |
168 | 242 |
169 void TrackRunIterator::AdvanceRun() { | 243 void TrackRunIterator::AdvanceRun() { |
170 ++run_itr_; | 244 ++run_itr_; |
171 ResetRun(); | 245 ResetRun(); |
172 } | 246 } |
173 | 247 |
174 void TrackRunIterator::ResetRun() { | 248 void TrackRunIterator::ResetRun() { |
175 if (!RunIsValid()) return; | 249 if (!IsRunValid()) return; |
176 sample_dts_ = run_itr_->start_dts; | 250 sample_dts_ = run_itr_->start_dts; |
177 sample_offset_ = run_itr_->sample_start_offset; | 251 sample_offset_ = run_itr_->sample_start_offset; |
178 sample_itr_ = run_itr_->samples.begin(); | 252 sample_itr_ = run_itr_->samples.begin(); |
253 cenc_info_.clear(); | |
179 } | 254 } |
180 | 255 |
181 void TrackRunIterator::AdvanceSample() { | 256 void TrackRunIterator::AdvanceSample() { |
182 DCHECK(SampleIsValid()); | 257 DCHECK(IsSampleValid()); |
183 sample_dts_ += sample_itr_->duration; | 258 sample_dts_ += sample_itr_->duration; |
184 sample_offset_ += sample_itr_->size; | 259 sample_offset_ += sample_itr_->size; |
185 ++sample_itr_; | 260 ++sample_itr_; |
186 } | 261 } |
187 | 262 |
188 bool TrackRunIterator::RunIsValid() const { | 263 // This implementation only indicates a need for caching if CENC auxiliary |
264 // info is available in the stream. | |
265 bool TrackRunIterator::AuxInfoNeedsToBeCached() { | |
266 DCHECK(IsRunValid()); | |
267 return is_encrypted() && aux_info_size() > 0 && cenc_info_.size() == 0; | |
268 } | |
269 | |
270 // This implementation currently only caches CENC auxiliary info. | |
271 bool TrackRunIterator::CacheAuxInfo(const uint8* buf, int buf_size) { | |
272 RCHECK(AuxInfoNeedsToBeCached() && buf_size >= aux_info_size()); | |
273 | |
274 cenc_info_.resize(run_itr_->samples.size()); | |
275 int64 pos = 0; | |
276 for (size_t i = 0; i < run_itr_->samples.size(); i++) { | |
277 int info_size = run_itr_->aux_info_default_size; | |
278 if (!info_size) | |
279 info_size = run_itr_->aux_info_sizes[i]; | |
280 | |
281 BufferReader reader(buf + pos, info_size); | |
282 RCHECK(cenc_info_[i].Parse(track_encryption().default_iv_size, &reader)); | |
283 pos += info_size; | |
284 } | |
285 | |
286 return true; | |
287 } | |
288 | |
289 bool TrackRunIterator::IsRunValid() const { | |
189 return run_itr_ != runs_.end(); | 290 return run_itr_ != runs_.end(); |
190 } | 291 } |
191 | 292 |
192 bool TrackRunIterator::SampleIsValid() const { | 293 bool TrackRunIterator::IsSampleValid() const { |
193 return RunIsValid() && (sample_itr_ != run_itr_->samples.end()); | 294 return IsRunValid() && (sample_itr_ != run_itr_->samples.end()); |
194 } | 295 } |
195 | 296 |
297 // Because tracks are in sorted order and auxiliary information is cached when | |
298 // returning samples, it is guaranteed that no data will be required before the | |
299 // lesser of the minimum data offset of this track and the next in sequence. | |
300 // (The stronger condition - that no data is required before the minimum data | |
301 // offset of this track alone - is not guaranteed, because the BMFF spec does | |
302 // not have any inter-run ordering restrictions.) | |
196 int64 TrackRunIterator::GetMaxClearOffset() { | 303 int64 TrackRunIterator::GetMaxClearOffset() { |
197 int64 offset = kint64max; | 304 int64 offset = kint64max; |
198 | 305 |
199 if (SampleIsValid()) | 306 if (IsSampleValid()) { |
200 offset = std::min(offset, sample_offset_); | 307 offset = std::min(offset, sample_offset_); |
201 if (run_itr_ == runs_.end()) | 308 if (AuxInfoNeedsToBeCached()) |
202 return offset; | 309 offset = std::min(offset, aux_info_offset()); |
203 std::vector<TrackRunInfo>::const_iterator next_run = run_itr_ + 1; | 310 } |
204 if (next_run != runs_.end()) | 311 if (run_itr_ != runs_.end()) { |
205 offset = std::min(offset, next_run->sample_start_offset); | 312 std::vector<TrackRunInfo>::const_iterator next_run = run_itr_ + 1; |
313 if (next_run != runs_.end()) { | |
314 offset = std::min(offset, next_run->sample_start_offset); | |
315 if (next_run->aux_info_total_size) | |
316 offset = std::min(offset, next_run->aux_info_start_offset); | |
317 } | |
318 } | |
319 if (offset == kint64max) return 0; | |
206 return offset; | 320 return offset; |
207 } | 321 } |
208 | 322 |
209 TimeDelta TrackRunIterator::GetMinDecodeTimestamp() { | 323 TimeDelta TrackRunIterator::GetMinDecodeTimestamp() { |
210 TimeDelta dts = kInfiniteDuration(); | 324 TimeDelta dts = kInfiniteDuration(); |
211 for (size_t i = 0; i < runs_.size(); i++) { | 325 for (size_t i = 0; i < runs_.size(); i++) { |
212 dts = std::min(dts, TimeDeltaFromFrac(runs_[i].start_dts, | 326 dts = std::min(dts, TimeDeltaFromRational(runs_[i].start_dts, |
213 runs_[i].timescale)); | 327 runs_[i].timescale)); |
214 } | 328 } |
215 return dts; | 329 return dts; |
216 } | 330 } |
217 | 331 |
218 uint32 TrackRunIterator::track_id() const { | 332 uint32 TrackRunIterator::track_id() const { |
219 DCHECK(RunIsValid()); | 333 DCHECK(IsRunValid()); |
220 return run_itr_->track_id; | 334 return run_itr_->track_id; |
221 } | 335 } |
222 | 336 |
223 bool TrackRunIterator::is_encrypted() const { | 337 bool TrackRunIterator::is_encrypted() const { |
224 DCHECK(RunIsValid()); | 338 DCHECK(IsRunValid()); |
225 return false; | 339 return track_encryption().is_encrypted; |
340 } | |
341 | |
342 int64 TrackRunIterator::aux_info_offset() const { | |
343 return run_itr_->aux_info_start_offset; | |
344 } | |
345 | |
346 int TrackRunIterator::aux_info_size() const { | |
347 return run_itr_->aux_info_total_size; | |
226 } | 348 } |
227 | 349 |
228 bool TrackRunIterator::is_audio() const { | 350 bool TrackRunIterator::is_audio() const { |
229 DCHECK(RunIsValid()); | 351 DCHECK(IsRunValid()); |
230 return run_itr_->is_audio; | 352 return run_itr_->is_audio; |
231 } | 353 } |
232 | 354 |
233 const AudioSampleEntry& TrackRunIterator::audio_description() const { | 355 const AudioSampleEntry& TrackRunIterator::audio_description() const { |
234 DCHECK(is_audio()); | 356 DCHECK(is_audio()); |
235 DCHECK(run_itr_->audio_description); | 357 DCHECK(run_itr_->audio_description); |
236 return *run_itr_->audio_description; | 358 return *run_itr_->audio_description; |
237 } | 359 } |
238 | 360 |
239 const VideoSampleEntry& TrackRunIterator::video_description() const { | 361 const VideoSampleEntry& TrackRunIterator::video_description() const { |
240 DCHECK(!is_audio()); | 362 DCHECK(!is_audio()); |
241 DCHECK(run_itr_->video_description); | 363 DCHECK(run_itr_->video_description); |
242 return *run_itr_->video_description; | 364 return *run_itr_->video_description; |
243 } | 365 } |
244 | 366 |
245 int64 TrackRunIterator::sample_offset() const { | 367 int64 TrackRunIterator::sample_offset() const { |
246 DCHECK(SampleIsValid()); | 368 DCHECK(IsSampleValid()); |
247 return sample_offset_; | 369 return sample_offset_; |
248 } | 370 } |
249 | 371 |
250 int TrackRunIterator::sample_size() const { | 372 int TrackRunIterator::sample_size() const { |
251 DCHECK(SampleIsValid()); | 373 DCHECK(IsSampleValid()); |
252 return sample_itr_->size; | 374 return sample_itr_->size; |
253 } | 375 } |
254 | 376 |
255 TimeDelta TrackRunIterator::dts() const { | 377 TimeDelta TrackRunIterator::dts() const { |
256 DCHECK(SampleIsValid()); | 378 DCHECK(IsSampleValid()); |
257 return TimeDeltaFromFrac(sample_dts_, run_itr_->timescale); | 379 return TimeDeltaFromRational(sample_dts_, run_itr_->timescale); |
258 } | 380 } |
259 | 381 |
260 TimeDelta TrackRunIterator::cts() const { | 382 TimeDelta TrackRunIterator::cts() const { |
261 DCHECK(SampleIsValid()); | 383 DCHECK(IsSampleValid()); |
262 return TimeDeltaFromFrac(sample_dts_ + sample_itr_->cts_offset, | 384 return TimeDeltaFromRational(sample_dts_ + sample_itr_->cts_offset, |
263 run_itr_->timescale); | 385 run_itr_->timescale); |
264 } | 386 } |
265 | 387 |
266 TimeDelta TrackRunIterator::duration() const { | 388 TimeDelta TrackRunIterator::duration() const { |
267 DCHECK(SampleIsValid()); | 389 DCHECK(IsSampleValid()); |
268 return TimeDeltaFromFrac(sample_itr_->duration, run_itr_->timescale); | 390 return TimeDeltaFromRational(sample_itr_->duration, run_itr_->timescale); |
269 } | 391 } |
270 | 392 |
271 bool TrackRunIterator::is_keyframe() const { | 393 bool TrackRunIterator::is_keyframe() const { |
272 DCHECK(SampleIsValid()); | 394 DCHECK(IsSampleValid()); |
273 return sample_itr_->is_keyframe; | 395 return sample_itr_->is_keyframe; |
274 } | 396 } |
275 | 397 |
398 const TrackEncryption& TrackRunIterator::track_encryption() const { | |
399 if (is_audio()) | |
400 return audio_description().sinf.info.track_encryption; | |
401 return video_description().sinf.info.track_encryption; | |
402 } | |
403 | |
404 scoped_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() { | |
405 size_t sample_idx = sample_itr_ - run_itr_->samples.begin(); | |
406 DCHECK(sample_idx < cenc_info_.size()); | |
407 const FrameCENCInfo& cenc_info = cenc_info_[sample_idx]; | |
408 DCHECK(is_encrypted() && !AuxInfoNeedsToBeCached()); | |
409 | |
410 if (!cenc_info.subsamples.empty() && | |
411 (cenc_info.GetTotalSizeOfSubsamples() != | |
412 static_cast<size_t>(sample_size()))) { | |
413 DVLOG(1) << "Incorrect CENC subsample size."; | |
414 return scoped_ptr<DecryptConfig>(); | |
415 } | |
416 | |
417 const std::vector<uint8>& kid = track_encryption().default_kid; | |
418 return scoped_ptr<DecryptConfig>(new DecryptConfig( | |
419 std::string(reinterpret_cast<const char*>(&kid[0]), kid.size()), | |
420 std::string(reinterpret_cast<const char*>(cenc_info.iv), | |
421 arraysize(cenc_info.iv)), | |
422 std::string(), // No checksum in CENC MP4 | |
ddorwin
2012/07/25 07:13:47
Period after comments.
CENC after container seems
strobe_
2012/07/25 21:12:36
Done.
| |
423 0, // No offset to start of media data in CENC MP4 | |
424 cenc_info.subsamples)); | |
425 } | |
426 | |
276 } // namespace mp4 | 427 } // namespace mp4 |
277 } // namespace media | 428 } // namespace media |
OLD | NEW |