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

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: Satisfy mac_rel buildbot Created 8 years, 4 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
« no previous file with comments | « media/mp4/track_run_iterator.h ('k') | media/mp4/track_run_iterator_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 {
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
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 MP4 using CENC.
423 0, // No offset to start of media data in MP4 using CENC.
424 cenc_info.subsamples));
425 }
426
276 } // namespace mp4 427 } // namespace mp4
277 } // namespace media 428 } // namespace media
OLDNEW
« no previous file with comments | « media/mp4/track_run_iterator.h ('k') | media/mp4/track_run_iterator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698