• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "media/mp4/box_reader.h"
6 
7 #include <string.h>
8 #include <algorithm>
9 #include <map>
10 #include <set>
11 
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "media/mp4/box_definitions.h"
15 #include "media/mp4/rcheck.h"
16 
17 namespace media {
18 namespace mp4 {
19 
~Box()20 Box::~Box() {}
21 
Read1(uint8 * v)22 bool BufferReader::Read1(uint8* v) {
23   RCHECK(HasBytes(1));
24   *v = buf_[pos_++];
25   return true;
26 }
27 
28 // Internal implementation of multi-byte reads
Read(T * v)29 template<typename T> bool BufferReader::Read(T* v) {
30   RCHECK(HasBytes(sizeof(T)));
31 
32   T tmp = 0;
33   for (size_t i = 0; i < sizeof(T); i++) {
34     tmp <<= 8;
35     tmp += buf_[pos_++];
36   }
37   *v = tmp;
38   return true;
39 }
40 
Read2(uint16 * v)41 bool BufferReader::Read2(uint16* v) { return Read(v); }
Read2s(int16 * v)42 bool BufferReader::Read2s(int16* v) { return Read(v); }
Read4(uint32 * v)43 bool BufferReader::Read4(uint32* v) { return Read(v); }
Read4s(int32 * v)44 bool BufferReader::Read4s(int32* v) { return Read(v); }
Read8(uint64 * v)45 bool BufferReader::Read8(uint64* v) { return Read(v); }
Read8s(int64 * v)46 bool BufferReader::Read8s(int64* v) { return Read(v); }
47 
ReadFourCC(FourCC * v)48 bool BufferReader::ReadFourCC(FourCC* v) {
49   return Read4(reinterpret_cast<uint32*>(v));
50 }
51 
ReadVec(std::vector<uint8> * vec,int count)52 bool BufferReader::ReadVec(std::vector<uint8>* vec, int count) {
53   RCHECK(HasBytes(count));
54   vec->clear();
55   vec->insert(vec->end(), buf_ + pos_, buf_ + pos_ + count);
56   pos_ += count;
57   return true;
58 }
59 
SkipBytes(int bytes)60 bool BufferReader::SkipBytes(int bytes) {
61   RCHECK(HasBytes(bytes));
62   pos_ += bytes;
63   return true;
64 }
65 
Read4Into8(uint64 * v)66 bool BufferReader::Read4Into8(uint64* v) {
67   uint32 tmp;
68   RCHECK(Read4(&tmp));
69   *v = tmp;
70   return true;
71 }
72 
Read4sInto8s(int64 * v)73 bool BufferReader::Read4sInto8s(int64* v) {
74   // Beware of the need for sign extension.
75   int32 tmp;
76   RCHECK(Read4s(&tmp));
77   *v = tmp;
78   return true;
79 }
80 
81 
BoxReader(const uint8 * buf,const int size,const LogCB & log_cb)82 BoxReader::BoxReader(const uint8* buf, const int size,
83                      const LogCB& log_cb)
84     : BufferReader(buf, size),
85       log_cb_(log_cb),
86       type_(FOURCC_NULL),
87       version_(0),
88       flags_(0),
89       scanned_(false) {
90 }
91 
~BoxReader()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);
97     }
98   }
99 }
100 
101 // static
ReadTopLevelBox(const uint8 * buf,const int buf_size,const LogCB & log_cb,bool * err)102 BoxReader* BoxReader::ReadTopLevelBox(const uint8* buf,
103                                       const int buf_size,
104                                       const LogCB& log_cb,
105                                       bool* err) {
106   scoped_ptr<BoxReader> reader(new BoxReader(buf, buf_size, log_cb));
107   if (!reader->ReadHeader(err))
108     return NULL;
109 
110   if (!IsValidTopLevelBox(reader->type(), log_cb)) {
111     *err = true;
112     return NULL;
113   }
114 
115   if (reader->size() <= buf_size)
116     return reader.release();
117 
118   return NULL;
119 }
120 
121 // static
StartTopLevelBox(const uint8 * buf,const int buf_size,const LogCB & log_cb,FourCC * type,int * box_size,bool * err)122 bool BoxReader::StartTopLevelBox(const uint8* buf,
123                                  const int buf_size,
124                                  const LogCB& log_cb,
125                                  FourCC* type,
126                                  int* box_size,
127                                  bool* err) {
128   BoxReader reader(buf, buf_size, log_cb);
129   if (!reader.ReadHeader(err)) return false;
130   if (!IsValidTopLevelBox(reader.type(), log_cb)) {
131     *err = true;
132     return false;
133   }
134   *type = reader.type();
135   *box_size = reader.size();
136   return true;
137 }
138 
139 // static
IsValidTopLevelBox(const FourCC & type,const LogCB & log_cb)140 bool BoxReader::IsValidTopLevelBox(const FourCC& type,
141                                    const LogCB& log_cb) {
142   switch (type) {
143     case FOURCC_FTYP:
144     case FOURCC_PDIN:
145     case FOURCC_BLOC:
146     case FOURCC_MOOV:
147     case FOURCC_MOOF:
148     case FOURCC_MFRA:
149     case FOURCC_MDAT:
150     case FOURCC_FREE:
151     case FOURCC_SKIP:
152     case FOURCC_META:
153     case FOURCC_MECO:
154     case FOURCC_STYP:
155     case FOURCC_SIDX:
156     case FOURCC_SSIX:
157     case FOURCC_PRFT:
158       return true;
159     default:
160       // Hex is used to show nonprintable characters and aid in debugging
161       MEDIA_LOG(log_cb) << "Unrecognized top-level box type 0x"
162                         << std::hex << type;
163       return false;
164   }
165 }
166 
ScanChildren()167 bool BoxReader::ScanChildren() {
168   DCHECK(!scanned_);
169   scanned_ = true;
170 
171   bool err = false;
172   while (pos() < size()) {
173     BoxReader child(&buf_[pos_], size_ - pos_, log_cb_);
174     if (!child.ReadHeader(&err)) break;
175 
176     children_.insert(std::pair<FourCC, BoxReader>(child.type(), child));
177     pos_ += child.size();
178   }
179 
180   DCHECK(!err);
181   return !err && pos() == size();
182 }
183 
ReadChild(Box * child)184 bool BoxReader::ReadChild(Box* child) {
185   DCHECK(scanned_);
186   FourCC child_type = child->BoxType();
187 
188   ChildMap::iterator itr = children_.find(child_type);
189   RCHECK(itr != children_.end());
190   DVLOG(2) << "Found a " << FourCCToString(child_type) << " box.";
191   RCHECK(child->Parse(&itr->second));
192   children_.erase(itr);
193   return true;
194 }
195 
MaybeReadChild(Box * child)196 bool BoxReader::MaybeReadChild(Box* child) {
197   if (!children_.count(child->BoxType())) return true;
198   return ReadChild(child);
199 }
200 
ReadFullBoxHeader()201 bool BoxReader::ReadFullBoxHeader() {
202   uint32 vflags;
203   RCHECK(Read4(&vflags));
204   version_ = vflags >> 24;
205   flags_ = vflags & 0xffffff;
206   return true;
207 }
208 
ReadHeader(bool * err)209 bool BoxReader::ReadHeader(bool* err) {
210   uint64 size = 0;
211   *err = false;
212 
213   if (!HasBytes(8)) return false;
214   CHECK(Read4Into8(&size) && ReadFourCC(&type_));
215 
216   if (size == 0) {
217     // Media Source specific: we do not support boxes that run to EOS.
218     *err = true;
219     return false;
220   } else if (size == 1) {
221     if (!HasBytes(8)) return false;
222     CHECK(Read8(&size));
223   }
224 
225   // Implementation-specific: support for boxes larger than 2^31 has been
226   // removed.
227   if (size < static_cast<uint64>(pos_) ||
228       size > static_cast<uint64>(kint32max)) {
229     *err = true;
230     return false;
231   }
232 
233   // Note that the pos_ head has advanced to the byte immediately after the
234   // header, which is where we want it.
235   size_ = size;
236   return true;
237 }
238 
239 }  // namespace mp4
240 }  // namespace media
241