Home | History | Annotate | Download | only in webm
      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
      3 // found in the LICENSE file.
      4 
      5 #include "media/formats/webm/cluster_builder.h"
      6 #include "media/formats/webm/webm_constants.h"
      7 #include "media/formats/webm/webm_parser.h"
      8 #include "testing/gmock/include/gmock/gmock.h"
      9 #include "testing/gtest/include/gtest/gtest.h"
     10 
     11 using ::testing::InSequence;
     12 using ::testing::Return;
     13 using ::testing::ReturnNull;
     14 using ::testing::StrictMock;
     15 using ::testing::_;
     16 
     17 namespace media {
     18 
     19 enum { kBlockCount = 5 };
     20 
     21 class MockWebMParserClient : public WebMParserClient {
     22  public:
     23   virtual ~MockWebMParserClient() {}
     24 
     25   // WebMParserClient methods.
     26   MOCK_METHOD1(OnListStart, WebMParserClient*(int));
     27   MOCK_METHOD1(OnListEnd, bool(int));
     28   MOCK_METHOD2(OnUInt, bool(int, int64));
     29   MOCK_METHOD2(OnFloat, bool(int, double));
     30   MOCK_METHOD3(OnBinary, bool(int, const uint8*, int));
     31   MOCK_METHOD2(OnString, bool(int, const std::string&));
     32 };
     33 
     34 class WebMParserTest : public testing::Test {
     35  protected:
     36   StrictMock<MockWebMParserClient> client_;
     37 };
     38 
     39 static scoped_ptr<Cluster> CreateCluster(int block_count) {
     40   ClusterBuilder cb;
     41   cb.SetClusterTimecode(0);
     42 
     43   for (int i = 0; i < block_count; i++) {
     44     uint8 data[] = { 0x00 };
     45     cb.AddSimpleBlock(0, i, 0, data, sizeof(data));
     46   }
     47 
     48   return cb.Finish();
     49 }
     50 
     51 static void CreateClusterExpectations(int block_count,
     52                                       bool is_complete_cluster,
     53                                       MockWebMParserClient* client) {
     54 
     55   InSequence s;
     56   EXPECT_CALL(*client, OnListStart(kWebMIdCluster)).WillOnce(Return(client));
     57   EXPECT_CALL(*client, OnUInt(kWebMIdTimecode, 0))
     58       .WillOnce(Return(true));
     59 
     60   for (int i = 0; i < block_count; i++) {
     61     EXPECT_CALL(*client, OnBinary(kWebMIdSimpleBlock, _, _))
     62         .WillOnce(Return(true));
     63   }
     64 
     65   if (is_complete_cluster)
     66     EXPECT_CALL(*client, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
     67 }
     68 
     69 TEST_F(WebMParserTest, EmptyCluster) {
     70   const uint8 kEmptyCluster[] = {
     71     0x1F, 0x43, 0xB6, 0x75, 0x80  // CLUSTER (size = 0)
     72   };
     73   int size = sizeof(kEmptyCluster);
     74 
     75   InSequence s;
     76   EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
     77   EXPECT_CALL(client_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
     78 
     79   WebMListParser parser(kWebMIdCluster, &client_);
     80   EXPECT_EQ(size, parser.Parse(kEmptyCluster, size));
     81   EXPECT_TRUE(parser.IsParsingComplete());
     82 }
     83 
     84 TEST_F(WebMParserTest, EmptyClusterInSegment) {
     85   const uint8 kBuffer[] = {
     86     0x18, 0x53, 0x80, 0x67, 0x85,  // SEGMENT (size = 5)
     87     0x1F, 0x43, 0xB6, 0x75, 0x80,  // CLUSTER (size = 0)
     88   };
     89   int size = sizeof(kBuffer);
     90 
     91   InSequence s;
     92   EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&client_));
     93   EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
     94   EXPECT_CALL(client_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
     95   EXPECT_CALL(client_, OnListEnd(kWebMIdSegment)).WillOnce(Return(true));
     96 
     97   WebMListParser parser(kWebMIdSegment, &client_);
     98   EXPECT_EQ(size, parser.Parse(kBuffer, size));
     99   EXPECT_TRUE(parser.IsParsingComplete());
    100 }
    101 
    102 // Test the case where a non-list child element has a size
    103 // that is beyond the end of the parent.
    104 TEST_F(WebMParserTest, ChildNonListLargerThanParent) {
    105   const uint8 kBuffer[] = {
    106     0x1F, 0x43, 0xB6, 0x75, 0x81,  // CLUSTER (size = 1)
    107     0xE7, 0x81, 0x01,  // Timecode (size=1, value=1)
    108   };
    109 
    110   InSequence s;
    111   EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
    112 
    113   WebMListParser parser(kWebMIdCluster, &client_);
    114   EXPECT_EQ(-1, parser.Parse(kBuffer, sizeof(kBuffer)));
    115   EXPECT_FALSE(parser.IsParsingComplete());
    116 }
    117 
    118 // Test the case where a list child element has a size
    119 // that is beyond the end of the parent.
    120 TEST_F(WebMParserTest, ChildListLargerThanParent) {
    121   const uint8 kBuffer[] = {
    122     0x18, 0x53, 0x80, 0x67, 0x85,  // SEGMENT (size = 5)
    123     0x1F, 0x43, 0xB6, 0x75, 0x81, 0x11  // CLUSTER (size = 1)
    124   };
    125 
    126   InSequence s;
    127   EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&client_));
    128 
    129   WebMListParser parser(kWebMIdSegment, &client_);
    130   EXPECT_EQ(-1, parser.Parse(kBuffer, sizeof(kBuffer)));
    131   EXPECT_FALSE(parser.IsParsingComplete());
    132 }
    133 
    134 // Expecting to parse a Cluster, but get a Segment.
    135 TEST_F(WebMParserTest, ListIdDoesNotMatch) {
    136   const uint8 kBuffer[] = {
    137     0x18, 0x53, 0x80, 0x67, 0x80,  // SEGMENT (size = 0)
    138   };
    139 
    140   WebMListParser parser(kWebMIdCluster, &client_);
    141   EXPECT_EQ(-1, parser.Parse(kBuffer, sizeof(kBuffer)));
    142   EXPECT_FALSE(parser.IsParsingComplete());
    143 }
    144 
    145 TEST_F(WebMParserTest, InvalidElementInList) {
    146   const uint8 kBuffer[] = {
    147     0x18, 0x53, 0x80, 0x67, 0x82,  // SEGMENT (size = 2)
    148     0xAE, 0x80,  // TrackEntry (size = 0)
    149   };
    150 
    151   InSequence s;
    152   EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&client_));
    153 
    154   WebMListParser parser(kWebMIdSegment, &client_);
    155   EXPECT_EQ(-1, parser.Parse(kBuffer, sizeof(kBuffer)));
    156   EXPECT_FALSE(parser.IsParsingComplete());
    157 }
    158 
    159 // Test specific case of InvalidElementInList to verify EBMLHEADER within
    160 // known-sized cluster causes parse error.
    161 TEST_F(WebMParserTest, InvalidEBMLHeaderInCluster) {
    162   const uint8 kBuffer[] = {
    163     0x1F, 0x43, 0xB6, 0x75, 0x85,  // CLUSTER (size = 5)
    164     0x1A, 0x45, 0xDF, 0xA3, 0x80,    // EBMLHEADER (size = 0)
    165   };
    166 
    167   InSequence s;
    168   EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
    169 
    170   WebMListParser parser(kWebMIdCluster, &client_);
    171   EXPECT_EQ(-1, parser.Parse(kBuffer, sizeof(kBuffer)));
    172   EXPECT_FALSE(parser.IsParsingComplete());
    173 }
    174 
    175 // Verify that EBMLHEADER ends a preceding "unknown"-sized CLUSTER.
    176 TEST_F(WebMParserTest, UnknownSizeClusterFollowedByEBMLHeader) {
    177   const uint8 kBuffer[] = {
    178     0x1F, 0x43, 0xB6, 0x75, 0xFF,  // CLUSTER (size = unknown; really 0 due to:)
    179     0x1A, 0x45, 0xDF, 0xA3, 0x80,  // EBMLHEADER (size = 0)
    180   };
    181 
    182   InSequence s;
    183   EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
    184   EXPECT_CALL(client_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
    185 
    186   WebMListParser parser(kWebMIdCluster, &client_);
    187 
    188   // List parse should consume the CLUSTER but not the EBMLHEADER.
    189   EXPECT_EQ(5, parser.Parse(kBuffer, sizeof(kBuffer)));
    190   EXPECT_TRUE(parser.IsParsingComplete());
    191 }
    192 
    193 TEST_F(WebMParserTest, VoidAndCRC32InList) {
    194   const uint8 kBuffer[] = {
    195     0x18, 0x53, 0x80, 0x67, 0x99,  // SEGMENT (size = 25)
    196     0xEC, 0x83, 0x00, 0x00, 0x00,  // Void (size = 3)
    197     0xBF, 0x83, 0x00, 0x00, 0x00,  // CRC32 (size = 3)
    198     0x1F, 0x43, 0xB6, 0x75, 0x8A,  // CLUSTER (size = 10)
    199     0xEC, 0x83, 0x00, 0x00, 0x00,  // Void (size = 3)
    200     0xBF, 0x83, 0x00, 0x00, 0x00,  // CRC32 (size = 3)
    201   };
    202   int size = sizeof(kBuffer);
    203 
    204   InSequence s;
    205   EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&client_));
    206   EXPECT_CALL(client_, OnListStart(kWebMIdCluster)).WillOnce(Return(&client_));
    207   EXPECT_CALL(client_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
    208   EXPECT_CALL(client_, OnListEnd(kWebMIdSegment)).WillOnce(Return(true));
    209 
    210   WebMListParser parser(kWebMIdSegment, &client_);
    211   EXPECT_EQ(size, parser.Parse(kBuffer, size));
    212   EXPECT_TRUE(parser.IsParsingComplete());
    213 }
    214 
    215 
    216 TEST_F(WebMParserTest, ParseListElementWithSingleCall) {
    217   scoped_ptr<Cluster> cluster(CreateCluster(kBlockCount));
    218   CreateClusterExpectations(kBlockCount, true, &client_);
    219 
    220   WebMListParser parser(kWebMIdCluster, &client_);
    221   EXPECT_EQ(cluster->size(), parser.Parse(cluster->data(), cluster->size()));
    222   EXPECT_TRUE(parser.IsParsingComplete());
    223 }
    224 
    225 TEST_F(WebMParserTest, ParseListElementWithMultipleCalls) {
    226   scoped_ptr<Cluster> cluster(CreateCluster(kBlockCount));
    227   CreateClusterExpectations(kBlockCount, true, &client_);
    228 
    229   const uint8* data = cluster->data();
    230   int size = cluster->size();
    231   int default_parse_size = 3;
    232   WebMListParser parser(kWebMIdCluster, &client_);
    233   int parse_size = std::min(default_parse_size, size);
    234 
    235   while (size > 0) {
    236     int result = parser.Parse(data, parse_size);
    237     ASSERT_GE(result, 0);
    238     ASSERT_LE(result, parse_size);
    239 
    240     if (result == 0) {
    241       // The parser needs more data so increase the parse_size a little.
    242       EXPECT_FALSE(parser.IsParsingComplete());
    243       parse_size += default_parse_size;
    244       parse_size = std::min(parse_size, size);
    245       continue;
    246     }
    247 
    248     parse_size = default_parse_size;
    249 
    250     data += result;
    251     size -= result;
    252 
    253     EXPECT_EQ((size == 0), parser.IsParsingComplete());
    254   }
    255   EXPECT_TRUE(parser.IsParsingComplete());
    256 }
    257 
    258 TEST_F(WebMParserTest, Reset) {
    259   InSequence s;
    260   scoped_ptr<Cluster> cluster(CreateCluster(kBlockCount));
    261 
    262   // First expect all but the last block.
    263   CreateClusterExpectations(kBlockCount - 1, false, &client_);
    264 
    265   // Now expect all blocks.
    266   CreateClusterExpectations(kBlockCount, true, &client_);
    267 
    268   WebMListParser parser(kWebMIdCluster, &client_);
    269 
    270   // Send slightly less than the full cluster so all but the last block is
    271   // parsed.
    272   int result = parser.Parse(cluster->data(), cluster->size() - 1);
    273   EXPECT_GT(result, 0);
    274   EXPECT_LT(result, cluster->size());
    275   EXPECT_FALSE(parser.IsParsingComplete());
    276 
    277   parser.Reset();
    278 
    279   // Now parse a whole cluster to verify that all the blocks will get parsed.
    280   EXPECT_EQ(cluster->size(), parser.Parse(cluster->data(), cluster->size()));
    281   EXPECT_TRUE(parser.IsParsingComplete());
    282 }
    283 
    284 // Test the case where multiple clients are used for different lists.
    285 TEST_F(WebMParserTest, MultipleClients) {
    286   const uint8 kBuffer[] = {
    287     0x18, 0x53, 0x80, 0x67, 0x94,  // SEGMENT (size = 20)
    288     0x16, 0x54, 0xAE, 0x6B, 0x85,  //   TRACKS (size = 5)
    289     0xAE, 0x83,                    //     TRACKENTRY (size = 3)
    290     0xD7, 0x81, 0x01,              //       TRACKNUMBER (size = 1)
    291     0x1F, 0x43, 0xB6, 0x75, 0x85,  //   CLUSTER (size = 5)
    292     0xEC, 0x83, 0x00, 0x00, 0x00,  //     Void (size = 3)
    293   };
    294   int size = sizeof(kBuffer);
    295 
    296   StrictMock<MockWebMParserClient> c1_;
    297   StrictMock<MockWebMParserClient> c2_;
    298   StrictMock<MockWebMParserClient> c3_;
    299 
    300   InSequence s;
    301   EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(Return(&c1_));
    302   EXPECT_CALL(c1_, OnListStart(kWebMIdTracks)).WillOnce(Return(&c2_));
    303   EXPECT_CALL(c2_, OnListStart(kWebMIdTrackEntry)).WillOnce(Return(&c3_));
    304   EXPECT_CALL(c3_, OnUInt(kWebMIdTrackNumber, 1)).WillOnce(Return(true));
    305   EXPECT_CALL(c2_, OnListEnd(kWebMIdTrackEntry)).WillOnce(Return(true));
    306   EXPECT_CALL(c1_, OnListEnd(kWebMIdTracks)).WillOnce(Return(true));
    307   EXPECT_CALL(c1_, OnListStart(kWebMIdCluster)).WillOnce(Return(&c2_));
    308   EXPECT_CALL(c1_, OnListEnd(kWebMIdCluster)).WillOnce(Return(true));
    309   EXPECT_CALL(client_, OnListEnd(kWebMIdSegment)).WillOnce(Return(true));
    310 
    311   WebMListParser parser(kWebMIdSegment, &client_);
    312   EXPECT_EQ(size, parser.Parse(kBuffer, size));
    313   EXPECT_TRUE(parser.IsParsingComplete());
    314 }
    315 
    316 // Test the case where multiple clients are used for different lists.
    317 TEST_F(WebMParserTest, InvalidClient) {
    318   const uint8 kBuffer[] = {
    319     0x18, 0x53, 0x80, 0x67, 0x85,  // SEGMENT (size = 20)
    320     0x16, 0x54, 0xAE, 0x6B, 0x80,  //   TRACKS (size = 5)
    321   };
    322 
    323   InSequence s;
    324   EXPECT_CALL(client_, OnListStart(kWebMIdSegment)).WillOnce(ReturnNull());
    325 
    326   WebMListParser parser(kWebMIdSegment, &client_);
    327   EXPECT_EQ(-1, parser.Parse(kBuffer, sizeof(kBuffer)));
    328   EXPECT_FALSE(parser.IsParsingComplete());
    329 }
    330 
    331 TEST_F(WebMParserTest, ReservedIds) {
    332   const uint8 k1ByteReservedId[] = { 0xFF, 0x81 };
    333   const uint8 k2ByteReservedId[] = { 0x7F, 0xFF, 0x81 };
    334   const uint8 k3ByteReservedId[] = { 0x3F, 0xFF, 0xFF, 0x81 };
    335   const uint8 k4ByteReservedId[] = { 0x1F, 0xFF, 0xFF, 0xFF, 0x81 };
    336   const uint8* kBuffers[] = {
    337     k1ByteReservedId,
    338     k2ByteReservedId,
    339     k3ByteReservedId,
    340     k4ByteReservedId
    341   };
    342 
    343   for (size_t i = 0; i < arraysize(kBuffers); i++) {
    344     int id;
    345     int64 element_size;
    346     int buffer_size = 2 + i;
    347     EXPECT_EQ(buffer_size, WebMParseElementHeader(kBuffers[i], buffer_size,
    348                                                   &id, &element_size));
    349     EXPECT_EQ(id, kWebMReservedId);
    350     EXPECT_EQ(element_size, 1);
    351   }
    352 }
    353 
    354 TEST_F(WebMParserTest, ReservedSizes) {
    355   const uint8 k1ByteReservedSize[] = { 0xA3, 0xFF };
    356   const uint8 k2ByteReservedSize[] = { 0xA3, 0x7F, 0xFF };
    357   const uint8 k3ByteReservedSize[] = { 0xA3, 0x3F, 0xFF, 0xFF };
    358   const uint8 k4ByteReservedSize[] = { 0xA3, 0x1F, 0xFF, 0xFF, 0xFF };
    359   const uint8 k5ByteReservedSize[] = { 0xA3, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF };
    360   const uint8 k6ByteReservedSize[] = { 0xA3, 0x07, 0xFF, 0xFF, 0xFF, 0xFF,
    361                                        0xFF };
    362   const uint8 k7ByteReservedSize[] = { 0xA3, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    363                                        0xFF };
    364   const uint8 k8ByteReservedSize[] = { 0xA3, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    365                                        0xFF, 0xFF };
    366   const uint8* kBuffers[] = {
    367     k1ByteReservedSize,
    368     k2ByteReservedSize,
    369     k3ByteReservedSize,
    370     k4ByteReservedSize,
    371     k5ByteReservedSize,
    372     k6ByteReservedSize,
    373     k7ByteReservedSize,
    374     k8ByteReservedSize
    375   };
    376 
    377   for (size_t i = 0; i < arraysize(kBuffers); i++) {
    378     int id;
    379     int64 element_size;
    380     int buffer_size = 2 + i;
    381     EXPECT_EQ(buffer_size, WebMParseElementHeader(kBuffers[i], buffer_size,
    382                                                   &id, &element_size));
    383     EXPECT_EQ(id, 0xA3);
    384     EXPECT_EQ(element_size, kWebMUnknownSize);
    385   }
    386 }
    387 
    388 TEST_F(WebMParserTest, ZeroPaddedStrings) {
    389   const uint8 kBuffer[] = {
    390     0x1A, 0x45, 0xDF, 0xA3, 0x91,  // EBMLHEADER (size = 17)
    391     0x42, 0x82, 0x80,  // DocType (size = 0)
    392     0x42, 0x82, 0x81, 0x00,  // DocType (size = 1) ""
    393     0x42, 0x82, 0x81, 'a',  // DocType (size = 1) "a"
    394     0x42, 0x82, 0x83, 'a', 0x00, 0x00  // DocType (size = 3) "a"
    395   };
    396   int size = sizeof(kBuffer);
    397 
    398   InSequence s;
    399   EXPECT_CALL(client_, OnListStart(kWebMIdEBMLHeader))
    400       .WillOnce(Return(&client_));
    401   EXPECT_CALL(client_, OnString(kWebMIdDocType, "")).WillOnce(Return(true));
    402   EXPECT_CALL(client_, OnString(kWebMIdDocType, "")).WillOnce(Return(true));
    403   EXPECT_CALL(client_, OnString(kWebMIdDocType, "a")).WillOnce(Return(true));
    404   EXPECT_CALL(client_, OnString(kWebMIdDocType, "a")).WillOnce(Return(true));
    405   EXPECT_CALL(client_, OnListEnd(kWebMIdEBMLHeader)).WillOnce(Return(true));
    406 
    407   WebMListParser parser(kWebMIdEBMLHeader, &client_);
    408   EXPECT_EQ(size, parser.Parse(kBuffer, size));
    409   EXPECT_TRUE(parser.IsParsingComplete());
    410 }
    411 
    412 }  // namespace media
    413