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, uint64 denom) { | 15 base::TimeDelta TimeDeltaFromFrac(int64 numer, uint64 denom) { |
16 DCHECK_LT((numer > 0 ? numer : -numer), | 16 DCHECK_LT((numer > 0 ? numer : -numer), |
17 kint64max / base::Time::kMicrosecondsPerSecond); | 17 kint64max / base::Time::kMicrosecondsPerSecond); |
18 return base::TimeDelta::FromMicroseconds( | 18 return base::TimeDelta::FromMicroseconds( |
19 base::Time::kMicrosecondsPerSecond * numer / denom); | 19 base::Time::kMicrosecondsPerSecond * numer / denom); |
20 } | 20 } |
21 | 21 |
22 static const uint32 kSampleIsDifferenceSampleFlagMask = 0x10000; | 22 static const uint32 kSampleIsDifferenceSampleFlagMask = 0x10000; |
23 | 23 |
24 TrackRunInfo::TrackRunInfo() | 24 TrackRunInfo::TrackRunInfo() |
25 : track_id(0), | 25 : track_id(0), |
26 sample_start_offset(-1), | 26 sample_start_offset(-1), |
27 is_encrypted(false), | 27 aux_info_start_offset(-1), |
28 cenc_start_offset(-1), | 28 aux_info_default_size(-1), |
29 cenc_total_size(-1), | 29 aux_info_total_size(-1) { |
30 default_cenc_size(0) {} | 30 } |
31 | 31 |
32 TrackRunInfo::~TrackRunInfo() {} | 32 TrackRunInfo::~TrackRunInfo() {} |
33 | 33 |
34 TrackRunIterator::TrackRunIterator() : sample_offset_(0) {} | 34 TrackRunIterator::TrackRunIterator() : sample_offset_(0) {} |
35 TrackRunIterator::~TrackRunIterator() {} | 35 TrackRunIterator::~TrackRunIterator() {} |
36 | 36 |
37 static void PopulateSampleInfo(const Track& trak, | 37 static void PopulateSampleInfo(const Track& trak, |
38 const TrackExtends& trex, | 38 const TrackExtends& trex, |
39 const TrackFragmentHeader& tfhd, | 39 const TrackFragmentHeader& tfhd, |
40 const TrackFragmentRun& trun, | 40 const TrackFragmentRun& trun, |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
74 } else { | 74 } else { |
75 flags = trex.default_sample_flags; | 75 flags = trex.default_sample_flags; |
76 } | 76 } |
77 sample_info->is_keyframe = !(flags & kSampleIsDifferenceSampleFlagMask); | 77 sample_info->is_keyframe = !(flags & kSampleIsDifferenceSampleFlagMask); |
78 } | 78 } |
79 | 79 |
80 class CompareOffset { | 80 class CompareOffset { |
81 public: | 81 public: |
82 bool operator()(const TrackRunInfo& a, const TrackRunInfo& b) { | 82 bool operator()(const TrackRunInfo& a, const TrackRunInfo& b) { |
83 int64 a_min = a.sample_start_offset; | 83 int64 a_min = a.sample_start_offset; |
84 if (a.is_encrypted && a.cenc_start_offset < a_min) | 84 if (a.aux_info_total_size > 0 && a.aux_info_start_offset < a_min) |
85 a_min = a.cenc_start_offset; | 85 a_min = a.aux_info_start_offset; |
86 int64 b_min = b.sample_start_offset; | 86 int64 b_min = b.sample_start_offset; |
87 if (b.is_encrypted && b.cenc_start_offset < b_min) | 87 if (b.aux_info_total_size > 0 && b.aux_info_start_offset < b_min) |
88 b_min = b.cenc_start_offset; | 88 b_min = b.aux_info_start_offset; |
89 return a_min < b_min; | 89 return a_min < b_min; |
90 } | 90 } |
91 }; | 91 }; |
92 | 92 |
93 bool TrackRunIterator::Init(const Movie& moov, const MovieFragment& moof) { | 93 bool TrackRunIterator::Init(const Movie& moov, const MovieFragment& moof) { |
94 runs_.clear(); | 94 runs_.clear(); |
95 | 95 |
96 for (size_t i = 0; i < moof.tracks.size(); i++) { | 96 for (size_t i = 0; i < moof.tracks.size(); i++) { |
97 const TrackFragment& traf = moof.tracks[i]; | 97 const TrackFragment& traf = moof.tracks[i]; |
98 | 98 |
(...skipping 15 matching lines...) Expand all Loading... | |
114 trak->media.information.sample_table.description; | 114 trak->media.information.sample_table.description; |
115 if (stsd.type == kAudio) { | 115 if (stsd.type == kAudio) { |
116 sinf = &stsd.audio_entries[0].sinf; | 116 sinf = &stsd.audio_entries[0].sinf; |
117 } else if (stsd.type == kVideo) { | 117 } else if (stsd.type == kVideo) { |
118 sinf = &stsd.video_entries[0].sinf; | 118 sinf = &stsd.video_entries[0].sinf; |
119 } else { | 119 } else { |
120 DVLOG(1) << "Skipping unhandled track type"; | 120 DVLOG(1) << "Skipping unhandled track type"; |
121 continue; | 121 continue; |
122 } | 122 } |
123 | 123 |
124 if (sinf->info.track_encryption.is_encrypted) { | |
125 // TODO(strobe): CENC recovery and testing (http://crbug.com/132351) | |
126 DVLOG(1) << "Encrypted tracks not handled"; | |
127 continue; | |
128 } | |
129 | |
130 for (size_t j = 0; j < traf.runs.size(); j++) { | 124 for (size_t j = 0; j < traf.runs.size(); j++) { |
131 const TrackFragmentRun& trun = traf.runs[j]; | 125 const TrackFragmentRun& trun = traf.runs[j]; |
132 TrackRunInfo tri; | 126 TrackRunInfo tri; |
133 tri.track_id = traf.header.track_id; | 127 tri.track_id = traf.header.track_id; |
134 tri.start_dts = TimeDeltaFromFrac(traf.decode_time.decode_time, | 128 tri.start_dts = TimeDeltaFromFrac(traf.decode_time.decode_time, |
135 trak->media.header.timescale); | 129 trak->media.header.timescale); |
136 tri.sample_start_offset = trun.data_offset; | 130 tri.sample_start_offset = trun.data_offset; |
137 | 131 |
138 tri.is_encrypted = false; | 132 // Collect information from the auxiliary_offset entry with the same index |
139 tri.cenc_start_offset = 0; | 133 // in the 'saiz' container as the current run's index in the 'trun' |
140 tri.cenc_total_size = 0; | 134 // container, if it is present |
xhwang
2012/06/27 19:37:43
Add period "." at the end.
strobe_
2012/07/13 00:47:07
Done.
| |
141 tri.default_cenc_size = 0; | 135 if (traf.auxiliary_offset.offsets.size() > j) { |
136 // There should be an auxiliary info entry corresponding to each sample | |
137 // in the auxiliary offset entry's corresponding track run | |
138 RCHECK(traf.auxiliary_size.sample_count == trun.sample_count); | |
139 tri.aux_info_start_offset = traf.auxiliary_offset.offsets[j]; | |
140 tri.aux_info_default_size = | |
141 traf.auxiliary_size.default_sample_info_size; | |
142 tri.aux_info_sizes = traf.auxiliary_size.sample_info_sizes; | |
143 | |
144 // If the default info size is positive, find the total size of the aux | |
145 // info block from it, otherwise sum over the individual sizes of each | |
146 // aux info entry in the aux_offset entry | |
147 if (tri.aux_info_default_size) { | |
148 tri.aux_info_total_size = | |
149 tri.aux_info_default_size * trun.sample_count; | |
150 } else { | |
151 tri.aux_info_total_size = 0; | |
152 for (size_t k = 0; k < trun.sample_count; k++) { | |
153 tri.aux_info_total_size += tri.aux_info_sizes[k]; | |
154 } | |
155 } | |
156 } else { | |
157 tri.aux_info_start_offset = 0; | |
158 tri.aux_info_total_size = 0; | |
159 } | |
160 tri.track_encryption = sinf->info.track_encryption; | |
142 | 161 |
143 tri.samples.resize(trun.sample_count); | 162 tri.samples.resize(trun.sample_count); |
144 | |
145 for (size_t k = 0; k < trun.sample_count; k++) { | 163 for (size_t k = 0; k < trun.sample_count; k++) { |
146 PopulateSampleInfo(*trak, *trex, traf.header, trun, k, &tri.samples[k]); | 164 PopulateSampleInfo(*trak, *trex, traf.header, trun, k, &tri.samples[k]); |
147 } | 165 } |
148 runs_.push_back(tri); | 166 runs_.push_back(tri); |
149 } | 167 } |
150 } | 168 } |
151 | 169 |
152 std::sort(runs_.begin(), runs_.end(), CompareOffset()); | 170 std::sort(runs_.begin(), runs_.end(), CompareOffset()); |
153 run_itr_ = runs_.begin(); | 171 run_itr_ = runs_.begin(); |
154 min_clear_offset_itr_ = min_clear_offsets_.begin(); | 172 min_clear_offset_itr_ = min_clear_offsets_.begin(); |
155 ResetRun(); | 173 ResetRun(); |
156 return true; | 174 return true; |
157 } | 175 } |
158 | 176 |
159 void TrackRunIterator::AdvanceRun() { | 177 void TrackRunIterator::AdvanceRun() { |
160 ++run_itr_; | 178 ++run_itr_; |
161 if (min_clear_offset_itr_ != min_clear_offsets_.end()) | 179 if (min_clear_offset_itr_ != min_clear_offsets_.end()) |
162 ++min_clear_offset_itr_; | 180 ++min_clear_offset_itr_; |
163 ResetRun(); | 181 ResetRun(); |
164 } | 182 } |
165 | 183 |
166 void TrackRunIterator::ResetRun() { | 184 void TrackRunIterator::ResetRun() { |
167 if (!RunValid()) return; | 185 if (!RunValid()) return; |
168 sample_dts_ = run_itr_->start_dts; | 186 sample_dts_ = run_itr_->start_dts; |
169 sample_offset_ = run_itr_->sample_start_offset; | 187 sample_offset_ = run_itr_->sample_start_offset; |
170 sample_itr_ = run_itr_->samples.begin(); | 188 sample_itr_ = run_itr_->samples.begin(); |
189 cenc_info_.clear(); | |
171 } | 190 } |
172 | 191 |
173 void TrackRunIterator::AdvanceSample() { | 192 void TrackRunIterator::AdvanceSample() { |
174 DCHECK(SampleValid()); | 193 DCHECK(SampleValid()); |
175 sample_dts_ += sample_itr_->duration; | 194 sample_dts_ += sample_itr_->duration; |
176 sample_offset_ += sample_itr_->size; | 195 sample_offset_ += sample_itr_->size; |
177 ++sample_itr_; | 196 ++sample_itr_; |
178 } | 197 } |
179 | 198 |
180 bool TrackRunIterator::NeedsCENC() { | 199 // This implementation only indicates a need for caching if CENC-style auxiliary |
181 CHECK(!is_encrypted()) << "TODO(strobe): Implement CENC."; | 200 // info is available in the stream. |
182 return is_encrypted(); | 201 bool TrackRunIterator::AuxInfoNeedsToBeCached() { |
202 DCHECK(RunValid()); | |
203 return is_encrypted() && aux_info_size() > 0 && cenc_info_.size() == 0; | |
183 } | 204 } |
184 | 205 |
185 bool TrackRunIterator::CacheCENC(const uint8* buf, int size) { | 206 // This implementation currently only caches CENC auxiliary info. |
ddorwin
2012/07/03 21:03:47
"CENC-style" to be consistent with 199?
strobe_
2012/07/13 00:47:07
Done.
| |
186 LOG(FATAL) << "Not implemented"; | 207 bool TrackRunIterator::CacheAuxInfo(const uint8* buf, int buf_size) { |
187 return false; | 208 RCHECK(AuxInfoNeedsToBeCached() && buf_size >= aux_info_size()); |
209 | |
210 cenc_info_.resize(run_itr_->samples.size()); | |
211 int64 pos = 0; | |
212 for (size_t i = 0; i < run_itr_->samples.size(); i++) { | |
213 int info_size = run_itr_->aux_info_default_size; | |
214 if (!info_size) | |
215 info_size = run_itr_->aux_info_sizes[i]; | |
216 | |
217 BufferReader reader(buf + pos, info_size); | |
218 RCHECK(cenc_info_[i].Parse(run_itr_->track_encryption.default_iv_size, | |
219 &reader)); | |
220 pos += info_size; | |
221 } | |
222 | |
223 return true; | |
188 } | 224 } |
189 | 225 |
190 bool TrackRunIterator::RunValid() const { | 226 bool TrackRunIterator::RunValid() const { |
191 return run_itr_ != runs_.end(); | 227 return run_itr_ != runs_.end(); |
192 } | 228 } |
193 | 229 |
194 bool TrackRunIterator::SampleValid() const { | 230 bool TrackRunIterator::SampleValid() const { |
195 return RunValid() && (sample_itr_ != run_itr_->samples.end()); | 231 return RunValid() && (sample_itr_ != run_itr_->samples.end()); |
196 } | 232 } |
197 | 233 |
198 int64 TrackRunIterator::GetMaxClearOffset() { | 234 int64 TrackRunIterator::GetMaxClearOffset() { |
199 int64 offset = kint64max; | 235 int64 offset = kint64max; |
200 | 236 |
201 if (SampleValid()) { | 237 if (SampleValid()) { |
202 offset = std::min(offset, sample_offset_); | 238 offset = std::min(offset, sample_offset_); |
203 if (NeedsCENC()) { | 239 if (AuxInfoNeedsToBeCached()) { |
204 offset = std::min(offset, cenc_offset()); | 240 offset = std::min(offset, aux_info_offset()); |
205 } | 241 } |
206 } | 242 } |
207 if (min_clear_offset_itr_ != min_clear_offsets_.end()) { | 243 if (min_clear_offset_itr_ != min_clear_offsets_.end()) { |
208 offset = std::min(offset, *min_clear_offset_itr_); | 244 offset = std::min(offset, *min_clear_offset_itr_); |
209 } | 245 } |
210 if (offset == kint64max) return 0; | 246 if (offset == kint64max) return 0; |
211 return offset; | 247 return offset; |
212 } | 248 } |
213 | 249 |
214 TimeDelta TrackRunIterator::GetMinDecodeTimestamp() { | 250 TimeDelta TrackRunIterator::GetMinDecodeTimestamp() { |
215 TimeDelta dts = kInfiniteDuration(); | 251 TimeDelta dts = kInfiniteDuration(); |
216 for (size_t i = 0; i < runs_.size(); i++) { | 252 for (size_t i = 0; i < runs_.size(); i++) { |
217 if (runs_[i].start_dts < dts) | 253 if (runs_[i].start_dts < dts) |
218 dts = runs_[i].start_dts; | 254 dts = runs_[i].start_dts; |
219 } | 255 } |
220 return dts; | 256 return dts; |
221 } | 257 } |
222 | 258 |
223 uint32 TrackRunIterator::track_id() const { | 259 uint32 TrackRunIterator::track_id() const { |
224 DCHECK(RunValid()); | 260 DCHECK(RunValid()); |
225 return run_itr_->track_id; | 261 return run_itr_->track_id; |
226 } | 262 } |
227 | 263 |
228 bool TrackRunIterator::is_encrypted() const { | 264 bool TrackRunIterator::is_encrypted() const { |
229 DCHECK(RunValid()); | 265 DCHECK(RunValid()); |
230 return run_itr_->is_encrypted; | 266 return run_itr_->track_encryption.is_encrypted; |
231 } | 267 } |
232 | 268 |
233 int64 TrackRunIterator::cenc_offset() const { | 269 int64 TrackRunIterator::aux_info_offset() const { |
234 DCHECK(is_encrypted()); | 270 return run_itr_->aux_info_start_offset; |
235 return run_itr_->cenc_start_offset; | |
236 } | 271 } |
237 | 272 |
238 int TrackRunIterator::cenc_size() const { | 273 int TrackRunIterator::aux_info_size() const { |
239 DCHECK(is_encrypted()); | 274 return run_itr_->aux_info_total_size; |
240 return run_itr_->cenc_total_size; | |
241 } | 275 } |
242 | 276 |
243 int64 TrackRunIterator::offset() const { | 277 int64 TrackRunIterator::sample_offset() const { |
244 DCHECK(SampleValid()); | 278 DCHECK(SampleValid()); |
245 return sample_offset_; | 279 return sample_offset_; |
246 } | 280 } |
247 | 281 |
248 int TrackRunIterator::size() const { | 282 int TrackRunIterator::sample_size() const { |
249 DCHECK(SampleValid()); | 283 DCHECK(SampleValid()); |
250 return sample_itr_->size; | 284 return sample_itr_->size; |
251 } | 285 } |
252 | 286 |
253 TimeDelta TrackRunIterator::dts() const { | 287 TimeDelta TrackRunIterator::dts() const { |
254 DCHECK(SampleValid()); | 288 DCHECK(SampleValid()); |
255 return sample_dts_; | 289 return sample_dts_; |
256 } | 290 } |
257 | 291 |
258 TimeDelta TrackRunIterator::cts() const { | 292 TimeDelta TrackRunIterator::cts() const { |
259 DCHECK(SampleValid()); | 293 DCHECK(SampleValid()); |
260 return sample_dts_ + sample_itr_->cts_offset; | 294 return sample_dts_ + sample_itr_->cts_offset; |
261 } | 295 } |
262 | 296 |
263 TimeDelta TrackRunIterator::duration() const { | 297 TimeDelta TrackRunIterator::duration() const { |
264 DCHECK(SampleValid()); | 298 DCHECK(SampleValid()); |
265 return sample_itr_->duration; | 299 return sample_itr_->duration; |
266 } | 300 } |
267 | 301 |
268 bool TrackRunIterator::is_keyframe() const { | 302 bool TrackRunIterator::is_keyframe() const { |
269 DCHECK(SampleValid()); | 303 DCHECK(SampleValid()); |
270 return sample_itr_->is_keyframe; | 304 return sample_itr_->is_keyframe; |
271 } | 305 } |
272 | 306 |
273 const FrameCENCInfo& TrackRunIterator::frame_cenc_info() { | 307 scoped_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() { |
274 DCHECK(is_encrypted()); | 308 const FrameCENCInfo& cenc_info = |
275 return frame_cenc_info_; | 309 cenc_info_[sample_itr_ - run_itr_->samples.begin()]; |
310 DCHECK(is_encrypted() && !AuxInfoNeedsToBeCached()); | |
311 | |
312 if (!cenc_info.subsamples.empty() && | |
313 (cenc_info.GetTotalSizeOfSubsamples() != | |
314 static_cast<size_t>(sample_size()))) { | |
315 DVLOG(1) << "Incorrect CENC subsample size."; | |
316 return scoped_ptr<DecryptConfig>(); | |
317 } | |
318 | |
319 return scoped_ptr<DecryptConfig>(new DecryptConfig( | |
320 &run_itr_->track_encryption.default_kid[0], | |
321 run_itr_->track_encryption.default_kid.size(), | |
322 cenc_info.iv, sizeof(cenc_info.iv), | |
323 &cenc_info.subsamples[0], cenc_info.subsamples.size())); | |
276 } | 324 } |
277 | 325 |
278 } // namespace mp4 | 326 } // namespace mp4 |
279 } // namespace media | 327 } // namespace media |
OLD | NEW |