1 // Copyright (c) 2015 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_WEBM2PES_H_ 9 #define LIBWEBM_M2TS_WEBM2PES_H_ 10 11 #include <cstddef> 12 #include <cstdint> 13 #include <memory> 14 #include <string> 15 #include <vector> 16 17 #include "common/libwebm_util.h" 18 #include "common/video_frame.h" 19 #include "mkvparser/mkvparser.h" 20 #include "mkvparser/mkvreader.h" 21 22 // Webm2pes 23 // 24 // Webm2pes consumes a WebM file containing a VP8 or VP9 video stream and 25 // outputs a PES stream suitable for inclusion in a MPEG2 Transport Stream. 26 // 27 // In the simplest case the PES stream output by Webm2pes consists of a sequence 28 // of PES packets with the following structure: 29 // | PES Header w/PTS | BCMV Header | Payload (VPx frame) | 30 // 31 // More typically the output will look like the following due to the PES 32 // payload size limitations caused by the format of the PES header. 33 // The PES header contains only 2 bytes of storage for expressing payload size. 34 // VPx PES streams containing fragmented packets look like this: 35 // 36 // | PH PTS | BCMV | Payload fragment 1 | PH | Payload fragment 2 | ... 37 // 38 // PH = PES Header 39 // PH PTS = PES Header with PTS 40 // BCMV = BCMV Header 41 // 42 // Note that start codes are properly escaped by Webm2pes, and start code 43 // emulation prevention bytes must be stripped from the output stream before 44 // it can be parsed. 45 46 namespace libwebm { 47 48 // Stores a value and its size in bits for writing into a PES Optional Header. 49 // Maximum size is 64 bits. Users may call the Check() method to perform minimal 50 // validation (size > 0 and <= 64). 51 struct PesHeaderField { PesHeaderFieldPesHeaderField52 PesHeaderField(std::uint64_t value, std::uint32_t size_in_bits, 53 std::uint8_t byte_index, std::uint8_t bits_to_shift) 54 : bits(value), 55 num_bits(size_in_bits), 56 index(byte_index), 57 shift(bits_to_shift) {} 58 PesHeaderField() = delete; 59 PesHeaderField(const PesHeaderField&) = default; 60 PesHeaderField(PesHeaderField&&) = default; 61 ~PesHeaderField() = default; CheckPesHeaderField62 bool Check() const { 63 return num_bits > 0 && num_bits <= 64 && shift >= 0 && shift < 64; 64 } 65 66 // Value to be stored in the field. 67 std::uint64_t bits; 68 69 // Number of bits in the value. 70 const int num_bits; 71 72 // Index into the header for the byte in which |bits| will be written. 73 const std::uint8_t index; 74 75 // Number of bits to shift value before or'ing. 76 const int shift; 77 }; 78 79 // Data is stored in buffers before being written to output files. 80 typedef std::vector<std::uint8_t> PacketDataBuffer; 81 82 // Storage for PES Optional Header values. Fields written in order using sizes 83 // specified. 84 struct PesOptionalHeader { 85 // TODO(tomfinegan): The fields could be in an array, which would allow the 86 // code writing the optional header to iterate over the fields instead of 87 // having code for dealing with each one. 88 89 // 2 bits (marker): 2 ('10') 90 const PesHeaderField marker = PesHeaderField(2, 2, 0, 6); 91 92 // 2 bits (no scrambling): 0x0 ('00') 93 const PesHeaderField scrambling = PesHeaderField(0, 2, 0, 4); 94 95 // 1 bit (priority): 0x0 ('0') 96 const PesHeaderField priority = PesHeaderField(0, 1, 0, 3); 97 98 // TODO(tomfinegan): The BCMV header could be considered a sync word, and this 99 // field should be 1 when a sync word follows the packet. Clarify. 100 // 1 bit (data alignment): 0x0 ('0') 101 const PesHeaderField data_alignment = PesHeaderField(0, 1, 0, 2); 102 103 // 1 bit (copyright): 0x0 ('0') 104 const PesHeaderField copyright = PesHeaderField(0, 1, 0, 1); 105 106 // 1 bit (original/copy): 0x0 ('0') 107 const PesHeaderField original = PesHeaderField(0, 1, 0, 0); 108 109 // 1 bit (has_pts): 0x1 ('1') 110 const PesHeaderField has_pts = PesHeaderField(1, 1, 1, 7); 111 112 // 1 bit (has_dts): 0x0 ('0') 113 const PesHeaderField has_dts = PesHeaderField(0, 1, 1, 6); 114 115 // 6 bits (unused fields): 0x0 ('000000') 116 const PesHeaderField unused = PesHeaderField(0, 6, 1, 0); 117 118 // 8 bits (size of remaining data in the Header). 119 const PesHeaderField remaining_size = PesHeaderField(6, 8, 2, 0); 120 121 // PTS: 5 bytes 122 // 4 bits (flag: PTS present, but no DTS): 0x2 ('0010') 123 // 36 bits (90khz PTS): 124 // top 3 bits 125 // marker ('1') 126 // middle 15 bits 127 // marker ('1') 128 // bottom 15 bits 129 // marker ('1') 130 PesHeaderField pts = PesHeaderField(0, 40, 3, 0); 131 132 PesHeaderField stuffing_byte = PesHeaderField(0xFF, 8, 8, 0); 133 134 // PTS omitted in fragments. Size remains unchanged: More stuffing bytes. 135 bool fragment = false; 136 size_in_bytesPesOptionalHeader137 static std::size_t size_in_bytes() { return 9; } 138 139 // Writes |pts_90khz| to |pts| per format described at its declaration above. 140 void SetPtsBits(std::int64_t pts_90khz); 141 142 // Writes fields to |buffer| and returns true. Returns false when write or 143 // field value validation fails. 144 bool Write(bool write_pts, PacketDataBuffer* buffer) const; 145 }; 146 147 // Describes custom 10 byte header that immediately follows the PES Optional 148 // Header in each PES packet output by Webm2Pes: 149 // 4 byte 'B' 'C' 'M' 'V' 150 // 4 byte big-endian length of frame 151 // 2 bytes 0 padding 152 struct BCMVHeader { BCMVHeaderBCMVHeader153 explicit BCMVHeader(std::uint32_t frame_length) : length(frame_length) {} 154 BCMVHeader() = delete; 155 BCMVHeader(const BCMVHeader&) = delete; 156 BCMVHeader(BCMVHeader&&) = delete; 157 ~BCMVHeader() = default; 158 const std::uint8_t bcmv[4] = {'B', 'C', 'M', 'V'}; 159 const std::uint32_t length; 160 sizeBCMVHeader161 static std::size_t size() { return 10; } 162 163 // Write the BCMV Header into |buffer|. Caller responsible for ensuring 164 // destination buffer is of size >= BCMVHeader::size(). 165 bool Write(PacketDataBuffer* buffer) const; 166 bool Write(uint8_t* buffer); 167 }; 168 169 struct PesHeader { 170 const std::uint8_t start_code[4] = { 171 0x00, 0x00, 172 0x01, // 0x000001 is the PES packet start code prefix. 173 0xE0}; // 0xE0 is the minimum video stream ID. 174 std::uint16_t packet_length = 0; // Number of bytes _after_ this field. 175 PesOptionalHeader optional_header; sizePesHeader176 std::size_t size() const { 177 return optional_header.size_in_bytes() + 178 6 /* start_code + packet_length */ + packet_length; 179 } 180 181 // Writes out the header to |buffer|. Calls PesOptionalHeader::Write() to 182 // write |optional_header| contents. Returns true when successful, false 183 // otherwise. 184 bool Write(bool write_pts, PacketDataBuffer* buffer) const; 185 }; 186 187 class PacketReceiverInterface { 188 public: ~PacketReceiverInterface()189 virtual ~PacketReceiverInterface() {} 190 virtual bool ReceivePacket(const PacketDataBuffer& packet) = 0; 191 }; 192 193 // Converts the VP9 track of a WebM file to a Packetized Elementary Stream 194 // suitable for use in a MPEG2TS. 195 // https://en.wikipedia.org/wiki/Packetized_elementary_stream 196 // https://en.wikipedia.org/wiki/MPEG_transport_stream 197 class Webm2Pes { 198 public: 199 static const std::size_t kMaxPayloadSize; 200 Webm2Pes(const std::string & input_file,const std::string & output_file)201 Webm2Pes(const std::string& input_file, const std::string& output_file) 202 : input_file_name_(input_file), output_file_name_(output_file) {} Webm2Pes(const std::string & input_file,PacketReceiverInterface * packet_sink)203 Webm2Pes(const std::string& input_file, PacketReceiverInterface* packet_sink) 204 : input_file_name_(input_file), packet_sink_(packet_sink) {} 205 206 Webm2Pes() = delete; 207 Webm2Pes(const Webm2Pes&) = delete; 208 Webm2Pes(Webm2Pes&&) = delete; 209 ~Webm2Pes() = default; 210 211 // Converts the VPx video stream to a PES file and returns true. Returns false 212 // to report failure. 213 bool ConvertToFile(); 214 215 // Converts the VPx video stream to a sequence of PES packets, and calls the 216 // PacketReceiverInterface::ReceivePacket() once for each VPx frame. The 217 // packet sent to the receiver may contain multiple PES packets. Returns only 218 // after full conversion or error. Returns true for success, and false when 219 // an error occurs. 220 bool ConvertToPacketReceiver(); 221 222 // Writes |vpx_frame| out as PES packet[s] and stores output in |packet_data|. 223 // Returns true for success, false for failure. 224 static bool WritePesPacket(const VideoFrame& frame, 225 PacketDataBuffer* packet_data); 226 bytes_written()227 uint64_t bytes_written() const { return bytes_written_; } 228 229 private: 230 bool InitWebmParser(); 231 bool ReadVideoFrame(const mkvparser::Block::Frame& mkvparser_frame, 232 VideoFrame* frame); 233 234 const std::string input_file_name_; 235 const std::string output_file_name_; 236 std::unique_ptr<mkvparser::Segment> webm_parser_; 237 mkvparser::MkvReader webm_reader_; 238 FilePtr output_file_; 239 240 // Video track num in the WebM file. 241 int video_track_num_ = 0; 242 243 // Video codec reported by CodecName from Video TrackEntry. 244 VideoFrame::Codec codec_; 245 246 // Input timecode scale. 247 std::int64_t timecode_scale_ = 1000000; 248 249 // Packet sink; when constructed with a PacketReceiverInterface*, packet and 250 // type of packet are sent to |packet_sink_| instead of written to an output 251 // file. 252 PacketReceiverInterface* packet_sink_ = nullptr; 253 254 PacketDataBuffer packet_data_; 255 256 std::uint64_t bytes_written_ = 0; 257 }; 258 259 // Copies |raw_input_length| bytes from |raw_input| to |packet_buffer| while 260 // escaping start codes. Returns true when bytes are successfully copied. 261 // A start code is the 3 byte sequence 0x00 0x00 0x01. When 262 // the sequence is encountered, the value 0x03 is inserted. To avoid 263 // any ambiguity at reassembly time, the same is done for the sequence 264 // 0x00 0x00 0x03. So, the following transformation occurs for when either 265 // of the noted sequences is encountered: 266 // 267 // 0x00 0x00 0x01 => 0x00 0x00 0x03 0x01 268 // 0x00 0x00 0x03 => 0x00 0x00 0x03 0x03 269 bool CopyAndEscapeStartCodes(const std::uint8_t* raw_input, 270 std::size_t raw_input_length, 271 PacketDataBuffer* packet_buffer); 272 } // namespace libwebm 273 274 #endif // LIBWEBM_M2TS_WEBM2PES_H_ 275