#ifndef LIBWEBM_M2TS_WEBM2PES_H_
#define LIBWEBM_M2TS_WEBM2PES_H_
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include "common/libwebm_util.h"
#include "common/video_frame.h"
#include "mkvparser/mkvparser.h"
#include "mkvparser/mkvreader.h"
namespace libwebm {
struct PesHeaderField {
PesHeaderField(std::uint64_t value, std::uint32_t size_in_bits,
std::uint8_t byte_index, std::uint8_t bits_to_shift)
: bits(value),
num_bits(size_in_bits),
index(byte_index),
shift(bits_to_shift) {}
PesHeaderField() = delete;
PesHeaderField(const PesHeaderField&) = default;
PesHeaderField(PesHeaderField&&) = default;
~PesHeaderField() = default;
bool Check() const {
return num_bits > 0 && num_bits <= 64 && shift >= 0 && shift < 64;
}
std::uint64_t bits;
const int num_bits;
const std::uint8_t index;
const int shift;
};
typedef std::vector<std::uint8_t> PacketDataBuffer;
struct PesOptionalHeader {
const PesHeaderField marker = PesHeaderField(2, 2, 0, 6);
const PesHeaderField scrambling = PesHeaderField(0, 2, 0, 4);
const PesHeaderField priority = PesHeaderField(0, 1, 0, 3);
const PesHeaderField data_alignment = PesHeaderField(0, 1, 0, 2);
const PesHeaderField copyright = PesHeaderField(0, 1, 0, 1);
const PesHeaderField original = PesHeaderField(0, 1, 0, 0);
const PesHeaderField has_pts = PesHeaderField(1, 1, 1, 7);
const PesHeaderField has_dts = PesHeaderField(0, 1, 1, 6);
const PesHeaderField unused = PesHeaderField(0, 6, 1, 0);
const PesHeaderField remaining_size = PesHeaderField(6, 8, 2, 0);
PesHeaderField pts = PesHeaderField(0, 40, 3, 0);
PesHeaderField stuffing_byte = PesHeaderField(0xFF, 8, 8, 0);
bool fragment = false;
static std::size_t size_in_bytes() { return 9; }
void SetPtsBits(std::int64_t pts_90khz);
bool Write(bool write_pts, PacketDataBuffer* buffer) const;
};
struct BCMVHeader {
explicit BCMVHeader(std::uint32_t frame_length) : length(frame_length) {}
BCMVHeader() = delete;
BCMVHeader(const BCMVHeader&) = delete;
BCMVHeader(BCMVHeader&&) = delete;
~BCMVHeader() = default;
const std::uint8_t bcmv[4] = {'B', 'C', 'M', 'V'};
const std::uint32_t length;
static std::size_t size() { return 10; }
bool Write(PacketDataBuffer* buffer) const;
bool Write(uint8_t* buffer);
};
struct PesHeader {
const std::uint8_t start_code[4] = {
0x00, 0x00,
0x01, 0xE0}; std::uint16_t packet_length = 0; PesOptionalHeader optional_header;
std::size_t size() const {
return optional_header.size_in_bytes() +
6 + packet_length;
}
bool Write(bool write_pts, PacketDataBuffer* buffer) const;
};
class PacketReceiverInterface {
public:
virtual ~PacketReceiverInterface() {}
virtual bool ReceivePacket(const PacketDataBuffer& packet) = 0;
};
class Webm2Pes {
public:
static const std::size_t kMaxPayloadSize;
Webm2Pes(const std::string& input_file, const std::string& output_file)
: input_file_name_(input_file), output_file_name_(output_file) {}
Webm2Pes(const std::string& input_file, PacketReceiverInterface* packet_sink)
: input_file_name_(input_file), packet_sink_(packet_sink) {}
Webm2Pes() = delete;
Webm2Pes(const Webm2Pes&) = delete;
Webm2Pes(Webm2Pes&&) = delete;
~Webm2Pes() = default;
bool ConvertToFile();
bool ConvertToPacketReceiver();
static bool WritePesPacket(const VideoFrame& frame,
PacketDataBuffer* packet_data);
uint64_t bytes_written() const { return bytes_written_; }
private:
bool InitWebmParser();
bool ReadVideoFrame(const mkvparser::Block::Frame& mkvparser_frame,
VideoFrame* frame);
const std::string input_file_name_;
const std::string output_file_name_;
std::unique_ptr<mkvparser::Segment> webm_parser_;
mkvparser::MkvReader webm_reader_;
FilePtr output_file_;
int video_track_num_ = 0;
VideoFrame::Codec codec_;
std::int64_t timecode_scale_ = 1000000;
PacketReceiverInterface* packet_sink_ = nullptr;
PacketDataBuffer packet_data_;
std::uint64_t bytes_written_ = 0;
};
bool CopyAndEscapeStartCodes(const std::uint8_t* raw_input,
std::size_t raw_input_length,
PacketDataBuffer* packet_buffer);
}
#endif