Home | History | Annotate | Download | only in mp4
      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.
      4 
      5 #include "media/formats/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/formats/mp4/box_definitions.h"
     15 #include "media/formats/mp4/rcheck.h"
     16 
     17 namespace media {
     18 namespace mp4 {
     19 
     20 Box::~Box() {}
     21 
     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
     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 
     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); }
     47 
     48 bool BufferReader::ReadFourCC(FourCC* v) {
     49   return Read4(reinterpret_cast<uint32*>(v));
     50 }
     51 
     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 
     60 bool BufferReader::SkipBytes(int bytes) {
     61   RCHECK(HasBytes(bytes));
     62   pos_ += bytes;
     63   return true;
     64 }
     65 
     66 bool BufferReader::Read4Into8(uint64* v) {
     67   uint32 tmp;
     68   RCHECK(Read4(&tmp));
     69   *v = tmp;
     70   return true;
     71 }
     72 
     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 
     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 
     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
    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
    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
    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     case FOURCC_UUID:
    159     case FOURCC_EMSG:
    160       return true;
    161     default:
    162       // Hex is used to show nonprintable characters and aid in debugging
    163       MEDIA_LOG(log_cb) << "Unrecognized top-level box type "
    164                         << FourCCToString(type);
    165       return false;
    166   }
    167 }
    168 
    169 bool BoxReader::ScanChildren() {
    170   DCHECK(!scanned_);
    171   scanned_ = true;
    172 
    173   bool err = false;
    174   while (pos() < size()) {
    175     BoxReader child(&buf_[pos_], size_ - pos_, log_cb_);
    176     if (!child.ReadHeader(&err)) break;
    177 
    178     children_.insert(std::pair<FourCC, BoxReader>(child.type(), child));
    179     pos_ += child.size();
    180   }
    181 
    182   DCHECK(!err);
    183   return !err && pos() == size();
    184 }
    185 
    186 bool BoxReader::HasChild(Box* child) {
    187   DCHECK(scanned_);
    188   DCHECK(child);
    189   return children_.count(child->BoxType()) > 0;
    190 }
    191 
    192 bool BoxReader::ReadChild(Box* child) {
    193   DCHECK(scanned_);
    194   FourCC child_type = child->BoxType();
    195 
    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);
    201   return true;
    202 }
    203 
    204 bool BoxReader::MaybeReadChild(Box* child) {
    205   if (!children_.count(child->BoxType())) return true;
    206   return ReadChild(child);
    207 }
    208 
    209 bool BoxReader::ReadFullBoxHeader() {
    210   uint32 vflags;
    211   RCHECK(Read4(&vflags));
    212   version_ = vflags >> 24;
    213   flags_ = vflags & 0xffffff;
    214   return true;
    215 }
    216 
    217 bool BoxReader::ReadHeader(bool* err) {
    218   uint64 size = 0;
    219   *err = false;
    220 
    221   if (!HasBytes(8)) return false;
    222   CHECK(Read4Into8(&size) && ReadFourCC(&type_));
    223 
    224   if (size == 0) {
    225     // Media Source specific: we do not support boxes that run to EOS.
    226     *err = true;
    227     return false;
    228   } else if (size == 1) {
    229     if (!HasBytes(8)) return false;
    230     CHECK(Read8(&size));
    231   }
    232 
    233   // Implementation-specific: support for boxes larger than 2^31 has been
    234   // removed.
    235   if (size < static_cast<uint64>(pos_) ||
    236       size > static_cast<uint64>(kint32max)) {
    237     *err = true;
    238     return false;
    239   }
    240 
    241   // Note that the pos_ head has advanced to the byte immediately after the
    242   // header, which is where we want it.
    243   size_ = size;
    244   return true;
    245 }
    246 
    247 }  // namespace mp4
    248 }  // namespace media
    249