• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
~MockWebMParserClient()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 
CreateCluster(int block_count)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 
CreateClusterExpectations(int block_count,bool is_complete_cluster,MockWebMParserClient * client)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 
TEST_F(WebMParserTest,EmptyCluster)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 
TEST_F(WebMParserTest,EmptyClusterInSegment)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.
TEST_F(WebMParserTest,ChildNonListLargerThanParent)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.
TEST_F(WebMParserTest,ChildListLargerThanParent)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.
TEST_F(WebMParserTest,ListIdDoesNotMatch)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 
TEST_F(WebMParserTest,InvalidElementInList)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.
TEST_F(WebMParserTest,InvalidEBMLHeaderInCluster)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.
TEST_F(WebMParserTest,UnknownSizeClusterFollowedByEBMLHeader)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 
TEST_F(WebMParserTest,VoidAndCRC32InList)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 
TEST_F(WebMParserTest,ParseListElementWithSingleCall)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 
TEST_F(WebMParserTest,ParseListElementWithMultipleCalls)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 
TEST_F(WebMParserTest,Reset)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.
TEST_F(WebMParserTest,MultipleClients)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.
TEST_F(WebMParserTest,InvalidClient)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 
TEST_F(WebMParserTest,ReservedIds)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 
TEST_F(WebMParserTest,ReservedSizes)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 
TEST_F(WebMParserTest,ZeroPaddedStrings)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