Shaka Packager SDK
Loading...
Searching...
No Matches
box_reader.cc
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 <packager/media/formats/mp4/box_reader.h>
6
7#include <cinttypes>
8#include <limits>
9#include <memory>
10
11#include <absl/log/check.h>
12#include <absl/log/log.h>
13#include <absl/strings/str_format.h>
14
15#include <packager/macros/logging.h>
16#include <packager/media/formats/mp4/box.h>
17
18namespace shaka {
19namespace media {
20namespace mp4 {
21
22BoxReader::BoxReader(const uint8_t* buf, size_t size)
23 : BufferReader(buf, size), type_(FOURCC_NULL), scanned_(false) {
24 DCHECK(buf);
25 DCHECK_LT(0u, size);
26}
27
28BoxReader::~BoxReader() {
29 if (scanned_ && !children_.empty()) {
30 for (ChildMap::iterator itr = children_.begin(); itr != children_.end();
31 ++itr) {
32 DVLOG(1) << "Skipping unknown box: " << FourCCToString(itr->first);
33 }
34 }
35}
36
37// static
38BoxReader* BoxReader::ReadBox(const uint8_t* buf,
39 const size_t buf_size,
40 bool* err) {
41 std::unique_ptr<BoxReader> reader(new BoxReader(buf, buf_size));
42 if (!reader->ReadHeader(err))
43 return NULL;
44
45 // We don't require the complete box to be available for MDAT box.
46 if (reader->type() == FOURCC_mdat)
47 return reader.release();
48
49 if (reader->size() <= buf_size)
50 return reader.release();
51
52 return NULL;
53}
54
55// static
56bool BoxReader::StartBox(const uint8_t* buf,
57 const size_t buf_size,
58 FourCC* type,
59 uint64_t* box_size,
60 bool* err) {
61 BoxReader reader(buf, buf_size);
62 if (!reader.ReadHeader(err))
63 return false;
64 *type = reader.type();
65 *box_size = reader.size();
66 return true;
67}
68
69bool BoxReader::ScanChildren() {
70 DCHECK(!scanned_);
71 scanned_ = true;
72
73 while (pos() < size()) {
74 std::unique_ptr<BoxReader> child(
75 new BoxReader(&data()[pos()], size() - pos()));
76 bool err;
77 if (!child->ReadHeader(&err))
78 return false;
79
80 FourCC box_type = child->type();
81 size_t box_size = child->size();
82 children_.insert(std::pair<FourCC, std::unique_ptr<BoxReader>>(
83 box_type, std::move(child)));
84 VLOG(2) << "Child " << FourCCToString(box_type) << " size 0x" << std::hex
85 << box_size << std::dec;
86 RCHECK(SkipBytes(box_size));
87 }
88
89 return true;
90}
91
92bool BoxReader::ReadChild(Box* child) {
93 DCHECK(scanned_);
94 FourCC child_type = child->BoxType();
95
96 ChildMap::iterator itr = children_.find(child_type);
97 RCHECK(itr != children_.end());
98 DVLOG(2) << "Found a " << FourCCToString(child_type) << " box.";
99 RCHECK(child->Parse(itr->second.get()));
100 children_.erase(itr);
101 return true;
102}
103
104bool BoxReader::ChildExist(Box* child) {
105 return children_.count(child->BoxType()) > 0;
106}
107
108bool BoxReader::TryReadChild(Box* child) {
109 if (!children_.count(child->BoxType()))
110 return true;
111 return ReadChild(child);
112}
113
114bool BoxReader::ReadHeader(bool* err) {
115 uint64_t size = 0;
116 *err = false;
117
118 if (!ReadNBytesInto8(&size, sizeof(uint32_t)) || !ReadFourCC(&type_))
119 return false;
120
121 if (size == 0) {
122 // Boxes that run to EOS are not supported.
123 NOTIMPLEMENTED() << absl::StrFormat("Box '%s' run to EOS.",
124 FourCCToString(type_).c_str());
125 *err = true;
126 return false;
127 } else if (size == 1) {
128 if (!Read8(&size))
129 return false;
130 }
131
132 // The box should have at least the size of what have been parsed.
133 if (size < pos()) {
134 LOG(ERROR) << absl::StrFormat("Box '%s' with size (%" PRIu64
135 ") is invalid.",
136 FourCCToString(type_).c_str(), size);
137 *err = true;
138 return false;
139 }
140
141 // 'mdat' box could have a 64-bit size; other boxes should be very small.
142 if (size > static_cast<uint64_t>(std::numeric_limits<int32_t>::max()) &&
143 type_ != FOURCC_mdat) {
144 LOG(ERROR) << absl::StrFormat("Box '%s' size (%" PRIu64 ") is too large.",
145 FourCCToString(type_).c_str(), size);
146 *err = true;
147 return false;
148 }
149
150 // Note that the pos_ head has advanced to the byte immediately after the
151 // header, which is where we want it.
152 set_size(size);
153 return true;
154}
155
156} // namespace mp4
157} // namespace media
158} // namespace shaka
Class for reading MP4 boxes.
Definition box_reader.h:28
All the methods that are virtual are virtual for mocking.
bool Parse(BoxReader *reader)
Definition box.cc:21
virtual FourCC BoxType() const =0