webm2pes: Add start code emulation prevention.
- Make start codes reliable for VPx in PES. - Stop setting the PES size field and stop splitting packets when larger than UINT16_MAX (always set 0; rely on start codes to find packet boundaries). Change-Id: I402e91c26562e930f61543ca59223b83cc92be29
This commit is contained in:
108
m2ts/webm2pes.cc
108
m2ts/webm2pes.cc
@@ -14,48 +14,6 @@
|
||||
|
||||
#include "common/libwebm_util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
bool GetPacketPayloadRanges(const libwebm::PesHeader& header,
|
||||
const libwebm::Ranges& frame_ranges,
|
||||
libwebm::Ranges* packet_payload_ranges) {
|
||||
// TODO(tomfinegan): The length field in PES is actually number of bytes that
|
||||
// follow the length field, and does not include the 6 byte fixed portion of
|
||||
// the header (4 byte start code + 2 bytes for the length). We can fit in 6
|
||||
// more bytes if we really want to, and avoid packetization when size is very
|
||||
// close to UINT16_MAX.
|
||||
if (packet_payload_ranges == nullptr) {
|
||||
std::fprintf(stderr, "Webm2Pes: nullptr getting payload ranges.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::size_t kMaxPacketPayloadSize = UINT16_MAX - header.size();
|
||||
|
||||
for (const libwebm::Range& frame_range : frame_ranges) {
|
||||
if (frame_range.length + header.size() > kMaxPacketPayloadSize) {
|
||||
// make packet ranges until range.length is exhausted
|
||||
const std::size_t kBytesToPacketize = frame_range.length;
|
||||
std::size_t packet_payload_length = 0;
|
||||
for (std::size_t pos = 0; pos < kBytesToPacketize;
|
||||
pos += packet_payload_length) {
|
||||
packet_payload_length =
|
||||
(frame_range.length - pos < kMaxPacketPayloadSize) ?
|
||||
frame_range.length - pos :
|
||||
kMaxPacketPayloadSize;
|
||||
packet_payload_ranges->push_back(
|
||||
libwebm::Range(frame_range.offset + pos, packet_payload_length));
|
||||
}
|
||||
} else {
|
||||
// copy range into |packet_ranges|
|
||||
packet_payload_ranges->push_back(
|
||||
libwebm::Range(frame_range.offset, frame_range.length));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace libwebm {
|
||||
|
||||
//
|
||||
@@ -106,7 +64,7 @@ void PesOptionalHeader::SetPtsBits(std::int64_t pts_90khz) {
|
||||
std::memcpy(reinterpret_cast<std::uint8_t*>(pts_bits), buffer, 5);
|
||||
}
|
||||
|
||||
// Writes fields to |file| and returns true. Returns false when write or
|
||||
// Writes fields to |buffer| and returns true. Returns false when write or
|
||||
// field value validation fails.
|
||||
bool PesOptionalHeader::Write(bool write_pts, PacketDataBuffer* buffer) const {
|
||||
if (buffer == nullptr) {
|
||||
@@ -166,10 +124,7 @@ bool PesOptionalHeader::Write(bool write_pts, PacketDataBuffer* buffer) const {
|
||||
for (int i = 0; i < num_stuffing_bytes; ++i)
|
||||
*++byte = stuffing_byte.bits & 0xff;
|
||||
|
||||
for (int i = 0; i < kHeaderSize; ++i)
|
||||
buffer->push_back(header[i]);
|
||||
|
||||
return true;
|
||||
return CopyAndEscapeStartCodes(&header[0], kHeaderSize, buffer);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -193,10 +148,8 @@ bool BCMVHeader::Write(PacketDataBuffer* buffer) const {
|
||||
static_cast<std::uint8_t>(length & 0xff),
|
||||
0,
|
||||
0 /* 2 bytes 0 padding */};
|
||||
for (int i = 0; i < kRemainingBytes; ++i)
|
||||
buffer->push_back(bcmv_buffer[i]);
|
||||
|
||||
return true;
|
||||
return CopyAndEscapeStartCodes(bcmv_buffer, kRemainingBytes, buffer);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -445,14 +398,6 @@ bool Webm2Pes::WritePesPacket(const mkvparser::Block::Frame& vpx_frame,
|
||||
frame_ranges.push_back(Range(0, vpx_frame.len));
|
||||
}
|
||||
|
||||
PesHeader header;
|
||||
Ranges packet_payload_ranges;
|
||||
if (GetPacketPayloadRanges(header, frame_ranges, &packet_payload_ranges) !=
|
||||
true) {
|
||||
std::fprintf(stderr, "Webm2Pes: Error preparing packet payload ranges!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
///
|
||||
/// TODO: DEBUG/REMOVE
|
||||
///
|
||||
@@ -462,23 +407,17 @@ bool Webm2Pes::WritePesPacket(const mkvparser::Block::Frame& vpx_frame,
|
||||
static_cast<unsigned int>(frame_range.offset),
|
||||
static_cast<unsigned int>(frame_range.length));
|
||||
}
|
||||
for (const Range& payload_range : packet_payload_ranges) {
|
||||
printf("---payload range: off:%u len:%u\n",
|
||||
static_cast<unsigned int>(payload_range.offset),
|
||||
static_cast<unsigned int>(payload_range.length));
|
||||
}
|
||||
|
||||
const std::int64_t khz90_pts =
|
||||
NanosecondsTo90KhzTicks(static_cast<std::int64_t>(nanosecond_pts));
|
||||
PesHeader header;
|
||||
header.optional_header.SetPtsBits(khz90_pts);
|
||||
|
||||
packet_data_.clear();
|
||||
|
||||
bool write_pts = true;
|
||||
for (const Range& packet_payload_range : packet_payload_ranges) {
|
||||
header.packet_length =
|
||||
(header.optional_header.size_in_bytes() + packet_payload_range.length) &
|
||||
0xffff;
|
||||
for (const Range& packet_payload_range : frame_ranges) {
|
||||
header.packet_length = 0;
|
||||
if (header.Write(write_pts, &packet_data_) != true) {
|
||||
std::fprintf(stderr, "Webm2Pes: packet header write failed.\n");
|
||||
return false;
|
||||
@@ -494,10 +433,41 @@ bool Webm2Pes::WritePesPacket(const mkvparser::Block::Frame& vpx_frame,
|
||||
// Insert the payload at the end of |packet_data_|.
|
||||
const std::uint8_t* payload_start =
|
||||
frame_data.get() + packet_payload_range.offset;
|
||||
packet_data_.insert(packet_data_.end(), payload_start,
|
||||
payload_start + packet_payload_range.length);
|
||||
|
||||
if (CopyAndEscapeStartCodes(payload_start,
|
||||
static_cast<int>(packet_payload_range.length),
|
||||
&packet_data_) == false) {
|
||||
fprintf(stderr, "Webm2Pes: Payload write failed.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CopyAndEscapeStartCodes(const std::uint8_t* raw_input,
|
||||
int raw_input_length,
|
||||
PacketDataBuffer* packet_buffer) {
|
||||
if (raw_input == nullptr || raw_input_length < 1 || packet_buffer == nullptr)
|
||||
return false;
|
||||
|
||||
int num_zeros = 0;
|
||||
for (int i = 0; i < raw_input_length; ++i) {
|
||||
const uint8_t byte = raw_input[i];
|
||||
|
||||
if (byte == 0) {
|
||||
++num_zeros;
|
||||
} else if (num_zeros >= 2 && (byte == 0x1 || byte == 0x3)) {
|
||||
packet_buffer->push_back(0x3);
|
||||
num_zeros = 0;
|
||||
} else {
|
||||
num_zeros = 0;
|
||||
}
|
||||
|
||||
packet_buffer->push_back(byte);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace libwebm
|
||||
|
Reference in New Issue
Block a user