| // Copyright (c) 2016 The WebM project authors. All Rights Reserved. |
| // |
| // Use of this source code is governed by a BSD-style license |
| // that can be found in the LICENSE file in the root of the source |
| // tree. An additional intellectual property rights grant can be found |
| // in the file PATENTS. All contributing project authors may |
| // be found in the AUTHORS file in the root of the source tree. |
| #ifndef LIBWEBM_M2TS_VPXPES_PARSER_H_ |
| #define LIBWEBM_M2TS_VPXPES_PARSER_H_ |
| |
| #include <cstdint> |
| #include <string> |
| #include <vector> |
| |
| #include "common/libwebm_util.h" |
| #include "common/video_frame.h" |
| |
| namespace libwebm { |
| |
| // Parser for VPx PES. Requires that the _entire_ PES stream can be stored in |
| // a std::vector<std::uint8_t> and read into memory when Open() is called. |
| // TODO(tomfinegan): Support incremental parse. |
| class VpxPesParser { |
| public: |
| typedef std::vector<std::uint8_t> PesFileData; |
| typedef std::vector<std::uint8_t> PacketData; |
| |
| enum ParseState { |
| kFindStartCode, |
| kParsePesHeader, |
| kParsePesOptionalHeader, |
| kParseBcmvHeader, |
| }; |
| |
| struct PesOptionalHeader { |
| int marker = 0; |
| int scrambling = 0; |
| int priority = 0; |
| int data_alignment = 0; |
| int copyright = 0; |
| int original = 0; |
| int has_pts = 0; |
| int has_dts = 0; |
| int unused_fields = 0; |
| int remaining_size = 0; |
| int pts_dts_flag = 0; |
| std::uint64_t pts = 0; |
| int stuffing_byte = 0; |
| }; |
| |
| struct BcmvHeader { |
| BcmvHeader() = default; |
| ~BcmvHeader() = default; |
| BcmvHeader(const BcmvHeader&) = delete; |
| BcmvHeader(BcmvHeader&&) = delete; |
| |
| // Convenience ctor for quick validation of expected values via operator== |
| // after parsing input. |
| explicit BcmvHeader(std::uint32_t len); |
| |
| bool operator==(const BcmvHeader& other) const; |
| |
| void Reset(); |
| bool Valid() const; |
| static std::size_t size() { return 10; } |
| |
| char id[4] = {0}; |
| std::uint32_t length = 0; |
| }; |
| |
| struct PesHeader { |
| std::uint8_t start_code[4] = {0}; |
| std::uint16_t packet_length = 0; |
| std::uint8_t stream_id = 0; |
| PesOptionalHeader opt_header; |
| BcmvHeader bcmv_header; |
| }; |
| |
| // Constants for validating known values from input data. |
| const std::uint8_t kMinVideoStreamId = 0xE0; |
| const std::uint8_t kMaxVideoStreamId = 0xEF; |
| const std::size_t kPesHeaderSize = 6; |
| const std::size_t kPesOptionalHeaderStartOffset = kPesHeaderSize; |
| const std::size_t kPesOptionalHeaderSize = 9; |
| const std::size_t kPesOptionalHeaderMarkerValue = 0x2; |
| const std::size_t kWebm2PesOptHeaderRemainingSize = 6; |
| const std::size_t kBcmvHeaderSize = 10; |
| |
| VpxPesParser() = default; |
| ~VpxPesParser() = default; |
| |
| // Opens file specified by |pes_file_path| and reads its contents. Returns |
| // true after successful read of input file. |
| bool Open(const std::string& pes_file_path); |
| |
| // Parses the next packet in the PES. PES header information is stored in |
| // |header|, and the frame payload is stored in |frame|. Returns true when |
| // a full frame has been consumed from the PES. |
| bool ParseNextPacket(PesHeader* header, VideoFrame* frame); |
| |
| // PES Header parsing utility functions. |
| // PES Header structure: |
| // Start code Stream ID Packet length (16 bits) |
| // / / ____/ |
| // | | / |
| // Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 |
| // 0 0 1 X Y |
| bool VerifyPacketStartCode() const; |
| bool ReadStreamId(std::uint8_t* stream_id) const; |
| bool ReadPacketLength(std::uint16_t* packet_length) const; |
| |
| std::uint64_t pes_file_size() const { return pes_file_size_; } |
| const PesFileData& pes_file_data() const { return pes_file_data_; } |
| |
| // Returns number of unparsed bytes remaining. |
| int BytesAvailable() const; |
| |
| private: |
| // Parses and verifies the static 6 byte portion that begins every PES packet. |
| bool ParsePesHeader(PesHeader* header); |
| |
| // Parses a PES optional header, the optional header following the static |
| // header that begins the VPX PES packet. |
| // https://en.wikipedia.org/wiki/Packetized_elementary_stream |
| bool ParsePesOptionalHeader(PesOptionalHeader* header); |
| |
| // Parses and validates the BCMV header. This immediately follows the optional |
| // header. |
| bool ParseBcmvHeader(BcmvHeader* header); |
| |
| // Returns true when a start code is found and sets |offset| to the position |
| // of the start code relative to |pes_file_data_[read_pos_]|. |
| // Does not set |offset| value if the end of |pes_file_data_| is reached |
| // without locating a start code. |
| // Note: A start code is the byte sequence 0x00 0x00 0x01. |
| bool FindStartCode(std::size_t origin, std::size_t* offset) const; |
| |
| // Returns true when a PES packet containing a BCMV header contains only a |
| // portion of the frame payload length reported by the BCMV header. |
| bool IsPayloadFragmented(const PesHeader& header) const; |
| |
| // Parses PES and PES Optional header while accumulating payload data in |
| // |payload_|. |
| // Returns true once all payload fragments have been stored in |payload_|. |
| // Returns false if unable to accumulate full payload. |
| bool AccumulateFragmentedPayload(std::size_t pes_packet_length, |
| std::size_t payload_length); |
| |
| // The byte sequence 0x0 0x0 0x1 is a start code in PES. When PES muxers |
| // encounter 0x0 0x0 0x1 or 0x0 0x0 0x3, an additional 0x3 is inserted into |
| // the PES. The following change occurs: |
| // 0x0 0x0 0x1 => 0x0 0x0 0x3 0x1 |
| // 0x0 0x0 0x3 => 0x0 0x0 0x3 0x3 |
| // PES demuxers must reverse the change: |
| // 0x0 0x0 0x3 0x1 => 0x0 0x0 0x1 |
| // 0x0 0x0 0x3 0x3 => 0x0 0x0 0x3 |
| // PES optional header, BCMV header, and payload data must be preprocessed to |
| // avoid potentially invalid data due to the presence of inserted bytes. |
| // |
| // Removes start code emulation prevention bytes while copying data from |
| // |raw_data| to |processed_data|. Returns true when |bytes_required| bytes |
| // have been written to |processed_data|. Reports bytes consumed during the |
| // operation via |bytes_consumed|. |
| bool RemoveStartCodeEmulationPreventionBytes( |
| const std::uint8_t* raw_data, std::size_t bytes_required, |
| PacketData* processed_data, std::size_t* bytes_consumed) const; |
| |
| std::size_t pes_file_size_ = 0; |
| PacketData payload_; |
| PesFileData pes_file_data_; |
| std::size_t read_pos_ = 0; |
| ParseState parse_state_ = kFindStartCode; |
| }; |
| |
| } // namespace libwebm |
| |
| #endif // LIBWEBM_M2TS_VPXPES_PARSER_H_ |