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"
11 #include "base/memory/scoped_ptr.h"
12 #include "media/formats/mp4/box_definitions.h"
19 bool BufferReader::Read1(uint8
* v
) {
25 // Internal implementation of multi-byte reads
26 template<typename T
> bool BufferReader::Read(T
* v
) {
27 RCHECK(HasBytes(sizeof(T
)));
30 for (size_t i
= 0; i
< sizeof(T
); i
++) {
38 bool BufferReader::Read2(uint16
* v
) { return Read(v
); }
39 bool BufferReader::Read2s(int16
* v
) { return Read(v
); }
40 bool BufferReader::Read4(uint32
* v
) { return Read(v
); }
41 bool BufferReader::Read4s(int32
* v
) { return Read(v
); }
42 bool BufferReader::Read8(uint64
* v
) { return Read(v
); }
43 bool BufferReader::Read8s(int64
* v
) { return Read(v
); }
45 bool BufferReader::ReadFourCC(FourCC
* v
) {
46 return Read4(reinterpret_cast<uint32
*>(v
));
49 bool BufferReader::ReadVec(std::vector
<uint8
>* vec
, int count
) {
50 RCHECK(HasBytes(count
));
52 vec
->insert(vec
->end(), buf_
+ pos_
, buf_
+ pos_
+ count
);
57 bool BufferReader::SkipBytes(int bytes
) {
58 RCHECK(HasBytes(bytes
));
63 bool BufferReader::Read4Into8(uint64
* v
) {
70 bool BufferReader::Read4sInto8s(int64
* v
) {
71 // Beware of the need for sign extension.
78 BoxReader::BoxReader(const uint8
* buf
,
80 const scoped_refptr
<MediaLog
>& media_log
,
82 : BufferReader(buf
, size
),
83 media_log_(media_log
),
91 BoxReader::~BoxReader() {
92 if (scanned_
&& !children_
.empty()) {
93 for (ChildMap::iterator itr
= children_
.begin();
94 itr
!= children_
.end(); ++itr
) {
95 DVLOG(1) << "Skipping unknown box: " << FourCCToString(itr
->first
);
101 BoxReader
* BoxReader::ReadTopLevelBox(const uint8
* buf
,
103 const scoped_refptr
<MediaLog
>& media_log
,
105 scoped_ptr
<BoxReader
> reader(new BoxReader(buf
, buf_size
, media_log
, false));
106 if (!reader
->ReadHeader(err
))
109 if (!IsValidTopLevelBox(reader
->type(), media_log
)) {
114 if (reader
->size() <= buf_size
)
115 return reader
.release();
121 bool BoxReader::StartTopLevelBox(const uint8
* buf
,
123 const scoped_refptr
<MediaLog
>& media_log
,
127 BoxReader
reader(buf
, buf_size
, media_log
, false);
128 if (!reader
.ReadHeader(err
)) return false;
129 if (!IsValidTopLevelBox(reader
.type(), media_log
)) {
133 *type
= reader
.type();
134 *box_size
= reader
.size();
139 BoxReader
* BoxReader::ReadConcatentatedBoxes(const uint8
* buf
,
140 const int buf_size
) {
141 return new BoxReader(buf
, buf_size
, new MediaLog(), true);
145 bool BoxReader::IsValidTopLevelBox(const FourCC
& type
,
146 const scoped_refptr
<MediaLog
>& media_log
) {
167 // Hex is used to show nonprintable characters and aid in debugging
168 MEDIA_LOG(DEBUG
, media_log
) << "Unrecognized top-level box type "
169 << FourCCToString(type
);
174 bool BoxReader::ScanChildren() {
179 while (pos() < size()) {
180 BoxReader
child(&buf_
[pos_
], size_
- pos_
, media_log_
, is_EOS_
);
181 if (!child
.ReadHeader(&err
)) break;
183 children_
.insert(std::pair
<FourCC
, BoxReader
>(child
.type(), child
));
184 pos_
+= child
.size();
188 return !err
&& pos() == size();
191 bool BoxReader::HasChild(Box
* child
) {
194 return children_
.count(child
->BoxType()) > 0;
197 bool BoxReader::ReadChild(Box
* child
) {
199 FourCC child_type
= child
->BoxType();
201 ChildMap::iterator itr
= children_
.find(child_type
);
202 RCHECK(itr
!= children_
.end());
203 DVLOG(2) << "Found a " << FourCCToString(child_type
) << " box.";
204 RCHECK(child
->Parse(&itr
->second
));
205 children_
.erase(itr
);
209 bool BoxReader::MaybeReadChild(Box
* child
) {
210 if (!children_
.count(child
->BoxType())) return true;
211 return ReadChild(child
);
214 bool BoxReader::ReadFullBoxHeader() {
216 RCHECK(Read4(&vflags
));
217 version_
= vflags
>> 24;
218 flags_
= vflags
& 0xffffff;
222 bool BoxReader::ReadHeader(bool* err
) {
227 // If EOS is known, then this is an error. If not, additional data may be
228 // appended later, so this is a soft error.
232 CHECK(Read4Into8(&size
) && ReadFourCC(&type_
));
236 // All the data bytes are expected to be provided.
239 MEDIA_LOG(DEBUG
, media_log_
)
240 << "ISO BMFF boxes that run to EOS are not supported";
244 } else if (size
== 1) {
246 // If EOS is known, then this is an error. If not, it's a soft error.
253 // Implementation-specific: support for boxes larger than 2^31 has been
255 if (size
< static_cast<uint64
>(pos_
) ||
256 size
> static_cast<uint64
>(kint32max
)) {
261 // Make sure the buffer contains at least the expected number of bytes.
262 // Since the data may be appended in pieces, this can only be checked if EOS.
263 if (is_EOS_
&& size
> static_cast<uint64
>(size_
)) {
268 // Note that the pos_ head has advanced to the byte immediately after the
269 // header, which is where we want it.