| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/formats/mp4/box_reader.h" |
| 6 |
| 5 #include <stdint.h> | 7 #include <stdint.h> |
| 6 #include <string.h> | 8 #include <string.h> |
| 7 | 9 |
| 10 #include <memory> |
| 11 |
| 8 #include "base/logging.h" | 12 #include "base/logging.h" |
| 9 #include "base/memory/scoped_ptr.h" | |
| 10 #include "media/base/mock_media_log.h" | 13 #include "media/base/mock_media_log.h" |
| 11 #include "media/formats/mp4/box_definitions.h" | 14 #include "media/formats/mp4/box_definitions.h" |
| 12 #include "media/formats/mp4/box_reader.h" | |
| 13 #include "media/formats/mp4/rcheck.h" | 15 #include "media/formats/mp4/rcheck.h" |
| 14 #include "testing/gmock/include/gmock/gmock.h" | 16 #include "testing/gmock/include/gmock/gmock.h" |
| 15 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
| 16 | 18 |
| 17 using ::testing::HasSubstr; | 19 using ::testing::HasSubstr; |
| 18 using ::testing::StrictMock; | 20 using ::testing::StrictMock; |
| 19 | 21 |
| 20 namespace media { | 22 namespace media { |
| 21 namespace mp4 { | 23 namespace mp4 { |
| 22 | 24 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 85 | 87 |
| 86 protected: | 88 protected: |
| 87 std::vector<uint8_t> GetBuf() { | 89 std::vector<uint8_t> GetBuf() { |
| 88 return std::vector<uint8_t>(kSkipBox, kSkipBox + sizeof(kSkipBox)); | 90 return std::vector<uint8_t>(kSkipBox, kSkipBox + sizeof(kSkipBox)); |
| 89 } | 91 } |
| 90 | 92 |
| 91 void TestTopLevelBox(const uint8_t* data, int size, uint32_t fourCC) { | 93 void TestTopLevelBox(const uint8_t* data, int size, uint32_t fourCC) { |
| 92 std::vector<uint8_t> buf(data, data + size); | 94 std::vector<uint8_t> buf(data, data + size); |
| 93 | 95 |
| 94 bool err; | 96 bool err; |
| 95 scoped_ptr<BoxReader> reader( | 97 std::unique_ptr<BoxReader> reader( |
| 96 BoxReader::ReadTopLevelBox(&buf[0], buf.size(), media_log_, &err)); | 98 BoxReader::ReadTopLevelBox(&buf[0], buf.size(), media_log_, &err)); |
| 97 | 99 |
| 98 EXPECT_FALSE(err); | 100 EXPECT_FALSE(err); |
| 99 EXPECT_TRUE(reader); | 101 EXPECT_TRUE(reader); |
| 100 EXPECT_EQ(fourCC, reader->type()); | 102 EXPECT_EQ(fourCC, reader->type()); |
| 101 EXPECT_EQ(reader->size(), static_cast<uint64_t>(size)); | 103 EXPECT_EQ(reader->size(), static_cast<uint64_t>(size)); |
| 102 } | 104 } |
| 103 | 105 |
| 104 scoped_refptr<StrictMock<MockMediaLog>> media_log_; | 106 scoped_refptr<StrictMock<MockMediaLog>> media_log_; |
| 105 }; | 107 }; |
| 106 | 108 |
| 107 TEST_F(BoxReaderTest, ExpectedOperationTest) { | 109 TEST_F(BoxReaderTest, ExpectedOperationTest) { |
| 108 std::vector<uint8_t> buf = GetBuf(); | 110 std::vector<uint8_t> buf = GetBuf(); |
| 109 bool err; | 111 bool err; |
| 110 scoped_ptr<BoxReader> reader( | 112 std::unique_ptr<BoxReader> reader( |
| 111 BoxReader::ReadTopLevelBox(&buf[0], buf.size(), media_log_, &err)); | 113 BoxReader::ReadTopLevelBox(&buf[0], buf.size(), media_log_, &err)); |
| 112 EXPECT_FALSE(err); | 114 EXPECT_FALSE(err); |
| 113 EXPECT_TRUE(reader.get()); | 115 EXPECT_TRUE(reader.get()); |
| 114 | 116 |
| 115 SkipBox box; | 117 SkipBox box; |
| 116 EXPECT_TRUE(box.Parse(reader.get())); | 118 EXPECT_TRUE(box.Parse(reader.get())); |
| 117 EXPECT_EQ(0x01, reader->version()); | 119 EXPECT_EQ(0x01, reader->version()); |
| 118 EXPECT_EQ(0x020304u, reader->flags()); | 120 EXPECT_EQ(0x020304u, reader->flags()); |
| 119 EXPECT_EQ(0x05, box.a); | 121 EXPECT_EQ(0x05, box.a); |
| 120 EXPECT_EQ(0x06, box.b); | 122 EXPECT_EQ(0x06, box.b); |
| 121 EXPECT_EQ(0x0708, box.c); | 123 EXPECT_EQ(0x0708, box.c); |
| 122 EXPECT_EQ(static_cast<int32_t>(0xf90a0b0c), box.d); | 124 EXPECT_EQ(static_cast<int32_t>(0xf90a0b0c), box.d); |
| 123 EXPECT_EQ(static_cast<int32_t>(0xfd0e0f10), box.e); | 125 EXPECT_EQ(static_cast<int32_t>(0xfd0e0f10), box.e); |
| 124 | 126 |
| 125 EXPECT_EQ(2u, box.kids.size()); | 127 EXPECT_EQ(2u, box.kids.size()); |
| 126 EXPECT_EQ(0xdeadbeef, box.kids[0].val); | 128 EXPECT_EQ(0xdeadbeef, box.kids[0].val); |
| 127 EXPECT_EQ(0xfacecafe, box.kids[1].val); | 129 EXPECT_EQ(0xfacecafe, box.kids[1].val); |
| 128 | 130 |
| 129 // Accounting for the extra byte outside of the box above | 131 // Accounting for the extra byte outside of the box above |
| 130 EXPECT_EQ(buf.size(), static_cast<uint64_t>(reader->size() + 1)); | 132 EXPECT_EQ(buf.size(), static_cast<uint64_t>(reader->size() + 1)); |
| 131 } | 133 } |
| 132 | 134 |
| 133 TEST_F(BoxReaderTest, OuterTooShortTest) { | 135 TEST_F(BoxReaderTest, OuterTooShortTest) { |
| 134 std::vector<uint8_t> buf = GetBuf(); | 136 std::vector<uint8_t> buf = GetBuf(); |
| 135 bool err; | 137 bool err; |
| 136 | 138 |
| 137 // Create a soft failure by truncating the outer box. | 139 // Create a soft failure by truncating the outer box. |
| 138 scoped_ptr<BoxReader> r( | 140 std::unique_ptr<BoxReader> r( |
| 139 BoxReader::ReadTopLevelBox(&buf[0], buf.size() - 2, media_log_, &err)); | 141 BoxReader::ReadTopLevelBox(&buf[0], buf.size() - 2, media_log_, &err)); |
| 140 | 142 |
| 141 EXPECT_FALSE(err); | 143 EXPECT_FALSE(err); |
| 142 EXPECT_FALSE(r.get()); | 144 EXPECT_FALSE(r.get()); |
| 143 } | 145 } |
| 144 | 146 |
| 145 TEST_F(BoxReaderTest, InnerTooLongTest) { | 147 TEST_F(BoxReaderTest, InnerTooLongTest) { |
| 146 std::vector<uint8_t> buf = GetBuf(); | 148 std::vector<uint8_t> buf = GetBuf(); |
| 147 bool err; | 149 bool err; |
| 148 | 150 |
| 149 // Make an inner box too big for its outer box. | 151 // Make an inner box too big for its outer box. |
| 150 buf[25] = 1; | 152 buf[25] = 1; |
| 151 scoped_ptr<BoxReader> reader( | 153 std::unique_ptr<BoxReader> reader( |
| 152 BoxReader::ReadTopLevelBox(&buf[0], buf.size(), media_log_, &err)); | 154 BoxReader::ReadTopLevelBox(&buf[0], buf.size(), media_log_, &err)); |
| 153 | 155 |
| 154 SkipBox box; | 156 SkipBox box; |
| 155 EXPECT_FALSE(box.Parse(reader.get())); | 157 EXPECT_FALSE(box.Parse(reader.get())); |
| 156 } | 158 } |
| 157 | 159 |
| 158 TEST_F(BoxReaderTest, WrongFourCCTest) { | 160 TEST_F(BoxReaderTest, WrongFourCCTest) { |
| 159 std::vector<uint8_t> buf = GetBuf(); | 161 std::vector<uint8_t> buf = GetBuf(); |
| 160 bool err; | 162 bool err; |
| 161 | 163 |
| 162 // Set an unrecognized top-level FourCC. | 164 // Set an unrecognized top-level FourCC. |
| 163 buf[4] = 0x44; | 165 buf[4] = 0x44; |
| 164 buf[5] = 0x41; | 166 buf[5] = 0x41; |
| 165 buf[6] = 0x4c; | 167 buf[6] = 0x4c; |
| 166 buf[7] = 0x45; | 168 buf[7] = 0x45; |
| 167 | 169 |
| 168 EXPECT_MEDIA_LOG(HasSubstr("Unrecognized top-level box type DALE")); | 170 EXPECT_MEDIA_LOG(HasSubstr("Unrecognized top-level box type DALE")); |
| 169 | 171 |
| 170 scoped_ptr<BoxReader> reader( | 172 std::unique_ptr<BoxReader> reader( |
| 171 BoxReader::ReadTopLevelBox(&buf[0], buf.size(), media_log_, &err)); | 173 BoxReader::ReadTopLevelBox(&buf[0], buf.size(), media_log_, &err)); |
| 172 EXPECT_FALSE(reader.get()); | 174 EXPECT_FALSE(reader.get()); |
| 173 EXPECT_TRUE(err); | 175 EXPECT_TRUE(err); |
| 174 } | 176 } |
| 175 | 177 |
| 176 TEST_F(BoxReaderTest, ScanChildrenTest) { | 178 TEST_F(BoxReaderTest, ScanChildrenTest) { |
| 177 std::vector<uint8_t> buf = GetBuf(); | 179 std::vector<uint8_t> buf = GetBuf(); |
| 178 bool err; | 180 bool err; |
| 179 scoped_ptr<BoxReader> reader( | 181 std::unique_ptr<BoxReader> reader( |
| 180 BoxReader::ReadTopLevelBox(&buf[0], buf.size(), media_log_, &err)); | 182 BoxReader::ReadTopLevelBox(&buf[0], buf.size(), media_log_, &err)); |
| 181 | 183 |
| 182 EXPECT_TRUE(reader->SkipBytes(16) && reader->ScanChildren()); | 184 EXPECT_TRUE(reader->SkipBytes(16) && reader->ScanChildren()); |
| 183 | 185 |
| 184 FreeBox free; | 186 FreeBox free; |
| 185 EXPECT_TRUE(reader->ReadChild(&free)); | 187 EXPECT_TRUE(reader->ReadChild(&free)); |
| 186 EXPECT_FALSE(reader->ReadChild(&free)); | 188 EXPECT_FALSE(reader->ReadChild(&free)); |
| 187 EXPECT_TRUE(reader->MaybeReadChild(&free)); | 189 EXPECT_TRUE(reader->MaybeReadChild(&free)); |
| 188 | 190 |
| 189 std::vector<PsshBox> kids; | 191 std::vector<PsshBox> kids; |
| 190 | 192 |
| 191 EXPECT_TRUE(reader->ReadChildren(&kids)); | 193 EXPECT_TRUE(reader->ReadChildren(&kids)); |
| 192 EXPECT_EQ(2u, kids.size()); | 194 EXPECT_EQ(2u, kids.size()); |
| 193 kids.clear(); | 195 kids.clear(); |
| 194 EXPECT_FALSE(reader->ReadChildren(&kids)); | 196 EXPECT_FALSE(reader->ReadChildren(&kids)); |
| 195 EXPECT_TRUE(reader->MaybeReadChildren(&kids)); | 197 EXPECT_TRUE(reader->MaybeReadChildren(&kids)); |
| 196 } | 198 } |
| 197 | 199 |
| 198 TEST_F(BoxReaderTest, ReadAllChildrenTest) { | 200 TEST_F(BoxReaderTest, ReadAllChildrenTest) { |
| 199 std::vector<uint8_t> buf = GetBuf(); | 201 std::vector<uint8_t> buf = GetBuf(); |
| 200 // Modify buffer to exclude its last 'free' box | 202 // Modify buffer to exclude its last 'free' box |
| 201 buf[3] = 0x38; | 203 buf[3] = 0x38; |
| 202 bool err; | 204 bool err; |
| 203 scoped_ptr<BoxReader> reader( | 205 std::unique_ptr<BoxReader> reader( |
| 204 BoxReader::ReadTopLevelBox(&buf[0], buf.size(), media_log_, &err)); | 206 BoxReader::ReadTopLevelBox(&buf[0], buf.size(), media_log_, &err)); |
| 205 | 207 |
| 206 std::vector<PsshBox> kids; | 208 std::vector<PsshBox> kids; |
| 207 EXPECT_TRUE(reader->SkipBytes(16) && reader->ReadAllChildren(&kids)); | 209 EXPECT_TRUE(reader->SkipBytes(16) && reader->ReadAllChildren(&kids)); |
| 208 EXPECT_EQ(2u, kids.size()); | 210 EXPECT_EQ(2u, kids.size()); |
| 209 EXPECT_EQ(kids[0].val, 0xdeadbeef); // Ensure order is preserved | 211 EXPECT_EQ(kids[0].val, 0xdeadbeef); // Ensure order is preserved |
| 210 } | 212 } |
| 211 | 213 |
| 212 TEST_F(BoxReaderTest, SkippingBloc) { | 214 TEST_F(BoxReaderTest, SkippingBloc) { |
| 213 static const uint8_t kData[] = {0x00, 0x00, 0x00, 0x09, 'b', | 215 static const uint8_t kData[] = {0x00, 0x00, 0x00, 0x09, 'b', |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 // The nested box ('junk') has a large size that was chosen to catch | 253 // The nested box ('junk') has a large size that was chosen to catch |
| 252 // integer overflows. The nested box should not specify more than the | 254 // integer overflows. The nested box should not specify more than the |
| 253 // number of remaining bytes in the enclosing box. | 255 // number of remaining bytes in the enclosing box. |
| 254 static const uint8_t kData[] = { | 256 static const uint8_t kData[] = { |
| 255 0x00, 0x00, 0x00, 0x24, 'e', 'm', 's', 'g', // outer box | 257 0x00, 0x00, 0x00, 0x24, 'e', 'm', 's', 'g', // outer box |
| 256 0x7f, 0xff, 0xff, 0xff, 'j', 'u', 'n', 'k', // nested box | 258 0x7f, 0xff, 0xff, 0xff, 'j', 'u', 'n', 'k', // nested box |
| 257 0x00, 0x01, 0x00, 0xff, 0xff, 0x00, 0x3b, 0x03, // random data for rest | 259 0x00, 0x01, 0x00, 0xff, 0xff, 0x00, 0x3b, 0x03, // random data for rest |
| 258 0x00, 0x01, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x05, 0x06, 0x07, 0x08}; | 260 0x00, 0x01, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x05, 0x06, 0x07, 0x08}; |
| 259 | 261 |
| 260 bool err; | 262 bool err; |
| 261 scoped_ptr<BoxReader> reader( | 263 std::unique_ptr<BoxReader> reader( |
| 262 BoxReader::ReadTopLevelBox(kData, sizeof(kData), media_log_, &err)); | 264 BoxReader::ReadTopLevelBox(kData, sizeof(kData), media_log_, &err)); |
| 263 | 265 |
| 264 EXPECT_FALSE(err); | 266 EXPECT_FALSE(err); |
| 265 EXPECT_TRUE(reader); | 267 EXPECT_TRUE(reader); |
| 266 EXPECT_EQ(FOURCC_EMSG, reader->type()); | 268 EXPECT_EQ(FOURCC_EMSG, reader->type()); |
| 267 EXPECT_FALSE(reader->ScanChildren()); | 269 EXPECT_FALSE(reader->ScanChildren()); |
| 268 } | 270 } |
| 269 | 271 |
| 270 TEST_F(BoxReaderTest, ScanChildrenWithInvalidChild) { | 272 TEST_F(BoxReaderTest, ScanChildrenWithInvalidChild) { |
| 271 // This data is not a valid 'emsg' box. It is just used as a top-level box | 273 // This data is not a valid 'emsg' box. It is just used as a top-level box |
| 272 // as ReadTopLevelBox() has a restricted set of boxes it allows. | 274 // as ReadTopLevelBox() has a restricted set of boxes it allows. |
| 273 // The nested 'elst' box is used as it includes a count of EditListEntry's. | 275 // The nested 'elst' box is used as it includes a count of EditListEntry's. |
| 274 // The sample specifies a large number of EditListEntry's, but only 1 is | 276 // The sample specifies a large number of EditListEntry's, but only 1 is |
| 275 // actually included in the box. This test verifies that the code checks | 277 // actually included in the box. This test verifies that the code checks |
| 276 // properly that the buffer contains the specified number of EditListEntry's | 278 // properly that the buffer contains the specified number of EditListEntry's |
| 277 // (does not cause an int32_t overflow when checking that the bytes are | 279 // (does not cause an int32_t overflow when checking that the bytes are |
| 278 // available, and does not read past the end of the buffer). | 280 // available, and does not read past the end of the buffer). |
| 279 static const uint8_t kData[] = { | 281 static const uint8_t kData[] = { |
| 280 0x00, 0x00, 0x00, 0x2c, 'e', 'm', 's', 'g', // outer box | 282 0x00, 0x00, 0x00, 0x2c, 'e', 'm', 's', 'g', // outer box |
| 281 0x00, 0x00, 0x00, 0x24, 'e', 'l', 's', 't', // nested box | 283 0x00, 0x00, 0x00, 0x24, 'e', 'l', 's', 't', // nested box |
| 282 0x01, 0x00, 0x00, 0x00, // version = 1, flags = 0 | 284 0x01, 0x00, 0x00, 0x00, // version = 1, flags = 0 |
| 283 0xff, 0xff, 0xff, 0xff, // count = max, but only 1 actually included | 285 0xff, 0xff, 0xff, 0xff, // count = max, but only 1 actually included |
| 284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | 287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| 286 | 288 |
| 287 bool err; | 289 bool err; |
| 288 scoped_ptr<BoxReader> reader( | 290 std::unique_ptr<BoxReader> reader( |
| 289 BoxReader::ReadTopLevelBox(kData, sizeof(kData), media_log_, &err)); | 291 BoxReader::ReadTopLevelBox(kData, sizeof(kData), media_log_, &err)); |
| 290 | 292 |
| 291 EXPECT_FALSE(err); | 293 EXPECT_FALSE(err); |
| 292 EXPECT_TRUE(reader); | 294 EXPECT_TRUE(reader); |
| 293 EXPECT_EQ(FOURCC_EMSG, reader->type()); | 295 EXPECT_EQ(FOURCC_EMSG, reader->type()); |
| 294 EXPECT_TRUE(reader->ScanChildren()); | 296 EXPECT_TRUE(reader->ScanChildren()); |
| 295 | 297 |
| 296 // 'elst' specifies lots of EditListEntry's but only includes 1. Thus | 298 // 'elst' specifies lots of EditListEntry's but only includes 1. Thus |
| 297 // parsing it should fail. | 299 // parsing it should fail. |
| 298 EditList child; | 300 EditList child; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 309 // to read past the end of the buffer. | 311 // to read past the end of the buffer. |
| 310 static const uint8_t kData[] = { | 312 static const uint8_t kData[] = { |
| 311 0x00, 0x00, 0x00, 0x28, 'e', 'm', 's', 'g', // outer box | 313 0x00, 0x00, 0x00, 0x28, 'e', 'm', 's', 'g', // outer box |
| 312 0x00, 0x00, 0x00, 0x20, 't', 'r', 'u', 'n', // nested box | 314 0x00, 0x00, 0x00, 0x20, 't', 'r', 'u', 'n', // nested box |
| 313 0x00, 0x00, 0x0f, 0x00, // version = 0, flags = samples present | 315 0x00, 0x00, 0x0f, 0x00, // version = 0, flags = samples present |
| 314 0xff, 0xff, 0xff, 0xff, // count = max, but only 1 actually included | 316 0xff, 0xff, 0xff, 0xff, // count = max, but only 1 actually included |
| 315 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 317 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 316 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | 318 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| 317 | 319 |
| 318 bool err; | 320 bool err; |
| 319 scoped_ptr<BoxReader> reader( | 321 std::unique_ptr<BoxReader> reader( |
| 320 BoxReader::ReadTopLevelBox(kData, sizeof(kData), media_log_, &err)); | 322 BoxReader::ReadTopLevelBox(kData, sizeof(kData), media_log_, &err)); |
| 321 | 323 |
| 322 EXPECT_FALSE(err); | 324 EXPECT_FALSE(err); |
| 323 EXPECT_TRUE(reader); | 325 EXPECT_TRUE(reader); |
| 324 EXPECT_EQ(FOURCC_EMSG, reader->type()); | 326 EXPECT_EQ(FOURCC_EMSG, reader->type()); |
| 325 | 327 |
| 326 // Reading the child should fail since the number of samples specified | 328 // Reading the child should fail since the number of samples specified |
| 327 // doesn't match what is in the box. | 329 // doesn't match what is in the box. |
| 328 std::vector<TrackFragmentRun> children; | 330 std::vector<TrackFragmentRun> children; |
| 329 EXPECT_FALSE(reader->ReadAllChildrenAndCheckFourCC(&children)); | 331 EXPECT_FALSE(reader->ReadAllChildrenAndCheckFourCC(&children)); |
| 330 } | 332 } |
| 331 | 333 |
| 332 } // namespace mp4 | 334 } // namespace mp4 |
| 333 } // namespace media | 335 } // namespace media |
| OLD | NEW |