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
3 // found in the LICENSE file.
8 #include "base/logging.h"
9 #include "media/base/decrypt_config.h"
10 #include "media/webm/cluster_builder.h"
11 #include "media/webm/webm_cluster_parser.h"
12 #include "media/webm/webm_constants.h"
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 using ::testing::InSequence
;
17 using ::testing::Return
;
23 kTimecodeScale
= 1000000, // Timecode scale for millisecond timestamps.
33 bool use_simple_block
;
36 static const BlockInfo kDefaultBlockInfo
[] = {
37 { kAudioTrackNum
, 0, 23, true },
38 { kAudioTrackNum
, 23, 23, true },
39 { kVideoTrackNum
, 33, 34, true },
40 { kAudioTrackNum
, 46, 23, true },
41 { kVideoTrackNum
, 67, 33, false },
42 { kAudioTrackNum
, 69, 23, false },
43 { kVideoTrackNum
, 100, 33, false },
46 static const uint8 kEncryptedFrame
[] = {
47 0x01, // Block is encrypted
48 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 // IV
51 static scoped_ptr
<Cluster
> CreateCluster(int timecode
,
52 const BlockInfo
* block_info
,
55 cb
.SetClusterTimecode(0);
57 for (int i
= 0; i
< block_count
; i
++) {
58 uint8 data
[] = { 0x00 };
59 if (block_info
[i
].use_simple_block
) {
60 cb
.AddSimpleBlock(block_info
[i
].track_num
,
61 block_info
[i
].timestamp
,
62 0, data
, sizeof(data
));
66 CHECK_GE(block_info
[i
].duration
, 0);
67 cb
.AddBlockGroup(block_info
[i
].track_num
,
68 block_info
[i
].timestamp
,
69 block_info
[i
].duration
,
70 0, data
, sizeof(data
));
76 // Creates a Cluster with one encrypted Block. |bytes_to_write| is number of
77 // bytes of the encrypted frame to write.
78 static scoped_ptr
<Cluster
> CreateEncryptedCluster(int bytes_to_write
) {
79 CHECK_GT(bytes_to_write
, 0);
80 CHECK_LE(bytes_to_write
, static_cast<int>(sizeof(kEncryptedFrame
)));
83 cb
.SetClusterTimecode(0);
84 cb
.AddSimpleBlock(kVideoTrackNum
, 0, 0, kEncryptedFrame
, bytes_to_write
);
88 static bool VerifyBuffers(const WebMClusterParser::BufferQueue
& audio_buffers
,
89 const WebMClusterParser::BufferQueue
& video_buffers
,
90 const WebMClusterParser::BufferQueue
& text_buffers
,
91 const BlockInfo
* block_info
,
93 size_t audio_offset
= 0;
94 size_t video_offset
= 0;
95 size_t text_offset
= 0;
96 for (int i
= 0; i
< block_count
; i
++) {
97 const WebMClusterParser::BufferQueue
* buffers
= NULL
;
100 if (block_info
[i
].track_num
== kAudioTrackNum
) {
101 buffers
= &audio_buffers
;
102 offset
= &audio_offset
;
103 } else if (block_info
[i
].track_num
== kVideoTrackNum
) {
104 buffers
= &video_buffers
;
105 offset
= &video_offset
;
106 } else if (block_info
[i
].track_num
== kTextTrackNum
) {
107 buffers
= &text_buffers
;
108 offset
= &text_offset
;
110 LOG(ERROR
) << "Unexpected track number " << block_info
[i
].track_num
;
114 if (*offset
>= buffers
->size())
117 scoped_refptr
<StreamParserBuffer
> buffer
= (*buffers
)[(*offset
)++];
120 EXPECT_EQ(buffer
->timestamp().InMilliseconds(), block_info
[i
].timestamp
);
122 if (!block_info
[i
].use_simple_block
)
123 EXPECT_NE(buffer
->duration(), kNoTimestamp());
125 if (buffer
->duration() != kNoTimestamp())
126 EXPECT_EQ(buffer
->duration().InMilliseconds(), block_info
[i
].duration
);
132 static bool VerifyBuffers(const scoped_ptr
<WebMClusterParser
>& parser
,
133 const BlockInfo
* block_info
,
135 typedef WebMClusterParser::TextTrackIterator TextTrackIterator
;
136 TextTrackIterator text_it
= parser
->CreateTextTrackIterator();
139 const WebMClusterParser::BufferQueue
* text_buffers
;
141 while (text_it(&text_track_num
, &text_buffers
))
144 const WebMClusterParser::BufferQueue no_text_buffers
;
146 if (text_buffers
== NULL
)
147 text_buffers
= &no_text_buffers
;
149 return VerifyBuffers(parser
->audio_buffers(),
150 parser
->video_buffers(),
156 static bool VerifyTextBuffers(
157 const scoped_ptr
<WebMClusterParser
>& parser
,
158 const BlockInfo
* block_info_ptr
,
161 const WebMClusterParser::BufferQueue
& text_buffers
) {
162 const BlockInfo
* const block_info_end
= block_info_ptr
+ block_count
;
164 typedef WebMClusterParser::BufferQueue::const_iterator TextBufferIter
;
165 TextBufferIter buffer_iter
= text_buffers
.begin();
166 const TextBufferIter buffer_end
= text_buffers
.end();
168 while (block_info_ptr
!= block_info_end
) {
169 const BlockInfo
& block_info
= *block_info_ptr
++;
171 if (block_info
.track_num
!= text_track_num
)
174 EXPECT_FALSE(block_info
.use_simple_block
);
175 EXPECT_FALSE(buffer_iter
== buffer_end
);
177 const scoped_refptr
<StreamParserBuffer
> buffer
= *buffer_iter
++;
178 EXPECT_EQ(buffer
->timestamp().InMilliseconds(), block_info
.timestamp
);
179 EXPECT_EQ(buffer
->duration().InMilliseconds(), block_info
.duration
);
182 EXPECT_TRUE(buffer_iter
== buffer_end
);
186 static bool VerifyEncryptedBuffer(
187 scoped_refptr
<StreamParserBuffer
> buffer
) {
188 EXPECT_TRUE(buffer
->decrypt_config());
189 EXPECT_EQ(static_cast<unsigned long>(DecryptConfig::kDecryptionKeySize
),
190 buffer
->decrypt_config()->iv().length());
191 const uint8
* data
= buffer
->data();
192 return data
[0] & kWebMFlagEncryptedFrame
;
195 static void AppendToEnd(const WebMClusterParser::BufferQueue
& src
,
196 WebMClusterParser::BufferQueue
* dest
) {
197 for (WebMClusterParser::BufferQueue::const_iterator itr
= src
.begin();
198 itr
!= src
.end(); ++itr
) {
199 dest
->push_back(*itr
);
203 class WebMClusterParserTest
: public testing::Test
{
205 WebMClusterParserTest()
206 : parser_(new WebMClusterParser(kTimecodeScale
,
209 WebMTracksParser::TextTracks(),
216 scoped_ptr
<WebMClusterParser
> parser_
;
219 TEST_F(WebMClusterParserTest
, Reset
) {
222 int block_count
= arraysize(kDefaultBlockInfo
);
223 scoped_ptr
<Cluster
> cluster(CreateCluster(0, kDefaultBlockInfo
, block_count
));
225 // Send slightly less than the full cluster so all but the last block is
227 int result
= parser_
->Parse(cluster
->data(), cluster
->size() - 1);
228 EXPECT_GT(result
, 0);
229 EXPECT_LT(result
, cluster
->size());
231 ASSERT_TRUE(VerifyBuffers(parser_
, kDefaultBlockInfo
, block_count
- 1));
234 // Now parse a whole cluster to verify that all the blocks will get parsed.
235 result
= parser_
->Parse(cluster
->data(), cluster
->size());
236 EXPECT_EQ(result
, cluster
->size());
237 ASSERT_TRUE(VerifyBuffers(parser_
, kDefaultBlockInfo
, block_count
));
240 TEST_F(WebMClusterParserTest
, ParseClusterWithSingleCall
) {
241 int block_count
= arraysize(kDefaultBlockInfo
);
242 scoped_ptr
<Cluster
> cluster(CreateCluster(0, kDefaultBlockInfo
, block_count
));
244 int result
= parser_
->Parse(cluster
->data(), cluster
->size());
245 EXPECT_EQ(cluster
->size(), result
);
246 ASSERT_TRUE(VerifyBuffers(parser_
, kDefaultBlockInfo
, block_count
));
249 TEST_F(WebMClusterParserTest
, ParseClusterWithMultipleCalls
) {
250 int block_count
= arraysize(kDefaultBlockInfo
);
251 scoped_ptr
<Cluster
> cluster(CreateCluster(0, kDefaultBlockInfo
, block_count
));
253 WebMClusterParser::BufferQueue audio_buffers
;
254 WebMClusterParser::BufferQueue video_buffers
;
255 const WebMClusterParser::BufferQueue no_text_buffers
;
257 const uint8
* data
= cluster
->data();
258 int size
= cluster
->size();
259 int default_parse_size
= 3;
260 int parse_size
= std::min(default_parse_size
, size
);
263 int result
= parser_
->Parse(data
, parse_size
);
264 ASSERT_GE(result
, 0);
265 ASSERT_LE(result
, parse_size
);
268 // The parser needs more data so increase the parse_size a little.
269 parse_size
+= default_parse_size
;
270 parse_size
= std::min(parse_size
, size
);
274 AppendToEnd(parser_
->audio_buffers(), &audio_buffers
);
275 AppendToEnd(parser_
->video_buffers(), &video_buffers
);
277 parse_size
= default_parse_size
;
282 ASSERT_TRUE(VerifyBuffers(audio_buffers
, video_buffers
,
283 no_text_buffers
, kDefaultBlockInfo
,
287 // Verify that both BlockGroups with the BlockDuration before the Block
288 // and BlockGroups with the BlockDuration after the Block are supported
290 // Note: Raw bytes are use here because ClusterBuilder only generates
291 // one of these scenarios.
292 TEST_F(WebMClusterParserTest
, ParseBlockGroup
) {
293 const BlockInfo kBlockInfo
[] = {
294 { kAudioTrackNum
, 0, 23, false },
295 { kVideoTrackNum
, 33, 34, false },
297 int block_count
= arraysize(kBlockInfo
);
299 const uint8 kClusterData
[] = {
300 0x1F, 0x43, 0xB6, 0x75, 0x9B, // Cluster(size=27)
301 0xE7, 0x81, 0x00, // Timecode(size=1, value=0)
302 // BlockGroup with BlockDuration before Block.
303 0xA0, 0x8A, // BlockGroup(size=10)
304 0x9B, 0x81, 0x17, // BlockDuration(size=1, value=23)
305 0xA1, 0x85, 0x81, 0x00, 0x00, 0x00, 0xaa, // Block(size=5, track=1, ts=0)
306 // BlockGroup with BlockDuration after Block.
307 0xA0, 0x8A, // BlockGroup(size=10)
308 0xA1, 0x85, 0x82, 0x00, 0x21, 0x00, 0x55, // Block(size=5, track=2, ts=33)
309 0x9B, 0x81, 0x22, // BlockDuration(size=1, value=34)
311 const int kClusterSize
= sizeof(kClusterData
);
313 int result
= parser_
->Parse(kClusterData
, kClusterSize
);
314 EXPECT_EQ(result
, kClusterSize
);
315 ASSERT_TRUE(VerifyBuffers(parser_
, kBlockInfo
, block_count
));
318 TEST_F(WebMClusterParserTest
, ParseSimpleBlockAndBlockGroupMixture
) {
319 const BlockInfo kBlockInfo
[] = {
320 { kAudioTrackNum
, 0, 23, true },
321 { kAudioTrackNum
, 23, 23, false },
322 { kVideoTrackNum
, 33, 34, true },
323 { kAudioTrackNum
, 46, 23, false },
324 { kVideoTrackNum
, 67, 33, false },
326 int block_count
= arraysize(kBlockInfo
);
327 scoped_ptr
<Cluster
> cluster(CreateCluster(0, kBlockInfo
, block_count
));
329 int result
= parser_
->Parse(cluster
->data(), cluster
->size());
330 EXPECT_EQ(cluster
->size(), result
);
331 ASSERT_TRUE(VerifyBuffers(parser_
, kBlockInfo
, block_count
));
334 TEST_F(WebMClusterParserTest
, IgnoredTracks
) {
335 std::set
<int64
> ignored_tracks
;
336 ignored_tracks
.insert(kTextTrackNum
);
338 parser_
.reset(new WebMClusterParser(kTimecodeScale
,
341 WebMTracksParser::TextTracks(),
347 const BlockInfo kInputBlockInfo
[] = {
348 { kAudioTrackNum
, 0, 23, true },
349 { kAudioTrackNum
, 23, 23, true },
350 { kVideoTrackNum
, 33, 33, true },
351 { kTextTrackNum
, 33, 99, true },
352 { kAudioTrackNum
, 46, 23, true },
353 { kVideoTrackNum
, 67, 33, true },
355 int input_block_count
= arraysize(kInputBlockInfo
);
357 const BlockInfo kOutputBlockInfo
[] = {
358 { kAudioTrackNum
, 0, 23, true },
359 { kAudioTrackNum
, 23, 23, true },
360 { kVideoTrackNum
, 33, 33, true },
361 { kAudioTrackNum
, 46, 23, true },
362 { kVideoTrackNum
, 67, 33, true },
364 int output_block_count
= arraysize(kOutputBlockInfo
);
366 scoped_ptr
<Cluster
> cluster(
367 CreateCluster(0, kInputBlockInfo
, input_block_count
));
369 int result
= parser_
->Parse(cluster
->data(), cluster
->size());
370 EXPECT_EQ(cluster
->size(), result
);
371 ASSERT_TRUE(VerifyBuffers(parser_
, kOutputBlockInfo
, output_block_count
));
374 TEST_F(WebMClusterParserTest
, ParseTextTracks
) {
375 typedef WebMTracksParser::TextTracks TextTracks
;
376 TextTracks text_tracks
;
377 WebMTracksParser::TextTrackInfo text_track_info
;
379 text_track_info
.kind
= kTextSubtitles
;
380 text_tracks
.insert(std::make_pair(TextTracks::key_type(kTextTrackNum
),
383 parser_
.reset(new WebMClusterParser(kTimecodeScale
,
392 const BlockInfo kInputBlockInfo
[] = {
393 { kAudioTrackNum
, 0, 23, true },
394 { kAudioTrackNum
, 23, 23, true },
395 { kVideoTrackNum
, 33, 33, true },
396 { kTextTrackNum
, 33, 42, false },
397 { kAudioTrackNum
, 46, 23, true },
398 { kTextTrackNum
, 55, 44, false },
399 { kVideoTrackNum
, 67, 33, true },
401 int input_block_count
= arraysize(kInputBlockInfo
);
403 scoped_ptr
<Cluster
> cluster(
404 CreateCluster(0, kInputBlockInfo
, input_block_count
));
406 int result
= parser_
->Parse(cluster
->data(), cluster
->size());
407 EXPECT_EQ(cluster
->size(), result
);
408 ASSERT_TRUE(VerifyBuffers(parser_
, kInputBlockInfo
, input_block_count
));
411 TEST_F(WebMClusterParserTest
, TextTracksSimpleBlock
) {
412 typedef WebMTracksParser::TextTracks TextTracks
;
413 TextTracks text_tracks
;
414 WebMTracksParser::TextTrackInfo text_track_info
;
416 text_track_info
.kind
= kTextSubtitles
;
417 text_tracks
.insert(std::make_pair(TextTracks::key_type(kTextTrackNum
),
420 parser_
.reset(new WebMClusterParser(kTimecodeScale
,
429 const BlockInfo kInputBlockInfo
[] = {
430 { kTextTrackNum
, 33, 42, true },
432 int input_block_count
= arraysize(kInputBlockInfo
);
434 scoped_ptr
<Cluster
> cluster(
435 CreateCluster(0, kInputBlockInfo
, input_block_count
));
437 int result
= parser_
->Parse(cluster
->data(), cluster
->size());
438 EXPECT_LT(result
, 0);
441 TEST_F(WebMClusterParserTest
, ParseMultipleTextTracks
) {
442 typedef WebMTracksParser::TextTracks TextTracks
;
443 TextTracks text_tracks
;
444 WebMTracksParser::TextTrackInfo text_track_info
;
446 const int kSubtitleTextTrackNum
= kTextTrackNum
;
447 const int kCaptionTextTrackNum
= kTextTrackNum
+ 1;
449 text_track_info
.kind
= kTextSubtitles
;
450 text_tracks
.insert(std::make_pair(TextTracks::key_type(kSubtitleTextTrackNum
),
453 text_track_info
.kind
= kTextCaptions
;
454 text_tracks
.insert(std::make_pair(TextTracks::key_type(kCaptionTextTrackNum
),
457 parser_
.reset(new WebMClusterParser(kTimecodeScale
,
466 const BlockInfo kInputBlockInfo
[] = {
467 { kAudioTrackNum
, 0, 23, true },
468 { kAudioTrackNum
, 23, 23, true },
469 { kVideoTrackNum
, 33, 33, true },
470 { kSubtitleTextTrackNum
, 33, 42, false },
471 { kAudioTrackNum
, 46, 23, true },
472 { kCaptionTextTrackNum
, 55, 44, false },
473 { kVideoTrackNum
, 67, 33, true },
474 { kSubtitleTextTrackNum
, 67, 33, false },
476 int input_block_count
= arraysize(kInputBlockInfo
);
478 scoped_ptr
<Cluster
> cluster(
479 CreateCluster(0, kInputBlockInfo
, input_block_count
));
481 int result
= parser_
->Parse(cluster
->data(), cluster
->size());
482 EXPECT_EQ(cluster
->size(), result
);
484 WebMClusterParser::TextTrackIterator text_it
=
485 parser_
->CreateTextTrackIterator();
488 const WebMClusterParser::BufferQueue
* text_buffers
;
490 while (text_it(&text_track_num
, &text_buffers
)) {
491 const WebMTracksParser::TextTracks::const_iterator find_result
=
492 text_tracks
.find(text_track_num
);
493 ASSERT_TRUE(find_result
!= text_tracks
.end());
494 ASSERT_TRUE(VerifyTextBuffers(parser_
, kInputBlockInfo
, input_block_count
,
495 text_track_num
, *text_buffers
));
499 TEST_F(WebMClusterParserTest
, ParseEncryptedBlock
) {
500 scoped_ptr
<Cluster
> cluster(CreateEncryptedCluster(sizeof(kEncryptedFrame
)));
502 parser_
.reset(new WebMClusterParser(kTimecodeScale
,
505 WebMTracksParser::TextTracks(),
510 int result
= parser_
->Parse(cluster
->data(), cluster
->size());
511 EXPECT_EQ(cluster
->size(), result
);
512 ASSERT_EQ(1UL, parser_
->video_buffers().size());
513 scoped_refptr
<StreamParserBuffer
> buffer
= parser_
->video_buffers()[0];
514 EXPECT_TRUE(VerifyEncryptedBuffer(buffer
));
517 TEST_F(WebMClusterParserTest
, ParseBadEncryptedBlock
) {
518 scoped_ptr
<Cluster
> cluster(
519 CreateEncryptedCluster(sizeof(kEncryptedFrame
) - 1));
521 parser_
.reset(new WebMClusterParser(kTimecodeScale
,
524 WebMTracksParser::TextTracks(),
529 int result
= parser_
->Parse(cluster
->data(), cluster
->size());
530 EXPECT_EQ(-1, result
);