box_reader_unittest.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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
184TEST_F(BoxReaderTest, SkippingBloc) {
185  static const uint8 kData[] = {
186    0x00, 0x00, 0x00, 0x09,  'b',  'l',  'o',  'c', 0x00
187  };
188
189  std::vector<uint8> buf(kData, kData + sizeof(kData));
190
191  bool err;
192  scoped_ptr<BoxReader> reader(
193      BoxReader::ReadTopLevelBox(&buf[0], buf.size(), LogCB(), &err));
194
195  EXPECT_FALSE(err);
196  EXPECT_TRUE(reader);
197  EXPECT_EQ(FOURCC_BLOC, reader->type());
198}
199
200}  // namespace mp4
201}  // namespace media
202