Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 <algorithm> | 5 #include <algorithm> |
| 6 #include <cstdlib> | |
| 6 | 7 |
| 7 #include "base/bind.h" | 8 #include "base/bind.h" |
| 8 #include "base/logging.h" | 9 #include "base/logging.h" |
| 9 #include "media/base/decrypt_config.h" | 10 #include "media/base/decrypt_config.h" |
| 10 #include "media/formats/webm/cluster_builder.h" | 11 #include "media/formats/webm/cluster_builder.h" |
| 11 #include "media/formats/webm/webm_cluster_parser.h" | 12 #include "media/formats/webm/webm_cluster_parser.h" |
| 12 #include "media/formats/webm/webm_constants.h" | 13 #include "media/formats/webm/webm_constants.h" |
| 13 #include "testing/gmock/include/gmock/gmock.h" | 14 #include "testing/gmock/include/gmock/gmock.h" |
| 14 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
| 15 | 16 |
| 16 using ::testing::InSequence; | 17 using ::testing::InSequence; |
| 17 using ::testing::Return; | 18 using ::testing::Return; |
| 18 using ::testing::_; | 19 using ::testing::_; |
| 19 | 20 |
| 20 namespace media { | 21 namespace media { |
| 21 | 22 |
| 23 typedef WebMTracksParser::TextTracks TextTracks; | |
|
acolwell GONE FROM CHROMIUM
2014/04/15 00:32:24
nit: How about "using" instead of a typedef?
wolenetz
2014/04/15 01:49:12
using only worked as an alias. Keeping as typedef.
| |
| 24 | |
| 22 enum { | 25 enum { |
| 23 kTimecodeScale = 1000000, // Timecode scale for millisecond timestamps. | 26 kTimecodeScale = 1000000, // Timecode scale for millisecond timestamps. |
| 24 kAudioTrackNum = 1, | 27 kAudioTrackNum = 1, |
| 25 kVideoTrackNum = 2, | 28 kVideoTrackNum = 2, |
| 26 kTextTrackNum = 3, | 29 kTextTrackNum = 3, |
| 30 kTestAudioFrameDefaultDurationInMs = 13, | |
| 31 kTestVideoFrameDefaultDurationInMs = 17 | |
| 27 }; | 32 }; |
| 28 | 33 |
| 34 COMPILE_ASSERT(kTestAudioFrameDefaultDurationInMs != | |
| 35 WebMClusterParser::kDefaultAudioBufferDurationInMs, | |
| 36 test_default_is_same_as_estimation_fallback_audio_duration); | |
| 37 COMPILE_ASSERT(kTestVideoFrameDefaultDurationInMs != | |
| 38 WebMClusterParser::kDefaultVideoBufferDurationInMs, | |
| 39 test_default_is_same_as_estimation_fallback_video_duration); | |
| 40 | |
| 29 struct BlockInfo { | 41 struct BlockInfo { |
| 30 int track_num; | 42 int track_num; |
| 31 int timestamp; | 43 int timestamp; |
| 44 | |
| 45 // Negative value is allowed only for block groups (not simple blocks) and | |
| 46 // directs CreateCluster() to exclude BlockDuration entry from the cluster for | |
| 47 // this BlockGroup. The absolute value is used for parser verification. | |
| 48 // For simple blocks, this value must be non-negative, and is used only for | |
| 49 // parser verification. | |
| 32 int duration; | 50 int duration; |
| 33 bool use_simple_block; | 51 bool use_simple_block; |
| 34 }; | 52 }; |
| 35 | 53 |
| 36 static const BlockInfo kDefaultBlockInfo[] = { | 54 static const BlockInfo kDefaultBlockInfo[] = { |
| 37 { kAudioTrackNum, 0, 23, true }, | 55 { kAudioTrackNum, 0, 23, true }, |
| 38 { kAudioTrackNum, 23, 23, true }, | 56 { kAudioTrackNum, 23, 23, true }, |
| 39 { kVideoTrackNum, 33, 34, true }, // Assumes not using DefaultDuration | 57 { kVideoTrackNum, 33, 34, true }, // Assumes not using DefaultDuration |
| 40 { kAudioTrackNum, 46, 23, true }, | 58 { kAudioTrackNum, 46, 23, true }, |
| 41 { kVideoTrackNum, 67, 33, false }, | 59 { kVideoTrackNum, 67, 33, false }, |
| 42 { kAudioTrackNum, 69, 23, false }, | 60 { kAudioTrackNum, 69, 23, false }, |
| 43 { kVideoTrackNum, 100, 33, false }, | 61 { kVideoTrackNum, 100, 33, false }, |
| 44 }; | 62 }; |
| 45 | 63 |
| 46 static const uint8 kEncryptedFrame[] = { | 64 static const uint8 kEncryptedFrame[] = { |
| 47 0x01, // Block is encrypted | 65 0x01, // Block is encrypted |
| 48 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 // IV | 66 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 // IV |
| 49 }; | 67 }; |
| 50 | 68 |
| 51 static scoped_ptr<Cluster> CreateCluster(int timecode, | 69 static scoped_ptr<Cluster> CreateCluster(int timecode, |
| 52 const BlockInfo* block_info, | 70 const BlockInfo* block_info, |
| 53 int block_count) { | 71 int block_count) { |
| 54 ClusterBuilder cb; | 72 ClusterBuilder cb; |
| 55 cb.SetClusterTimecode(0); | 73 cb.SetClusterTimecode(0); |
| 56 | 74 |
| 57 for (int i = 0; i < block_count; i++) { | 75 for (int i = 0; i < block_count; i++) { |
| 58 uint8 data[] = { 0x00 }; | 76 uint8 data[] = { 0x00 }; |
| 59 if (block_info[i].use_simple_block) { | 77 if (block_info[i].use_simple_block) { |
| 78 CHECK_GE(block_info[i].duration, 0); | |
| 60 cb.AddSimpleBlock(block_info[i].track_num, | 79 cb.AddSimpleBlock(block_info[i].track_num, |
| 61 block_info[i].timestamp, | 80 block_info[i].timestamp, |
| 62 0, data, sizeof(data)); | 81 0, data, sizeof(data)); |
| 63 continue; | 82 continue; |
| 64 } | 83 } |
| 65 | 84 |
| 66 CHECK_GE(block_info[i].duration, 0); | 85 if (block_info[i].duration < 0) { |
| 86 cb.AddBlockGroupWithoutBlockDuration(block_info[i].track_num, | |
| 87 block_info[i].timestamp, | |
| 88 0, data, sizeof(data)); | |
| 89 continue; | |
| 90 } | |
| 91 | |
| 67 cb.AddBlockGroup(block_info[i].track_num, | 92 cb.AddBlockGroup(block_info[i].track_num, |
| 68 block_info[i].timestamp, | 93 block_info[i].timestamp, |
| 69 block_info[i].duration, | 94 block_info[i].duration, |
| 70 0, data, sizeof(data)); | 95 0, data, sizeof(data)); |
| 71 } | 96 } |
| 72 | 97 |
| 73 return cb.Finish(); | 98 return cb.Finish(); |
| 74 } | 99 } |
| 75 | 100 |
| 76 // Creates a Cluster with one encrypted Block. |bytes_to_write| is number of | 101 // Creates a Cluster with one encrypted Block. |bytes_to_write| is number of |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 114 LOG(ERROR) << "Unexpected track number " << block_info[i].track_num; | 139 LOG(ERROR) << "Unexpected track number " << block_info[i].track_num; |
| 115 return false; | 140 return false; |
| 116 } | 141 } |
| 117 | 142 |
| 118 if (*offset >= buffers->size()) | 143 if (*offset >= buffers->size()) |
| 119 return false; | 144 return false; |
| 120 | 145 |
| 121 scoped_refptr<StreamParserBuffer> buffer = (*buffers)[(*offset)++]; | 146 scoped_refptr<StreamParserBuffer> buffer = (*buffers)[(*offset)++]; |
| 122 | 147 |
| 123 EXPECT_EQ(block_info[i].timestamp, buffer->timestamp().InMilliseconds()); | 148 EXPECT_EQ(block_info[i].timestamp, buffer->timestamp().InMilliseconds()); |
| 124 EXPECT_EQ(block_info[i].duration, buffer->duration().InMilliseconds()); | 149 EXPECT_EQ(std::abs(block_info[i].duration), |
| 150 buffer->duration().InMilliseconds()); | |
| 125 EXPECT_EQ(expected_type, buffer->type()); | 151 EXPECT_EQ(expected_type, buffer->type()); |
| 126 EXPECT_EQ(block_info[i].track_num, buffer->track_id()); | 152 EXPECT_EQ(block_info[i].track_num, buffer->track_id()); |
| 127 } | 153 } |
| 128 | 154 |
| 129 return true; | 155 return true; |
| 130 } | 156 } |
| 131 | 157 |
| 132 static bool VerifyBuffers(const scoped_ptr<WebMClusterParser>& parser, | 158 static bool VerifyBuffers(const scoped_ptr<WebMClusterParser>& parser, |
| 133 const BlockInfo* block_info, | 159 const BlockInfo* block_info, |
| 134 int block_count) { | 160 int block_count) { |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 164 const BlockInfo& block_info = *block_info_ptr++; | 190 const BlockInfo& block_info = *block_info_ptr++; |
| 165 | 191 |
| 166 if (block_info.track_num != text_track_num) | 192 if (block_info.track_num != text_track_num) |
| 167 continue; | 193 continue; |
| 168 | 194 |
| 169 EXPECT_FALSE(block_info.use_simple_block); | 195 EXPECT_FALSE(block_info.use_simple_block); |
| 170 EXPECT_FALSE(buffer_iter == buffer_end); | 196 EXPECT_FALSE(buffer_iter == buffer_end); |
| 171 | 197 |
| 172 const scoped_refptr<StreamParserBuffer> buffer = *buffer_iter++; | 198 const scoped_refptr<StreamParserBuffer> buffer = *buffer_iter++; |
| 173 EXPECT_EQ(block_info.timestamp, buffer->timestamp().InMilliseconds()); | 199 EXPECT_EQ(block_info.timestamp, buffer->timestamp().InMilliseconds()); |
| 174 EXPECT_EQ(block_info.duration, buffer->duration().InMilliseconds()); | 200 EXPECT_EQ(std::abs(block_info.duration), |
| 201 buffer->duration().InMilliseconds()); | |
| 175 EXPECT_EQ(DemuxerStream::TEXT, buffer->type()); | 202 EXPECT_EQ(DemuxerStream::TEXT, buffer->type()); |
| 176 EXPECT_EQ(text_track_num, buffer->track_id()); | 203 EXPECT_EQ(text_track_num, buffer->track_id()); |
| 177 } | 204 } |
| 178 | 205 |
| 179 EXPECT_TRUE(buffer_iter == buffer_end); | 206 EXPECT_TRUE(buffer_iter == buffer_end); |
| 180 return true; | 207 return true; |
| 181 } | 208 } |
| 182 | 209 |
| 183 static void VerifyEncryptedBuffer( | 210 static void VerifyEncryptedBuffer( |
| 184 scoped_refptr<StreamParserBuffer> buffer) { | 211 scoped_refptr<StreamParserBuffer> buffer) { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 196 } | 223 } |
| 197 | 224 |
| 198 class WebMClusterParserTest : public testing::Test { | 225 class WebMClusterParserTest : public testing::Test { |
| 199 public: | 226 public: |
| 200 WebMClusterParserTest() | 227 WebMClusterParserTest() |
| 201 : parser_(new WebMClusterParser(kTimecodeScale, | 228 : parser_(new WebMClusterParser(kTimecodeScale, |
| 202 kAudioTrackNum, | 229 kAudioTrackNum, |
| 203 kNoTimestamp(), | 230 kNoTimestamp(), |
| 204 kVideoTrackNum, | 231 kVideoTrackNum, |
| 205 kNoTimestamp(), | 232 kNoTimestamp(), |
| 206 WebMTracksParser::TextTracks(), | 233 TextTracks(), |
| 207 std::set<int64>(), | 234 std::set<int64>(), |
| 208 std::string(), | 235 std::string(), |
| 209 std::string(), | 236 std::string(), |
| 210 LogCB())) {} | 237 LogCB())) {} |
| 211 | 238 |
| 212 protected: | 239 protected: |
| 240 void ResetParserToHaveDefaultDurations() { | |
| 241 base::TimeDelta default_audio_duration = base::TimeDelta::FromMilliseconds( | |
| 242 kTestAudioFrameDefaultDurationInMs); | |
| 243 base::TimeDelta default_video_duration = base::TimeDelta::FromMilliseconds( | |
| 244 kTestVideoFrameDefaultDurationInMs); | |
| 245 ASSERT_GE(default_audio_duration, base::TimeDelta()); | |
| 246 ASSERT_GE(default_video_duration, base::TimeDelta()); | |
| 247 ASSERT_NE(kNoTimestamp(), default_audio_duration); | |
| 248 ASSERT_NE(kNoTimestamp(), default_video_duration); | |
| 249 | |
| 250 parser_.reset(new WebMClusterParser(kTimecodeScale, | |
| 251 kAudioTrackNum, | |
| 252 default_audio_duration, | |
| 253 kVideoTrackNum, | |
| 254 default_video_duration, | |
| 255 TextTracks(), | |
| 256 std::set<int64>(), | |
| 257 std::string(), | |
| 258 std::string(), | |
| 259 LogCB())); | |
| 260 } | |
| 261 | |
| 213 scoped_ptr<WebMClusterParser> parser_; | 262 scoped_ptr<WebMClusterParser> parser_; |
| 263 | |
| 264 private: | |
| 265 DISALLOW_COPY_AND_ASSIGN(WebMClusterParserTest); | |
| 214 }; | 266 }; |
| 215 | 267 |
| 216 TEST_F(WebMClusterParserTest, Reset) { | 268 TEST_F(WebMClusterParserTest, Reset) { |
| 217 InSequence s; | 269 InSequence s; |
| 218 | 270 |
| 219 int block_count = arraysize(kDefaultBlockInfo); | 271 int block_count = arraysize(kDefaultBlockInfo); |
| 220 scoped_ptr<Cluster> cluster(CreateCluster(0, kDefaultBlockInfo, block_count)); | 272 scoped_ptr<Cluster> cluster(CreateCluster(0, kDefaultBlockInfo, block_count)); |
| 221 | 273 |
| 222 // Send slightly less than the full cluster so all but the last block is | 274 // Send slightly less than the full cluster so all but the last block is |
| 223 // parsed. | 275 // parsed. |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 330 | 382 |
| 331 TEST_F(WebMClusterParserTest, IgnoredTracks) { | 383 TEST_F(WebMClusterParserTest, IgnoredTracks) { |
| 332 std::set<int64> ignored_tracks; | 384 std::set<int64> ignored_tracks; |
| 333 ignored_tracks.insert(kTextTrackNum); | 385 ignored_tracks.insert(kTextTrackNum); |
| 334 | 386 |
| 335 parser_.reset(new WebMClusterParser(kTimecodeScale, | 387 parser_.reset(new WebMClusterParser(kTimecodeScale, |
| 336 kAudioTrackNum, | 388 kAudioTrackNum, |
| 337 kNoTimestamp(), | 389 kNoTimestamp(), |
| 338 kVideoTrackNum, | 390 kVideoTrackNum, |
| 339 kNoTimestamp(), | 391 kNoTimestamp(), |
| 340 WebMTracksParser::TextTracks(), | 392 TextTracks(), |
| 341 ignored_tracks, | 393 ignored_tracks, |
| 342 std::string(), | 394 std::string(), |
| 343 std::string(), | 395 std::string(), |
| 344 LogCB())); | 396 LogCB())); |
| 345 | 397 |
| 346 const BlockInfo kInputBlockInfo[] = { | 398 const BlockInfo kInputBlockInfo[] = { |
| 347 { kAudioTrackNum, 0, 23, true }, | 399 { kAudioTrackNum, 0, 23, true }, |
| 348 { kAudioTrackNum, 23, 23, true }, | 400 { kAudioTrackNum, 23, 23, true }, |
| 349 { kVideoTrackNum, 33, 34, true }, | 401 { kVideoTrackNum, 33, 34, true }, |
| 350 { kTextTrackNum, 33, 99, true }, | 402 { kTextTrackNum, 33, 99, true }, |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 364 | 416 |
| 365 scoped_ptr<Cluster> cluster( | 417 scoped_ptr<Cluster> cluster( |
| 366 CreateCluster(0, kInputBlockInfo, input_block_count)); | 418 CreateCluster(0, kInputBlockInfo, input_block_count)); |
| 367 | 419 |
| 368 int result = parser_->Parse(cluster->data(), cluster->size()); | 420 int result = parser_->Parse(cluster->data(), cluster->size()); |
| 369 EXPECT_EQ(cluster->size(), result); | 421 EXPECT_EQ(cluster->size(), result); |
| 370 ASSERT_TRUE(VerifyBuffers(parser_, kOutputBlockInfo, output_block_count)); | 422 ASSERT_TRUE(VerifyBuffers(parser_, kOutputBlockInfo, output_block_count)); |
| 371 } | 423 } |
| 372 | 424 |
| 373 TEST_F(WebMClusterParserTest, ParseTextTracks) { | 425 TEST_F(WebMClusterParserTest, ParseTextTracks) { |
| 374 typedef WebMTracksParser::TextTracks TextTracks; | |
| 375 TextTracks text_tracks; | 426 TextTracks text_tracks; |
| 376 | 427 |
| 377 text_tracks.insert(std::make_pair(TextTracks::key_type(kTextTrackNum), | 428 text_tracks.insert(std::make_pair(TextTracks::key_type(kTextTrackNum), |
| 378 TextTrackConfig(kTextSubtitles, "", "", | 429 TextTrackConfig(kTextSubtitles, "", "", |
| 379 ""))); | 430 ""))); |
| 380 | 431 |
| 381 parser_.reset(new WebMClusterParser(kTimecodeScale, | 432 parser_.reset(new WebMClusterParser(kTimecodeScale, |
| 382 kAudioTrackNum, | 433 kAudioTrackNum, |
| 383 kNoTimestamp(), | 434 kNoTimestamp(), |
| 384 kVideoTrackNum, | 435 kVideoTrackNum, |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 402 | 453 |
| 403 scoped_ptr<Cluster> cluster( | 454 scoped_ptr<Cluster> cluster( |
| 404 CreateCluster(0, kInputBlockInfo, input_block_count)); | 455 CreateCluster(0, kInputBlockInfo, input_block_count)); |
| 405 | 456 |
| 406 int result = parser_->Parse(cluster->data(), cluster->size()); | 457 int result = parser_->Parse(cluster->data(), cluster->size()); |
| 407 EXPECT_EQ(cluster->size(), result); | 458 EXPECT_EQ(cluster->size(), result); |
| 408 ASSERT_TRUE(VerifyBuffers(parser_, kInputBlockInfo, input_block_count)); | 459 ASSERT_TRUE(VerifyBuffers(parser_, kInputBlockInfo, input_block_count)); |
| 409 } | 460 } |
| 410 | 461 |
| 411 TEST_F(WebMClusterParserTest, TextTracksSimpleBlock) { | 462 TEST_F(WebMClusterParserTest, TextTracksSimpleBlock) { |
| 412 typedef WebMTracksParser::TextTracks TextTracks; | 463 TextTracks text_tracks; |
| 413 WebMTracksParser::TextTracks text_tracks; | |
| 414 | 464 |
| 415 text_tracks.insert(std::make_pair(TextTracks::key_type(kTextTrackNum), | 465 text_tracks.insert(std::make_pair(TextTracks::key_type(kTextTrackNum), |
| 416 TextTrackConfig(kTextSubtitles, "", "", | 466 TextTrackConfig(kTextSubtitles, "", "", |
| 417 ""))); | 467 ""))); |
| 418 | 468 |
| 419 parser_.reset(new WebMClusterParser(kTimecodeScale, | 469 parser_.reset(new WebMClusterParser(kTimecodeScale, |
| 420 kAudioTrackNum, | 470 kAudioTrackNum, |
| 421 kNoTimestamp(), | 471 kNoTimestamp(), |
| 422 kVideoTrackNum, | 472 kVideoTrackNum, |
| 423 kNoTimestamp(), | 473 kNoTimestamp(), |
| 424 text_tracks, | 474 text_tracks, |
| 425 std::set<int64>(), | 475 std::set<int64>(), |
| 426 std::string(), | 476 std::string(), |
| 427 std::string(), | 477 std::string(), |
| 428 LogCB())); | 478 LogCB())); |
| 429 | 479 |
| 430 const BlockInfo kInputBlockInfo[] = { | 480 const BlockInfo kInputBlockInfo[] = { |
| 431 { kTextTrackNum, 33, 42, true }, | 481 { kTextTrackNum, 33, 42, true }, |
| 432 }; | 482 }; |
| 433 int input_block_count = arraysize(kInputBlockInfo); | 483 int input_block_count = arraysize(kInputBlockInfo); |
| 434 | 484 |
| 435 scoped_ptr<Cluster> cluster( | 485 scoped_ptr<Cluster> cluster( |
| 436 CreateCluster(0, kInputBlockInfo, input_block_count)); | 486 CreateCluster(0, kInputBlockInfo, input_block_count)); |
| 437 | 487 |
| 438 int result = parser_->Parse(cluster->data(), cluster->size()); | 488 int result = parser_->Parse(cluster->data(), cluster->size()); |
| 439 EXPECT_LT(result, 0); | 489 EXPECT_LT(result, 0); |
| 440 } | 490 } |
| 441 | 491 |
| 442 TEST_F(WebMClusterParserTest, ParseMultipleTextTracks) { | 492 TEST_F(WebMClusterParserTest, ParseMultipleTextTracks) { |
| 443 typedef WebMTracksParser::TextTracks TextTracks; | |
| 444 TextTracks text_tracks; | 493 TextTracks text_tracks; |
| 445 | 494 |
| 446 const int kSubtitleTextTrackNum = kTextTrackNum; | 495 const int kSubtitleTextTrackNum = kTextTrackNum; |
| 447 const int kCaptionTextTrackNum = kTextTrackNum + 1; | 496 const int kCaptionTextTrackNum = kTextTrackNum + 1; |
| 448 | 497 |
| 449 text_tracks.insert(std::make_pair(TextTracks::key_type(kSubtitleTextTrackNum), | 498 text_tracks.insert(std::make_pair(TextTracks::key_type(kSubtitleTextTrackNum), |
| 450 TextTrackConfig(kTextSubtitles, "", "", | 499 TextTrackConfig(kTextSubtitles, "", "", |
| 451 ""))); | 500 ""))); |
| 452 | 501 |
| 453 text_tracks.insert(std::make_pair(TextTracks::key_type(kCaptionTextTrackNum), | 502 text_tracks.insert(std::make_pair(TextTracks::key_type(kCaptionTextTrackNum), |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 482 | 531 |
| 483 int result = parser_->Parse(cluster->data(), cluster->size()); | 532 int result = parser_->Parse(cluster->data(), cluster->size()); |
| 484 EXPECT_EQ(cluster->size(), result); | 533 EXPECT_EQ(cluster->size(), result); |
| 485 | 534 |
| 486 const WebMClusterParser::TextBufferQueueMap& text_map = | 535 const WebMClusterParser::TextBufferQueueMap& text_map = |
| 487 parser_->GetTextBuffers(); | 536 parser_->GetTextBuffers(); |
| 488 for (WebMClusterParser::TextBufferQueueMap::const_iterator itr = | 537 for (WebMClusterParser::TextBufferQueueMap::const_iterator itr = |
| 489 text_map.begin(); | 538 text_map.begin(); |
| 490 itr != text_map.end(); | 539 itr != text_map.end(); |
| 491 ++itr) { | 540 ++itr) { |
| 492 const WebMTracksParser::TextTracks::const_iterator find_result = | 541 const TextTracks::const_iterator find_result = |
| 493 text_tracks.find(itr->first); | 542 text_tracks.find(itr->first); |
| 494 ASSERT_TRUE(find_result != text_tracks.end()); | 543 ASSERT_TRUE(find_result != text_tracks.end()); |
| 495 ASSERT_TRUE(VerifyTextBuffers(parser_, kInputBlockInfo, input_block_count, | 544 ASSERT_TRUE(VerifyTextBuffers(parser_, kInputBlockInfo, input_block_count, |
| 496 itr->first, itr->second)); | 545 itr->first, itr->second)); |
| 497 } | 546 } |
| 498 } | 547 } |
| 499 | 548 |
| 500 TEST_F(WebMClusterParserTest, ParseEncryptedBlock) { | 549 TEST_F(WebMClusterParserTest, ParseEncryptedBlock) { |
| 501 scoped_ptr<Cluster> cluster(CreateEncryptedCluster(sizeof(kEncryptedFrame))); | 550 scoped_ptr<Cluster> cluster(CreateEncryptedCluster(sizeof(kEncryptedFrame))); |
| 502 | 551 |
| 503 parser_.reset(new WebMClusterParser(kTimecodeScale, | 552 parser_.reset(new WebMClusterParser(kTimecodeScale, |
| 504 kAudioTrackNum, | 553 kAudioTrackNum, |
| 505 kNoTimestamp(), | 554 kNoTimestamp(), |
| 506 kVideoTrackNum, | 555 kVideoTrackNum, |
| 507 kNoTimestamp(), | 556 kNoTimestamp(), |
| 508 WebMTracksParser::TextTracks(), | 557 TextTracks(), |
| 509 std::set<int64>(), | 558 std::set<int64>(), |
| 510 std::string(), | 559 std::string(), |
| 511 "video_key_id", | 560 "video_key_id", |
| 512 LogCB())); | 561 LogCB())); |
| 513 int result = parser_->Parse(cluster->data(), cluster->size()); | 562 int result = parser_->Parse(cluster->data(), cluster->size()); |
| 514 EXPECT_EQ(cluster->size(), result); | 563 EXPECT_EQ(cluster->size(), result); |
| 515 ASSERT_EQ(1UL, parser_->GetVideoBuffers().size()); | 564 ASSERT_EQ(1UL, parser_->GetVideoBuffers().size()); |
| 516 scoped_refptr<StreamParserBuffer> buffer = parser_->GetVideoBuffers()[0]; | 565 scoped_refptr<StreamParserBuffer> buffer = parser_->GetVideoBuffers()[0]; |
| 517 VerifyEncryptedBuffer(buffer); | 566 VerifyEncryptedBuffer(buffer); |
| 518 } | 567 } |
| 519 | 568 |
| 520 TEST_F(WebMClusterParserTest, ParseBadEncryptedBlock) { | 569 TEST_F(WebMClusterParserTest, ParseBadEncryptedBlock) { |
| 521 scoped_ptr<Cluster> cluster( | 570 scoped_ptr<Cluster> cluster( |
| 522 CreateEncryptedCluster(sizeof(kEncryptedFrame) - 1)); | 571 CreateEncryptedCluster(sizeof(kEncryptedFrame) - 1)); |
| 523 | 572 |
| 524 parser_.reset(new WebMClusterParser(kTimecodeScale, | 573 parser_.reset(new WebMClusterParser(kTimecodeScale, |
| 525 kAudioTrackNum, | 574 kAudioTrackNum, |
| 526 kNoTimestamp(), | 575 kNoTimestamp(), |
| 527 kVideoTrackNum, | 576 kVideoTrackNum, |
| 528 kNoTimestamp(), | 577 kNoTimestamp(), |
| 529 WebMTracksParser::TextTracks(), | 578 TextTracks(), |
| 530 std::set<int64>(), | 579 std::set<int64>(), |
| 531 std::string(), | 580 std::string(), |
| 532 "video_key_id", | 581 "video_key_id", |
| 533 LogCB())); | 582 LogCB())); |
| 534 int result = parser_->Parse(cluster->data(), cluster->size()); | 583 int result = parser_->Parse(cluster->data(), cluster->size()); |
| 535 EXPECT_EQ(-1, result); | 584 EXPECT_EQ(-1, result); |
| 536 } | 585 } |
| 537 | 586 |
| 538 TEST_F(WebMClusterParserTest, ParseInvalidZeroSizedCluster) { | 587 TEST_F(WebMClusterParserTest, ParseInvalidZeroSizedCluster) { |
| 539 const uint8 kBuffer[] = { | 588 const uint8 kBuffer[] = { |
| 540 0x1F, 0x43, 0xB6, 0x75, 0x80, // CLUSTER (size = 0) | 589 0x1F, 0x43, 0xB6, 0x75, 0x80, // CLUSTER (size = 0) |
| 541 }; | 590 }; |
| 542 | 591 |
| 543 EXPECT_EQ(-1, parser_->Parse(kBuffer, sizeof(kBuffer))); | 592 EXPECT_EQ(-1, parser_->Parse(kBuffer, sizeof(kBuffer))); |
| 544 } | 593 } |
| 545 | 594 |
| 546 TEST_F(WebMClusterParserTest, ParseInvalidUnknownButActuallyZeroSizedCluster) { | 595 TEST_F(WebMClusterParserTest, ParseInvalidUnknownButActuallyZeroSizedCluster) { |
| 547 const uint8 kBuffer[] = { | 596 const uint8 kBuffer[] = { |
| 548 0x1F, 0x43, 0xB6, 0x75, 0xFF, // CLUSTER (size = "unknown") | 597 0x1F, 0x43, 0xB6, 0x75, 0xFF, // CLUSTER (size = "unknown") |
| 549 0x1F, 0x43, 0xB6, 0x75, 0x85, // CLUSTER (size = 5) | 598 0x1F, 0x43, 0xB6, 0x75, 0x85, // CLUSTER (size = 5) |
| 550 }; | 599 }; |
| 551 | 600 |
| 552 EXPECT_EQ(-1, parser_->Parse(kBuffer, sizeof(kBuffer))); | 601 EXPECT_EQ(-1, parser_->Parse(kBuffer, sizeof(kBuffer))); |
| 553 } | 602 } |
| 554 | 603 |
| 604 TEST_F(WebMClusterParserTest, ParseInvalidTextBlockGroupWithoutDuration) { | |
| 605 // Text track frames must have explicitly specified BlockGroup BlockDurations. | |
| 606 TextTracks text_tracks; | |
| 607 | |
| 608 text_tracks.insert(std::make_pair(TextTracks::key_type(kTextTrackNum), | |
| 609 TextTrackConfig(kTextSubtitles, "", "", | |
| 610 ""))); | |
| 611 | |
| 612 parser_.reset(new WebMClusterParser(kTimecodeScale, | |
| 613 kAudioTrackNum, | |
| 614 kNoTimestamp(), | |
| 615 kVideoTrackNum, | |
| 616 kNoTimestamp(), | |
| 617 text_tracks, | |
| 618 std::set<int64>(), | |
| 619 std::string(), | |
| 620 std::string(), | |
| 621 LogCB())); | |
| 622 | |
| 623 const BlockInfo kBlockInfo[] = { | |
| 624 { kTextTrackNum, 33, -42, false }, | |
| 625 }; | |
| 626 int block_count = arraysize(kBlockInfo); | |
| 627 scoped_ptr<Cluster> cluster(CreateCluster(0, kBlockInfo, block_count)); | |
| 628 int result = parser_->Parse(cluster->data(), cluster->size()); | |
| 629 EXPECT_LT(result, 0); | |
| 630 } | |
| 631 | |
| 632 TEST_F(WebMClusterParserTest, ParseWithDefaultDurationsSimpleBlocks) { | |
| 633 InSequence s; | |
| 634 ResetParserToHaveDefaultDurations(); | |
| 635 | |
| 636 EXPECT_LT(kTestAudioFrameDefaultDurationInMs, 23); | |
| 637 EXPECT_LT(kTestVideoFrameDefaultDurationInMs, 33); | |
| 638 | |
| 639 const BlockInfo kBlockInfo[] = { | |
| 640 { kAudioTrackNum, 0, kTestAudioFrameDefaultDurationInMs, true }, | |
| 641 { kAudioTrackNum, 23, kTestAudioFrameDefaultDurationInMs, true }, | |
| 642 { kVideoTrackNum, 33, kTestVideoFrameDefaultDurationInMs, true }, | |
| 643 { kAudioTrackNum, 46, kTestAudioFrameDefaultDurationInMs, true }, | |
| 644 { kVideoTrackNum, 67, kTestVideoFrameDefaultDurationInMs, true }, | |
| 645 { kAudioTrackNum, 69, kTestAudioFrameDefaultDurationInMs, true }, | |
| 646 { kVideoTrackNum, 100, kTestVideoFrameDefaultDurationInMs, true }, | |
| 647 }; | |
| 648 | |
| 649 int block_count = arraysize(kBlockInfo); | |
| 650 scoped_ptr<Cluster> cluster(CreateCluster(0, kBlockInfo, block_count)); | |
| 651 | |
| 652 // Send slightly less than the full cluster so all but the last block is | |
| 653 // parsed. Though all the blocks are simple blocks, none should be held aside | |
| 654 // for duration estimation prior to end of cluster detection because all the | |
| 655 // tracks have DefaultDurations. | |
| 656 int result = parser_->Parse(cluster->data(), cluster->size() - 1); | |
| 657 EXPECT_GT(result, 0); | |
| 658 EXPECT_LT(result, cluster->size()); | |
| 659 ASSERT_TRUE(VerifyBuffers(parser_, kBlockInfo, block_count - 1)); | |
| 660 | |
| 661 parser_->Reset(); | |
| 662 | |
| 663 // Now parse a whole cluster to verify that all the blocks will get parsed. | |
| 664 result = parser_->Parse(cluster->data(), cluster->size()); | |
| 665 EXPECT_EQ(cluster->size(), result); | |
| 666 ASSERT_TRUE(VerifyBuffers(parser_, kBlockInfo, block_count)); | |
| 667 } | |
| 668 | |
| 669 TEST_F(WebMClusterParserTest, ParseWithoutAnyDurationsSimpleBlocks) { | |
| 670 InSequence s; | |
| 671 | |
| 672 // Absent DefaultDuration information, SimpleBlock durations are derived from | |
| 673 // inter-buffer track timestamp delta if within the cluster, and are estimated | |
| 674 // as the highest duration seen so far if the last buffer in the track in the | |
| 675 // cluster (independently for each track in the cluster). | |
| 676 const BlockInfo kBlockInfo1[] = { | |
| 677 { kAudioTrackNum, 0, 23, true }, | |
| 678 { kAudioTrackNum, 23, 22, true }, | |
| 679 { kVideoTrackNum, 33, 33, true }, | |
| 680 { kAudioTrackNum, 45, 23, true }, | |
| 681 { kVideoTrackNum, 66, 34, true }, | |
| 682 { kAudioTrackNum, 68, 23, true }, // Estimated from maximum audio dur | |
| 683 { kVideoTrackNum, 100, 34, true }, // Estimated from maximum video dur | |
| 684 }; | |
| 685 | |
| 686 int block_count1 = arraysize(kBlockInfo1); | |
| 687 scoped_ptr<Cluster> cluster1(CreateCluster(0, kBlockInfo1, block_count1)); | |
| 688 | |
| 689 // Send slightly less than the first full cluster so all but the last video | |
| 690 // block is parsed. Verify the last fully parsed audio and video buffer are | |
| 691 // both missing from the result (parser should hold them aside for duration | |
| 692 // estimation prior to end of cluster detection in the absence of | |
| 693 // DefaultDurations.) | |
| 694 int result = parser_->Parse(cluster1->data(), cluster1->size() - 1); | |
| 695 EXPECT_GT(result, 0); | |
| 696 EXPECT_LT(result, cluster1->size()); | |
| 697 ASSERT_TRUE(VerifyBuffers(parser_, kBlockInfo1, block_count1 - 3)); | |
| 698 EXPECT_EQ(3UL, parser_->GetAudioBuffers().size()); | |
| 699 EXPECT_EQ(1UL, parser_->GetVideoBuffers().size()); | |
| 700 | |
| 701 parser_->Reset(); | |
| 702 | |
| 703 // Now parse the full first cluster and verify all the blocks are parsed. | |
| 704 result = parser_->Parse(cluster1->data(), cluster1->size()); | |
| 705 EXPECT_EQ(cluster1->size(), result); | |
| 706 ASSERT_TRUE(VerifyBuffers(parser_, kBlockInfo1, block_count1)); | |
| 707 | |
| 708 // Verify that the estimated frame duration is tracked across clusters for | |
| 709 // each track. | |
| 710 const BlockInfo kBlockInfo2[] = { | |
| 711 { kAudioTrackNum, 200, 23, true }, // Estimate carries over across clusters | |
| 712 { kVideoTrackNum, 201, 34, true }, // Estimate carries over across clusters | |
| 713 }; | |
| 714 | |
| 715 int block_count2 = arraysize(kBlockInfo2); | |
| 716 scoped_ptr<Cluster> cluster2(CreateCluster(0, kBlockInfo2, block_count2)); | |
| 717 result = parser_->Parse(cluster2->data(), cluster2->size()); | |
| 718 EXPECT_EQ(cluster2->size(), result); | |
| 719 ASSERT_TRUE(VerifyBuffers(parser_, kBlockInfo2, block_count2)); | |
| 720 } | |
| 721 | |
| 722 TEST_F(WebMClusterParserTest, ParseWithoutAnyDurationsBlockGroups) { | |
| 723 InSequence s; | |
| 724 | |
| 725 // Absent DefaultDuration and BlockDuration information, BlockGroup block | |
| 726 // durations are derived from inter-buffer track timestamp delta if within the | |
| 727 // cluster, and are estimated as the highest duration seen so far if the last | |
|
acolwell GONE FROM CHROMIUM
2014/04/15 00:32:24
Doesn't this become lowest w/ Dale's change?
wolenetz
2014/04/15 01:49:12
Correct. In patch set 3, I've rebased onto his CL
| |
| 728 // buffer in the track in the cluster (independently for each track in the | |
| 729 // cluster). | |
| 730 const BlockInfo kBlockInfo1[] = { | |
| 731 { kAudioTrackNum, 0, -23, false }, | |
| 732 { kAudioTrackNum, 23, -22, false }, | |
| 733 { kVideoTrackNum, 33, -33, false }, | |
| 734 { kAudioTrackNum, 45, -23, false }, | |
| 735 { kVideoTrackNum, 66, -34, false }, | |
| 736 { kAudioTrackNum, 68, -23, false }, // Estimated from maximum audio dur | |
| 737 { kVideoTrackNum, 100, -34, false }, // Estimated from maximum video dur | |
| 738 }; | |
| 739 | |
| 740 int block_count1 = arraysize(kBlockInfo1); | |
| 741 scoped_ptr<Cluster> cluster1(CreateCluster(0, kBlockInfo1, block_count1)); | |
| 742 | |
| 743 // Send slightly less than the first full cluster so all but the last video | |
| 744 // block is parsed. Verify the last fully parsed audio and video buffer are | |
| 745 // both missing from the result (parser should hold them aside for duration | |
| 746 // estimation prior to end of cluster detection in the absence of | |
| 747 // DefaultDurations.) | |
| 748 int result = parser_->Parse(cluster1->data(), cluster1->size() - 1); | |
| 749 EXPECT_GT(result, 0); | |
| 750 EXPECT_LT(result, cluster1->size()); | |
| 751 ASSERT_TRUE(VerifyBuffers(parser_, kBlockInfo1, block_count1 - 3)); | |
| 752 EXPECT_EQ(3UL, parser_->GetAudioBuffers().size()); | |
| 753 EXPECT_EQ(1UL, parser_->GetVideoBuffers().size()); | |
| 754 | |
| 755 parser_->Reset(); | |
| 756 | |
| 757 // Now parse the full first cluster and verify all the blocks are parsed. | |
| 758 result = parser_->Parse(cluster1->data(), cluster1->size()); | |
| 759 EXPECT_EQ(cluster1->size(), result); | |
| 760 ASSERT_TRUE(VerifyBuffers(parser_, kBlockInfo1, block_count1)); | |
| 761 | |
| 762 // Verify that the estimated frame duration is tracked across clusters for | |
| 763 // each track. | |
| 764 const BlockInfo kBlockInfo2[] = { | |
| 765 { kAudioTrackNum, 200, -23, false }, | |
| 766 { kVideoTrackNum, 201, -34, false }, | |
| 767 }; | |
| 768 | |
| 769 int block_count2 = arraysize(kBlockInfo2); | |
| 770 scoped_ptr<Cluster> cluster2(CreateCluster(0, kBlockInfo2, block_count2)); | |
| 771 result = parser_->Parse(cluster2->data(), cluster2->size()); | |
| 772 EXPECT_EQ(cluster2->size(), result); | |
| 773 ASSERT_TRUE(VerifyBuffers(parser_, kBlockInfo2, block_count2)); | |
| 774 } | |
| 775 | |
| 776 // TODO(wolenetz): Is parser behavior correct? See http://crbug.com/363433. | |
| 777 TEST_F(WebMClusterParserTest, | |
| 778 ParseWithDefaultDurationsBlockGroupsWithoutDurations) { | |
| 779 InSequence s; | |
| 780 ResetParserToHaveDefaultDurations(); | |
| 781 | |
| 782 EXPECT_LT(kTestAudioFrameDefaultDurationInMs, 23); | |
| 783 EXPECT_LT(kTestVideoFrameDefaultDurationInMs, 33); | |
| 784 | |
| 785 const BlockInfo kBlockInfo[] = { | |
| 786 { kAudioTrackNum, 0, -kTestAudioFrameDefaultDurationInMs, false }, | |
| 787 { kAudioTrackNum, 23, -kTestAudioFrameDefaultDurationInMs, false }, | |
| 788 { kVideoTrackNum, 33, -kTestVideoFrameDefaultDurationInMs, false }, | |
| 789 { kAudioTrackNum, 46, -kTestAudioFrameDefaultDurationInMs, false }, | |
| 790 { kVideoTrackNum, 67, -kTestVideoFrameDefaultDurationInMs, false }, | |
| 791 { kAudioTrackNum, 69, -kTestAudioFrameDefaultDurationInMs, false }, | |
| 792 { kVideoTrackNum, 100, -kTestVideoFrameDefaultDurationInMs, false }, | |
| 793 }; | |
| 794 | |
| 795 int block_count = arraysize(kBlockInfo); | |
| 796 scoped_ptr<Cluster> cluster(CreateCluster(0, kBlockInfo, block_count)); | |
| 797 | |
| 798 // Send slightly less than the full cluster so all but the last block is | |
| 799 // parsed. None should be held aside for duration estimation prior to end of | |
| 800 // cluster detection because all the tracks have DefaultDurations. | |
| 801 int result = parser_->Parse(cluster->data(), cluster->size() - 1); | |
| 802 EXPECT_GT(result, 0); | |
| 803 EXPECT_LT(result, cluster->size()); | |
| 804 ASSERT_TRUE(VerifyBuffers(parser_, kBlockInfo, block_count - 1)); | |
| 805 | |
| 806 parser_->Reset(); | |
| 807 | |
| 808 // Now parse a whole cluster to verify that all the blocks will get parsed. | |
| 809 result = parser_->Parse(cluster->data(), cluster->size()); | |
| 810 EXPECT_EQ(cluster->size(), result); | |
| 811 ASSERT_TRUE(VerifyBuffers(parser_, kBlockInfo, block_count)); | |
| 812 } | |
| 813 | |
| 814 TEST_F(WebMClusterParserTest, | |
| 815 ParseDegenerateClusterYieldsHardcodedEstimatedDurations) { | |
| 816 const BlockInfo kBlockInfo[] = { | |
| 817 { | |
| 818 kAudioTrackNum, | |
| 819 0, | |
| 820 WebMClusterParser::kDefaultAudioBufferDurationInMs, | |
| 821 true | |
| 822 }, { | |
| 823 kVideoTrackNum, | |
| 824 0, | |
| 825 WebMClusterParser::kDefaultVideoBufferDurationInMs, | |
| 826 true | |
| 827 }, | |
| 828 }; | |
| 829 | |
| 830 int block_count = arraysize(kBlockInfo); | |
| 831 scoped_ptr<Cluster> cluster(CreateCluster(0, kBlockInfo, block_count)); | |
| 832 int result = parser_->Parse(cluster->data(), cluster->size()); | |
| 833 EXPECT_EQ(cluster->size(), result); | |
| 834 ASSERT_TRUE(VerifyBuffers(parser_, kBlockInfo, block_count)); | |
| 835 } | |
| 836 | |
| 837 TEST_F(WebMClusterParserTest, | |
| 838 ParseDegenerateClusterWithDefaultDurationsYieldsDefaultDurations) { | |
| 839 ResetParserToHaveDefaultDurations(); | |
| 840 EXPECT_LT(kTestAudioFrameDefaultDurationInMs, 23); | |
| 841 EXPECT_LT(kTestVideoFrameDefaultDurationInMs, 33); | |
| 842 | |
| 843 const BlockInfo kBlockInfo[] = { | |
| 844 { kAudioTrackNum, 0, kTestAudioFrameDefaultDurationInMs, true }, | |
| 845 { kVideoTrackNum, 0, kTestVideoFrameDefaultDurationInMs, true }, | |
| 846 }; | |
| 847 | |
| 848 int block_count = arraysize(kBlockInfo); | |
| 849 scoped_ptr<Cluster> cluster(CreateCluster(0, kBlockInfo, block_count)); | |
| 850 int result = parser_->Parse(cluster->data(), cluster->size()); | |
| 851 EXPECT_EQ(cluster->size(), result); | |
| 852 ASSERT_TRUE(VerifyBuffers(parser_, kBlockInfo, block_count)); | |
| 853 } | |
| 854 | |
| 555 } // namespace media | 855 } // namespace media |
| OLD | NEW |