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
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/mp4/box_reader.h"
11 #include "media/mp4/rcheck.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace media {
15 namespace mp4 {
16
17 static 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
33 struct FreeBox : Box {
Parsemedia::mp4::FreeBox34 virtual bool Parse(BoxReader* reader) OVERRIDE {
35 return true;
36 }
BoxTypemedia::mp4::FreeBox37 virtual FourCC BoxType() const OVERRIDE { return FOURCC_FREE; }
38 };
39
40 struct PsshBox : Box {
41 uint32 val;
42
Parsemedia::mp4::PsshBox43 virtual bool Parse(BoxReader* reader) OVERRIDE {
44 return reader->Read4(&val);
45 }
BoxTypemedia::mp4::PsshBox46 virtual FourCC BoxType() const OVERRIDE { return FOURCC_PSSH; }
47 };
48
49 struct 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
Parsemedia::mp4::SkipBox58 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 }
BoxTypemedia::mp4::SkipBox69 virtual FourCC BoxType() const OVERRIDE { return FOURCC_SKIP; }
70
71 SkipBox();
72 virtual ~SkipBox();
73 };
74
SkipBox()75 SkipBox::SkipBox() {}
~SkipBox()76 SkipBox::~SkipBox() {}
77
78 class BoxReaderTest : public testing::Test {
79 protected:
GetBuf()80 std::vector<uint8> GetBuf() {
81 return std::vector<uint8>(kSkipBox, kSkipBox + sizeof(kSkipBox));
82 }
83 };
84
TEST_F(BoxReaderTest,ExpectedOperationTest)85 TEST_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
TEST_F(BoxReaderTest,OuterTooShortTest)111 TEST_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
TEST_F(BoxReaderTest,InnerTooLongTest)123 TEST_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
TEST_F(BoxReaderTest,WrongFourCCTest)136 TEST_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
TEST_F(BoxReaderTest,ScanChildrenTest)148 TEST_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
TEST_F(BoxReaderTest,ReadAllChildrenTest)170 TEST_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
TEST_F(BoxReaderTest,SkippingBloc)184 TEST_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