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

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

Issue 10651006: Add Common Encryption support to BMFF, including subsample decryption. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Fix another case issue Created 8 years, 5 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 (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
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
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
OLDNEW
« media/mp4/track_run_iterator.h ('K') | « media/mp4/track_run_iterator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698