1 // Copyright (c) 2016 The WebM project authors. All Rights Reserved. 2 // 3 // Use of this source code is governed by a BSD-style license 4 // that can be found in the LICENSE file in the root of the source 5 // tree. An additional intellectual property rights grant can be found 6 // in the file PATENTS. All contributing project authors may 7 // be found in the AUTHORS file in the root of the source tree. 8 #ifndef LIBWEBM_M2TS_VPXPES_PARSER_H_ 9 #define LIBWEBM_M2TS_VPXPES_PARSER_H_ 10 11 #include <cstdint> 12 #include <string> 13 #include <vector> 14 15 #include "common/libwebm_util.h" 16 #include "common/video_frame.h" 17 18 namespace libwebm { 19 20 // Parser for VPx PES. Requires that the _entire_ PES stream can be stored in 21 // a std::vector<std::uint8_t> and read into memory when Open() is called. 22 // TODO(tomfinegan): Support incremental parse. 23 class VpxPesParser { 24 public: 25 typedef std::vector<std::uint8_t> PesFileData; 26 typedef std::vector<std::uint8_t> PacketData; 27 28 enum ParseState { 29 kFindStartCode, 30 kParsePesHeader, 31 kParsePesOptionalHeader, 32 kParseBcmvHeader, 33 }; 34 35 struct PesOptionalHeader { 36 int marker = 0; 37 int scrambling = 0; 38 int priority = 0; 39 int data_alignment = 0; 40 int copyright = 0; 41 int original = 0; 42 int has_pts = 0; 43 int has_dts = 0; 44 int unused_fields = 0; 45 int remaining_size = 0; 46 int pts_dts_flag = 0; 47 std::uint64_t pts = 0; 48 int stuffing_byte = 0; 49 }; 50 51 struct BcmvHeader { 52 BcmvHeader() = default; 53 ~BcmvHeader() = default; 54 BcmvHeader(const BcmvHeader&) = delete; 55 BcmvHeader(BcmvHeader&&) = delete; 56 57 // Convenience ctor for quick validation of expected values via operator== 58 // after parsing input. 59 explicit BcmvHeader(std::uint32_t len); 60 61 bool operator==(const BcmvHeader& other) const; 62 63 void Reset(); 64 bool Valid() const; sizeBcmvHeader65 static std::size_t size() { return 10; } 66 67 char id[4] = {0}; 68 std::uint32_t length = 0; 69 }; 70 71 struct PesHeader { 72 std::uint8_t start_code[4] = {0}; 73 std::uint16_t packet_length = 0; 74 std::uint8_t stream_id = 0; 75 PesOptionalHeader opt_header; 76 BcmvHeader bcmv_header; 77 }; 78 79 // Constants for validating known values from input data. 80 const std::uint8_t kMinVideoStreamId = 0xE0; 81 const std::uint8_t kMaxVideoStreamId = 0xEF; 82 const std::size_t kPesHeaderSize = 6; 83 const std::size_t kPesOptionalHeaderStartOffset = kPesHeaderSize; 84 const std::size_t kPesOptionalHeaderSize = 9; 85 const std::size_t kPesOptionalHeaderMarkerValue = 0x2; 86 const std::size_t kWebm2PesOptHeaderRemainingSize = 6; 87 const std::size_t kBcmvHeaderSize = 10; 88 89 VpxPesParser() = default; 90 ~VpxPesParser() = default; 91 92 // Opens file specified by |pes_file_path| and reads its contents. Returns 93 // true after successful read of input file. 94 bool Open(const std::string& pes_file_path); 95 96 // Parses the next packet in the PES. PES header information is stored in 97 // |header|, and the frame payload is stored in |frame|. Returns true when 98 // a full frame has been consumed from the PES. 99 bool ParseNextPacket(PesHeader* header, VideoFrame* frame); 100 101 // PES Header parsing utility functions. 102 // PES Header structure: 103 // Start code Stream ID Packet length (16 bits) 104 // / / ____/ 105 // | | / 106 // Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 107 // 0 0 1 X Y 108 bool VerifyPacketStartCode() const; 109 bool ReadStreamId(std::uint8_t* stream_id) const; 110 bool ReadPacketLength(std::uint16_t* packet_length) const; 111 pes_file_size()112 std::uint64_t pes_file_size() const { return pes_file_size_; } pes_file_data()113 const PesFileData& pes_file_data() const { return pes_file_data_; } 114 115 // Returns number of unparsed bytes remaining. 116 int BytesAvailable() const; 117 118 private: 119 // Parses and verifies the static 6 byte portion that begins every PES packet. 120 bool ParsePesHeader(PesHeader* header); 121 122 // Parses a PES optional header, the optional header following the static 123 // header that begins the VPX PES packet. 124 // https://en.wikipedia.org/wiki/Packetized_elementary_stream 125 bool ParsePesOptionalHeader(PesOptionalHeader* header); 126 127 // Parses and validates the BCMV header. This immediately follows the optional 128 // header. 129 bool ParseBcmvHeader(BcmvHeader* header); 130 131 // Returns true when a start code is found and sets |offset| to the position 132 // of the start code relative to |pes_file_data_[read_pos_]|. 133 // Does not set |offset| value if the end of |pes_file_data_| is reached 134 // without locating a start code. 135 // Note: A start code is the byte sequence 0x00 0x00 0x01. 136 bool FindStartCode(std::size_t origin, std::size_t* offset) const; 137 138 // Returns true when a PES packet containing a BCMV header contains only a 139 // portion of the frame payload length reported by the BCMV header. 140 bool IsPayloadFragmented(const PesHeader& header) const; 141 142 // Parses PES and PES Optional header while accumulating payload data in 143 // |payload_|. 144 // Returns true once all payload fragments have been stored in |payload_|. 145 // Returns false if unable to accumulate full payload. 146 bool AccumulateFragmentedPayload(std::size_t pes_packet_length, 147 std::size_t payload_length); 148 149 // The byte sequence 0x0 0x0 0x1 is a start code in PES. When PES muxers 150 // encounter 0x0 0x0 0x1 or 0x0 0x0 0x3, an additional 0x3 is inserted into 151 // the PES. The following change occurs: 152 // 0x0 0x0 0x1 => 0x0 0x0 0x3 0x1 153 // 0x0 0x0 0x3 => 0x0 0x0 0x3 0x3 154 // PES demuxers must reverse the change: 155 // 0x0 0x0 0x3 0x1 => 0x0 0x0 0x1 156 // 0x0 0x0 0x3 0x3 => 0x0 0x0 0x3 157 // PES optional header, BCMV header, and payload data must be preprocessed to 158 // avoid potentially invalid data due to the presence of inserted bytes. 159 // 160 // Removes start code emulation prevention bytes while copying data from 161 // |raw_data| to |processed_data|. Returns true when |bytes_required| bytes 162 // have been written to |processed_data|. Reports bytes consumed during the 163 // operation via |bytes_consumed|. 164 bool RemoveStartCodeEmulationPreventionBytes( 165 const std::uint8_t* raw_data, std::size_t bytes_required, 166 PacketData* processed_data, std::size_t* bytes_consumed) const; 167 168 std::size_t pes_file_size_ = 0; 169 PacketData payload_; 170 PesFileData pes_file_data_; 171 std::size_t read_pos_ = 0; 172 ParseState parse_state_ = kFindStartCode; 173 }; 174 175 } // namespace libwebm 176 177 #endif // LIBWEBM_M2TS_VPXPES_PARSER_H_ 178