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