box_reader_unittest.cc revision e5d81f57cb97b3b6b7fccc9c5610d21eb81db09d
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 <string.h>
6
7#include "base/basictypes.h"
8#include "base/logging.h"
9#include "base/memory/scoped_ptr.h"
10#include "media/formats/mp4/box_reader.h"
11#include "media/formats/mp4/rcheck.h"
12#include "testing/gtest/include/gtest/gtest.h"
13
14namespace media {
15namespace mp4 {
16
17static const uint8 kSkipBox[] = {
18  // Top-level test box containing three children
19  0x00, 0x00, 0x00, 0x40, 's', 'k', 'i', 'p',
20  0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
21  0xf9, 0x0a, 0x0b, 0x0c, 0xfd, 0x0e, 0x0f, 0x10,
22  // Ordinary (8-byte header) child box
23  0x00, 0x00, 0x00, 0x0c,  'p',  's',  's',  'h', 0xde, 0xad, 0xbe, 0xef,
24  // Extended-size header child box
25  0x00, 0x00, 0x00, 0x01,  'p',  's',  's',  'h',
26  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14,
27  0xfa, 0xce, 0xca, 0xfe,
28  // Empty free box
29  0x00, 0x00, 0x00, 0x08,  'f',  'r',  'e',  'e',
30  // Trailing garbage
31  0x00 };
32
33struct FreeBox : Box {
34  virtual bool Parse(BoxReader* reader) OVERRIDE {
35    return true;
36  }
37  virtual FourCC BoxType() const OVERRIDE { return FOURCC_FREE; }
38};
39
40struct PsshBox : Box {
41  uint32 val;
42
43  virtual bool Parse(BoxReader* reader) OVERRIDE {
44    return reader->Read4(&val);
45  }
46  virtual FourCC BoxType() const OVERRIDE { return FOURCC_PSSH; }
47};
48
49struct SkipBox : Box {
50  uint8 a, b;
51  uint16 c;
52  int32 d;
53  int64 e;
54
55  std::vector<PsshBox> kids;
56  FreeBox mpty;
57
58  virtual bool Parse(BoxReader* reader) OVERRIDE {
59    RCHECK(reader->ReadFullBoxHeader() &&
60           reader->Read1(&a) &&
61           reader->Read1(&b) &&
62           reader->Read2(&c) &&
63           reader->Read4s(&d) &&
64           reader->Read4sInto8s(&e));
65    return reader->ScanChildren() &&
66           reader->ReadChildren(&kids) &&
67           reader->MaybeReadChild(&mpty);
68  }
69  virtual FourCC BoxType() const OVERRIDE { return FOURCC_SKIP; }
70
71  SkipBox();
72  virtual ~SkipBox();
73};
74
75SkipBox::SkipBox() {}
76SkipBox::~SkipBox() {}
77
78class BoxReaderTest : public testing::Test {
79 protected:
80  std::vector<uint8> GetBuf() {
81    return std::vector<uint8>(kSkipBox, kSkipBox + sizeof(kSkipBox));
82  }
83};
84
85TEST_F(BoxReaderTest, ExpectedOperationTest) {
86  std::vector<uint8> buf = GetBuf();
87  bool err;
88  scoped_ptr<BoxReader> reader(
89      BoxReader::ReadTopLevelBox(&buf[0], buf.size(), LogCB(), &err));
90  EXPECT_FALSE(err);
91  EXPECT_TRUE(reader.get());
92
93  SkipBox box;
94  EXPECT_TRUE(box.Parse(reader.get()));
95  EXPECT_EQ(0x01, reader->version());
96  EXPECT_EQ(0x020304u, reader->flags());
97  EXPECT_EQ(0x05, box.a);
98  EXPECT_EQ(0x06, box.b);
99  EXPECT_EQ(0x0708, box.c);
100  EXPECT_EQ(static_cast<int32>(0xf90a0b0c), box.d);
101  EXPECT_EQ(static_cast<int32>(0xfd0e0f10), box.e);
102
103  EXPECT_EQ(2u, box.kids.size());
104  EXPECT_EQ(0xdeadbeef, box.kids[0].val);
105  EXPECT_EQ(0xfacecafe, box.kids[1].val);
106
107  // Accounting for the extra byte outside of the box above
108  EXPECT_EQ(buf.size(), static_cast<uint64>(reader->size() + 1));
109}
110
111TEST_F(BoxReaderTest, OuterTooShortTest) {
112  std::vector<uint8> buf = GetBuf();
113  bool err;
114
115  // Create a soft failure by truncating the outer box.
116  scoped_ptr<BoxReader> r(
117      BoxReader::ReadTopLevelBox(&buf[0], buf.size() - 2, LogCB(), &err));
118
119  EXPECT_FALSE(err);
120  EXPECT_FALSE(r.get());
121}
122
123TEST_F(BoxReaderTest, InnerTooLongTest) {
124  std::vector<uint8> buf = GetBuf();
125  bool err;
126
127  // Make an inner box too big for its outer box.
128  buf[25] = 1;
129  scoped_ptr<BoxReader> reader(
130      BoxReader::ReadTopLevelBox(&buf[0], buf.size(), LogCB(), &err));
131
132  SkipBox box;
133  EXPECT_FALSE(box.Parse(reader.get()));
134}
135
136TEST_F(BoxReaderTest, WrongFourCCTest) {
137  std::vector<uint8> buf = GetBuf();
138  bool err;
139
140  // Set an unrecognized top-level FourCC.
141  buf[5] = 1;
142  scoped_ptr<BoxReader> reader(
143      BoxReader::ReadTopLevelBox(&buf[0], buf.size(), LogCB(), &err));
144  EXPECT_FALSE(reader.get());
145  EXPECT_TRUE(err);
146}
147
148TEST_F(BoxReaderTest, ScanChildrenTest) {
149  std::vector<uint8> buf = GetBuf();
150  bool err;
151  scoped_ptr<BoxReader> reader(
152      BoxReader::ReadTopLevelBox(&buf[0], buf.size(), LogCB(), &err));
153
154  EXPECT_TRUE(reader->SkipBytes(16) && reader->ScanChildren());
155
156  FreeBox free;
157  EXPECT_TRUE(reader->ReadChild(&free));
158  EXPECT_FALSE(reader->ReadChild(&free));
159  EXPECT_TRUE(reader->MaybeReadChild(&free));
160
161  std::vector<PsshBox> kids;
162
163  EXPECT_TRUE(reader->ReadChildren(&kids));
164  EXPECT_EQ(2u, kids.size());
165  kids.clear();
166  EXPECT_FALSE(reader->ReadChildren(&kids));
167  EXPECT_TRUE(reader->MaybeReadChildren(&kids));
168}
169
170TEST_F(BoxReaderTest, ReadAllChildrenTest) {
171  std::vector<uint8> buf = GetBuf();
172  // Modify buffer to exclude its last 'free' box
173  buf[3] = 0x38;
174  bool err;
175  scoped_ptr<BoxReader> reader(
176      BoxReader::ReadTopLevelBox(&buf[0], buf.size(), LogCB(), &err));
177
178  std::vector<PsshBox> kids;
179  EXPECT_TRUE(reader->SkipBytes(16) && reader->ReadAllChildren(&kids));
180  EXPECT_EQ(2u, kids.size());
181  EXPECT_EQ(kids[0].val, 0xdeadbeef);   // Ensure order is preserved
182}
183
184static void TestTopLevelBox(const uint8* data, int size, uint32 fourCC) {
185
186  std::vector<uint8> buf(data, data + size);
187
188  bool err;
189  scoped_ptr<BoxReader> reader(
190      BoxReader::ReadTopLevelBox(&buf[0], buf.size(), LogCB(), &err));
191
192  EXPECT_FALSE(err);
193  EXPECT_TRUE(reader);
194  EXPECT_EQ(fourCC, reader->type());
195  EXPECT_EQ(reader->size(), size);
196}
197
198TEST_F(BoxReaderTest, SkippingBloc) {
199  static const uint8 kData[] = {
200    0x00, 0x00, 0x00, 0x09,  'b',  'l',  'o',  'c', 0x00
201  };
202
203  TestTopLevelBox(kData, sizeof(kData), FOURCC_BLOC);
204}
205
206TEST_F(BoxReaderTest, SkippingEmsg) {
207  static const uint8 kData[] = {
208    0x00, 0x00, 0x00, 0x24,  'e',  'm',  's',  'g',
209    0x00,  // version = 0
210    0x00, 0x00, 0x00,  // flags = 0
211    0x61, 0x00,  // scheme_id_uri = "a"
212    0x61, 0x00,  // value = "a"
213    0x00, 0x00, 0x00, 0x01,  // timescale = 1
214    0x00, 0x00, 0x00, 0x02,  // presentation_time_delta = 2
215    0x00, 0x00, 0x00, 0x03,  // event_duration = 3
216    0x00, 0x00, 0x00, 0x04,  // id = 4
217    0x05, 0x06, 0x07, 0x08,  // message_data[4] = 0x05060708
218  };
219
220  TestTopLevelBox(kData, sizeof(kData), FOURCC_EMSG);
221}
222
223TEST_F(BoxReaderTest, SkippingUuid) {
224  static const uint8 kData[] = {
225    0x00, 0x00, 0x00, 0x19,  'u',  'u',  'i',  'd',
226    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
227    0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,  // usertype
228    0x00,
229  };
230
231  TestTopLevelBox(kData, sizeof(kData), FOURCC_UUID);
232}
233
234}  // namespace mp4
235}  // namespace media
236