| OLD | NEW |
| 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 <algorithm> | 5 #include <algorithm> |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "media/base/decrypt_config.h" |
| 9 #include "media/webm/cluster_builder.h" | 10 #include "media/webm/cluster_builder.h" |
| 10 #include "media/webm/webm_cluster_parser.h" | 11 #include "media/webm/webm_cluster_parser.h" |
| 11 #include "media/webm/webm_constants.h" | 12 #include "media/webm/webm_constants.h" |
| 12 #include "testing/gmock/include/gmock/gmock.h" | 13 #include "testing/gmock/include/gmock/gmock.h" |
| 13 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
| 14 | 15 |
| 15 using ::testing::InSequence; | 16 using ::testing::InSequence; |
| 16 using ::testing::Return; | 17 using ::testing::Return; |
| 17 using ::testing::_; | 18 using ::testing::_; |
| 18 | 19 |
| 19 namespace media { | 20 namespace media { |
| 20 | 21 |
| 21 enum { | 22 enum { |
| 22 kTimecodeScale = 1000000, // Timecode scale for millisecond timestamps. | 23 kTimecodeScale = 1000000, // Timecode scale for millisecond timestamps. |
| 23 kAudioTrackNum = 1, | 24 kAudioTrackNum = 1, |
| 24 kVideoTrackNum = 2, | 25 kVideoTrackNum = 2, |
| 25 kTextTrackNum = 3, | 26 kTextTrackNum = 3, |
| 26 }; | 27 }; |
| 27 | 28 |
| 28 struct BlockInfo { | 29 struct BlockInfo { |
| 29 int track_num; | 30 int track_num; |
| 30 int timestamp; | 31 int timestamp; |
| 31 int duration; | 32 int duration; |
| 32 bool use_simple_block; | 33 bool use_simple_block; |
| 33 }; | 34 }; |
| 34 | 35 |
| 35 const BlockInfo kDefaultBlockInfo[] = { | 36 static const BlockInfo kDefaultBlockInfo[] = { |
| 36 { kAudioTrackNum, 0, 23, true }, | 37 { kAudioTrackNum, 0, 23, true }, |
| 37 { kAudioTrackNum, 23, 23, true }, | 38 { kAudioTrackNum, 23, 23, true }, |
| 38 { kVideoTrackNum, 33, 34, true }, | 39 { kVideoTrackNum, 33, 34, true }, |
| 39 { kAudioTrackNum, 46, 23, true }, | 40 { kAudioTrackNum, 46, 23, true }, |
| 40 { kVideoTrackNum, 67, 33, false }, | 41 { kVideoTrackNum, 67, 33, false }, |
| 41 { kAudioTrackNum, 69, 23, false }, | 42 { kAudioTrackNum, 69, 23, false }, |
| 42 { kVideoTrackNum, 100, 33, false }, | 43 { kVideoTrackNum, 100, 33, false }, |
| 43 }; | 44 }; |
| 44 | 45 |
| 46 static const uint8 kEncryptedFrame[] = { |
| 47 0x01, // Block is encrypted |
| 48 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 // IV |
| 49 }; |
| 50 |
| 45 static scoped_ptr<Cluster> CreateCluster(int timecode, | 51 static scoped_ptr<Cluster> CreateCluster(int timecode, |
| 46 const BlockInfo* block_info, | 52 const BlockInfo* block_info, |
| 47 int block_count) { | 53 int block_count) { |
| 48 ClusterBuilder cb; | 54 ClusterBuilder cb; |
| 49 cb.SetClusterTimecode(0); | 55 cb.SetClusterTimecode(0); |
| 50 | 56 |
| 51 for (int i = 0; i < block_count; i++) { | 57 for (int i = 0; i < block_count; i++) { |
| 52 uint8 data[] = { 0x00 }; | 58 uint8 data[] = { 0x00 }; |
| 53 if (block_info[i].use_simple_block) { | 59 if (block_info[i].use_simple_block) { |
| 54 cb.AddSimpleBlock(block_info[i].track_num, | 60 cb.AddSimpleBlock(block_info[i].track_num, |
| 55 block_info[i].timestamp, | 61 block_info[i].timestamp, |
| 56 0, data, sizeof(data)); | 62 0, data, sizeof(data)); |
| 57 continue; | 63 continue; |
| 58 } | 64 } |
| 59 | 65 |
| 60 CHECK_GE(block_info[i].duration, 0); | 66 CHECK_GE(block_info[i].duration, 0); |
| 61 cb.AddBlockGroup(block_info[i].track_num, | 67 cb.AddBlockGroup(block_info[i].track_num, |
| 62 block_info[i].timestamp, | 68 block_info[i].timestamp, |
| 63 block_info[i].duration, | 69 block_info[i].duration, |
| 64 0, data, sizeof(data)); | 70 0, data, sizeof(data)); |
| 65 } | 71 } |
| 66 | 72 |
| 67 return cb.Finish(); | 73 return cb.Finish(); |
| 68 } | 74 } |
| 69 | 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 |
| 70 static bool VerifyBuffers(const WebMClusterParser::BufferQueue& audio_buffers, | 88 static bool VerifyBuffers(const WebMClusterParser::BufferQueue& audio_buffers, |
| 71 const WebMClusterParser::BufferQueue& video_buffers, | 89 const WebMClusterParser::BufferQueue& video_buffers, |
| 72 const WebMClusterParser::BufferQueue& text_buffers, | 90 const WebMClusterParser::BufferQueue& text_buffers, |
| 73 const BlockInfo* block_info, | 91 const BlockInfo* block_info, |
| 74 int block_count) { | 92 int block_count) { |
| 75 size_t audio_offset = 0; | 93 size_t audio_offset = 0; |
| 76 size_t video_offset = 0; | 94 size_t video_offset = 0; |
| 77 size_t text_offset = 0; | 95 size_t text_offset = 0; |
| 78 for (int i = 0; i < block_count; i++) { | 96 for (int i = 0; i < block_count; i++) { |
| 79 const WebMClusterParser::BufferQueue* buffers = NULL; | 97 const WebMClusterParser::BufferQueue* buffers = NULL; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 158 | 176 |
| 159 const scoped_refptr<StreamParserBuffer> buffer = *buffer_iter++; | 177 const scoped_refptr<StreamParserBuffer> buffer = *buffer_iter++; |
| 160 EXPECT_EQ(buffer->GetTimestamp().InMilliseconds(), block_info.timestamp); | 178 EXPECT_EQ(buffer->GetTimestamp().InMilliseconds(), block_info.timestamp); |
| 161 EXPECT_EQ(buffer->GetDuration().InMilliseconds(), block_info.duration); | 179 EXPECT_EQ(buffer->GetDuration().InMilliseconds(), block_info.duration); |
| 162 } | 180 } |
| 163 | 181 |
| 164 EXPECT_TRUE(buffer_iter == buffer_end); | 182 EXPECT_TRUE(buffer_iter == buffer_end); |
| 165 return true; | 183 return true; |
| 166 } | 184 } |
| 167 | 185 |
| 186 static bool VerifyEncryptedBuffer( |
| 187 scoped_refptr<StreamParserBuffer> buffer) { |
| 188 EXPECT_TRUE(buffer->GetDecryptConfig()); |
| 189 EXPECT_EQ(DecryptConfig::kDecryptionKeySize, |
| 190 buffer->GetDecryptConfig()->iv().length()); |
| 191 const uint8* data = buffer->GetData(); |
| 192 return data[0] & kWebMFlagEncryptedFrame; |
| 193 } |
| 194 |
| 168 static void AppendToEnd(const WebMClusterParser::BufferQueue& src, | 195 static void AppendToEnd(const WebMClusterParser::BufferQueue& src, |
| 169 WebMClusterParser::BufferQueue* dest) { | 196 WebMClusterParser::BufferQueue* dest) { |
| 170 for (WebMClusterParser::BufferQueue::const_iterator itr = src.begin(); | 197 for (WebMClusterParser::BufferQueue::const_iterator itr = src.begin(); |
| 171 itr != src.end(); ++itr) { | 198 itr != src.end(); ++itr) { |
| 172 dest->push_back(*itr); | 199 dest->push_back(*itr); |
| 173 } | 200 } |
| 174 } | 201 } |
| 175 | 202 |
| 176 class WebMClusterParserTest : public testing::Test { | 203 class WebMClusterParserTest : public testing::Test { |
| 177 public: | 204 public: |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 433 | 460 |
| 434 while (text_it(&text_track_num, &text_buffers)) { | 461 while (text_it(&text_track_num, &text_buffers)) { |
| 435 const TextTrackSet::const_iterator find_result = | 462 const TextTrackSet::const_iterator find_result = |
| 436 text_tracks.find(text_track_num); | 463 text_tracks.find(text_track_num); |
| 437 ASSERT_TRUE(find_result != text_tracks.end()); | 464 ASSERT_TRUE(find_result != text_tracks.end()); |
| 438 ASSERT_TRUE(VerifyTextBuffers(parser_, kInputBlockInfo, input_block_count, | 465 ASSERT_TRUE(VerifyTextBuffers(parser_, kInputBlockInfo, input_block_count, |
| 439 text_track_num, *text_buffers)); | 466 text_track_num, *text_buffers)); |
| 440 } | 467 } |
| 441 } | 468 } |
| 442 | 469 |
| 470 TEST_F(WebMClusterParserTest, ParseEncryptedBlock) { |
| 471 scoped_ptr<Cluster> cluster(CreateEncryptedCluster(sizeof(kEncryptedFrame))); |
| 472 |
| 473 parser_.reset(new WebMClusterParser( |
| 474 kTimecodeScale, kAudioTrackNum, kVideoTrackNum, |
| 475 std::set<int>(), |
| 476 std::set<int64>(), "", "video_key_id", |
| 477 LogCB())); |
| 478 int result = parser_->Parse(cluster->data(), cluster->size()); |
| 479 EXPECT_EQ(cluster->size(), result); |
| 480 ASSERT_EQ(1, parser_->video_buffers().size()); |
| 481 scoped_refptr<StreamParserBuffer> buffer = parser_->video_buffers()[0]; |
| 482 EXPECT_TRUE(VerifyEncryptedBuffer(buffer)); |
| 483 } |
| 484 |
| 485 TEST_F(WebMClusterParserTest, ParseBadEncryptedBlock) { |
| 486 scoped_ptr<Cluster> cluster( |
| 487 CreateEncryptedCluster(sizeof(kEncryptedFrame) - 1)); |
| 488 |
| 489 parser_.reset(new WebMClusterParser( |
| 490 kTimecodeScale, kAudioTrackNum, kVideoTrackNum, |
| 491 std::set<int>(), |
| 492 std::set<int64>(), "", "video_key_id", |
| 493 LogCB())); |
| 494 int result = parser_->Parse(cluster->data(), cluster->size()); |
| 495 EXPECT_EQ(-1, result); |
| 496 } |
| 497 |
| 443 } // namespace media | 498 } // namespace media |
| OLD | NEW |