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