xref: /aosp_15_r20/external/libwebm/m2ts/webm2pes.h (revision 103e46e4cd4b6efcf6001f23fa8665fb110abf8d)
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