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