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