xref: /aosp_15_r20/external/libwebm/m2ts/webm2pes.cc (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 #include "m2ts/webm2pes.h"
9*103e46e4SHarish Mahendrakar 
10*103e46e4SHarish Mahendrakar #include <algorithm>
11*103e46e4SHarish Mahendrakar #include <cassert>
12*103e46e4SHarish Mahendrakar #include <cstdio>
13*103e46e4SHarish Mahendrakar #include <cstring>
14*103e46e4SHarish Mahendrakar #include <new>
15*103e46e4SHarish Mahendrakar #include <vector>
16*103e46e4SHarish Mahendrakar 
17*103e46e4SHarish Mahendrakar #include "common/libwebm_util.h"
18*103e46e4SHarish Mahendrakar 
19*103e46e4SHarish Mahendrakar namespace libwebm {
20*103e46e4SHarish Mahendrakar 
21*103e46e4SHarish Mahendrakar const std::size_t Webm2Pes::kMaxPayloadSize = 32768;
22*103e46e4SHarish Mahendrakar 
23*103e46e4SHarish Mahendrakar namespace {
24*103e46e4SHarish Mahendrakar 
ToString(const char * str)25*103e46e4SHarish Mahendrakar std::string ToString(const char* str) {
26*103e46e4SHarish Mahendrakar   return std::string((str == nullptr) ? "" : str);
27*103e46e4SHarish Mahendrakar }
28*103e46e4SHarish Mahendrakar 
29*103e46e4SHarish Mahendrakar }  // namespace
30*103e46e4SHarish Mahendrakar 
31*103e46e4SHarish Mahendrakar //
32*103e46e4SHarish Mahendrakar // PesOptionalHeader methods.
33*103e46e4SHarish Mahendrakar //
34*103e46e4SHarish Mahendrakar 
SetPtsBits(std::int64_t pts_90khz)35*103e46e4SHarish Mahendrakar void PesOptionalHeader::SetPtsBits(std::int64_t pts_90khz) {
36*103e46e4SHarish Mahendrakar   // PTS is broken up and stored in 40 bits as shown:
37*103e46e4SHarish Mahendrakar   //
38*103e46e4SHarish Mahendrakar   //  PES PTS Only flag
39*103e46e4SHarish Mahendrakar   // /                  Marker              Marker              Marker
40*103e46e4SHarish Mahendrakar   // |                 /                   /                   /
41*103e46e4SHarish Mahendrakar   // |                 |                   |                   |
42*103e46e4SHarish Mahendrakar   // 7654  321         0  765432107654321  0  765432107654321  0
43*103e46e4SHarish Mahendrakar   // 0010  PTS 32-30   1  PTS 29-15        1  PTS 14-0         1
44*103e46e4SHarish Mahendrakar   const std::uint32_t pts1 = (pts_90khz >> 30) & 0x7;
45*103e46e4SHarish Mahendrakar   const std::uint32_t pts2 = (pts_90khz >> 15) & 0x7FFF;
46*103e46e4SHarish Mahendrakar   const std::uint32_t pts3 = pts_90khz & 0x7FFF;
47*103e46e4SHarish Mahendrakar 
48*103e46e4SHarish Mahendrakar   pts.bits = 0;
49*103e46e4SHarish Mahendrakar 
50*103e46e4SHarish Mahendrakar   // bottom 7 bits of second PTS chunk.
51*103e46e4SHarish Mahendrakar   pts.bits |= (pts3 << 1) & 0xff;
52*103e46e4SHarish Mahendrakar   // Marker.
53*103e46e4SHarish Mahendrakar   pts.bits |= 1;
54*103e46e4SHarish Mahendrakar 
55*103e46e4SHarish Mahendrakar   // Last 15 bits of pts and 1 bit marker.
56*103e46e4SHarish Mahendrakar   // Top 8 bits of second PTS chunk.
57*103e46e4SHarish Mahendrakar   pts.bits <<= 8;
58*103e46e4SHarish Mahendrakar   pts.bits |= (pts3 >> 7) & 0xff;
59*103e46e4SHarish Mahendrakar 
60*103e46e4SHarish Mahendrakar   // bottom 7 bits of second PTS chunk.
61*103e46e4SHarish Mahendrakar   pts.bits <<= 8;
62*103e46e4SHarish Mahendrakar   pts.bits |= (pts2 << 1);
63*103e46e4SHarish Mahendrakar   // Marker.
64*103e46e4SHarish Mahendrakar   pts.bits |= 1;
65*103e46e4SHarish Mahendrakar 
66*103e46e4SHarish Mahendrakar   // Next 15 bits of pts and 1 bit marker.
67*103e46e4SHarish Mahendrakar   // Top 8 bits of second PTS chunk.
68*103e46e4SHarish Mahendrakar   pts.bits <<= 8;
69*103e46e4SHarish Mahendrakar   pts.bits |= (pts2 >> 7) & 0xff;
70*103e46e4SHarish Mahendrakar 
71*103e46e4SHarish Mahendrakar   // PTS only flag.
72*103e46e4SHarish Mahendrakar   pts.bits <<= 8;
73*103e46e4SHarish Mahendrakar   pts.bits |= 1 << 5;
74*103e46e4SHarish Mahendrakar   // Top 3 bits of PTS and 1 bit marker.
75*103e46e4SHarish Mahendrakar   pts.bits |= pts1 << 1;
76*103e46e4SHarish Mahendrakar   // Marker.
77*103e46e4SHarish Mahendrakar   pts.bits |= 1;
78*103e46e4SHarish Mahendrakar }
79*103e46e4SHarish Mahendrakar 
80*103e46e4SHarish Mahendrakar // Writes fields to |buffer| and returns true. Returns false when write or
81*103e46e4SHarish Mahendrakar // field value validation fails.
Write(bool write_pts,PacketDataBuffer * buffer) const82*103e46e4SHarish Mahendrakar bool PesOptionalHeader::Write(bool write_pts, PacketDataBuffer* buffer) const {
83*103e46e4SHarish Mahendrakar   if (buffer == nullptr) {
84*103e46e4SHarish Mahendrakar     std::fprintf(stderr, "Webm2Pes: nullptr in opt header writer.\n");
85*103e46e4SHarish Mahendrakar     return false;
86*103e46e4SHarish Mahendrakar   }
87*103e46e4SHarish Mahendrakar 
88*103e46e4SHarish Mahendrakar   const int kHeaderSize = 9;
89*103e46e4SHarish Mahendrakar   std::uint8_t header[kHeaderSize] = {0};
90*103e46e4SHarish Mahendrakar   std::uint8_t* byte = header;
91*103e46e4SHarish Mahendrakar 
92*103e46e4SHarish Mahendrakar   if (marker.Check() != true || scrambling.Check() != true ||
93*103e46e4SHarish Mahendrakar       priority.Check() != true || data_alignment.Check() != true ||
94*103e46e4SHarish Mahendrakar       copyright.Check() != true || original.Check() != true ||
95*103e46e4SHarish Mahendrakar       has_pts.Check() != true || has_dts.Check() != true ||
96*103e46e4SHarish Mahendrakar       pts.Check() != true || stuffing_byte.Check() != true) {
97*103e46e4SHarish Mahendrakar     std::fprintf(stderr, "Webm2Pes: Invalid PES Optional Header field.\n");
98*103e46e4SHarish Mahendrakar     return false;
99*103e46e4SHarish Mahendrakar   }
100*103e46e4SHarish Mahendrakar 
101*103e46e4SHarish Mahendrakar   // TODO(tomfinegan): As noted in above, the PesHeaderFields should be an
102*103e46e4SHarish Mahendrakar   // array (or some data structure) that can be iterated over.
103*103e46e4SHarish Mahendrakar 
104*103e46e4SHarish Mahendrakar   // First byte of header, fields: marker, scrambling, priority, alignment,
105*103e46e4SHarish Mahendrakar   // copyright, original.
106*103e46e4SHarish Mahendrakar   *byte = 0;
107*103e46e4SHarish Mahendrakar   *byte |= marker.bits << marker.shift;
108*103e46e4SHarish Mahendrakar   *byte |= scrambling.bits << scrambling.shift;
109*103e46e4SHarish Mahendrakar   *byte |= priority.bits << priority.shift;
110*103e46e4SHarish Mahendrakar   *byte |= data_alignment.bits << data_alignment.shift;
111*103e46e4SHarish Mahendrakar   *byte |= copyright.bits << copyright.shift;
112*103e46e4SHarish Mahendrakar   *byte |= original.bits << original.shift;
113*103e46e4SHarish Mahendrakar 
114*103e46e4SHarish Mahendrakar   // Second byte of header, fields: has_pts, has_dts, unused fields.
115*103e46e4SHarish Mahendrakar   *++byte = 0;
116*103e46e4SHarish Mahendrakar   if (write_pts == true)
117*103e46e4SHarish Mahendrakar     *byte |= has_pts.bits << has_pts.shift;
118*103e46e4SHarish Mahendrakar 
119*103e46e4SHarish Mahendrakar   *byte |= has_dts.bits << has_dts.shift;
120*103e46e4SHarish Mahendrakar 
121*103e46e4SHarish Mahendrakar   // Third byte of header, fields: remaining size of header.
122*103e46e4SHarish Mahendrakar   *++byte = remaining_size.bits & 0xff;  // Field is 8 bits wide.
123*103e46e4SHarish Mahendrakar 
124*103e46e4SHarish Mahendrakar   int num_stuffing_bytes =
125*103e46e4SHarish Mahendrakar       (pts.num_bits + 7) / 8 + 1 /* always 1 stuffing byte */;
126*103e46e4SHarish Mahendrakar   if (write_pts == true) {
127*103e46e4SHarish Mahendrakar     // Write the PTS value as big endian and adjust stuffing byte count
128*103e46e4SHarish Mahendrakar     // accordingly.
129*103e46e4SHarish Mahendrakar     *++byte = pts.bits & 0xff;
130*103e46e4SHarish Mahendrakar     *++byte = (pts.bits >> 8) & 0xff;
131*103e46e4SHarish Mahendrakar     *++byte = (pts.bits >> 16) & 0xff;
132*103e46e4SHarish Mahendrakar     *++byte = (pts.bits >> 24) & 0xff;
133*103e46e4SHarish Mahendrakar     *++byte = (pts.bits >> 32) & 0xff;
134*103e46e4SHarish Mahendrakar     num_stuffing_bytes = 1;
135*103e46e4SHarish Mahendrakar   }
136*103e46e4SHarish Mahendrakar 
137*103e46e4SHarish Mahendrakar   // Add the stuffing byte(s).
138*103e46e4SHarish Mahendrakar   for (int i = 0; i < num_stuffing_bytes; ++i)
139*103e46e4SHarish Mahendrakar     *++byte = stuffing_byte.bits & 0xff;
140*103e46e4SHarish Mahendrakar 
141*103e46e4SHarish Mahendrakar   return CopyAndEscapeStartCodes(&header[0], kHeaderSize, buffer);
142*103e46e4SHarish Mahendrakar }
143*103e46e4SHarish Mahendrakar 
144*103e46e4SHarish Mahendrakar //
145*103e46e4SHarish Mahendrakar // BCMVHeader methods.
146*103e46e4SHarish Mahendrakar //
147*103e46e4SHarish Mahendrakar 
Write(PacketDataBuffer * buffer) const148*103e46e4SHarish Mahendrakar bool BCMVHeader::Write(PacketDataBuffer* buffer) const {
149*103e46e4SHarish Mahendrakar   if (buffer == nullptr) {
150*103e46e4SHarish Mahendrakar     std::fprintf(stderr, "Webm2Pes: nullptr for buffer in BCMV Write.\n");
151*103e46e4SHarish Mahendrakar     return false;
152*103e46e4SHarish Mahendrakar   }
153*103e46e4SHarish Mahendrakar   const int kBcmvSize = 4;
154*103e46e4SHarish Mahendrakar   for (int i = 0; i < kBcmvSize; ++i)
155*103e46e4SHarish Mahendrakar     buffer->push_back(bcmv[i]);
156*103e46e4SHarish Mahendrakar 
157*103e46e4SHarish Mahendrakar   // Note: The 4 byte length field must include the size of the BCMV header.
158*103e46e4SHarish Mahendrakar   const int kRemainingBytes = 6;
159*103e46e4SHarish Mahendrakar   const uint32_t bcmv_total_length = length + static_cast<uint32_t>(size());
160*103e46e4SHarish Mahendrakar   const uint8_t bcmv_buffer[kRemainingBytes] = {
161*103e46e4SHarish Mahendrakar       static_cast<std::uint8_t>((bcmv_total_length >> 24) & 0xff),
162*103e46e4SHarish Mahendrakar       static_cast<std::uint8_t>((bcmv_total_length >> 16) & 0xff),
163*103e46e4SHarish Mahendrakar       static_cast<std::uint8_t>((bcmv_total_length >> 8) & 0xff),
164*103e46e4SHarish Mahendrakar       static_cast<std::uint8_t>(bcmv_total_length & 0xff),
165*103e46e4SHarish Mahendrakar       0,
166*103e46e4SHarish Mahendrakar       0 /* 2 bytes 0 padding */};
167*103e46e4SHarish Mahendrakar 
168*103e46e4SHarish Mahendrakar   return CopyAndEscapeStartCodes(bcmv_buffer, kRemainingBytes, buffer);
169*103e46e4SHarish Mahendrakar }
170*103e46e4SHarish Mahendrakar 
171*103e46e4SHarish Mahendrakar //
172*103e46e4SHarish Mahendrakar // PesHeader methods.
173*103e46e4SHarish Mahendrakar //
174*103e46e4SHarish Mahendrakar 
175*103e46e4SHarish Mahendrakar // Writes out the header to |buffer|. Calls PesOptionalHeader::Write() to write
176*103e46e4SHarish Mahendrakar // |optional_header| contents. Returns true when successful, false otherwise.
Write(bool write_pts,PacketDataBuffer * buffer) const177*103e46e4SHarish Mahendrakar bool PesHeader::Write(bool write_pts, PacketDataBuffer* buffer) const {
178*103e46e4SHarish Mahendrakar   if (buffer == nullptr) {
179*103e46e4SHarish Mahendrakar     std::fprintf(stderr, "Webm2Pes: nullptr in header writer.\n");
180*103e46e4SHarish Mahendrakar     return false;
181*103e46e4SHarish Mahendrakar   }
182*103e46e4SHarish Mahendrakar 
183*103e46e4SHarish Mahendrakar   // Write |start_code|.
184*103e46e4SHarish Mahendrakar   const int kStartCodeLength = 4;
185*103e46e4SHarish Mahendrakar   for (int i = 0; i < kStartCodeLength; ++i)
186*103e46e4SHarish Mahendrakar     buffer->push_back(start_code[i]);
187*103e46e4SHarish Mahendrakar 
188*103e46e4SHarish Mahendrakar   // The length field here reports number of bytes following the field. The
189*103e46e4SHarish Mahendrakar   // length of the optional header must be added to the payload length set by
190*103e46e4SHarish Mahendrakar   // the user.
191*103e46e4SHarish Mahendrakar   const std::size_t header_length =
192*103e46e4SHarish Mahendrakar       packet_length + optional_header.size_in_bytes();
193*103e46e4SHarish Mahendrakar   if (header_length > UINT16_MAX)
194*103e46e4SHarish Mahendrakar     return false;
195*103e46e4SHarish Mahendrakar 
196*103e46e4SHarish Mahendrakar   // Write |header_length| as big endian.
197*103e46e4SHarish Mahendrakar   std::uint8_t byte = (header_length >> 8) & 0xff;
198*103e46e4SHarish Mahendrakar   buffer->push_back(byte);
199*103e46e4SHarish Mahendrakar   byte = header_length & 0xff;
200*103e46e4SHarish Mahendrakar   buffer->push_back(byte);
201*103e46e4SHarish Mahendrakar 
202*103e46e4SHarish Mahendrakar   // Write the (not really) optional header.
203*103e46e4SHarish Mahendrakar   if (optional_header.Write(write_pts, buffer) != true) {
204*103e46e4SHarish Mahendrakar     std::fprintf(stderr, "Webm2Pes: PES optional header write failed.");
205*103e46e4SHarish Mahendrakar     return false;
206*103e46e4SHarish Mahendrakar   }
207*103e46e4SHarish Mahendrakar   return true;
208*103e46e4SHarish Mahendrakar }
209*103e46e4SHarish Mahendrakar 
210*103e46e4SHarish Mahendrakar //
211*103e46e4SHarish Mahendrakar // Webm2Pes methods.
212*103e46e4SHarish Mahendrakar //
213*103e46e4SHarish Mahendrakar 
ConvertToFile()214*103e46e4SHarish Mahendrakar bool Webm2Pes::ConvertToFile() {
215*103e46e4SHarish Mahendrakar   if (input_file_name_.empty() || output_file_name_.empty()) {
216*103e46e4SHarish Mahendrakar     std::fprintf(stderr, "Webm2Pes: input and/or output file name(s) empty.\n");
217*103e46e4SHarish Mahendrakar     return false;
218*103e46e4SHarish Mahendrakar   }
219*103e46e4SHarish Mahendrakar 
220*103e46e4SHarish Mahendrakar   output_file_ = FilePtr(fopen(output_file_name_.c_str(), "wb"), FILEDeleter());
221*103e46e4SHarish Mahendrakar   if (output_file_ == nullptr) {
222*103e46e4SHarish Mahendrakar     std::fprintf(stderr, "Webm2Pes: Cannot open %s for output.\n",
223*103e46e4SHarish Mahendrakar                  output_file_name_.c_str());
224*103e46e4SHarish Mahendrakar     return false;
225*103e46e4SHarish Mahendrakar   }
226*103e46e4SHarish Mahendrakar 
227*103e46e4SHarish Mahendrakar   if (InitWebmParser() != true) {
228*103e46e4SHarish Mahendrakar     std::fprintf(stderr, "Webm2Pes: Cannot initialize WebM parser.\n");
229*103e46e4SHarish Mahendrakar     return false;
230*103e46e4SHarish Mahendrakar   }
231*103e46e4SHarish Mahendrakar 
232*103e46e4SHarish Mahendrakar   // Walk clusters in segment.
233*103e46e4SHarish Mahendrakar   const mkvparser::Cluster* cluster = webm_parser_->GetFirst();
234*103e46e4SHarish Mahendrakar   while (cluster != nullptr && cluster->EOS() == false) {
235*103e46e4SHarish Mahendrakar     const mkvparser::BlockEntry* block_entry = nullptr;
236*103e46e4SHarish Mahendrakar     std::int64_t block_status = cluster->GetFirst(block_entry);
237*103e46e4SHarish Mahendrakar     if (block_status < 0) {
238*103e46e4SHarish Mahendrakar       std::fprintf(stderr, "Webm2Pes: Cannot parse first block in %s.\n",
239*103e46e4SHarish Mahendrakar                    input_file_name_.c_str());
240*103e46e4SHarish Mahendrakar       return false;
241*103e46e4SHarish Mahendrakar     }
242*103e46e4SHarish Mahendrakar 
243*103e46e4SHarish Mahendrakar     // Walk blocks in cluster.
244*103e46e4SHarish Mahendrakar     while (block_entry != nullptr && block_entry->EOS() == false) {
245*103e46e4SHarish Mahendrakar       const mkvparser::Block* block = block_entry->GetBlock();
246*103e46e4SHarish Mahendrakar       if (block->GetTrackNumber() == video_track_num_) {
247*103e46e4SHarish Mahendrakar         const int frame_count = block->GetFrameCount();
248*103e46e4SHarish Mahendrakar 
249*103e46e4SHarish Mahendrakar         // Walk frames in block.
250*103e46e4SHarish Mahendrakar         for (int frame_num = 0; frame_num < frame_count; ++frame_num) {
251*103e46e4SHarish Mahendrakar           const mkvparser::Block::Frame& mkvparser_frame =
252*103e46e4SHarish Mahendrakar               block->GetFrame(frame_num);
253*103e46e4SHarish Mahendrakar 
254*103e46e4SHarish Mahendrakar           // Read the frame.
255*103e46e4SHarish Mahendrakar           VideoFrame vpx_frame(block->GetTime(cluster), codec_);
256*103e46e4SHarish Mahendrakar           if (ReadVideoFrame(mkvparser_frame, &vpx_frame) == false) {
257*103e46e4SHarish Mahendrakar             fprintf(stderr, "Webm2Pes: frame read failed.\n");
258*103e46e4SHarish Mahendrakar             return false;
259*103e46e4SHarish Mahendrakar           }
260*103e46e4SHarish Mahendrakar 
261*103e46e4SHarish Mahendrakar           // Write frame out as PES packet(s).
262*103e46e4SHarish Mahendrakar           if (WritePesPacket(vpx_frame, &packet_data_) == false) {
263*103e46e4SHarish Mahendrakar             std::fprintf(stderr, "Webm2Pes: WritePesPacket failed.\n");
264*103e46e4SHarish Mahendrakar             return false;
265*103e46e4SHarish Mahendrakar           }
266*103e46e4SHarish Mahendrakar 
267*103e46e4SHarish Mahendrakar           // Write contents of |packet_data_| to |output_file_|.
268*103e46e4SHarish Mahendrakar           if (std::fwrite(&packet_data_[0], 1, packet_data_.size(),
269*103e46e4SHarish Mahendrakar                           output_file_.get()) != packet_data_.size()) {
270*103e46e4SHarish Mahendrakar             std::fprintf(stderr, "Webm2Pes: packet payload write failed.\n");
271*103e46e4SHarish Mahendrakar             return false;
272*103e46e4SHarish Mahendrakar           }
273*103e46e4SHarish Mahendrakar           bytes_written_ += packet_data_.size();
274*103e46e4SHarish Mahendrakar         }
275*103e46e4SHarish Mahendrakar       }
276*103e46e4SHarish Mahendrakar       block_status = cluster->GetNext(block_entry, block_entry);
277*103e46e4SHarish Mahendrakar       if (block_status < 0) {
278*103e46e4SHarish Mahendrakar         std::fprintf(stderr, "Webm2Pes: Cannot parse block in %s.\n",
279*103e46e4SHarish Mahendrakar                      input_file_name_.c_str());
280*103e46e4SHarish Mahendrakar         return false;
281*103e46e4SHarish Mahendrakar       }
282*103e46e4SHarish Mahendrakar     }
283*103e46e4SHarish Mahendrakar 
284*103e46e4SHarish Mahendrakar     cluster = webm_parser_->GetNext(cluster);
285*103e46e4SHarish Mahendrakar   }
286*103e46e4SHarish Mahendrakar 
287*103e46e4SHarish Mahendrakar   std::fflush(output_file_.get());
288*103e46e4SHarish Mahendrakar   return true;
289*103e46e4SHarish Mahendrakar }
290*103e46e4SHarish Mahendrakar 
ConvertToPacketReceiver()291*103e46e4SHarish Mahendrakar bool Webm2Pes::ConvertToPacketReceiver() {
292*103e46e4SHarish Mahendrakar   if (input_file_name_.empty() || packet_sink_ == nullptr) {
293*103e46e4SHarish Mahendrakar     std::fprintf(stderr, "Webm2Pes: input file name empty or null sink.\n");
294*103e46e4SHarish Mahendrakar     return false;
295*103e46e4SHarish Mahendrakar   }
296*103e46e4SHarish Mahendrakar 
297*103e46e4SHarish Mahendrakar   if (InitWebmParser() != true) {
298*103e46e4SHarish Mahendrakar     std::fprintf(stderr, "Webm2Pes: Cannot initialize WebM parser.\n");
299*103e46e4SHarish Mahendrakar     return false;
300*103e46e4SHarish Mahendrakar   }
301*103e46e4SHarish Mahendrakar 
302*103e46e4SHarish Mahendrakar   // Walk clusters in segment.
303*103e46e4SHarish Mahendrakar   const mkvparser::Cluster* cluster = webm_parser_->GetFirst();
304*103e46e4SHarish Mahendrakar   while (cluster != nullptr && cluster->EOS() == false) {
305*103e46e4SHarish Mahendrakar     const mkvparser::BlockEntry* block_entry = nullptr;
306*103e46e4SHarish Mahendrakar     std::int64_t block_status = cluster->GetFirst(block_entry);
307*103e46e4SHarish Mahendrakar     if (block_status < 0) {
308*103e46e4SHarish Mahendrakar       std::fprintf(stderr, "Webm2Pes: Cannot parse first block in %s.\n",
309*103e46e4SHarish Mahendrakar                    input_file_name_.c_str());
310*103e46e4SHarish Mahendrakar       return false;
311*103e46e4SHarish Mahendrakar     }
312*103e46e4SHarish Mahendrakar 
313*103e46e4SHarish Mahendrakar     // Walk blocks in cluster.
314*103e46e4SHarish Mahendrakar     while (block_entry != nullptr && block_entry->EOS() == false) {
315*103e46e4SHarish Mahendrakar       const mkvparser::Block* block = block_entry->GetBlock();
316*103e46e4SHarish Mahendrakar       if (block->GetTrackNumber() == video_track_num_) {
317*103e46e4SHarish Mahendrakar         const int frame_count = block->GetFrameCount();
318*103e46e4SHarish Mahendrakar 
319*103e46e4SHarish Mahendrakar         // Walk frames in block.
320*103e46e4SHarish Mahendrakar         for (int frame_num = 0; frame_num < frame_count; ++frame_num) {
321*103e46e4SHarish Mahendrakar           const mkvparser::Block::Frame& mkvparser_frame =
322*103e46e4SHarish Mahendrakar               block->GetFrame(frame_num);
323*103e46e4SHarish Mahendrakar 
324*103e46e4SHarish Mahendrakar           // Read the frame.
325*103e46e4SHarish Mahendrakar           VideoFrame frame(block->GetTime(cluster), codec_);
326*103e46e4SHarish Mahendrakar           if (ReadVideoFrame(mkvparser_frame, &frame) == false) {
327*103e46e4SHarish Mahendrakar             fprintf(stderr, "Webm2Pes: frame read failed.\n");
328*103e46e4SHarish Mahendrakar             return false;
329*103e46e4SHarish Mahendrakar           }
330*103e46e4SHarish Mahendrakar 
331*103e46e4SHarish Mahendrakar           // Write frame out as PES packet(s).
332*103e46e4SHarish Mahendrakar           if (WritePesPacket(frame, &packet_data_) == false) {
333*103e46e4SHarish Mahendrakar             std::fprintf(stderr, "Webm2Pes: WritePesPacket failed.\n");
334*103e46e4SHarish Mahendrakar             return false;
335*103e46e4SHarish Mahendrakar           }
336*103e46e4SHarish Mahendrakar           if (packet_sink_->ReceivePacket(packet_data_) != true) {
337*103e46e4SHarish Mahendrakar             std::fprintf(stderr, "Webm2Pes: ReceivePacket failed.\n");
338*103e46e4SHarish Mahendrakar             return false;
339*103e46e4SHarish Mahendrakar           }
340*103e46e4SHarish Mahendrakar           bytes_written_ += packet_data_.size();
341*103e46e4SHarish Mahendrakar         }
342*103e46e4SHarish Mahendrakar       }
343*103e46e4SHarish Mahendrakar       block_status = cluster->GetNext(block_entry, block_entry);
344*103e46e4SHarish Mahendrakar       if (block_status < 0) {
345*103e46e4SHarish Mahendrakar         std::fprintf(stderr, "Webm2Pes: Cannot parse block in %s.\n",
346*103e46e4SHarish Mahendrakar                      input_file_name_.c_str());
347*103e46e4SHarish Mahendrakar         return false;
348*103e46e4SHarish Mahendrakar       }
349*103e46e4SHarish Mahendrakar     }
350*103e46e4SHarish Mahendrakar 
351*103e46e4SHarish Mahendrakar     cluster = webm_parser_->GetNext(cluster);
352*103e46e4SHarish Mahendrakar   }
353*103e46e4SHarish Mahendrakar 
354*103e46e4SHarish Mahendrakar   return true;
355*103e46e4SHarish Mahendrakar }
356*103e46e4SHarish Mahendrakar 
InitWebmParser()357*103e46e4SHarish Mahendrakar bool Webm2Pes::InitWebmParser() {
358*103e46e4SHarish Mahendrakar   if (webm_reader_.Open(input_file_name_.c_str()) != 0) {
359*103e46e4SHarish Mahendrakar     std::fprintf(stderr, "Webm2Pes: Cannot open %s as input.\n",
360*103e46e4SHarish Mahendrakar                  input_file_name_.c_str());
361*103e46e4SHarish Mahendrakar     return false;
362*103e46e4SHarish Mahendrakar   }
363*103e46e4SHarish Mahendrakar 
364*103e46e4SHarish Mahendrakar   using mkvparser::Segment;
365*103e46e4SHarish Mahendrakar   Segment* webm_parser = nullptr;
366*103e46e4SHarish Mahendrakar   if (Segment::CreateInstance(&webm_reader_, 0 /* pos */,
367*103e46e4SHarish Mahendrakar                               webm_parser /* Segment*& */) != 0) {
368*103e46e4SHarish Mahendrakar     std::fprintf(stderr, "Webm2Pes: Cannot create WebM parser.\n");
369*103e46e4SHarish Mahendrakar     return false;
370*103e46e4SHarish Mahendrakar   }
371*103e46e4SHarish Mahendrakar   webm_parser_.reset(webm_parser);
372*103e46e4SHarish Mahendrakar 
373*103e46e4SHarish Mahendrakar   if (webm_parser_->Load() != 0) {
374*103e46e4SHarish Mahendrakar     std::fprintf(stderr, "Webm2Pes: Cannot parse %s.\n",
375*103e46e4SHarish Mahendrakar                  input_file_name_.c_str());
376*103e46e4SHarish Mahendrakar     return false;
377*103e46e4SHarish Mahendrakar   }
378*103e46e4SHarish Mahendrakar 
379*103e46e4SHarish Mahendrakar   // Make sure there's a video track.
380*103e46e4SHarish Mahendrakar   const mkvparser::Tracks* tracks = webm_parser_->GetTracks();
381*103e46e4SHarish Mahendrakar   if (tracks == nullptr) {
382*103e46e4SHarish Mahendrakar     std::fprintf(stderr, "Webm2Pes: %s has no tracks.\n",
383*103e46e4SHarish Mahendrakar                  input_file_name_.c_str());
384*103e46e4SHarish Mahendrakar     return false;
385*103e46e4SHarish Mahendrakar   }
386*103e46e4SHarish Mahendrakar 
387*103e46e4SHarish Mahendrakar   timecode_scale_ = webm_parser_->GetInfo()->GetTimeCodeScale();
388*103e46e4SHarish Mahendrakar 
389*103e46e4SHarish Mahendrakar   for (int track_index = 0;
390*103e46e4SHarish Mahendrakar        track_index < static_cast<int>(tracks->GetTracksCount());
391*103e46e4SHarish Mahendrakar        ++track_index) {
392*103e46e4SHarish Mahendrakar     const mkvparser::Track* track = tracks->GetTrackByIndex(track_index);
393*103e46e4SHarish Mahendrakar     if (track && track->GetType() == mkvparser::Track::kVideo) {
394*103e46e4SHarish Mahendrakar       const std::string codec_id = ToString(track->GetCodecId());
395*103e46e4SHarish Mahendrakar       if (codec_id == std::string("V_VP8")) {
396*103e46e4SHarish Mahendrakar         codec_ = VideoFrame::kVP8;
397*103e46e4SHarish Mahendrakar       } else if (codec_id == std::string("V_VP9")) {
398*103e46e4SHarish Mahendrakar         codec_ = VideoFrame::kVP9;
399*103e46e4SHarish Mahendrakar       } else {
400*103e46e4SHarish Mahendrakar         fprintf(stderr, "Webm2Pes: Codec must be VP8 or VP9.\n");
401*103e46e4SHarish Mahendrakar         return false;
402*103e46e4SHarish Mahendrakar       }
403*103e46e4SHarish Mahendrakar       video_track_num_ = track_index + 1;
404*103e46e4SHarish Mahendrakar       break;
405*103e46e4SHarish Mahendrakar     }
406*103e46e4SHarish Mahendrakar   }
407*103e46e4SHarish Mahendrakar   if (video_track_num_ < 1) {
408*103e46e4SHarish Mahendrakar     std::fprintf(stderr, "Webm2Pes: No video track found in %s.\n",
409*103e46e4SHarish Mahendrakar                  input_file_name_.c_str());
410*103e46e4SHarish Mahendrakar     return false;
411*103e46e4SHarish Mahendrakar   }
412*103e46e4SHarish Mahendrakar   return true;
413*103e46e4SHarish Mahendrakar }
414*103e46e4SHarish Mahendrakar 
ReadVideoFrame(const mkvparser::Block::Frame & mkvparser_frame,VideoFrame * frame)415*103e46e4SHarish Mahendrakar bool Webm2Pes::ReadVideoFrame(const mkvparser::Block::Frame& mkvparser_frame,
416*103e46e4SHarish Mahendrakar                               VideoFrame* frame) {
417*103e46e4SHarish Mahendrakar   if (mkvparser_frame.len < 1 || frame == nullptr)
418*103e46e4SHarish Mahendrakar     return false;
419*103e46e4SHarish Mahendrakar 
420*103e46e4SHarish Mahendrakar   const std::size_t mkv_len = static_cast<std::size_t>(mkvparser_frame.len);
421*103e46e4SHarish Mahendrakar   if (mkv_len > frame->buffer().capacity) {
422*103e46e4SHarish Mahendrakar     const std::size_t new_size = 2 * mkv_len;
423*103e46e4SHarish Mahendrakar     if (frame->Init(new_size) == false) {
424*103e46e4SHarish Mahendrakar       std::fprintf(stderr, "Webm2Pes: Out of memory.\n");
425*103e46e4SHarish Mahendrakar       return false;
426*103e46e4SHarish Mahendrakar     }
427*103e46e4SHarish Mahendrakar   }
428*103e46e4SHarish Mahendrakar   if (mkvparser_frame.Read(&webm_reader_, frame->buffer().data.get()) != 0) {
429*103e46e4SHarish Mahendrakar     std::fprintf(stderr, "Webm2Pes: Error reading VPx frame!\n");
430*103e46e4SHarish Mahendrakar     return false;
431*103e46e4SHarish Mahendrakar   }
432*103e46e4SHarish Mahendrakar   return frame->SetBufferLength(mkv_len);
433*103e46e4SHarish Mahendrakar }
434*103e46e4SHarish Mahendrakar 
WritePesPacket(const VideoFrame & frame,PacketDataBuffer * packet_data)435*103e46e4SHarish Mahendrakar bool Webm2Pes::WritePesPacket(const VideoFrame& frame,
436*103e46e4SHarish Mahendrakar                               PacketDataBuffer* packet_data) {
437*103e46e4SHarish Mahendrakar   if (frame.buffer().data.get() == nullptr || frame.buffer().length < 1)
438*103e46e4SHarish Mahendrakar     return false;
439*103e46e4SHarish Mahendrakar 
440*103e46e4SHarish Mahendrakar   Ranges frame_ranges;
441*103e46e4SHarish Mahendrakar   if (frame.codec() == VideoFrame::kVP9) {
442*103e46e4SHarish Mahendrakar     bool error = false;
443*103e46e4SHarish Mahendrakar     const bool has_superframe_index =
444*103e46e4SHarish Mahendrakar         ParseVP9SuperFrameIndex(frame.buffer().data.get(),
445*103e46e4SHarish Mahendrakar                                 frame.buffer().length, &frame_ranges, &error);
446*103e46e4SHarish Mahendrakar     if (error) {
447*103e46e4SHarish Mahendrakar       std::fprintf(stderr, "Webm2Pes: Superframe index parse failed.\n");
448*103e46e4SHarish Mahendrakar       return false;
449*103e46e4SHarish Mahendrakar     }
450*103e46e4SHarish Mahendrakar     if (has_superframe_index == false) {
451*103e46e4SHarish Mahendrakar       frame_ranges.push_back(Range(0, frame.buffer().length));
452*103e46e4SHarish Mahendrakar     }
453*103e46e4SHarish Mahendrakar   } else {
454*103e46e4SHarish Mahendrakar     frame_ranges.push_back(Range(0, frame.buffer().length));
455*103e46e4SHarish Mahendrakar   }
456*103e46e4SHarish Mahendrakar 
457*103e46e4SHarish Mahendrakar   const std::int64_t khz90_pts =
458*103e46e4SHarish Mahendrakar       NanosecondsTo90KhzTicks(frame.nanosecond_pts());
459*103e46e4SHarish Mahendrakar   PesHeader header;
460*103e46e4SHarish Mahendrakar   header.optional_header.SetPtsBits(khz90_pts);
461*103e46e4SHarish Mahendrakar 
462*103e46e4SHarish Mahendrakar   packet_data->clear();
463*103e46e4SHarish Mahendrakar 
464*103e46e4SHarish Mahendrakar   for (const Range& packet_payload_range : frame_ranges) {
465*103e46e4SHarish Mahendrakar     std::size_t extra_bytes = 0;
466*103e46e4SHarish Mahendrakar     if (packet_payload_range.length > kMaxPayloadSize) {
467*103e46e4SHarish Mahendrakar       extra_bytes = packet_payload_range.length - kMaxPayloadSize;
468*103e46e4SHarish Mahendrakar     }
469*103e46e4SHarish Mahendrakar     if (packet_payload_range.length + packet_payload_range.offset >
470*103e46e4SHarish Mahendrakar         frame.buffer().length) {
471*103e46e4SHarish Mahendrakar       std::fprintf(stderr, "Webm2Pes: Invalid frame length.\n");
472*103e46e4SHarish Mahendrakar       return false;
473*103e46e4SHarish Mahendrakar     }
474*103e46e4SHarish Mahendrakar 
475*103e46e4SHarish Mahendrakar     // First packet of new frame. Always include PTS and BCMV header.
476*103e46e4SHarish Mahendrakar     header.packet_length =
477*103e46e4SHarish Mahendrakar         packet_payload_range.length - extra_bytes + BCMVHeader::size();
478*103e46e4SHarish Mahendrakar     if (header.Write(true, packet_data) != true) {
479*103e46e4SHarish Mahendrakar       std::fprintf(stderr, "Webm2Pes: packet header write failed.\n");
480*103e46e4SHarish Mahendrakar       return false;
481*103e46e4SHarish Mahendrakar     }
482*103e46e4SHarish Mahendrakar 
483*103e46e4SHarish Mahendrakar     BCMVHeader bcmv_header(static_cast<uint32_t>(packet_payload_range.length));
484*103e46e4SHarish Mahendrakar     if (bcmv_header.Write(packet_data) != true) {
485*103e46e4SHarish Mahendrakar       std::fprintf(stderr, "Webm2Pes: BCMV write failed.\n");
486*103e46e4SHarish Mahendrakar       return false;
487*103e46e4SHarish Mahendrakar     }
488*103e46e4SHarish Mahendrakar 
489*103e46e4SHarish Mahendrakar     // Insert the payload at the end of |packet_data|.
490*103e46e4SHarish Mahendrakar     const std::uint8_t* const payload_start =
491*103e46e4SHarish Mahendrakar         frame.buffer().data.get() + packet_payload_range.offset;
492*103e46e4SHarish Mahendrakar 
493*103e46e4SHarish Mahendrakar     const std::size_t bytes_to_copy = packet_payload_range.length - extra_bytes;
494*103e46e4SHarish Mahendrakar     if (CopyAndEscapeStartCodes(payload_start, bytes_to_copy, packet_data) ==
495*103e46e4SHarish Mahendrakar         false) {
496*103e46e4SHarish Mahendrakar       fprintf(stderr, "Webm2Pes: Payload write failed.\n");
497*103e46e4SHarish Mahendrakar       return false;
498*103e46e4SHarish Mahendrakar     }
499*103e46e4SHarish Mahendrakar 
500*103e46e4SHarish Mahendrakar     std::size_t bytes_copied = bytes_to_copy;
501*103e46e4SHarish Mahendrakar     while (extra_bytes) {
502*103e46e4SHarish Mahendrakar       // Write PES packets for the remaining data, but omit the PTS and BCMV
503*103e46e4SHarish Mahendrakar       // header.
504*103e46e4SHarish Mahendrakar       const std::size_t extra_bytes_to_copy =
505*103e46e4SHarish Mahendrakar           std::min(kMaxPayloadSize, extra_bytes);
506*103e46e4SHarish Mahendrakar       extra_bytes -= extra_bytes_to_copy;
507*103e46e4SHarish Mahendrakar       header.packet_length = extra_bytes_to_copy;
508*103e46e4SHarish Mahendrakar       if (header.Write(false, packet_data) != true) {
509*103e46e4SHarish Mahendrakar         fprintf(stderr, "Webm2pes: fragment write failed.\n");
510*103e46e4SHarish Mahendrakar         return false;
511*103e46e4SHarish Mahendrakar       }
512*103e46e4SHarish Mahendrakar 
513*103e46e4SHarish Mahendrakar       const std::uint8_t* fragment_start = payload_start + bytes_copied;
514*103e46e4SHarish Mahendrakar       if (CopyAndEscapeStartCodes(fragment_start, extra_bytes_to_copy,
515*103e46e4SHarish Mahendrakar                                   packet_data) == false) {
516*103e46e4SHarish Mahendrakar         fprintf(stderr, "Webm2Pes: Payload write failed.\n");
517*103e46e4SHarish Mahendrakar         return false;
518*103e46e4SHarish Mahendrakar       }
519*103e46e4SHarish Mahendrakar 
520*103e46e4SHarish Mahendrakar       bytes_copied += extra_bytes_to_copy;
521*103e46e4SHarish Mahendrakar     }
522*103e46e4SHarish Mahendrakar   }
523*103e46e4SHarish Mahendrakar 
524*103e46e4SHarish Mahendrakar   return true;
525*103e46e4SHarish Mahendrakar }
526*103e46e4SHarish Mahendrakar 
CopyAndEscapeStartCodes(const std::uint8_t * raw_input,std::size_t raw_input_length,PacketDataBuffer * packet_buffer)527*103e46e4SHarish Mahendrakar bool CopyAndEscapeStartCodes(const std::uint8_t* raw_input,
528*103e46e4SHarish Mahendrakar                              std::size_t raw_input_length,
529*103e46e4SHarish Mahendrakar                              PacketDataBuffer* packet_buffer) {
530*103e46e4SHarish Mahendrakar   if (raw_input == nullptr || raw_input_length < 1 || packet_buffer == nullptr)
531*103e46e4SHarish Mahendrakar     return false;
532*103e46e4SHarish Mahendrakar 
533*103e46e4SHarish Mahendrakar   int num_zeros = 0;
534*103e46e4SHarish Mahendrakar   for (std::size_t i = 0; i < raw_input_length; ++i) {
535*103e46e4SHarish Mahendrakar     const uint8_t byte = raw_input[i];
536*103e46e4SHarish Mahendrakar 
537*103e46e4SHarish Mahendrakar     if (byte == 0) {
538*103e46e4SHarish Mahendrakar       ++num_zeros;
539*103e46e4SHarish Mahendrakar     } else if (num_zeros >= 2 && (byte == 0x1 || byte == 0x3)) {
540*103e46e4SHarish Mahendrakar       packet_buffer->push_back(0x3);
541*103e46e4SHarish Mahendrakar       num_zeros = 0;
542*103e46e4SHarish Mahendrakar     } else {
543*103e46e4SHarish Mahendrakar       num_zeros = 0;
544*103e46e4SHarish Mahendrakar     }
545*103e46e4SHarish Mahendrakar 
546*103e46e4SHarish Mahendrakar     packet_buffer->push_back(byte);
547*103e46e4SHarish Mahendrakar   }
548*103e46e4SHarish Mahendrakar 
549*103e46e4SHarish Mahendrakar   return true;
550*103e46e4SHarish Mahendrakar }
551*103e46e4SHarish Mahendrakar 
552*103e46e4SHarish Mahendrakar }  // namespace libwebm
553