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.
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"
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,
29 0x00, 0x00, 0x00, 0x08, 'f', 'r', 'e', 'e',
33 struct FreeBox
: Box
{
34 virtual bool Parse(BoxReader
* reader
) override
{
37 virtual FourCC
BoxType() const override
{ return FOURCC_FREE
; }
40 struct PsshBox
: Box
{
43 virtual bool Parse(BoxReader
* reader
) override
{
44 return reader
->Read4(&val
);
46 virtual FourCC
BoxType() const override
{ return FOURCC_PSSH
; }
49 struct SkipBox
: Box
{
55 std::vector
<PsshBox
> kids
;
58 virtual bool Parse(BoxReader
* reader
) override
{
59 RCHECK(reader
->ReadFullBoxHeader() &&
64 reader
->Read4sInto8s(&e
));
65 return reader
->ScanChildren() &&
66 reader
->ReadChildren(&kids
) &&
67 reader
->MaybeReadChild(&mpty
);
69 virtual FourCC
BoxType() const override
{ return FOURCC_SKIP
; }
76 SkipBox::~SkipBox() {}
78 class BoxReaderTest
: public testing::Test
{
80 std::vector
<uint8
> GetBuf() {
81 return std::vector
<uint8
>(kSkipBox
, kSkipBox
+ sizeof(kSkipBox
));
85 TEST_F(BoxReaderTest
, ExpectedOperationTest
) {
86 std::vector
<uint8
> buf
= GetBuf();
88 scoped_ptr
<BoxReader
> reader(
89 BoxReader::ReadTopLevelBox(&buf
[0], buf
.size(), LogCB(), &err
));
91 EXPECT_TRUE(reader
.get());
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
);
103 EXPECT_EQ(2u, box
.kids
.size());
104 EXPECT_EQ(0xdeadbeef, box
.kids
[0].val
);
105 EXPECT_EQ(0xfacecafe, box
.kids
[1].val
);
107 // Accounting for the extra byte outside of the box above
108 EXPECT_EQ(buf
.size(), static_cast<uint64
>(reader
->size() + 1));
111 TEST_F(BoxReaderTest
, OuterTooShortTest
) {
112 std::vector
<uint8
> buf
= GetBuf();
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
));
120 EXPECT_FALSE(r
.get());
123 TEST_F(BoxReaderTest
, InnerTooLongTest
) {
124 std::vector
<uint8
> buf
= GetBuf();
127 // Make an inner box too big for its outer box.
129 scoped_ptr
<BoxReader
> reader(
130 BoxReader::ReadTopLevelBox(&buf
[0], buf
.size(), LogCB(), &err
));
133 EXPECT_FALSE(box
.Parse(reader
.get()));
136 TEST_F(BoxReaderTest
, WrongFourCCTest
) {
137 std::vector
<uint8
> buf
= GetBuf();
140 // Set an unrecognized top-level FourCC.
142 scoped_ptr
<BoxReader
> reader(
143 BoxReader::ReadTopLevelBox(&buf
[0], buf
.size(), LogCB(), &err
));
144 EXPECT_FALSE(reader
.get());
148 TEST_F(BoxReaderTest
, ScanChildrenTest
) {
149 std::vector
<uint8
> buf
= GetBuf();
151 scoped_ptr
<BoxReader
> reader(
152 BoxReader::ReadTopLevelBox(&buf
[0], buf
.size(), LogCB(), &err
));
154 EXPECT_TRUE(reader
->SkipBytes(16) && reader
->ScanChildren());
157 EXPECT_TRUE(reader
->ReadChild(&free
));
158 EXPECT_FALSE(reader
->ReadChild(&free
));
159 EXPECT_TRUE(reader
->MaybeReadChild(&free
));
161 std::vector
<PsshBox
> kids
;
163 EXPECT_TRUE(reader
->ReadChildren(&kids
));
164 EXPECT_EQ(2u, kids
.size());
166 EXPECT_FALSE(reader
->ReadChildren(&kids
));
167 EXPECT_TRUE(reader
->MaybeReadChildren(&kids
));
170 TEST_F(BoxReaderTest
, ReadAllChildrenTest
) {
171 std::vector
<uint8
> buf
= GetBuf();
172 // Modify buffer to exclude its last 'free' box
175 scoped_ptr
<BoxReader
> reader(
176 BoxReader::ReadTopLevelBox(&buf
[0], buf
.size(), LogCB(), &err
));
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
184 static void TestTopLevelBox(const uint8
* data
, int size
, uint32 fourCC
) {
186 std::vector
<uint8
> buf(data
, data
+ size
);
189 scoped_ptr
<BoxReader
> reader(
190 BoxReader::ReadTopLevelBox(&buf
[0], buf
.size(), LogCB(), &err
));
194 EXPECT_EQ(fourCC
, reader
->type());
195 EXPECT_EQ(reader
->size(), size
);
198 TEST_F(BoxReaderTest
, SkippingBloc
) {
199 static const uint8 kData
[] = {
200 0x00, 0x00, 0x00, 0x09, 'b', 'l', 'o', 'c', 0x00
203 TestTopLevelBox(kData
, sizeof(kData
), FOURCC_BLOC
);
206 TEST_F(BoxReaderTest
, SkippingEmsg
) {
207 static const uint8 kData
[] = {
208 0x00, 0x00, 0x00, 0x24, 'e', 'm', 's', 'g',
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
220 TestTopLevelBox(kData
, sizeof(kData
), FOURCC_EMSG
);
223 TEST_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
231 TestTopLevelBox(kData
, sizeof(kData
), FOURCC_UUID
);