| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/formats/mp4/box_reader.h" | 5 #include "media/formats/mp4/box_reader.h" |
| 6 | 6 |
| 7 #include <string.h> | 7 #include <string.h> |
| 8 #include <algorithm> | 8 #include <algorithm> |
| 9 #include <set> | 9 #include <set> |
| 10 | 10 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 } | 68 } |
| 69 | 69 |
| 70 bool BufferReader::Read4sInto8s(int64* v) { | 70 bool BufferReader::Read4sInto8s(int64* v) { |
| 71 // Beware of the need for sign extension. | 71 // Beware of the need for sign extension. |
| 72 int32 tmp; | 72 int32 tmp; |
| 73 RCHECK(Read4s(&tmp)); | 73 RCHECK(Read4s(&tmp)); |
| 74 *v = tmp; | 74 *v = tmp; |
| 75 return true; | 75 return true; |
| 76 } | 76 } |
| 77 | 77 |
| 78 BoxReader::BoxReader(const uint8* buf, | 78 |
| 79 const int size, | 79 BoxReader::BoxReader(const uint8* buf, const int size, |
| 80 const LogCB& log_cb, | 80 const LogCB& log_cb) |
| 81 bool is_EOS) | |
| 82 : BufferReader(buf, size), | 81 : BufferReader(buf, size), |
| 83 log_cb_(log_cb), | 82 log_cb_(log_cb), |
| 84 type_(FOURCC_NULL), | 83 type_(FOURCC_NULL), |
| 85 version_(0), | 84 version_(0), |
| 86 flags_(0), | 85 flags_(0), |
| 87 scanned_(false), | 86 scanned_(false) { |
| 88 is_EOS_(is_EOS) { | |
| 89 } | 87 } |
| 90 | 88 |
| 91 BoxReader::~BoxReader() { | 89 BoxReader::~BoxReader() { |
| 92 if (scanned_ && !children_.empty()) { | 90 if (scanned_ && !children_.empty()) { |
| 93 for (ChildMap::iterator itr = children_.begin(); | 91 for (ChildMap::iterator itr = children_.begin(); |
| 94 itr != children_.end(); ++itr) { | 92 itr != children_.end(); ++itr) { |
| 95 DVLOG(1) << "Skipping unknown box: " << FourCCToString(itr->first); | 93 DVLOG(1) << "Skipping unknown box: " << FourCCToString(itr->first); |
| 96 } | 94 } |
| 97 } | 95 } |
| 98 } | 96 } |
| 99 | 97 |
| 100 // static | 98 // static |
| 101 BoxReader* BoxReader::ReadTopLevelBox(const uint8* buf, | 99 BoxReader* BoxReader::ReadTopLevelBox(const uint8* buf, |
| 102 const int buf_size, | 100 const int buf_size, |
| 103 const LogCB& log_cb, | 101 const LogCB& log_cb, |
| 104 bool* err) { | 102 bool* err) { |
| 105 scoped_ptr<BoxReader> reader( | 103 scoped_ptr<BoxReader> reader(new BoxReader(buf, buf_size, log_cb)); |
| 106 new BoxReader(buf, buf_size, log_cb, false)); | |
| 107 if (!reader->ReadHeader(err)) | 104 if (!reader->ReadHeader(err)) |
| 108 return NULL; | 105 return NULL; |
| 109 | 106 |
| 110 if (!IsValidTopLevelBox(reader->type(), log_cb)) { | 107 if (!IsValidTopLevelBox(reader->type(), log_cb)) { |
| 111 *err = true; | 108 *err = true; |
| 112 return NULL; | 109 return NULL; |
| 113 } | 110 } |
| 114 | 111 |
| 115 if (reader->size() <= buf_size) | 112 if (reader->size() <= buf_size) |
| 116 return reader.release(); | 113 return reader.release(); |
| 117 | 114 |
| 118 return NULL; | 115 return NULL; |
| 119 } | 116 } |
| 120 | 117 |
| 121 // static | 118 // static |
| 122 bool BoxReader::StartTopLevelBox(const uint8* buf, | 119 bool BoxReader::StartTopLevelBox(const uint8* buf, |
| 123 const int buf_size, | 120 const int buf_size, |
| 124 const LogCB& log_cb, | 121 const LogCB& log_cb, |
| 125 FourCC* type, | 122 FourCC* type, |
| 126 int* box_size, | 123 int* box_size, |
| 127 bool* err) { | 124 bool* err) { |
| 128 BoxReader reader(buf, buf_size, log_cb, false); | 125 BoxReader reader(buf, buf_size, log_cb); |
| 129 if (!reader.ReadHeader(err)) return false; | 126 if (!reader.ReadHeader(err)) return false; |
| 130 if (!IsValidTopLevelBox(reader.type(), log_cb)) { | 127 if (!IsValidTopLevelBox(reader.type(), log_cb)) { |
| 131 *err = true; | 128 *err = true; |
| 132 return false; | 129 return false; |
| 133 } | 130 } |
| 134 *type = reader.type(); | 131 *type = reader.type(); |
| 135 *box_size = reader.size(); | 132 *box_size = reader.size(); |
| 136 return true; | 133 return true; |
| 137 } | 134 } |
| 138 | 135 |
| 139 // static | 136 // static |
| 140 BoxReader* BoxReader::ReadConcatentatedBoxes(const uint8* buf, | |
| 141 const int buf_size) { | |
| 142 return new BoxReader(buf, buf_size, LogCB(), true); | |
| 143 } | |
| 144 | |
| 145 // static | |
| 146 bool BoxReader::IsValidTopLevelBox(const FourCC& type, | 137 bool BoxReader::IsValidTopLevelBox(const FourCC& type, |
| 147 const LogCB& log_cb) { | 138 const LogCB& log_cb) { |
| 148 switch (type) { | 139 switch (type) { |
| 149 case FOURCC_FTYP: | 140 case FOURCC_FTYP: |
| 150 case FOURCC_PDIN: | 141 case FOURCC_PDIN: |
| 151 case FOURCC_BLOC: | 142 case FOURCC_BLOC: |
| 152 case FOURCC_MOOV: | 143 case FOURCC_MOOV: |
| 153 case FOURCC_MOOF: | 144 case FOURCC_MOOF: |
| 154 case FOURCC_MFRA: | 145 case FOURCC_MFRA: |
| 155 case FOURCC_MDAT: | 146 case FOURCC_MDAT: |
| (...skipping 15 matching lines...) Expand all Loading... |
| 171 return false; | 162 return false; |
| 172 } | 163 } |
| 173 } | 164 } |
| 174 | 165 |
| 175 bool BoxReader::ScanChildren() { | 166 bool BoxReader::ScanChildren() { |
| 176 DCHECK(!scanned_); | 167 DCHECK(!scanned_); |
| 177 scanned_ = true; | 168 scanned_ = true; |
| 178 | 169 |
| 179 bool err = false; | 170 bool err = false; |
| 180 while (pos() < size()) { | 171 while (pos() < size()) { |
| 181 BoxReader child(&buf_[pos_], size_ - pos_, log_cb_, is_EOS_); | 172 BoxReader child(&buf_[pos_], size_ - pos_, log_cb_); |
| 182 if (!child.ReadHeader(&err)) break; | 173 if (!child.ReadHeader(&err)) break; |
| 183 | 174 |
| 184 children_.insert(std::pair<FourCC, BoxReader>(child.type(), child)); | 175 children_.insert(std::pair<FourCC, BoxReader>(child.type(), child)); |
| 185 pos_ += child.size(); | 176 pos_ += child.size(); |
| 186 } | 177 } |
| 187 | 178 |
| 188 DCHECK(!err); | 179 DCHECK(!err); |
| 189 return !err && pos() == size(); | 180 return !err && pos() == size(); |
| 190 } | 181 } |
| 191 | 182 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 217 RCHECK(Read4(&vflags)); | 208 RCHECK(Read4(&vflags)); |
| 218 version_ = vflags >> 24; | 209 version_ = vflags >> 24; |
| 219 flags_ = vflags & 0xffffff; | 210 flags_ = vflags & 0xffffff; |
| 220 return true; | 211 return true; |
| 221 } | 212 } |
| 222 | 213 |
| 223 bool BoxReader::ReadHeader(bool* err) { | 214 bool BoxReader::ReadHeader(bool* err) { |
| 224 uint64 size = 0; | 215 uint64 size = 0; |
| 225 *err = false; | 216 *err = false; |
| 226 | 217 |
| 227 if (!HasBytes(8)) { | 218 if (!HasBytes(8)) return false; |
| 228 // If EOS is known, then this is an error. If not, additional data may be | |
| 229 // appended later, so this is a soft error. | |
| 230 *err = is_EOS_; | |
| 231 return false; | |
| 232 } | |
| 233 CHECK(Read4Into8(&size) && ReadFourCC(&type_)); | 219 CHECK(Read4Into8(&size) && ReadFourCC(&type_)); |
| 234 | 220 |
| 235 if (size == 0) { | 221 if (size == 0) { |
| 236 if (is_EOS_) { | 222 MEDIA_LOG(DEBUG, log_cb_) << "Media Source Extensions do not support ISO " |
| 237 // All the data bytes are expected to be provided. | 223 "BMFF boxes that run to EOS"; |
| 238 size = size_; | 224 *err = true; |
| 239 } else { | 225 return false; |
| 240 MEDIA_LOG(DEBUG, log_cb_) | |
| 241 << "ISO BMFF boxes that run to EOS are not supported"; | |
| 242 *err = true; | |
| 243 return false; | |
| 244 } | |
| 245 } else if (size == 1) { | 226 } else if (size == 1) { |
| 246 if (!HasBytes(8)) { | 227 if (!HasBytes(8)) return false; |
| 247 // If EOS is known, then this is an error. If not, it's a soft error. | |
| 248 *err = is_EOS_; | |
| 249 return false; | |
| 250 } | |
| 251 CHECK(Read8(&size)); | 228 CHECK(Read8(&size)); |
| 252 } | 229 } |
| 253 | 230 |
| 254 // Implementation-specific: support for boxes larger than 2^31 has been | 231 // Implementation-specific: support for boxes larger than 2^31 has been |
| 255 // removed. | 232 // removed. |
| 256 if (size < static_cast<uint64>(pos_) || | 233 if (size < static_cast<uint64>(pos_) || |
| 257 size > static_cast<uint64>(kint32max)) { | 234 size > static_cast<uint64>(kint32max)) { |
| 258 *err = true; | 235 *err = true; |
| 259 return false; | 236 return false; |
| 260 } | 237 } |
| 261 | 238 |
| 262 // Make sure the buffer contains at least the expected number of bytes. | |
| 263 // Since the data may be appended in pieces, this can only be checked if EOS. | |
| 264 if (is_EOS_ && size > static_cast<uint64>(size_)) { | |
| 265 *err = true; | |
| 266 return false; | |
| 267 } | |
| 268 | |
| 269 // Note that the pos_ head has advanced to the byte immediately after the | 239 // Note that the pos_ head has advanced to the byte immediately after the |
| 270 // header, which is where we want it. | 240 // header, which is where we want it. |
| 271 size_ = size; | 241 size_ = size; |
| 272 return true; | 242 return true; |
| 273 } | 243 } |
| 274 | 244 |
| 275 } // namespace mp4 | 245 } // namespace mp4 |
| 276 } // namespace media | 246 } // namespace media |
| OLD | NEW |