box_reader.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  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. #ifndef MEDIA_FORMATS_MP4_BOX_READER_H_
  5. #define MEDIA_FORMATS_MP4_BOX_READER_H_
  6. #include <stdint.h>
  7. #include <limits>
  8. #include <map>
  9. #include <memory>
  10. #include <vector>
  11. #include "base/logging.h"
  12. #include "base/memory/raw_ptr.h"
  13. #include "base/numerics/safe_conversions.h"
  14. #include "media/base/media_export.h"
  15. #include "media/base/media_log.h"
  16. #include "media/formats/mp4/fourccs.h"
  17. #include "media/formats/mp4/parse_result.h"
  18. #include "media/formats/mp4/rcheck.h"
  19. namespace media {
  20. namespace mp4 {
  21. enum DisplayMatrixSize {
  22. kDisplayMatrixWidth = 3,
  23. kDisplayMatrixHeight = 3,
  24. kDisplayMatrixDimension = kDisplayMatrixHeight * kDisplayMatrixWidth
  25. };
  26. using DisplayMatrix = int32_t[kDisplayMatrixDimension];
  27. class BoxReader;
  28. struct MEDIA_EXPORT Box {
  29. virtual ~Box();
  30. // Parse errors may be logged using the BoxReader's media log.
  31. virtual bool Parse(BoxReader* reader) = 0;
  32. virtual FourCC BoxType() const = 0;
  33. };
  34. class MEDIA_EXPORT BufferReader {
  35. public:
  36. BufferReader(const uint8_t* buf, const size_t buf_size)
  37. : buf_(buf), buf_size_(buf_size), pos_(0) {
  38. CHECK(buf);
  39. }
  40. bool HasBytes(size_t count) {
  41. // As the size of a box is implementation limited to 2^31, fail if
  42. // attempting to check for too many bytes.
  43. const size_t impl_limit =
  44. static_cast<size_t>(std::numeric_limits<int32_t>::max());
  45. return pos_ <= buf_size_ && count <= impl_limit &&
  46. count <= buf_size_ - pos_;
  47. }
  48. // Read a value from the stream, performing endian correction, and advance the
  49. // stream pointer.
  50. [[nodiscard]] bool Read1(uint8_t* v);
  51. [[nodiscard]] bool Read2(uint16_t* v);
  52. [[nodiscard]] bool Read2s(int16_t* v);
  53. [[nodiscard]] bool Read4(uint32_t* v);
  54. [[nodiscard]] bool Read4s(int32_t* v);
  55. [[nodiscard]] bool Read8(uint64_t* v);
  56. [[nodiscard]] bool Read8s(int64_t* v);
  57. [[nodiscard]] bool ReadFourCC(FourCC* v);
  58. [[nodiscard]] bool ReadVec(std::vector<uint8_t>* t, uint64_t count);
  59. // These variants read a 4-byte integer of the corresponding signedness and
  60. // store it in the 8-byte return type.
  61. [[nodiscard]] bool Read4Into8(uint64_t* v);
  62. [[nodiscard]] bool Read4sInto8s(int64_t* v);
  63. // Advance the stream by this many bytes.
  64. [[nodiscard]] bool SkipBytes(uint64_t nbytes);
  65. const uint8_t* buffer() const { return buf_; }
  66. // Returns the size of the buffer. This may not match the size specified
  67. // in the mp4 box header and could be less than the box size when the full box
  68. // has not been appended. Always consult buffer_size() to avoid OOB reads.
  69. // See BoxReader::box_size().
  70. size_t buffer_size() const { return buf_size_; }
  71. size_t pos() const { return pos_; }
  72. protected:
  73. const uint8_t* buf_;
  74. size_t buf_size_;
  75. size_t pos_;
  76. template <typename T>
  77. [[nodiscard]] bool Read(T* t);
  78. };
  79. class MEDIA_EXPORT BoxReader : public BufferReader {
  80. public:
  81. BoxReader(const BoxReader& other);
  82. ~BoxReader();
  83. // Create a BoxReader from a buffer. If the result is kOk, then |out_reader|
  84. // will be set, otherwise |out_reader| will be unchanged.
  85. //
  86. // |buf| is retained but not owned, and must outlive the BoxReader instance.
  87. [[nodiscard]] static ParseResult ReadTopLevelBox(
  88. const uint8_t* buf,
  89. const size_t buf_size,
  90. MediaLog* media_log,
  91. std::unique_ptr<BoxReader>* out_reader);
  92. // Read the box header from the current buffer, and return its type and size.
  93. // This function returns kNeedMoreData if the box is incomplete, even if the
  94. // box header is complete.
  95. //
  96. // |buf| is not retained.
  97. [[nodiscard]] static ParseResult StartTopLevelBox(const uint8_t* buf,
  98. const size_t buf_size,
  99. MediaLog* media_log,
  100. FourCC* out_type,
  101. size_t* out_box_size);
  102. // Create a BoxReader from a buffer. |buf| must be the complete buffer, as
  103. // errors are returned when sufficient data is not available. |buf| can start
  104. // with any type of box -- it does not have to be IsValidTopLevelBox().
  105. //
  106. // |buf| is retained but not owned, and must outlive the BoxReader instance.
  107. static BoxReader* ReadConcatentatedBoxes(const uint8_t* buf,
  108. const size_t buf_size,
  109. MediaLog* media_log);
  110. // Returns true if |type| is recognized to be a top-level box, false
  111. // otherwise. This returns true for some boxes which we do not parse.
  112. // Helpful in debugging misaligned appends.
  113. static bool IsValidTopLevelBox(const FourCC& type, MediaLog* media_log);
  114. // Scan through all boxes within the current box, starting at the current
  115. // buffer position. Must be called before any of the *Child functions work.
  116. [[nodiscard]] bool ScanChildren();
  117. // Return true if child with type |child.BoxType()| exists.
  118. [[nodiscard]] bool HasChild(Box* child);
  119. // Read exactly one child box from the set of children. The type of the child
  120. // will be determined by the BoxType() method of |child|.
  121. [[nodiscard]] bool ReadChild(Box* child);
  122. // Read one child if available. Returns false on error, true on successful
  123. // read or on child absent.
  124. [[nodiscard]] bool MaybeReadChild(Box* child);
  125. // ISO-BMFF streams files use a 3x3 matrix consisting of 6 16.16 fixed point
  126. // decimals and 3 2.30 fixed point decimals.
  127. bool ReadDisplayMatrix(DisplayMatrix matrix);
  128. // Read at least one child. False means error or no such child present.
  129. template <typename T>
  130. [[nodiscard]] bool ReadChildren(std::vector<T>* children);
  131. // Read any number of children. False means error.
  132. template <typename T>
  133. [[nodiscard]] bool MaybeReadChildren(std::vector<T>* children);
  134. // Read all children, regardless of FourCC. This is used from exactly one box,
  135. // corresponding to a rather significant inconsistency in the BMFF spec.
  136. // Note that this method is mutually exclusive with ScanChildren() and
  137. // ReadAllChildrenAndCheckFourCC().
  138. template <typename T>
  139. [[nodiscard]] bool ReadAllChildren(std::vector<T>* children);
  140. // Read all children and verify that the FourCC matches what is expected.
  141. // Returns true if all children are successfully parsed and have the correct
  142. // box type for |T|. Note that this method is mutually exclusive with
  143. // ScanChildren() and ReadAllChildren().
  144. template <typename T>
  145. [[nodiscard]] bool ReadAllChildrenAndCheckFourCC(std::vector<T>* children);
  146. // Populate the values of 'version()' and 'flags()' from a full box header.
  147. // Many boxes, but not all, use these values. This call should happen after
  148. // the box has been initialized, and does not re-read the main box header.
  149. [[nodiscard]] bool ReadFullBoxHeader();
  150. size_t box_size() const {
  151. DCHECK(box_size_known_);
  152. return box_size_;
  153. }
  154. FourCC type() const { return type_; }
  155. uint8_t version() const { return version_; }
  156. uint32_t flags() const { return flags_; }
  157. MediaLog* media_log() const { return media_log_; }
  158. private:
  159. // Create a BoxReader from |buf|. |is_EOS| should be true if |buf| is
  160. // complete stream (i.e. no additional data is expected to be appended).
  161. BoxReader(const uint8_t* buf,
  162. const size_t buf_size,
  163. MediaLog* media_log,
  164. bool is_EOS);
  165. // Must be called immediately after init.
  166. [[nodiscard]] ParseResult ReadHeader();
  167. // Read all children, optionally checking FourCC. Returns true if all
  168. // children are successfully parsed and, if |check_box_type|, have the
  169. // correct box type for |T|. Note that this method is mutually exclusive
  170. // with ScanChildren().
  171. template <typename T>
  172. bool ReadAllChildrenInternal(std::vector<T>* children, bool check_box_type);
  173. raw_ptr<MediaLog> media_log_;
  174. size_t box_size_;
  175. bool box_size_known_;
  176. FourCC type_;
  177. uint8_t version_;
  178. uint32_t flags_;
  179. typedef std::multimap<FourCC, BoxReader> ChildMap;
  180. // The set of child box FourCCs and their corresponding buffer readers. Only
  181. // valid if scanned_ is true.
  182. ChildMap children_;
  183. bool scanned_;
  184. // True if the buffer provided to the reader is the complete stream.
  185. const bool is_EOS_;
  186. };
  187. // Template definitions
  188. template<typename T> bool BoxReader::ReadChildren(std::vector<T>* children) {
  189. RCHECK(MaybeReadChildren(children) && !children->empty());
  190. return true;
  191. }
  192. template<typename T>
  193. bool BoxReader::MaybeReadChildren(std::vector<T>* children) {
  194. DCHECK(scanned_);
  195. DCHECK(children->empty());
  196. children->resize(1);
  197. FourCC child_type = (*children)[0].BoxType();
  198. ChildMap::iterator start_itr = children_.lower_bound(child_type);
  199. ChildMap::iterator end_itr = children_.upper_bound(child_type);
  200. children->resize(std::distance(start_itr, end_itr));
  201. typename std::vector<T>::iterator child_itr = children->begin();
  202. for (ChildMap::iterator itr = start_itr; itr != end_itr; ++itr) {
  203. RCHECK(child_itr->Parse(&itr->second));
  204. ++child_itr;
  205. }
  206. children_.erase(start_itr, end_itr);
  207. DVLOG(2) << "Found " << children->size() << " "
  208. << FourCCToString(child_type) << " boxes.";
  209. return true;
  210. }
  211. template <typename T>
  212. bool BoxReader::ReadAllChildren(std::vector<T>* children) {
  213. return ReadAllChildrenInternal(children, false);
  214. }
  215. template <typename T>
  216. bool BoxReader::ReadAllChildrenAndCheckFourCC(std::vector<T>* children) {
  217. return ReadAllChildrenInternal(children, true);
  218. }
  219. template <typename T>
  220. bool BoxReader::ReadAllChildrenInternal(std::vector<T>* children,
  221. bool check_box_type) {
  222. DCHECK(!scanned_);
  223. scanned_ = true;
  224. // Must know our box size before attempting to parse child boxes.
  225. RCHECK(box_size_known_);
  226. DCHECK_LE(pos_, box_size_);
  227. while (pos_ < box_size_) {
  228. BoxReader child_reader(&buf_[pos_], box_size_ - pos_, media_log_, is_EOS_);
  229. if (child_reader.ReadHeader() != ParseResult::kOk)
  230. return false;
  231. T child;
  232. RCHECK(!check_box_type || child_reader.type() == child.BoxType());
  233. RCHECK(child.Parse(&child_reader));
  234. children->push_back(child);
  235. pos_ += child_reader.box_size();
  236. }
  237. DCHECK_EQ(pos_, box_size_);
  238. return true;
  239. }
  240. } // namespace mp4
  241. } // namespace media
  242. #endif // MEDIA_FORMATS_MP4_BOX_READER_H_