box_reader.cc 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  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. #include "media/formats/mp4/box_reader.h"
  5. #include <stddef.h>
  6. #include <string.h>
  7. #include <algorithm>
  8. #include <set>
  9. #include "base/big_endian.h"
  10. #include "media/formats/mp4/box_definitions.h"
  11. namespace media {
  12. namespace mp4 {
  13. Box::~Box() = default;
  14. bool BufferReader::Read1(uint8_t* v) {
  15. RCHECK(HasBytes(1));
  16. *v = buf_[pos_++];
  17. return true;
  18. }
  19. // Internal implementation of multi-byte reads
  20. template<typename T> bool BufferReader::Read(T* v) {
  21. RCHECK(HasBytes(sizeof(T)));
  22. // MPEG-4 uses big endian byte order
  23. base::ReadBigEndian(buf_ + pos_, v);
  24. pos_ += sizeof(T);
  25. return true;
  26. }
  27. bool BufferReader::Read2(uint16_t* v) {
  28. return Read(v);
  29. }
  30. bool BufferReader::Read2s(int16_t* v) {
  31. return Read(v);
  32. }
  33. bool BufferReader::Read4(uint32_t* v) {
  34. return Read(v);
  35. }
  36. bool BufferReader::Read4s(int32_t* v) {
  37. return Read(v);
  38. }
  39. bool BufferReader::Read8(uint64_t* v) {
  40. return Read(v);
  41. }
  42. bool BufferReader::Read8s(int64_t* v) {
  43. return Read(v);
  44. }
  45. bool BufferReader::ReadFourCC(FourCC* v) {
  46. return Read4(reinterpret_cast<uint32_t*>(v));
  47. }
  48. bool BufferReader::ReadVec(std::vector<uint8_t>* vec, uint64_t count) {
  49. RCHECK(HasBytes(count));
  50. vec->clear();
  51. vec->insert(vec->end(), buf_ + pos_, buf_ + pos_ + count);
  52. pos_ += count;
  53. return true;
  54. }
  55. bool BufferReader::SkipBytes(uint64_t bytes) {
  56. RCHECK(HasBytes(bytes));
  57. pos_ += bytes;
  58. return true;
  59. }
  60. bool BufferReader::Read4Into8(uint64_t* v) {
  61. uint32_t tmp;
  62. RCHECK(Read4(&tmp));
  63. *v = tmp;
  64. return true;
  65. }
  66. bool BufferReader::Read4sInto8s(int64_t* v) {
  67. // Beware of the need for sign extension.
  68. int32_t tmp;
  69. RCHECK(Read4s(&tmp));
  70. *v = tmp;
  71. return true;
  72. }
  73. BoxReader::BoxReader(const uint8_t* buf,
  74. const size_t buf_size,
  75. MediaLog* media_log,
  76. bool is_EOS)
  77. : BufferReader(buf, buf_size),
  78. media_log_(media_log),
  79. box_size_(0),
  80. box_size_known_(false),
  81. type_(FOURCC_NULL),
  82. version_(0),
  83. flags_(0),
  84. scanned_(false),
  85. is_EOS_(is_EOS) {}
  86. BoxReader::BoxReader(const BoxReader& other) = default;
  87. BoxReader::~BoxReader() {
  88. if (scanned_ && !children_.empty()) {
  89. for (auto itr = children_.begin(); itr != children_.end(); ++itr) {
  90. DVLOG(1) << "Skipping unknown box: " << FourCCToString(itr->first);
  91. }
  92. }
  93. }
  94. // static
  95. ParseResult BoxReader::ReadTopLevelBox(const uint8_t* buf,
  96. const size_t buf_size,
  97. MediaLog* media_log,
  98. std::unique_ptr<BoxReader>* out_reader) {
  99. DCHECK(out_reader);
  100. std::unique_ptr<BoxReader> reader(
  101. new BoxReader(buf, buf_size, media_log, false));
  102. RCHECK_OK_PARSE_RESULT(reader->ReadHeader());
  103. if (!IsValidTopLevelBox(reader->type(), media_log))
  104. return ParseResult::kError;
  105. *out_reader = std::move(reader);
  106. return ParseResult::kOk;
  107. }
  108. // static
  109. ParseResult BoxReader::StartTopLevelBox(const uint8_t* buf,
  110. const size_t buf_size,
  111. MediaLog* media_log,
  112. FourCC* out_type,
  113. size_t* out_box_size) {
  114. std::unique_ptr<BoxReader> reader;
  115. RCHECK_OK_PARSE_RESULT(ReadTopLevelBox(buf, buf_size, media_log, &reader));
  116. *out_type = reader->type();
  117. *out_box_size = reader->box_size();
  118. return ParseResult::kOk;
  119. }
  120. // static
  121. BoxReader* BoxReader::ReadConcatentatedBoxes(const uint8_t* buf,
  122. const size_t buf_size,
  123. MediaLog* media_log) {
  124. BoxReader* reader = new BoxReader(buf, buf_size, media_log, true);
  125. // Concatenated boxes are passed in without a wrapping parent box. Set
  126. // |box_size_| to the concatenated buffer length to mimic having already
  127. // parsed the parent box.
  128. reader->box_size_ = buf_size;
  129. reader->box_size_known_ = true;
  130. return reader;
  131. }
  132. // static
  133. bool BoxReader::IsValidTopLevelBox(const FourCC& type, MediaLog* media_log) {
  134. switch (type) {
  135. case FOURCC_FTYP:
  136. case FOURCC_PDIN:
  137. case FOURCC_BLOC:
  138. case FOURCC_MOOV:
  139. case FOURCC_MOOF:
  140. case FOURCC_MFRA:
  141. case FOURCC_MDAT:
  142. case FOURCC_FREE:
  143. case FOURCC_SKIP:
  144. case FOURCC_META:
  145. case FOURCC_MECO:
  146. case FOURCC_STYP:
  147. case FOURCC_SIDX:
  148. case FOURCC_SSIX:
  149. case FOURCC_PRFT:
  150. case FOURCC_UUID:
  151. case FOURCC_EMSG:
  152. return true;
  153. default:
  154. // Hex is used to show nonprintable characters and aid in debugging.
  155. MEDIA_LOG(ERROR, media_log)
  156. << "Invalid top-level ISO BMFF box type " << FourCCToString(type);
  157. return false;
  158. }
  159. }
  160. bool BoxReader::ScanChildren() {
  161. // Must be able to trust box_size_ below.
  162. RCHECK(box_size_known_);
  163. DCHECK(!scanned_);
  164. scanned_ = true;
  165. DCHECK_LE(pos_, box_size_);
  166. while (pos_ < box_size_) {
  167. BoxReader child(&buf_[pos_], box_size_ - pos_, media_log_, is_EOS_);
  168. if (child.ReadHeader() != ParseResult::kOk)
  169. return false;
  170. children_.insert(std::pair<FourCC, BoxReader>(child.type(), child));
  171. pos_ += child.box_size();
  172. }
  173. DCHECK_EQ(pos_, box_size_);
  174. return true;
  175. }
  176. bool BoxReader::ReadDisplayMatrix(DisplayMatrix matrix) {
  177. for (int i = 0; i < kDisplayMatrixDimension; i++) {
  178. if (!Read4s(&matrix[i])) {
  179. return false;
  180. }
  181. }
  182. return true;
  183. }
  184. bool BoxReader::HasChild(Box* child) {
  185. DCHECK(scanned_);
  186. DCHECK(child);
  187. return children_.count(child->BoxType()) > 0;
  188. }
  189. bool BoxReader::ReadChild(Box* child) {
  190. DCHECK(scanned_);
  191. FourCC child_type = child->BoxType();
  192. auto itr = children_.find(child_type);
  193. RCHECK(itr != children_.end());
  194. DVLOG(2) << "Found a " << FourCCToString(child_type) << " box.";
  195. RCHECK(child->Parse(&itr->second));
  196. children_.erase(itr);
  197. return true;
  198. }
  199. bool BoxReader::MaybeReadChild(Box* child) {
  200. if (!children_.count(child->BoxType())) return true;
  201. return ReadChild(child);
  202. }
  203. bool BoxReader::ReadFullBoxHeader() {
  204. uint32_t vflags;
  205. RCHECK(Read4(&vflags));
  206. version_ = vflags >> 24;
  207. flags_ = vflags & 0xffffff;
  208. return true;
  209. }
  210. ParseResult BoxReader::ReadHeader() {
  211. uint64_t box_size = 0;
  212. if (!HasBytes(8))
  213. return is_EOS_ ? ParseResult::kError : ParseResult::kNeedMoreData;
  214. CHECK(Read4Into8(&box_size));
  215. CHECK(ReadFourCC(&type_));
  216. if (box_size == 0) {
  217. if (is_EOS_) {
  218. // All the data bytes are expected to be provided.
  219. // TODO(sandersd): The whole |is_EOS_| feature seems to exist just for
  220. // this special case (and is used only for PSSH parsing). Can we get rid
  221. // of it? The caller can treat kNeedMoreData as an error, and the only
  222. // difference would be lack of support for |box_size == 0|.
  223. box_size = base::strict_cast<uint64_t>(buf_size_);
  224. } else {
  225. MEDIA_LOG(DEBUG, media_log_)
  226. << "ISO BMFF boxes that run to EOS are not supported";
  227. return ParseResult::kError;
  228. }
  229. } else if (box_size == 1) {
  230. if (!HasBytes(8))
  231. return is_EOS_ ? ParseResult::kError : ParseResult::kNeedMoreData;
  232. CHECK(Read8(&box_size));
  233. }
  234. // Implementation-specific: support for boxes larger than 2^31 has been
  235. // removed.
  236. if (box_size < base::strict_cast<uint64_t>(pos_) ||
  237. box_size > static_cast<uint64_t>(std::numeric_limits<int32_t>::max())) {
  238. return ParseResult::kError;
  239. }
  240. // Make sure the buffer contains at least the expected number of bytes.
  241. // Since the data may be appended in pieces, this is only an error if EOS.
  242. if (box_size > base::strict_cast<uint64_t>(buf_size_))
  243. return is_EOS_ ? ParseResult::kError : ParseResult::kNeedMoreData;
  244. // Note that the pos_ head has advanced to the byte immediately after the
  245. // header, which is where we want it.
  246. box_size_ = base::checked_cast<size_t>(box_size);
  247. box_size_known_ = true;
  248. // We don't want future reads to go beyond the box.
  249. buf_size_ = std::min(buf_size_, box_size_);
  250. return ParseResult::kOk;
  251. }
  252. } // namespace mp4
  253. } // namespace media