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.
5 #include "media/formats/mp4/box_reader.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "media/formats/mp4/box_definitions.h"
15 #include "media/formats/mp4/rcheck.h"
22 bool BufferReader::Read1(uint8
* v
) {
28 // Internal implementation of multi-byte reads
29 template<typename T
> bool BufferReader::Read(T
* v
) {
30 RCHECK(HasBytes(sizeof(T
)));
33 for (size_t i
= 0; i
< sizeof(T
); i
++) {
41 bool BufferReader::Read2(uint16
* v
) { return Read(v
); }
42 bool BufferReader::Read2s(int16
* v
) { return Read(v
); }
43 bool BufferReader::Read4(uint32
* v
) { return Read(v
); }
44 bool BufferReader::Read4s(int32
* v
) { return Read(v
); }
45 bool BufferReader::Read8(uint64
* v
) { return Read(v
); }
46 bool BufferReader::Read8s(int64
* v
) { return Read(v
); }
48 bool BufferReader::ReadFourCC(FourCC
* v
) {
49 return Read4(reinterpret_cast<uint32
*>(v
));
52 bool BufferReader::ReadVec(std::vector
<uint8
>* vec
, int count
) {
53 RCHECK(HasBytes(count
));
55 vec
->insert(vec
->end(), buf_
+ pos_
, buf_
+ pos_
+ count
);
60 bool BufferReader::SkipBytes(int bytes
) {
61 RCHECK(HasBytes(bytes
));
66 bool BufferReader::Read4Into8(uint64
* v
) {
73 bool BufferReader::Read4sInto8s(int64
* v
) {
74 // Beware of the need for sign extension.
82 BoxReader::BoxReader(const uint8
* buf
, const int size
,
84 : BufferReader(buf
, size
),
92 BoxReader::~BoxReader() {
93 if (scanned_
&& !children_
.empty()) {
94 for (ChildMap::iterator itr
= children_
.begin();
95 itr
!= children_
.end(); ++itr
) {
96 DVLOG(1) << "Skipping unknown box: " << FourCCToString(itr
->first
);
102 BoxReader
* BoxReader::ReadTopLevelBox(const uint8
* buf
,
106 scoped_ptr
<BoxReader
> reader(new BoxReader(buf
, buf_size
, log_cb
));
107 if (!reader
->ReadHeader(err
))
110 if (!IsValidTopLevelBox(reader
->type(), log_cb
)) {
115 if (reader
->size() <= buf_size
)
116 return reader
.release();
122 bool BoxReader::StartTopLevelBox(const uint8
* buf
,
128 BoxReader
reader(buf
, buf_size
, log_cb
);
129 if (!reader
.ReadHeader(err
)) return false;
130 if (!IsValidTopLevelBox(reader
.type(), log_cb
)) {
134 *type
= reader
.type();
135 *box_size
= reader
.size();
140 bool BoxReader::IsValidTopLevelBox(const FourCC
& type
,
141 const LogCB
& log_cb
) {
162 // Hex is used to show nonprintable characters and aid in debugging
163 MEDIA_LOG(DEBUG
, log_cb
) << "Unrecognized top-level box type "
164 << FourCCToString(type
);
169 bool BoxReader::ScanChildren() {
174 while (pos() < size()) {
175 BoxReader
child(&buf_
[pos_
], size_
- pos_
, log_cb_
);
176 if (!child
.ReadHeader(&err
)) break;
178 children_
.insert(std::pair
<FourCC
, BoxReader
>(child
.type(), child
));
179 pos_
+= child
.size();
183 return !err
&& pos() == size();
186 bool BoxReader::HasChild(Box
* child
) {
189 return children_
.count(child
->BoxType()) > 0;
192 bool BoxReader::ReadChild(Box
* child
) {
194 FourCC child_type
= child
->BoxType();
196 ChildMap::iterator itr
= children_
.find(child_type
);
197 RCHECK(itr
!= children_
.end());
198 DVLOG(2) << "Found a " << FourCCToString(child_type
) << " box.";
199 RCHECK(child
->Parse(&itr
->second
));
200 children_
.erase(itr
);
204 bool BoxReader::MaybeReadChild(Box
* child
) {
205 if (!children_
.count(child
->BoxType())) return true;
206 return ReadChild(child
);
209 bool BoxReader::ReadFullBoxHeader() {
211 RCHECK(Read4(&vflags
));
212 version_
= vflags
>> 24;
213 flags_
= vflags
& 0xffffff;
217 bool BoxReader::ReadHeader(bool* err
) {
221 if (!HasBytes(8)) return false;
222 CHECK(Read4Into8(&size
) && ReadFourCC(&type_
));
225 // Media Source specific: we do not support boxes that run to EOS.
228 } else if (size
== 1) {
229 if (!HasBytes(8)) return false;
233 // Implementation-specific: support for boxes larger than 2^31 has been
235 if (size
< static_cast<uint64
>(pos_
) ||
236 size
> static_cast<uint64
>(kint32max
)) {
241 // Note that the pos_ head has advanced to the byte immediately after the
242 // header, which is where we want it.