vpxpes_parser: Store frame payloads.
libwebm_util: - Add 90khz -> nanosecond conversion. vpxpes_parser: - Get rid of VpxPesParser::VpxFrame and use VideoFrame. - Store/Accumulate (when neccessary) PES payloads in VideoFrames. - Change type of size constants from int to size_t. - Return offset accounting for origin from FindStartCode(). - Check all PTS marker bits (instead of checking the second marker twice). video_frame: - Add nanosecond_pts mutator. webm2pes: - Write DTS/PTS presence flag correctly when PTS is not present. Change-Id: I10f16cd03bb3a51205a25331527ddceb3769ba03
This commit is contained in:
parent
25d26028c1
commit
6cf0a0f400
@ -13,11 +13,15 @@
|
|||||||
namespace libwebm {
|
namespace libwebm {
|
||||||
|
|
||||||
std::int64_t NanosecondsTo90KhzTicks(std::int64_t nanoseconds) {
|
std::int64_t NanosecondsTo90KhzTicks(std::int64_t nanoseconds) {
|
||||||
const double kNanosecondsPerSecond = 1000000000.0;
|
|
||||||
const double pts_seconds = nanoseconds / kNanosecondsPerSecond;
|
const double pts_seconds = nanoseconds / kNanosecondsPerSecond;
|
||||||
return static_cast<std::int64_t>(pts_seconds * 90000);
|
return static_cast<std::int64_t>(pts_seconds * 90000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::int64_t Khz90TicksToNanoseconds(std::int64_t ticks) {
|
||||||
|
const double seconds = ticks / 90000.0;
|
||||||
|
return static_cast<std::int64_t>(seconds * kNanosecondsPerSecond);
|
||||||
|
}
|
||||||
|
|
||||||
bool ParseVP9SuperFrameIndex(const std::uint8_t* frame,
|
bool ParseVP9SuperFrameIndex(const std::uint8_t* frame,
|
||||||
std::size_t frame_length, Ranges* frame_ranges) {
|
std::size_t frame_length, Ranges* frame_ranges) {
|
||||||
if (frame == nullptr || frame_length == 0 || frame_ranges == nullptr)
|
if (frame == nullptr || frame_length == 0 || frame_ranges == nullptr)
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
namespace libwebm {
|
namespace libwebm {
|
||||||
|
|
||||||
|
const double kNanosecondsPerSecond = 1000000000.0;
|
||||||
|
|
||||||
// fclose functor for wrapping FILE in std::unique_ptr.
|
// fclose functor for wrapping FILE in std::unique_ptr.
|
||||||
// TODO(tomfinegan): Move this to file_util once c++11 restrictions are
|
// TODO(tomfinegan): Move this to file_util once c++11 restrictions are
|
||||||
// relaxed.
|
// relaxed.
|
||||||
@ -37,11 +39,12 @@ struct Range {
|
|||||||
const std::size_t offset;
|
const std::size_t offset;
|
||||||
const std::size_t length;
|
const std::size_t length;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<Range> Ranges;
|
typedef std::vector<Range> Ranges;
|
||||||
|
|
||||||
// Converts |nanoseconds| to 90000 Hz clock ticks and returns the value.
|
// Converts |nanoseconds| to 90000 Hz clock ticks and vice versa. Each return
|
||||||
|
// the converted value.
|
||||||
std::int64_t NanosecondsTo90KhzTicks(std::int64_t nanoseconds);
|
std::int64_t NanosecondsTo90KhzTicks(std::int64_t nanoseconds);
|
||||||
|
std::int64_t Khz90TicksToNanoseconds(std::int64_t khz90_ticks);
|
||||||
|
|
||||||
// Returns true and stores frame offsets and lengths in |frame_ranges| when
|
// Returns true and stores frame offsets and lengths in |frame_ranges| when
|
||||||
// |frame| has a valid VP9 super frame index.
|
// |frame| has a valid VP9 super frame index.
|
||||||
|
@ -53,6 +53,9 @@ class VideoFrame {
|
|||||||
std::int64_t nanosecond_pts() const { return nanosecond_pts_; }
|
std::int64_t nanosecond_pts() const { return nanosecond_pts_; }
|
||||||
Codec codec() const { return codec_; }
|
Codec codec() const { return codec_; }
|
||||||
|
|
||||||
|
// Mutators.
|
||||||
|
void set_nanosecond_pts(std::int64_t nano_pts) { nanosecond_pts_ = nano_pts; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Buffer buffer_;
|
Buffer buffer_;
|
||||||
bool keyframe_ = false;
|
bool keyframe_ = false;
|
||||||
|
@ -68,7 +68,7 @@ TEST_F(Webm2PesTests, CreatePesFile) { CreateAndLoadTestInput(); }
|
|||||||
TEST_F(Webm2PesTests, CanParseFirstPacket) {
|
TEST_F(Webm2PesTests, CanParseFirstPacket) {
|
||||||
CreateAndLoadTestInput();
|
CreateAndLoadTestInput();
|
||||||
libwebm::VpxPesParser::PesHeader header;
|
libwebm::VpxPesParser::PesHeader header;
|
||||||
libwebm::VpxPesParser::VpxFrame frame;
|
libwebm::VideoFrame frame;
|
||||||
ASSERT_TRUE(parser()->ParseNextPacket(&header, &frame));
|
ASSERT_TRUE(parser()->ParseNextPacket(&header, &frame));
|
||||||
EXPECT_TRUE(VerifyPacketStartCode(header));
|
EXPECT_TRUE(VerifyPacketStartCode(header));
|
||||||
|
|
||||||
|
@ -9,11 +9,11 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/libwebm_util.h"
|
|
||||||
|
|
||||||
namespace libwebm {
|
namespace libwebm {
|
||||||
|
|
||||||
@ -30,8 +30,8 @@ bool VpxPesParser::BcmvHeader::operator==(const BcmvHeader& other) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool VpxPesParser::BcmvHeader::Valid() const {
|
bool VpxPesParser::BcmvHeader::Valid() const {
|
||||||
return (length > 0 && length <= std::numeric_limits<std::uint16_t>::max() &&
|
return (length > 0 && id[0] == 'B' && id[1] == 'C' && id[2] == 'M' &&
|
||||||
id[0] == 'B' && id[1] == 'C' && id[2] == 'M' && id[3] == 'V');
|
id[3] == 'V');
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(tomfinegan): Break Open() into separate functions. One that opens the
|
// TODO(tomfinegan): Break Open() into separate functions. One that opens the
|
||||||
@ -154,18 +154,20 @@ bool VpxPesParser::ParsePesOptionalHeader(PesOptionalHeader* header) {
|
|||||||
header->data_alignment = (pes_file_data_[offset] & 0xc) >> 2;
|
header->data_alignment = (pes_file_data_[offset] & 0xc) >> 2;
|
||||||
header->copyright = (pes_file_data_[offset] & 0x2) >> 1;
|
header->copyright = (pes_file_data_[offset] & 0x2) >> 1;
|
||||||
header->original = pes_file_data_[offset] & 0x1;
|
header->original = pes_file_data_[offset] & 0x1;
|
||||||
|
|
||||||
offset++;
|
offset++;
|
||||||
|
|
||||||
header->has_pts = (pes_file_data_[offset] & 0x80) >> 7;
|
header->has_pts = (pes_file_data_[offset] & 0x80) >> 7;
|
||||||
header->has_dts = (pes_file_data_[offset] & 0x40) >> 6;
|
header->has_dts = (pes_file_data_[offset] & 0x40) >> 6;
|
||||||
header->unused_fields = pes_file_data_[offset] & 0x3f;
|
header->unused_fields = pes_file_data_[offset] & 0x3f;
|
||||||
|
|
||||||
offset++;
|
offset++;
|
||||||
|
|
||||||
header->remaining_size = pes_file_data_[offset];
|
header->remaining_size = pes_file_data_[offset];
|
||||||
if (header->remaining_size != kWebm2PesOptHeaderRemainingSize)
|
if (header->remaining_size !=
|
||||||
|
static_cast<int>(kWebm2PesOptHeaderRemainingSize))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
size_t bytes_left = header->remaining_size;
|
size_t bytes_left = header->remaining_size;
|
||||||
|
offset++;
|
||||||
|
|
||||||
if (header->has_pts) {
|
if (header->has_pts) {
|
||||||
// Read PTS markers. Format:
|
// Read PTS markers. Format:
|
||||||
@ -179,14 +181,14 @@ bool VpxPesParser::ParsePesOptionalHeader(PesOptionalHeader* header) {
|
|||||||
// bottom 15 bits
|
// bottom 15 bits
|
||||||
// marker ('1')
|
// marker ('1')
|
||||||
// TODO(tomfinegan): read/store the timestamp.
|
// TODO(tomfinegan): read/store the timestamp.
|
||||||
offset++;
|
|
||||||
header->pts_dts_flag = (pes_file_data_[offset] & 0x20) >> 4;
|
header->pts_dts_flag = (pes_file_data_[offset] & 0x20) >> 4;
|
||||||
// Check the marker bits.
|
// Check the marker bits.
|
||||||
if ((pes_file_data_[offset] & 1) != 1 ||
|
if ((pes_file_data_[offset + 0] & 1) != 1 ||
|
||||||
(pes_file_data_[offset + 2] & 1) != 1 ||
|
(pes_file_data_[offset + 2] & 1) != 1 ||
|
||||||
(pes_file_data_[offset + 2] & 1) != 1) {
|
(pes_file_data_[offset + 4] & 1) != 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += 5;
|
offset += 5;
|
||||||
bytes_left -= 5;
|
bytes_left -= 5;
|
||||||
}
|
}
|
||||||
@ -214,6 +216,7 @@ bool VpxPesParser::ParseBcmvHeader(BcmvHeader* header) {
|
|||||||
header->id[2] = pes_file_data_[offset++];
|
header->id[2] = pes_file_data_[offset++];
|
||||||
header->id[3] = pes_file_data_[offset++];
|
header->id[3] = pes_file_data_[offset++];
|
||||||
|
|
||||||
|
header->length = 0;
|
||||||
header->length |= pes_file_data_[offset++] << 24;
|
header->length |= pes_file_data_[offset++] << 24;
|
||||||
header->length |= pes_file_data_[offset++] << 16;
|
header->length |= pes_file_data_[offset++] << 16;
|
||||||
header->length |= pes_file_data_[offset++] << 8;
|
header->length |= pes_file_data_[offset++] << 8;
|
||||||
@ -226,13 +229,14 @@ bool VpxPesParser::ParseBcmvHeader(BcmvHeader* header) {
|
|||||||
if (!header->Valid())
|
if (!header->Valid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// TODO(tomfinegan): Verify data instead of jumping to the next packet.
|
|
||||||
read_pos_ += header->length;
|
|
||||||
parse_state_ = kFindStartCode;
|
parse_state_ = kFindStartCode;
|
||||||
|
read_pos_ += header->size();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VpxPesParser::FindStartCode(std::size_t origin, std::size_t* offset) {
|
bool VpxPesParser::FindStartCode(std::size_t origin,
|
||||||
|
std::size_t* offset) const {
|
||||||
if (read_pos_ + 2 >= pes_file_size_)
|
if (read_pos_ + 2 >= pes_file_size_)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -243,8 +247,7 @@ bool VpxPesParser::FindStartCode(std::size_t origin, std::size_t* offset) {
|
|||||||
const uint8_t* const data = &pes_file_data_[origin];
|
const uint8_t* const data = &pes_file_data_[origin];
|
||||||
for (std::size_t i = 0; i < length - 3; ++i) {
|
for (std::size_t i = 0; i < length - 3; ++i) {
|
||||||
if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1) {
|
if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1) {
|
||||||
*offset = i;
|
*offset = origin + i;
|
||||||
parse_state_ = kParsePesHeader;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -252,11 +255,53 @@ bool VpxPesParser::FindStartCode(std::size_t origin, std::size_t* offset) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VpxPesParser::IsPayloadFragmented(const PesHeader& header) const {
|
||||||
|
return (header.packet_length != 0 &&
|
||||||
|
(header.packet_length - kPesOptionalHeaderSize) !=
|
||||||
|
header.bcmv_header.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VpxPesParser::AccumulateFragmentedPayload(std::size_t pes_packet_length,
|
||||||
|
std::size_t payload_length) {
|
||||||
|
PesHeader fragment_header;
|
||||||
|
const std::size_t first_fragment_length =
|
||||||
|
pes_packet_length - kPesOptionalHeaderSize - kBcmvHeaderSize;
|
||||||
|
for (std::size_t i = 0; i < first_fragment_length; ++i) {
|
||||||
|
payload_.push_back(pes_file_data_[read_pos_ + i]);
|
||||||
|
}
|
||||||
|
read_pos_ += first_fragment_length;
|
||||||
|
parse_state_ = kFindStartCode;
|
||||||
|
|
||||||
|
while (payload_.size() < payload_length) {
|
||||||
|
PesHeader header;
|
||||||
|
std::size_t packet_start_pos = read_pos_;
|
||||||
|
if (!FindStartCode(read_pos_, &packet_start_pos)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
parse_state_ = kParsePesHeader;
|
||||||
|
read_pos_ = packet_start_pos;
|
||||||
|
|
||||||
|
if (!ParsePesHeader(&header)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!ParsePesOptionalHeader(&header.opt_header)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const std::size_t fragment_length =
|
||||||
|
header.packet_length - kPesOptionalHeaderSize;
|
||||||
|
for (std::size_t i = 0; i < fragment_length; ++i) {
|
||||||
|
payload_.push_back(pes_file_data_[read_pos_ + i]);
|
||||||
|
}
|
||||||
|
read_pos_ += fragment_length;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int VpxPesParser::BytesAvailable() const {
|
int VpxPesParser::BytesAvailable() const {
|
||||||
return static_cast<int>(pes_file_data_.size() - read_pos_);
|
return static_cast<int>(pes_file_data_.size() - read_pos_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VpxPesParser::ParseNextPacket(PesHeader* header, VpxFrame* frame) {
|
bool VpxPesParser::ParseNextPacket(PesHeader* header, VideoFrame* frame) {
|
||||||
if (!header || !frame || parse_state_ != kFindStartCode) {
|
if (!header || !frame || parse_state_ != kFindStartCode) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -265,6 +310,7 @@ bool VpxPesParser::ParseNextPacket(PesHeader* header, VpxFrame* frame) {
|
|||||||
if (!FindStartCode(read_pos_, &packet_start_pos)) {
|
if (!FindStartCode(read_pos_, &packet_start_pos)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
parse_state_ = kParsePesHeader;
|
||||||
read_pos_ = packet_start_pos;
|
read_pos_ = packet_start_pos;
|
||||||
|
|
||||||
if (!ParsePesHeader(header)) {
|
if (!ParsePesHeader(header)) {
|
||||||
@ -277,12 +323,46 @@ bool VpxPesParser::ParseNextPacket(PesHeader* header, VpxFrame* frame) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(tomfinegan): Process data payload/store in frame. This requires
|
// BCMV header length includes the length of the BCMVHeader itself. Adjust:
|
||||||
// changes to Webm2Pes:
|
const std::size_t payload_length =
|
||||||
// 1. BCMV header must contain entire frame length, and pes header
|
header->bcmv_header.length - BcmvHeader::size();
|
||||||
// payload size will be what's in the current packet-- parsing code needs
|
|
||||||
// needs to know how to reassemble frames.
|
// Make sure there's enough input data to read the entire frame.
|
||||||
// 2. Random access bit must be set in Adaptation Field for key frames.
|
if (read_pos_ + payload_length > pes_file_data_.size()) {
|
||||||
|
// Need more data.
|
||||||
|
printf("VpxPesParser: Not enough data. Required: %u Available: %u\n",
|
||||||
|
static_cast<unsigned int>(payload_length),
|
||||||
|
static_cast<unsigned int>(pes_file_data_.size() - read_pos_));
|
||||||
|
parse_state_ = kFindStartCode;
|
||||||
|
read_pos_ = packet_start_pos;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsPayloadFragmented(*header)) {
|
||||||
|
if (!AccumulateFragmentedPayload(header->packet_length, payload_length)) {
|
||||||
|
fprintf(stderr, "VpxPesParser: Failed parsing fragmented payload!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (std::size_t i = 0; i < payload_length; ++i) {
|
||||||
|
payload_.push_back(pes_file_data_[read_pos_ + i]);
|
||||||
|
}
|
||||||
|
read_pos_ += payload_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame->buffer().capacity < payload_.size()) {
|
||||||
|
if (frame->Init(payload_.size()) == false) {
|
||||||
|
fprintf(stderr, "VpxPesParser: Out of memory.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
frame->set_nanosecond_pts(Khz90TicksToNanoseconds(header->opt_header.pts));
|
||||||
|
std::memcpy(frame->buffer().data.get(), &payload_[0], payload_.size());
|
||||||
|
frame->SetBufferLength(payload_.size());
|
||||||
|
|
||||||
|
payload_.clear();
|
||||||
|
parse_state_ = kFindStartCode;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/libwebm_util.h"
|
||||||
|
#include "common/video_frame.h"
|
||||||
|
|
||||||
namespace libwebm {
|
namespace libwebm {
|
||||||
|
|
||||||
// Parser for VPx PES. Requires that the _entire_ PES stream can be stored in
|
// Parser for VPx PES. Requires that the _entire_ PES stream can be stored in
|
||||||
@ -29,22 +32,6 @@ class VpxPesParser {
|
|||||||
kParseBcmvHeader,
|
kParseBcmvHeader,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VpxFrame {
|
|
||||||
enum Codec {
|
|
||||||
VP8,
|
|
||||||
VP9,
|
|
||||||
};
|
|
||||||
|
|
||||||
Codec codec = VP9;
|
|
||||||
bool keyframe = false;
|
|
||||||
|
|
||||||
// Frame data.
|
|
||||||
std::vector<std::uint8_t> data;
|
|
||||||
|
|
||||||
// Raw PES PTS.
|
|
||||||
std::int64_t pts = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PesOptionalHeader {
|
struct PesOptionalHeader {
|
||||||
int marker = 0;
|
int marker = 0;
|
||||||
int scrambling = 0;
|
int scrambling = 0;
|
||||||
@ -73,7 +60,9 @@ class VpxPesParser {
|
|||||||
|
|
||||||
bool operator==(const BcmvHeader& other) const;
|
bool operator==(const BcmvHeader& other) const;
|
||||||
|
|
||||||
|
void Reset();
|
||||||
bool Valid() const;
|
bool Valid() const;
|
||||||
|
static std::size_t size() { return 10; }
|
||||||
|
|
||||||
char id[4] = {0};
|
char id[4] = {0};
|
||||||
std::uint32_t length = 0;
|
std::uint32_t length = 0;
|
||||||
@ -90,12 +79,12 @@ class VpxPesParser {
|
|||||||
// Constants for validating known values from input data.
|
// Constants for validating known values from input data.
|
||||||
const std::uint8_t kMinVideoStreamId = 0xE0;
|
const std::uint8_t kMinVideoStreamId = 0xE0;
|
||||||
const std::uint8_t kMaxVideoStreamId = 0xEF;
|
const std::uint8_t kMaxVideoStreamId = 0xEF;
|
||||||
const int kPesHeaderSize = 6;
|
const std::size_t kPesHeaderSize = 6;
|
||||||
const int kPesOptionalHeaderStartOffset = kPesHeaderSize;
|
const std::size_t kPesOptionalHeaderStartOffset = kPesHeaderSize;
|
||||||
const int kPesOptionalHeaderSize = 9;
|
const std::size_t kPesOptionalHeaderSize = 9;
|
||||||
const int kPesOptionalHeaderMarkerValue = 0x2;
|
const std::size_t kPesOptionalHeaderMarkerValue = 0x2;
|
||||||
const int kWebm2PesOptHeaderRemainingSize = 6;
|
const std::size_t kWebm2PesOptHeaderRemainingSize = 6;
|
||||||
const int kBcmvHeaderSize = 10;
|
const std::size_t kBcmvHeaderSize = 10;
|
||||||
|
|
||||||
VpxPesParser() = default;
|
VpxPesParser() = default;
|
||||||
~VpxPesParser() = default;
|
~VpxPesParser() = default;
|
||||||
@ -106,8 +95,8 @@ class VpxPesParser {
|
|||||||
|
|
||||||
// Parses the next packet in the PES. PES header information is stored in
|
// Parses the next packet in the PES. PES header information is stored in
|
||||||
// |header|, and the frame payload is stored in |frame|. Returns true when
|
// |header|, and the frame payload is stored in |frame|. Returns true when
|
||||||
// packet is parsed successfully.
|
// a full frame has been consumed from the PES.
|
||||||
bool ParseNextPacket(PesHeader* header, VpxFrame* frame);
|
bool ParseNextPacket(PesHeader* header, VideoFrame* frame);
|
||||||
|
|
||||||
// PES Header parsing utility functions.
|
// PES Header parsing utility functions.
|
||||||
// PES Header structure:
|
// PES Header structure:
|
||||||
@ -144,10 +133,21 @@ class VpxPesParser {
|
|||||||
// Does not set |offset| value if the end of |pes_file_data_| is reached
|
// Does not set |offset| value if the end of |pes_file_data_| is reached
|
||||||
// without locating a start code.
|
// without locating a start code.
|
||||||
// Note: A start code is the byte sequence 0x00 0x00 0x01.
|
// Note: A start code is the byte sequence 0x00 0x00 0x01.
|
||||||
bool FindStartCode(std::size_t origin, std::size_t* offset);
|
bool FindStartCode(std::size_t origin, std::size_t* offset) const;
|
||||||
|
|
||||||
|
// Returns true when a PES packet containing a BCMV header contains only a
|
||||||
|
// portion of the frame payload length reported by the BCMV header.
|
||||||
|
bool IsPayloadFragmented(const PesHeader& header) const;
|
||||||
|
|
||||||
|
// Parses PES and PES Optional header while accumulating payload data in
|
||||||
|
// |payload_|.
|
||||||
|
// Returns true once all payload fragments have been stored in |payload_|.
|
||||||
|
// Returns false if unable to accumulate full payload.
|
||||||
|
bool AccumulateFragmentedPayload(std::size_t pes_packet_length,
|
||||||
|
std::size_t payload_length);
|
||||||
|
|
||||||
std::size_t pes_file_size_ = 0;
|
std::size_t pes_file_size_ = 0;
|
||||||
PacketData packet_data_;
|
PacketData payload_;
|
||||||
PesFileData pes_file_data_;
|
PesFileData pes_file_data_;
|
||||||
std::size_t read_pos_ = 0;
|
std::size_t read_pos_ = 0;
|
||||||
ParseState parse_state_ = kFindStartCode;
|
ParseState parse_state_ = kFindStartCode;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
// be found in the AUTHORS file in the root of the source tree.
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
#include "m2ts/webm2pes.h"
|
#include "m2ts/webm2pes.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <new>
|
#include <new>
|
||||||
@ -102,10 +103,10 @@ bool PesOptionalHeader::Write(bool write_pts, PacketDataBuffer* buffer) const {
|
|||||||
|
|
||||||
// Second byte of header, fields: has_pts, has_dts, unused fields.
|
// Second byte of header, fields: has_pts, has_dts, unused fields.
|
||||||
*++byte = 0;
|
*++byte = 0;
|
||||||
if (write_pts == true) {
|
if (write_pts == true)
|
||||||
*byte |= has_pts.bits << has_pts.shift;
|
*byte |= has_pts.bits << has_pts.shift;
|
||||||
*byte |= has_dts.bits << has_dts.shift;
|
|
||||||
}
|
*byte |= has_dts.bits << has_dts.shift;
|
||||||
|
|
||||||
// Third byte of header, fields: remaining size of header.
|
// Third byte of header, fields: remaining size of header.
|
||||||
*++byte = remaining_size.bits & 0xff; // Field is 8 bits wide.
|
*++byte = remaining_size.bits & 0xff; // Field is 8 bits wide.
|
||||||
@ -459,7 +460,8 @@ bool Webm2Pes::WritePesPacket(const VideoFrame& frame,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// First packet of new frame. Always include PTS and BCMV header.
|
// First packet of new frame. Always include PTS and BCMV header.
|
||||||
header.packet_length = packet_payload_range.length + BCMVHeader::size();
|
header.packet_length =
|
||||||
|
packet_payload_range.length - extra_bytes + BCMVHeader::size();
|
||||||
if (header.Write(true, packet_data) != true) {
|
if (header.Write(true, packet_data) != true) {
|
||||||
std::fprintf(stderr, "Webm2Pes: packet header write failed.\n");
|
std::fprintf(stderr, "Webm2Pes: packet header write failed.\n");
|
||||||
return false;
|
return false;
|
||||||
@ -472,7 +474,7 @@ bool Webm2Pes::WritePesPacket(const VideoFrame& frame,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Insert the payload at the end of |packet_data|.
|
// Insert the payload at the end of |packet_data|.
|
||||||
const std::uint8_t* payload_start =
|
const std::uint8_t* const payload_start =
|
||||||
frame.buffer().data.get() + packet_payload_range.offset;
|
frame.buffer().data.get() + packet_payload_range.offset;
|
||||||
|
|
||||||
const std::size_t bytes_to_copy = packet_payload_range.length - extra_bytes;
|
const std::size_t bytes_to_copy = packet_payload_range.length - extra_bytes;
|
||||||
@ -498,8 +500,8 @@ bool Webm2Pes::WritePesPacket(const VideoFrame& frame,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
payload_start += bytes_copied;
|
const std::uint8_t* fragment_start = payload_start + bytes_copied;
|
||||||
if (CopyAndEscapeStartCodes(payload_start, extra_bytes_to_copy,
|
if (CopyAndEscapeStartCodes(fragment_start, extra_bytes_to_copy,
|
||||||
packet_data) == false) {
|
packet_data) == false) {
|
||||||
fprintf(stderr, "Webm2Pes: Payload write failed.\n");
|
fprintf(stderr, "Webm2Pes: Payload write failed.\n");
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
Reference in New Issue
Block a user