// 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 #include #include #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 and read into memory when Open() is called. // TODO(tomfinegan): Support incremental parse. class VpxPesParser { public: typedef std::vector PesFileData; typedef std::vector 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_