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:
Tom Finegan
2016-05-27 14:21:04 -07:00
parent 82903f36fa
commit 4b735452bb
5 changed files with 125 additions and 82 deletions

View File

@@ -34,6 +34,9 @@ bool VpxPesParser::BcmvHeader::Valid() const {
id[0] == 'B' && id[1] == 'C' && id[2] == 'M' && id[3] == 'V');
}
// TODO(tomfinegan): Break Open() into separate functions. One that opens the
// file, and one that reads one packet at a time. As things are files larger
// than the maximum availble memory for the current process cannot be loaded.
bool VpxPesParser::Open(const std::string& pes_file) {
pes_file_size_ = static_cast<size_t>(libwebm::GetFileSize(pes_file));
if (pes_file_size_ <= 0)
@@ -41,18 +44,38 @@ bool VpxPesParser::Open(const std::string& pes_file) {
pes_file_data_.reserve(static_cast<size_t>(pes_file_size_));
libwebm::FilePtr file = libwebm::FilePtr(std::fopen(pes_file.c_str(), "rb"),
libwebm::FILEDeleter());
int byte;
while ((byte = fgetc(file.get())) != EOF)
pes_file_data_.push_back(static_cast<std::uint8_t>(byte));
int zero_count = 0;
int bytes_skipped = 0;
bool skip_byte = false;
while ((byte = fgetc(file.get())) != EOF) {
if (zero_count >= 2) {
if (byte == 3) {
skip_byte = true;
zero_count = 0;
} else if (byte == 0) {
++zero_count;
} else {
zero_count = 0;
}
}
if (!skip_byte)
pes_file_data_.push_back(static_cast<std::uint8_t>(byte));
else
++bytes_skipped;
skip_byte = false;
}
if (!feof(file.get()) || ferror(file.get()) ||
pes_file_size_ != pes_file_data_.size()) {
pes_file_size_ != pes_file_data_.size() + bytes_skipped) {
return false;
}
read_pos_ = 0;
parse_state_ = kParsePesHeader;
parse_state_ = kFindStartCode;
return true;
}
@@ -205,18 +228,45 @@ bool VpxPesParser::ParseBcmvHeader(BcmvHeader* header) {
// TODO(tomfinegan): Verify data instead of jumping to the next packet.
read_pos_ += kBcmvHeaderSize + header->length;
parse_state_ = kParsePesHeader;
parse_state_ = kFindStartCode;
return true;
}
bool VpxPesParser::FindStartCode(std::size_t origin, std::size_t* offset) {
if (read_pos_ + 2 >= pes_file_size_)
return false;
const std::size_t length = pes_file_size_ - origin;
if (length < 3)
return false;
const uint8_t* const data = &pes_file_data_[origin];
for (std::size_t i = 0; i < length - 3; ++i) {
if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1) {
*offset = i;
parse_state_ = kParsePesHeader;
return true;
}
}
return false;
}
int VpxPesParser::BytesAvailable() const {
return static_cast<int>(pes_file_data_.size() - read_pos_);
}
bool VpxPesParser::ParseNextPacket(PesHeader* header, VpxFrame* frame) {
if (!header || !frame) {
if (!header || !frame || parse_state_ != kFindStartCode) {
return false;
}
std::size_t packet_start_pos = read_pos_;
if (!FindStartCode(read_pos_, &packet_start_pos)) {
return false;
}
read_pos_ = packet_start_pos;
if (!ParsePesHeader(header)) {
return false;
}