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

Side by Side Diff: media/mp4/track_run_iterator_unittest.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: Add wrong subsample size test 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
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
ddorwin 2012/07/17 01:14:21 Did not review. Will review after test CL is lande
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/basictypes.h"
6 #include "base/logging.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "media/mp4/box_definitions.h"
9 #include "media/mp4/rcheck.h"
10 #include "media/mp4/track_run_iterator.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12
13 // The sum of the elements in a vector initialized with SumAscending,
14 // less the value of the last element.
15 static const int kSumAscending1 = 45;
16
17 static const int kAudioScale = 48000;
18 static const int kVideoScale = 25;
19
20 static const uint32 kSampleIsDifferenceSampleFlagMask = 0x10000;
21
22 static const uint8 kAuxInfo[] = {
23 0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x31,
24 0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x32,
25 0x00, 0x02,
26 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
27 0x00, 0x03, 0x00, 0x00, 0x00, 0x04
28 };
29
30 static const char kIv1[] = {
31 0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x31,
32 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
33 };
34
35 static const uint8 kKeyId[] = {
36 0x41, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x54,
37 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x49, 0x44
38 };
39
40 namespace media {
41 namespace mp4 {
42
43 class TrackRunIteratorTest : public testing::Test {
44 public:
45 virtual void SetUp() OVERRIDE {
46 iter_.reset(new TrackRunIterator());
47 }
48
49 protected:
50 scoped_ptr<TrackRunIterator> iter_;
51
52 Movie CreateMovie() {
53 Movie moov;
54 moov.header.timescale = 1000;
55 moov.tracks.resize(3);
56 moov.extends.tracks.resize(2);
57 moov.tracks[0].header.track_id = 1;
58 moov.tracks[0].media.header.timescale = kAudioScale;
59 SampleDescription& desc1 =
60 moov.tracks[0].media.information.sample_table.description;
61 desc1.type = kAudio;
62 desc1.audio_entries.resize(1);
63 desc1.audio_entries[0].format = FOURCC_MP4A;
64 moov.extends.tracks[0].track_id = 1;
65
66 moov.tracks[1].header.track_id = 2;
67 moov.tracks[1].media.header.timescale = kVideoScale;
68 SampleDescription& desc2 =
69 moov.tracks[1].media.information.sample_table.description;
70 desc2.type = kVideo;
71 desc2.video_entries.resize(1);
72 desc2.video_entries[0].sinf.info.track_encryption.is_encrypted = false;
73 moov.extends.tracks[1].track_id = 2;
74
75 moov.tracks[2].header.track_id = 3;
76 moov.tracks[2].media.information.sample_table.description.type = kHint;
77 return moov;
78 }
79
80 MovieFragment CreateFragment() {
81 MovieFragment moof;
82 moof.tracks.resize(2);
83 moof.tracks[0].decode_time.decode_time = 0;
84 moof.tracks[0].header.track_id = 1;
85 moof.tracks[0].header.has_default_sample_flags = true;
86 moof.tracks[0].header.default_sample_duration = 1024;
87 moof.tracks[0].header.default_sample_size = 4;
88 moof.tracks[0].runs.resize(2);
89 moof.tracks[0].runs[0].sample_count = 10;
90 moof.tracks[0].runs[0].data_offset = 100;
91 SetAscending(&moof.tracks[0].runs[0].sample_sizes);
92
93 moof.tracks[0].runs[1].sample_count = 10;
94 moof.tracks[0].runs[1].data_offset = 10000;
95
96 moof.tracks[1].header.track_id = 2;
97 moof.tracks[1].header.has_default_sample_flags = false;
98 moof.tracks[1].decode_time.decode_time = 10;
99 moof.tracks[1].runs.resize(1);
100 moof.tracks[1].runs[0].sample_count = 10;
101 moof.tracks[1].runs[0].data_offset = 200;
102 SetAscending(&moof.tracks[1].runs[0].sample_sizes);
103 SetAscending(&moof.tracks[1].runs[0].sample_durations);
104 moof.tracks[1].runs[0].sample_flags.resize(10);
105 for (size_t i = 1; i < moof.tracks[1].runs[0].sample_flags.size(); i++) {
106 moof.tracks[1].runs[0].sample_flags[i] =
107 kSampleIsDifferenceSampleFlagMask;
108 }
109
110 return moof;
111 }
112
113 // Update the first sample description of a Track to indicate encryption
114 void AddEncryption(Track* track) {
115 SampleDescription* stsd =
116 &track->media.information.sample_table.description;
117 ProtectionSchemeInfo* sinf;
118 if (!stsd->video_entries.empty()) {
119 sinf = &stsd->video_entries[0].sinf;
120 } else {
121 sinf = &stsd->audio_entries[0].sinf;
122 }
123
124 sinf->type.type = FOURCC_CENC;
125 sinf->info.track_encryption.is_encrypted = true;
126 sinf->info.track_encryption.default_iv_size = 8;
127 sinf->info.track_encryption.default_kid.insert(
128 sinf->info.track_encryption.default_kid.begin(),
129 kKeyId, kKeyId + arraysize(kKeyId));
130 }
131
132 // Add aux info covering the first track run to a TrackFragment, and update
133 // the run to ensure it matches length and subsample information.
134 void AddAuxInfoHeaders(int offset, TrackFragment* frag) {
135 frag->auxiliary_offset.offsets.push_back(offset);
136 frag->auxiliary_size.sample_count = 2;
137 frag->auxiliary_size.sample_info_sizes.push_back(8);
138 frag->auxiliary_size.sample_info_sizes.push_back(22);
139 frag->runs[0].sample_count = 2;
140 frag->runs[0].sample_sizes[1] = 10;
141 }
142
143 void SetAscending(std::vector<uint32>* vec) {
144 vec->resize(10);
145 for (size_t i = 0; i < vec->size(); i++)
146 (*vec)[i] = i+1;
147 }
148 };
149
150 TEST_F(TrackRunIteratorTest, NoRunsTest) {
151 ASSERT_TRUE(iter_->Init(CreateMovie(), MovieFragment()));
152 EXPECT_FALSE(iter_->RunIsValid());
153 EXPECT_FALSE(iter_->SampleIsValid());
154 }
155
156
157 TEST_F(TrackRunIteratorTest, BasicOperationTest) {
158 MovieFragment moof = CreateFragment();
159 ASSERT_TRUE(iter_->Init(CreateMovie(), moof));
160 EXPECT_TRUE(iter_->RunIsValid());
161 EXPECT_FALSE(iter_->is_encrypted());
162 EXPECT_EQ(1u, iter_->track_id());
163 EXPECT_EQ(100, iter_->sample_offset());
164 EXPECT_EQ(1, iter_->sample_size());
165 EXPECT_EQ(TimeDeltaFromFrac(0, kAudioScale), iter_->dts());
166 EXPECT_EQ(TimeDeltaFromFrac(0, kAudioScale), iter_->cts());
167 EXPECT_EQ(TimeDeltaFromFrac(1024, kAudioScale), iter_->duration());
168 EXPECT_TRUE(iter_->is_keyframe());
169
170 for (int i = 0; i < 9; i++) iter_->AdvanceSample();
171
172 EXPECT_EQ(1u, iter_->track_id());
173 EXPECT_EQ(100 + kSumAscending1, iter_->sample_offset());
174 EXPECT_EQ(10, iter_->sample_size());
175 EXPECT_EQ(TimeDeltaFromFrac(1024 * 9, kAudioScale), iter_->dts());
176 EXPECT_EQ(TimeDeltaFromFrac(1024, kAudioScale), iter_->duration());
177 EXPECT_TRUE(iter_->is_keyframe());
178
179 iter_->AdvanceSample();
180 EXPECT_FALSE(iter_->SampleIsValid());
181 iter_->AdvanceRun();
182 EXPECT_TRUE(iter_->is_keyframe());
183 for (int i = 0; i < 9; i++) iter_->AdvanceSample();
184 EXPECT_EQ(2u, iter_->track_id());
185 EXPECT_EQ(200 + kSumAscending1, iter_->sample_offset());
186 EXPECT_EQ(10, iter_->sample_size());
187 int64 base_dts = kSumAscending1 + moof.tracks[1].decode_time.decode_time;
188 EXPECT_EQ(TimeDeltaFromFrac(base_dts, kVideoScale), iter_->dts());
189 EXPECT_EQ(TimeDeltaFromFrac(10, kVideoScale), iter_->duration());
190 EXPECT_FALSE(iter_->is_keyframe());
191
192 iter_->AdvanceRun();
193 EXPECT_EQ(1u, iter_->track_id());
194 EXPECT_EQ(TimeDeltaFromFrac(1024 * 10, kAudioScale), iter_->dts());
195 iter_->AdvanceSample();
196 EXPECT_EQ(moof.tracks[0].runs[1].data_offset +
197 moof.tracks[0].header.default_sample_size,
198 iter_->sample_offset());
199 iter_->AdvanceRun();
200 EXPECT_FALSE(iter_->RunIsValid());
201 }
202
203 TEST_F(TrackRunIteratorTest, TrackExtendsDefaultsTest) {
204 Movie moov = CreateMovie();
205 MovieFragment moof = CreateFragment();
206 moov.extends.tracks[0].default_sample_duration = 50;
207 moov.extends.tracks[0].default_sample_size = 3;
208 moov.extends.tracks[0].default_sample_flags =
209 kSampleIsDifferenceSampleFlagMask;
210 moof.tracks[0].header.has_default_sample_flags = false;
211 moof.tracks[0].header.default_sample_size = 0;
212 moof.tracks[0].header.default_sample_duration = 0;
213 moof.tracks[0].runs[0].sample_sizes.clear();
214 ASSERT_TRUE(iter_->Init(moov, moof));
215 iter_->AdvanceSample();
216 EXPECT_FALSE(iter_->is_keyframe());
217 EXPECT_EQ(3, iter_->sample_size());
218 EXPECT_EQ(moof.tracks[0].runs[0].data_offset + 3, iter_->sample_offset());
219 EXPECT_EQ(TimeDeltaFromFrac(50, kAudioScale), iter_->duration());
220 EXPECT_EQ(TimeDeltaFromFrac(50, kAudioScale), iter_->dts());
221 }
222
223 TEST_F(TrackRunIteratorTest, FirstSampleFlagTest) {
224 MovieFragment moof = CreateFragment();
225 moof.tracks[1].header.has_default_sample_flags = true;
226 moof.tracks[1].header.default_sample_flags =
227 kSampleIsDifferenceSampleFlagMask;
228 moof.tracks[1].runs[0].sample_flags.resize(1);
229 ASSERT_TRUE(iter_->Init(CreateMovie(), moof));
230 iter_->AdvanceRun();
231 EXPECT_TRUE(iter_->is_keyframe());
232 iter_->AdvanceSample();
233 EXPECT_FALSE(iter_->is_keyframe());
234 }
235
236 TEST_F(TrackRunIteratorTest, MinDecodeTest) {
237 MovieFragment moof = CreateFragment();
238 moof.tracks[0].decode_time.decode_time = kAudioScale;
239 ASSERT_TRUE(iter_->Init(CreateMovie(), moof));
240 EXPECT_EQ(TimeDeltaFromFrac(moof.tracks[1].decode_time.decode_time,
241 kVideoScale),
242 iter_->GetMinDecodeTimestamp());
243 }
244
245 TEST_F(TrackRunIteratorTest, ReorderingTest) {
246 MovieFragment moof = CreateFragment();
247 std::vector<int32>& cts_offsets =
248 moof.tracks[1].runs[0].sample_composition_time_offsets;
249 cts_offsets.resize(10);
250 cts_offsets[0] = 2;
251 cts_offsets[1] = -1;
252 moof.tracks[1].decode_time.decode_time = 0;
253 ASSERT_TRUE(iter_->Init(CreateMovie(), moof));
254 iter_->AdvanceRun();
255 EXPECT_EQ(TimeDeltaFromFrac(0, kVideoScale), iter_->dts());
256 EXPECT_EQ(TimeDeltaFromFrac(2, kVideoScale), iter_->cts());
257 EXPECT_EQ(TimeDeltaFromFrac(1, kVideoScale), iter_->duration());
258 iter_->AdvanceSample();
259 EXPECT_EQ(TimeDeltaFromFrac(1, kVideoScale), iter_->dts());
260 EXPECT_EQ(TimeDeltaFromFrac(0, kVideoScale), iter_->cts());
261 EXPECT_EQ(TimeDeltaFromFrac(2, kVideoScale), iter_->duration());
262 }
263
264 TEST_F(TrackRunIteratorTest, IgnoreUnknownAuxInfoTest) {
265 MovieFragment moof = CreateFragment();
266 moof.tracks[1].auxiliary_offset.offsets.push_back(50);
267 moof.tracks[1].auxiliary_size.default_sample_info_size = 2;
268 moof.tracks[1].auxiliary_size.sample_count = 2;
269 moof.tracks[1].runs[0].sample_count = 2;
270 ASSERT_TRUE(iter_->Init(CreateMovie(), moof));
271 iter_->AdvanceRun();
272 EXPECT_FALSE(iter_->AuxInfoNeedsToBeCached());
273 }
274
275 TEST_F(TrackRunIteratorTest, DecryptConfigTest) {
276 Movie moov = CreateMovie();
277 AddEncryption(&moov.tracks[1]);
278
279 MovieFragment moof = CreateFragment();
280 AddAuxInfoHeaders(50, &moof.tracks[1]);
281
282 ASSERT_TRUE(iter_->Init(moov, moof));
283
284 // The run for track 2 will be first, since its aux info offset is the first
285 // element in the file.
286 EXPECT_TRUE(iter_->is_encrypted());
287 EXPECT_TRUE(iter_->AuxInfoNeedsToBeCached());
288 EXPECT_EQ(arraysize(kAuxInfo), static_cast<uint32>(iter_->aux_info_size()));
289 EXPECT_EQ(50, iter_->aux_info_offset());
290 EXPECT_EQ(50, iter_->GetMaxClearOffset());
291 EXPECT_FALSE(iter_->CacheAuxInfo(NULL, 0));
292 EXPECT_FALSE(iter_->CacheAuxInfo(kAuxInfo, 3));
293 EXPECT_TRUE(iter_->AuxInfoNeedsToBeCached());
294 EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
295 EXPECT_FALSE(iter_->AuxInfoNeedsToBeCached());
296 EXPECT_EQ(200, iter_->sample_offset());
297 EXPECT_EQ(moof.tracks[0].runs[0].data_offset, iter_->GetMaxClearOffset());
298 scoped_ptr<DecryptConfig> config = iter_->GetDecryptConfig();
299 ASSERT_EQ(arraysize(kKeyId), static_cast<uint32>(config->key_id_size()));
300 EXPECT_TRUE(!memcmp(kKeyId, config->key_id(), config->key_id_size()));
301 ASSERT_EQ(arraysize(kIv1), config->iv().size());
302 EXPECT_TRUE(!memcmp(kIv1, config->iv().data(), config->iv().size()));
303 EXPECT_TRUE(config->subsamples().empty());
304 iter_->AdvanceSample();
305 config = iter_->GetDecryptConfig();
306 EXPECT_EQ(2u, config->subsamples().size());
307 EXPECT_EQ(1, config->subsamples()[0].clear_bytes);
308 EXPECT_EQ(4, config->subsamples()[1].cypher_bytes);
309 }
310
311 // It is legal for aux info blocks to be shared among multiple formats.
312 TEST_F(TrackRunIteratorTest, SharedAuxInfoTest) {
313 Movie moov = CreateMovie();
314 AddEncryption(&moov.tracks[0]);
315 AddEncryption(&moov.tracks[1]);
316
317 MovieFragment moof = CreateFragment();
318 moof.tracks[0].runs.resize(1);
319 AddAuxInfoHeaders(50, &moof.tracks[0]);
320 AddAuxInfoHeaders(50, &moof.tracks[1]);
321 moof.tracks[0].auxiliary_size.default_sample_info_size = 8;
322
323 ASSERT_TRUE(iter_->Init(moov, moof));
324 EXPECT_EQ(1u, iter_->track_id());
325 EXPECT_EQ(50, iter_->aux_info_offset());
326 EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
327 scoped_ptr<DecryptConfig> config = iter_->GetDecryptConfig();
328 ASSERT_EQ(arraysize(kIv1), config->iv().size());
329 EXPECT_TRUE(!memcmp(kIv1, config->iv().data(), config->iv().size()));
330 iter_->AdvanceSample();
331 EXPECT_EQ(50, iter_->GetMaxClearOffset());
332 iter_->AdvanceRun();
333 EXPECT_EQ(50, iter_->GetMaxClearOffset());
334 EXPECT_EQ(50, iter_->aux_info_offset());
335 EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
336 EXPECT_EQ(200, iter_->GetMaxClearOffset());
337 ASSERT_EQ(arraysize(kIv1), config->iv().size());
338 EXPECT_TRUE(!memcmp(kIv1, config->iv().data(), config->iv().size()));
339 iter_->AdvanceSample();
340 EXPECT_EQ(201, iter_->GetMaxClearOffset());
341 }
342
343
344 // Sensible files are expected to place auxiliary information for a run
345 // immediately before the main data for that run. Alternative schemes are
346 // possible, however, including the somewhat reasonable behavior of placing all
347 // aux info at the head of the 'mdat' box together, and the completely
348 // unreasonable behavior demonstrated here:
349 // byte 50: track 2, run 1 aux info
350 // byte 100: track 1, run 1 data
351 // byte 200: track 2, run 1 data
352 // byte 201: track 1, run 2 aux info (*inside* track 2, run 1 data)
353 // byte 10000: track 1, run 2 data
354 // byte 20000: track 1, run 1 aux info
355 TEST_F(TrackRunIteratorTest, PathologicalOrderingTest) {
356 return;
357 Movie moov = CreateMovie();
358 AddEncryption(&moov.tracks[0]);
359 AddEncryption(&moov.tracks[1]);
360
361 MovieFragment moof = CreateFragment();
362 AddAuxInfoHeaders(20000, &moof.tracks[0]);
363 moof.tracks[0].auxiliary_offset.offsets.push_back(201);
364 moof.tracks[0].auxiliary_size.sample_count += 2;
365 moof.tracks[0].auxiliary_size.default_sample_info_size = 8;
366 moof.tracks[0].runs[1].sample_count = 2;
367 AddAuxInfoHeaders(50, &moof.tracks[1]);
368 moof.tracks[1].runs[0].sample_sizes[0] = 5;
369
370 ASSERT_TRUE(iter_->Init(moov, moof));
371 EXPECT_EQ(2u, iter_->track_id());
372 EXPECT_EQ(50, iter_->aux_info_offset());
373 EXPECT_EQ(200, iter_->sample_offset());
374 EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
375 EXPECT_EQ(100, iter_->GetMaxClearOffset());
376 iter_->AdvanceRun();
377 EXPECT_EQ(1u, iter_->track_id());
378 EXPECT_EQ(20000, iter_->aux_info_offset());
379 EXPECT_EQ(100, iter_->sample_offset());
380 EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
381 EXPECT_EQ(200, iter_->GetMaxClearOffset());
382 iter_->AdvanceSample();
383 EXPECT_EQ(201, iter_->GetMaxClearOffset());
384 iter_->AdvanceRun();
385 EXPECT_EQ(1u, iter_->track_id());
386 EXPECT_EQ(201, iter_->aux_info_offset());
387 EXPECT_EQ(10000, iter_->sample_offset());
388 EXPECT_EQ(201, iter_->GetMaxClearOffset());
389 EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
390 EXPECT_EQ(10000, iter_->GetMaxClearOffset());
391 }
392
393 } // namespace mp4
394 } // namespace media
OLDNEW
« media/mp4/track_run_iterator.cc ('K') | « media/mp4/track_run_iterator.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698