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. 4 5 #include <algorithm> 6 7 #include "base/bind.h" 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" 15 16 using ::testing::InSequence; 17 using ::testing::Return; 18 using ::testing::_; 19 20 namespace media { 21 22 enum { 23 kTimecodeScale = 1000000, // Timecode scale for millisecond timestamps. 24 kAudioTrackNum = 1, 25 kVideoTrackNum = 2, 26 kTextTrackNum = 3, 27 }; 28 29 struct BlockInfo { 30 int track_num; 31 int timestamp; 32 int duration; 33 bool use_simple_block; 34 }; 35 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 }, 44 }; 45 46 static const uint8 kEncryptedFrame[] = { 47 0x01, // Block is encrypted 48 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 // IV 49 }; 50 51 static scoped_ptr<Cluster> CreateCluster(int timecode, 52 const BlockInfo* block_info, 53 int block_count) { 54 ClusterBuilder cb; 55 cb.SetClusterTimecode(0); 56 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)); 63 continue; 64 } 65 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)); 71 } 72 73 return cb.Finish(); 74 } 75 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))); 81 82 ClusterBuilder cb; 83 cb.SetClusterTimecode(0); 84 cb.AddSimpleBlock(kVideoTrackNum, 0, 0, kEncryptedFrame, bytes_to_write); 85 return cb.Finish(); 86 } 87 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, 92 int block_count) { 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; 98 size_t* offset; 99 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; 109 } else { 110 LOG(ERROR) << "Unexpected track number " << block_info[i].track_num; 111 return false; 112 } 113 114 if (*offset >= buffers->size()) 115 return false; 116 117 scoped_refptr<StreamParserBuffer> buffer = (*buffers)[(*offset)++]; 118 119 120 EXPECT_EQ(buffer->timestamp().InMilliseconds(), block_info[i].timestamp); 121 122 if (!block_info[i].use_simple_block) 123 EXPECT_NE(buffer->duration(), kNoTimestamp()); 124 125 if (buffer->duration() != kNoTimestamp()) 126 EXPECT_EQ(buffer->duration().InMilliseconds(), block_info[i].duration); 127 } 128 129 return true; 130 } 131 132 static bool VerifyBuffers(const scoped_ptr<WebMClusterParser>& parser, 133 const BlockInfo* block_info, 134 int block_count) { 135 typedef WebMClusterParser::TextTrackIterator TextTrackIterator; 136 TextTrackIterator text_it = parser->CreateTextTrackIterator(); 137 138 int text_track_num; 139 const WebMClusterParser::BufferQueue* text_buffers; 140 141 while (text_it(&text_track_num, &text_buffers)) 142 break; 143 144 const WebMClusterParser::BufferQueue no_text_buffers; 145 146 if (text_buffers == NULL) 147 text_buffers = &no_text_buffers; 148 149 return VerifyBuffers(parser->audio_buffers(), 150 parser->video_buffers(), 151 *text_buffers, 152 block_info, 153 block_count); 154 } 155 156 static bool VerifyTextBuffers( 157 const scoped_ptr<WebMClusterParser>& parser, 158 const BlockInfo* block_info_ptr, 159 int block_count, 160 int text_track_num, 161 const WebMClusterParser::BufferQueue& text_buffers) { 162 const BlockInfo* const block_info_end = block_info_ptr + block_count; 163 164 typedef WebMClusterParser::BufferQueue::const_iterator TextBufferIter; 165 TextBufferIter buffer_iter = text_buffers.begin(); 166 const TextBufferIter buffer_end = text_buffers.end(); 167 168 while (block_info_ptr != block_info_end) { 169 const BlockInfo& block_info = *block_info_ptr++; 170 171 if (block_info.track_num != text_track_num) 172 continue; 173 174 EXPECT_FALSE(block_info.use_simple_block); 175 EXPECT_FALSE(buffer_iter == buffer_end); 176 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); 180 } 181 182 EXPECT_TRUE(buffer_iter == buffer_end); 183 return true; 184 } 185 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; 193 } 194 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); 200 } 201 } 202 203 class WebMClusterParserTest : public testing::Test { 204 public: 205 WebMClusterParserTest() 206 : parser_(new WebMClusterParser(kTimecodeScale, 207 kAudioTrackNum, 208 kVideoTrackNum, 209 WebMTracksParser::TextTracks(), 210 std::set<int64>(), 211 std::string(), 212 std::string(), 213 LogCB())) {} 214 215 protected: 216 scoped_ptr<WebMClusterParser> parser_; 217 }; 218 219 TEST_F(WebMClusterParserTest, Reset) { 220 InSequence s; 221 222 int block_count = arraysize(kDefaultBlockInfo); 223 scoped_ptr<Cluster> cluster(CreateCluster(0, kDefaultBlockInfo, block_count)); 224 225 // Send slightly less than the full cluster so all but the last block is 226 // parsed. 227 int result = parser_->Parse(cluster->data(), cluster->size() - 1); 228 EXPECT_GT(result, 0); 229 EXPECT_LT(result, cluster->size()); 230 231 ASSERT_TRUE(VerifyBuffers(parser_, kDefaultBlockInfo, block_count - 1)); 232 parser_->Reset(); 233 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)); 238 } 239 240 TEST_F(WebMClusterParserTest, ParseClusterWithSingleCall) { 241 int block_count = arraysize(kDefaultBlockInfo); 242 scoped_ptr<Cluster> cluster(CreateCluster(0, kDefaultBlockInfo, block_count)); 243 244 int result = parser_->Parse(cluster->data(), cluster->size()); 245 EXPECT_EQ(cluster->size(), result); 246 ASSERT_TRUE(VerifyBuffers(parser_, kDefaultBlockInfo, block_count)); 247 } 248 249 TEST_F(WebMClusterParserTest, ParseClusterWithMultipleCalls) { 250 int block_count = arraysize(kDefaultBlockInfo); 251 scoped_ptr<Cluster> cluster(CreateCluster(0, kDefaultBlockInfo, block_count)); 252 253 WebMClusterParser::BufferQueue audio_buffers; 254 WebMClusterParser::BufferQueue video_buffers; 255 const WebMClusterParser::BufferQueue no_text_buffers; 256 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); 261 262 while (size > 0) { 263 int result = parser_->Parse(data, parse_size); 264 ASSERT_GE(result, 0); 265 ASSERT_LE(result, parse_size); 266 267 if (result == 0) { 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); 271 continue; 272 } 273 274 AppendToEnd(parser_->audio_buffers(), &audio_buffers); 275 AppendToEnd(parser_->video_buffers(), &video_buffers); 276 277 parse_size = default_parse_size; 278 279 data += result; 280 size -= result; 281 } 282 ASSERT_TRUE(VerifyBuffers(audio_buffers, video_buffers, 283 no_text_buffers, kDefaultBlockInfo, 284 block_count)); 285 } 286 287 // Verify that both BlockGroups with the BlockDuration before the Block 288 // and BlockGroups with the BlockDuration after the Block are supported 289 // correctly. 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 }, 296 }; 297 int block_count = arraysize(kBlockInfo); 298 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) 310 }; 311 const int kClusterSize = sizeof(kClusterData); 312 313 int result = parser_->Parse(kClusterData, kClusterSize); 314 EXPECT_EQ(result, kClusterSize); 315 ASSERT_TRUE(VerifyBuffers(parser_, kBlockInfo, block_count)); 316 } 317 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 }, 325 }; 326 int block_count = arraysize(kBlockInfo); 327 scoped_ptr<Cluster> cluster(CreateCluster(0, kBlockInfo, block_count)); 328 329 int result = parser_->Parse(cluster->data(), cluster->size()); 330 EXPECT_EQ(cluster->size(), result); 331 ASSERT_TRUE(VerifyBuffers(parser_, kBlockInfo, block_count)); 332 } 333 334 TEST_F(WebMClusterParserTest, IgnoredTracks) { 335 std::set<int64> ignored_tracks; 336 ignored_tracks.insert(kTextTrackNum); 337 338 parser_.reset(new WebMClusterParser(kTimecodeScale, 339 kAudioTrackNum, 340 kVideoTrackNum, 341 WebMTracksParser::TextTracks(), 342 ignored_tracks, 343 std::string(), 344 std::string(), 345 LogCB())); 346 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 }, 354 }; 355 int input_block_count = arraysize(kInputBlockInfo); 356 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 }, 363 }; 364 int output_block_count = arraysize(kOutputBlockInfo); 365 366 scoped_ptr<Cluster> cluster( 367 CreateCluster(0, kInputBlockInfo, input_block_count)); 368 369 int result = parser_->Parse(cluster->data(), cluster->size()); 370 EXPECT_EQ(cluster->size(), result); 371 ASSERT_TRUE(VerifyBuffers(parser_, kOutputBlockInfo, output_block_count)); 372 } 373 374 TEST_F(WebMClusterParserTest, ParseTextTracks) { 375 typedef WebMTracksParser::TextTracks TextTracks; 376 TextTracks text_tracks; 377 WebMTracksParser::TextTrackInfo text_track_info; 378 379 text_track_info.kind = kTextSubtitles; 380 text_tracks.insert(std::make_pair(TextTracks::key_type(kTextTrackNum), 381 text_track_info)); 382 383 parser_.reset(new WebMClusterParser(kTimecodeScale, 384 kAudioTrackNum, 385 kVideoTrackNum, 386 text_tracks, 387 std::set<int64>(), 388 std::string(), 389 std::string(), 390 LogCB())); 391 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 }, 400 }; 401 int input_block_count = arraysize(kInputBlockInfo); 402 403 scoped_ptr<Cluster> cluster( 404 CreateCluster(0, kInputBlockInfo, input_block_count)); 405 406 int result = parser_->Parse(cluster->data(), cluster->size()); 407 EXPECT_EQ(cluster->size(), result); 408 ASSERT_TRUE(VerifyBuffers(parser_, kInputBlockInfo, input_block_count)); 409 } 410 411 TEST_F(WebMClusterParserTest, TextTracksSimpleBlock) { 412 typedef WebMTracksParser::TextTracks TextTracks; 413 TextTracks text_tracks; 414 WebMTracksParser::TextTrackInfo text_track_info; 415 416 text_track_info.kind = kTextSubtitles; 417 text_tracks.insert(std::make_pair(TextTracks::key_type(kTextTrackNum), 418 text_track_info)); 419 420 parser_.reset(new WebMClusterParser(kTimecodeScale, 421 kAudioTrackNum, 422 kVideoTrackNum, 423 text_tracks, 424 std::set<int64>(), 425 std::string(), 426 std::string(), 427 LogCB())); 428 429 const BlockInfo kInputBlockInfo[] = { 430 { kTextTrackNum, 33, 42, true }, 431 }; 432 int input_block_count = arraysize(kInputBlockInfo); 433 434 scoped_ptr<Cluster> cluster( 435 CreateCluster(0, kInputBlockInfo, input_block_count)); 436 437 int result = parser_->Parse(cluster->data(), cluster->size()); 438 EXPECT_LT(result, 0); 439 } 440 441 TEST_F(WebMClusterParserTest, ParseMultipleTextTracks) { 442 typedef WebMTracksParser::TextTracks TextTracks; 443 TextTracks text_tracks; 444 WebMTracksParser::TextTrackInfo text_track_info; 445 446 const int kSubtitleTextTrackNum = kTextTrackNum; 447 const int kCaptionTextTrackNum = kTextTrackNum + 1; 448 449 text_track_info.kind = kTextSubtitles; 450 text_tracks.insert(std::make_pair(TextTracks::key_type(kSubtitleTextTrackNum), 451 text_track_info)); 452 453 text_track_info.kind = kTextCaptions; 454 text_tracks.insert(std::make_pair(TextTracks::key_type(kCaptionTextTrackNum), 455 text_track_info)); 456 457 parser_.reset(new WebMClusterParser(kTimecodeScale, 458 kAudioTrackNum, 459 kVideoTrackNum, 460 text_tracks, 461 std::set<int64>(), 462 std::string(), 463 std::string(), 464 LogCB())); 465 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 }, 475 }; 476 int input_block_count = arraysize(kInputBlockInfo); 477 478 scoped_ptr<Cluster> cluster( 479 CreateCluster(0, kInputBlockInfo, input_block_count)); 480 481 int result = parser_->Parse(cluster->data(), cluster->size()); 482 EXPECT_EQ(cluster->size(), result); 483 484 WebMClusterParser::TextTrackIterator text_it = 485 parser_->CreateTextTrackIterator(); 486 487 int text_track_num; 488 const WebMClusterParser::BufferQueue* text_buffers; 489 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)); 496 } 497 } 498 499 TEST_F(WebMClusterParserTest, ParseEncryptedBlock) { 500 scoped_ptr<Cluster> cluster(CreateEncryptedCluster(sizeof(kEncryptedFrame))); 501 502 parser_.reset(new WebMClusterParser(kTimecodeScale, 503 kAudioTrackNum, 504 kVideoTrackNum, 505 WebMTracksParser::TextTracks(), 506 std::set<int64>(), 507 std::string(), 508 "video_key_id", 509 LogCB())); 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)); 515 } 516 517 TEST_F(WebMClusterParserTest, ParseBadEncryptedBlock) { 518 scoped_ptr<Cluster> cluster( 519 CreateEncryptedCluster(sizeof(kEncryptedFrame) - 1)); 520 521 parser_.reset(new WebMClusterParser(kTimecodeScale, 522 kAudioTrackNum, 523 kVideoTrackNum, 524 WebMTracksParser::TextTracks(), 525 std::set<int64>(), 526 std::string(), 527 "video_key_id", 528 LogCB())); 529 int result = parser_->Parse(cluster->data(), cluster->size()); 530 EXPECT_EQ(-1, result); 531 } 532 533 } // namespace media 534