mkvmuxer: Add DiscardPadding support.
Also a bit of refactoring to remove some duplicate code. Change-Id: Ia3d17461ae5f6275534e06c31f348bdfc4bba169
This commit is contained in:
290
mkvmuxer.cpp
290
mkvmuxer.cpp
@@ -124,7 +124,8 @@ Frame::Frame()
|
|||||||
is_key_(false),
|
is_key_(false),
|
||||||
length_(0),
|
length_(0),
|
||||||
track_number_(0),
|
track_number_(0),
|
||||||
timestamp_(0) {
|
timestamp_(0),
|
||||||
|
discard_padding_(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Frame::~Frame() {
|
Frame::~Frame() {
|
||||||
@@ -1513,6 +1514,21 @@ bool Cluster::AddFrameWithAdditional(const uint8* frame,
|
|||||||
&WriteBlockWithAdditional);
|
&WriteBlockWithAdditional);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Cluster::AddFrameWithDiscardPadding(const uint8* frame,
|
||||||
|
uint64 length,
|
||||||
|
int64 discard_padding,
|
||||||
|
uint64 track_number,
|
||||||
|
uint64 abs_timecode,
|
||||||
|
bool is_key) {
|
||||||
|
return DoWriteBlockWithDiscardPadding(frame,
|
||||||
|
length,
|
||||||
|
discard_padding,
|
||||||
|
track_number,
|
||||||
|
abs_timecode,
|
||||||
|
is_key ? 1 : 0,
|
||||||
|
&WriteBlockWithDiscardPadding);
|
||||||
|
}
|
||||||
|
|
||||||
bool Cluster::AddMetadata(const uint8* frame,
|
bool Cluster::AddMetadata(const uint8* frame,
|
||||||
uint64 length,
|
uint64 length,
|
||||||
uint64 track_number,
|
uint64 track_number,
|
||||||
@@ -1559,6 +1575,42 @@ uint64 Cluster::Size() const {
|
|||||||
return element_size;
|
return element_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
bool Cluster::PreWriteBlock(Type* write_function) {
|
||||||
|
if (write_function == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (finalized_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!header_written_) {
|
||||||
|
if (!WriteClusterHeader())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cluster::PostWriteBlock(uint64 element_size) {
|
||||||
|
AddPayloadSize(element_size);
|
||||||
|
++blocks_added_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Cluster::IsValidTrackNumber(uint64 track_number) const {
|
||||||
|
return (track_number > 0 && track_number <= 0x7E);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 Cluster::GetRelativeTimecode(int64 abs_timecode) const {
|
||||||
|
const int64 cluster_timecode = this->Cluster::timecode();
|
||||||
|
const int64 rel_timecode =
|
||||||
|
static_cast<int64>(abs_timecode) - cluster_timecode;
|
||||||
|
|
||||||
|
if (rel_timecode < 0 || rel_timecode > kMaxBlockTimecode)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return rel_timecode;
|
||||||
|
}
|
||||||
|
|
||||||
bool Cluster::DoWriteBlock(
|
bool Cluster::DoWriteBlock(
|
||||||
const uint8* frame,
|
const uint8* frame,
|
||||||
uint64 length,
|
uint64 length,
|
||||||
@@ -1569,46 +1621,26 @@ bool Cluster::DoWriteBlock(
|
|||||||
if (frame == NULL || length == 0)
|
if (frame == NULL || length == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// To simplify things, we require that there be fewer than 127
|
if (!IsValidTrackNumber(track_number))
|
||||||
// tracks -- this allows us to serialize the track number value for
|
|
||||||
// a stream using a single byte, per the Matroska encoding.
|
|
||||||
|
|
||||||
if (track_number == 0 || track_number > 0x7E)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const int64 cluster_timecode = this->Cluster::timecode();
|
const int64 rel_timecode = GetRelativeTimecode(abs_timecode);
|
||||||
const int64 rel_timecode =
|
|
||||||
static_cast<int64>(abs_timecode) - cluster_timecode;
|
|
||||||
|
|
||||||
if (rel_timecode < 0)
|
if (rel_timecode < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (rel_timecode > kMaxBlockTimecode)
|
if (!PreWriteBlock(write_block))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (write_block == NULL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (finalized_)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!header_written_)
|
|
||||||
if (!WriteClusterHeader())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const uint64 element_size = (*write_block)(writer_,
|
const uint64 element_size = (*write_block)(writer_,
|
||||||
frame,
|
frame,
|
||||||
length,
|
length,
|
||||||
track_number,
|
track_number,
|
||||||
rel_timecode,
|
rel_timecode,
|
||||||
generic_arg);
|
generic_arg);
|
||||||
|
|
||||||
if (element_size == 0)
|
if (element_size == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
AddPayloadSize(element_size);
|
PostWriteBlock(element_size);
|
||||||
blocks_added_++;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1626,33 +1658,16 @@ bool Cluster::DoWriteBlockWithAdditional(
|
|||||||
additional == NULL || additional_length == 0)
|
additional == NULL || additional_length == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// To simplify things, we require that there be fewer than 127
|
if (!IsValidTrackNumber(track_number))
|
||||||
// tracks -- this allows us to serialize the track number value for
|
|
||||||
// a stream using a single byte, per the Matroska encoding.
|
|
||||||
|
|
||||||
if (track_number == 0 || track_number > 0x7E)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const int64 cluster_timecode = this->Cluster::timecode();
|
const int64 rel_timecode = GetRelativeTimecode(abs_timecode);
|
||||||
const int64 rel_timecode =
|
|
||||||
static_cast<int64>(abs_timecode) - cluster_timecode;
|
|
||||||
|
|
||||||
if (rel_timecode < 0)
|
if (rel_timecode < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (rel_timecode > kMaxBlockTimecode)
|
if (!PreWriteBlock(write_block))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (write_block == NULL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (finalized_)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!header_written_)
|
|
||||||
if (!WriteClusterHeader())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const uint64 element_size = (*write_block)(writer_,
|
const uint64 element_size = (*write_block)(writer_,
|
||||||
frame,
|
frame,
|
||||||
length,
|
length,
|
||||||
@@ -1662,13 +1677,45 @@ bool Cluster::DoWriteBlockWithAdditional(
|
|||||||
track_number,
|
track_number,
|
||||||
rel_timecode,
|
rel_timecode,
|
||||||
generic_arg);
|
generic_arg);
|
||||||
|
|
||||||
if (element_size == 0)
|
if (element_size == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
AddPayloadSize(element_size);
|
PostWriteBlock(element_size);
|
||||||
blocks_added_++;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Cluster::DoWriteBlockWithDiscardPadding(
|
||||||
|
const uint8* frame,
|
||||||
|
uint64 length,
|
||||||
|
int64 discard_padding,
|
||||||
|
uint64 track_number,
|
||||||
|
uint64 abs_timecode,
|
||||||
|
uint64 generic_arg,
|
||||||
|
WriteBlockDiscardPadding write_block) {
|
||||||
|
if (frame == NULL || length == 0 || discard_padding <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!IsValidTrackNumber(track_number))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const int64 rel_timecode = GetRelativeTimecode(abs_timecode);
|
||||||
|
if (rel_timecode < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!PreWriteBlock(write_block))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const uint64 element_size = (*write_block)(writer_,
|
||||||
|
frame,
|
||||||
|
length,
|
||||||
|
discard_padding,
|
||||||
|
track_number,
|
||||||
|
rel_timecode,
|
||||||
|
generic_arg);
|
||||||
|
if (element_size == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
PostWriteBlock(element_size);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2348,8 +2395,8 @@ bool Segment::AddFrame(const uint8* frame,
|
|||||||
// audio that is associated with the start time of a video key-frame is
|
// audio that is associated with the start time of a video key-frame is
|
||||||
// muxed into the same cluster.
|
// muxed into the same cluster.
|
||||||
if (has_video_ && tracks_.TrackIsAudio(track_number) && !force_new_cluster_) {
|
if (has_video_ && tracks_.TrackIsAudio(track_number) && !force_new_cluster_) {
|
||||||
Frame* const new_frame = new Frame();
|
Frame* const new_frame = new (std::nothrow) Frame();
|
||||||
if (!new_frame->Init(frame, length))
|
if (new_frame == NULL || !new_frame->Init(frame, length))
|
||||||
return false;
|
return false;
|
||||||
new_frame->set_track_number(track_number);
|
new_frame->set_track_number(track_number);
|
||||||
new_frame->set_timestamp(timestamp);
|
new_frame->set_timestamp(timestamp);
|
||||||
@@ -2400,7 +2447,7 @@ bool Segment::AddFrameWithAdditional(const uint8* frame,
|
|||||||
uint64 track_number,
|
uint64 track_number,
|
||||||
uint64 timestamp,
|
uint64 timestamp,
|
||||||
bool is_key) {
|
bool is_key) {
|
||||||
if (!frame || !additional)
|
if (frame == NULL || additional == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!CheckHeaderInfo())
|
if (!CheckHeaderInfo())
|
||||||
@@ -2414,8 +2461,8 @@ bool Segment::AddFrameWithAdditional(const uint8* frame,
|
|||||||
// audio that is associated with the start time of a video key-frame is
|
// audio that is associated with the start time of a video key-frame is
|
||||||
// muxed into the same cluster.
|
// muxed into the same cluster.
|
||||||
if (has_video_ && tracks_.TrackIsAudio(track_number) && !force_new_cluster_) {
|
if (has_video_ && tracks_.TrackIsAudio(track_number) && !force_new_cluster_) {
|
||||||
Frame* const new_frame = new Frame();
|
Frame* const new_frame = new (std::nothrow) Frame();
|
||||||
if (!new_frame->Init(frame, length))
|
if (new_frame == NULL || !new_frame->Init(frame, length))
|
||||||
return false;
|
return false;
|
||||||
new_frame->set_track_number(track_number);
|
new_frame->set_track_number(track_number);
|
||||||
new_frame->set_timestamp(timestamp);
|
new_frame->set_timestamp(timestamp);
|
||||||
@@ -2427,6 +2474,74 @@ bool Segment::AddFrameWithAdditional(const uint8* frame,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!DoNewClusterProcessing(track_number, timestamp, is_key))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (cluster_list_size_ < 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Cluster* const cluster = cluster_list_[cluster_list_size_ - 1];
|
||||||
|
if (cluster == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const uint64 timecode_scale = segment_info_.timecode_scale();
|
||||||
|
const uint64 abs_timecode = timestamp / timecode_scale;
|
||||||
|
|
||||||
|
if (!cluster->AddFrameWithAdditional(frame,
|
||||||
|
length,
|
||||||
|
additional,
|
||||||
|
additional_length,
|
||||||
|
add_id,
|
||||||
|
track_number,
|
||||||
|
abs_timecode,
|
||||||
|
is_key))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (new_cuepoint_ && cues_track_ == track_number) {
|
||||||
|
if (!AddCuePoint(timestamp, cues_track_))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timestamp > last_timestamp_)
|
||||||
|
last_timestamp_ = timestamp;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Segment::AddFrameWithDiscardPadding(const uint8* frame,
|
||||||
|
uint64 length,
|
||||||
|
int64 discard_padding,
|
||||||
|
uint64 track_number,
|
||||||
|
uint64 timestamp,
|
||||||
|
bool is_key) {
|
||||||
|
if (frame == NULL || discard_padding <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!CheckHeaderInfo())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check for non-monotonically increasing timestamps.
|
||||||
|
if (timestamp < last_timestamp_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If the segment has a video track hold onto audio frames to make sure the
|
||||||
|
// audio that is associated with the start time of a video key-frame is
|
||||||
|
// muxed into the same cluster.
|
||||||
|
if (has_video_ && tracks_.TrackIsAudio(track_number) && !force_new_cluster_) {
|
||||||
|
Frame* const new_frame = new (std::nothrow) Frame();
|
||||||
|
if (new_frame == NULL || !new_frame->Init(frame, length))
|
||||||
|
return false;
|
||||||
|
new_frame->set_track_number(track_number);
|
||||||
|
new_frame->set_timestamp(timestamp);
|
||||||
|
new_frame->set_is_key(is_key);
|
||||||
|
new_frame->set_discard_padding(discard_padding);
|
||||||
|
|
||||||
|
if (!QueueFrame(new_frame))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!DoNewClusterProcessing(track_number, timestamp, is_key))
|
if (!DoNewClusterProcessing(track_number, timestamp, is_key))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -2440,15 +2555,13 @@ bool Segment::AddFrameWithAdditional(const uint8* frame,
|
|||||||
const uint64 timecode_scale = segment_info_.timecode_scale();
|
const uint64 timecode_scale = segment_info_.timecode_scale();
|
||||||
const uint64 abs_timecode = timestamp / timecode_scale;
|
const uint64 abs_timecode = timestamp / timecode_scale;
|
||||||
|
|
||||||
if (!cluster->AddFrameWithAdditional(frame,
|
if (!cluster->AddFrameWithDiscardPadding(frame, length,
|
||||||
length,
|
discard_padding,
|
||||||
additional,
|
track_number,
|
||||||
additional_length,
|
abs_timecode,
|
||||||
add_id,
|
is_key)) {
|
||||||
track_number,
|
|
||||||
abs_timecode,
|
|
||||||
is_key))
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (new_cuepoint_ && cues_track_ == track_number) {
|
if (new_cuepoint_ && cues_track_ == track_number) {
|
||||||
if (!AddCuePoint(timestamp, cues_track_))
|
if (!AddCuePoint(timestamp, cues_track_))
|
||||||
@@ -2523,6 +2636,12 @@ bool Segment::AddGenericFrame(const Frame* frame) {
|
|||||||
frame->track_number(),
|
frame->track_number(),
|
||||||
frame->timestamp(),
|
frame->timestamp(),
|
||||||
frame->is_key());
|
frame->is_key());
|
||||||
|
} else if (frame->discard_padding() > 0) {
|
||||||
|
return AddFrameWithDiscardPadding(frame->frame(), frame->length(),
|
||||||
|
frame->discard_padding(),
|
||||||
|
frame->track_number(),
|
||||||
|
frame->timestamp(),
|
||||||
|
frame->is_key());
|
||||||
} else {
|
} else {
|
||||||
return AddFrame(frame->frame(),
|
return AddFrame(frame->frame(),
|
||||||
frame->length(),
|
frame->length(),
|
||||||
@@ -3006,12 +3125,24 @@ int Segment::WriteFramesAll() {
|
|||||||
const uint64 frame_timestamp = frame->timestamp(); // ns
|
const uint64 frame_timestamp = frame->timestamp(); // ns
|
||||||
const uint64 frame_timecode = frame_timestamp / timecode_scale;
|
const uint64 frame_timecode = frame_timestamp / timecode_scale;
|
||||||
|
|
||||||
if (!cluster->AddFrame(frame->frame(),
|
if (frame->discard_padding() > 0) {
|
||||||
frame->length(),
|
if (!cluster->AddFrameWithDiscardPadding(frame->frame(),
|
||||||
frame->track_number(),
|
frame->length(),
|
||||||
frame_timecode,
|
frame->discard_padding(),
|
||||||
frame->is_key()))
|
frame->track_number(),
|
||||||
return -1;
|
frame_timecode,
|
||||||
|
frame->is_key())) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!cluster->AddFrame(frame->frame(),
|
||||||
|
frame->length(),
|
||||||
|
frame->track_number(),
|
||||||
|
frame_timecode,
|
||||||
|
frame->is_key())) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (new_cuepoint_ && cues_track_ == frame->track_number()) {
|
if (new_cuepoint_ && cues_track_ == frame->track_number()) {
|
||||||
if (!AddCuePoint(frame_timestamp, cues_track_))
|
if (!AddCuePoint(frame_timestamp, cues_track_))
|
||||||
@@ -3057,13 +3188,26 @@ bool Segment::WriteFramesLessThan(uint64 timestamp) {
|
|||||||
const Frame* const frame_prev = frames_[i-1];
|
const Frame* const frame_prev = frames_[i-1];
|
||||||
const uint64 frame_timestamp = frame_prev->timestamp();
|
const uint64 frame_timestamp = frame_prev->timestamp();
|
||||||
const uint64 frame_timecode = frame_timestamp / timecode_scale;
|
const uint64 frame_timecode = frame_timestamp / timecode_scale;
|
||||||
|
const int64 discard_padding = frame_prev->discard_padding();
|
||||||
|
|
||||||
if (!cluster->AddFrame(frame_prev->frame(),
|
if (discard_padding > 0) {
|
||||||
frame_prev->length(),
|
if (!cluster->AddFrameWithDiscardPadding(frame_prev->frame(),
|
||||||
frame_prev->track_number(),
|
frame_prev->length(),
|
||||||
frame_timecode,
|
discard_padding,
|
||||||
frame_prev->is_key()))
|
frame_prev->track_number(),
|
||||||
return false;
|
frame_timecode,
|
||||||
|
frame_prev->is_key())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!cluster->AddFrame(frame_prev->frame(),
|
||||||
|
frame_prev->length(),
|
||||||
|
frame_prev->track_number(),
|
||||||
|
frame_timecode,
|
||||||
|
frame_prev->is_key())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (new_cuepoint_ && cues_track_ == frame_prev->track_number()) {
|
if (new_cuepoint_ && cues_track_ == frame_prev->track_number()) {
|
||||||
if (!AddCuePoint(frame_timestamp, cues_track_))
|
if (!AddCuePoint(frame_timestamp, cues_track_))
|
||||||
|
|||||||
81
mkvmuxer.hpp
81
mkvmuxer.hpp
@@ -90,6 +90,10 @@ class Frame {
|
|||||||
uint64 track_number() const { return track_number_; }
|
uint64 track_number() const { return track_number_; }
|
||||||
void set_timestamp(uint64 timestamp) { timestamp_ = timestamp; }
|
void set_timestamp(uint64 timestamp) { timestamp_ = timestamp; }
|
||||||
uint64 timestamp() const { return timestamp_; }
|
uint64 timestamp() const { return timestamp_; }
|
||||||
|
void set_discard_padding(uint64 discard_padding) {
|
||||||
|
discard_padding_ = discard_padding;
|
||||||
|
}
|
||||||
|
uint64 discard_padding() const { return discard_padding_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Id of the Additional data.
|
// Id of the Additional data.
|
||||||
@@ -118,6 +122,9 @@ class Frame {
|
|||||||
|
|
||||||
// Timestamp of the data in nanoseconds.
|
// Timestamp of the data in nanoseconds.
|
||||||
uint64 timestamp_;
|
uint64 timestamp_;
|
||||||
|
|
||||||
|
// Discard padding for the frame.
|
||||||
|
int64 discard_padding_;
|
||||||
};
|
};
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
@@ -745,6 +752,24 @@ class Cluster {
|
|||||||
uint64 abs_timecode,
|
uint64 abs_timecode,
|
||||||
bool is_key);
|
bool is_key);
|
||||||
|
|
||||||
|
// Adds a frame to be output in the file. The frame is written out through
|
||||||
|
// |writer_| if successful. Returns true on success.
|
||||||
|
// Inputs:
|
||||||
|
// frame: Pointer to the data.
|
||||||
|
// length: Length of the data.
|
||||||
|
// discard_padding: DiscardPadding element value.
|
||||||
|
// track_number: Track to add the data to. Value returned by Add track
|
||||||
|
// functions. The range of allowed values is [1, 126].
|
||||||
|
// abs_timecode: Absolute (not relative to cluster) timestamp of the
|
||||||
|
// frame, expressed in timecode units.
|
||||||
|
// is_key: Flag telling whether or not this frame is a key frame.
|
||||||
|
bool AddFrameWithDiscardPadding(const uint8* frame,
|
||||||
|
uint64 length,
|
||||||
|
int64 discard_padding,
|
||||||
|
uint64 track_number,
|
||||||
|
uint64 abs_timecode,
|
||||||
|
bool is_key);
|
||||||
|
|
||||||
// Writes a frame of metadata to the output medium; returns true on
|
// Writes a frame of metadata to the output medium; returns true on
|
||||||
// success.
|
// success.
|
||||||
// Inputs:
|
// Inputs:
|
||||||
@@ -803,6 +828,35 @@ class Cluster {
|
|||||||
int64 timecode,
|
int64 timecode,
|
||||||
uint64 is_key);
|
uint64 is_key);
|
||||||
|
|
||||||
|
// Signature that matches WriteBlockWithDiscardPadding
|
||||||
|
// in the muxer utilities package.
|
||||||
|
typedef uint64 (*WriteBlockDiscardPadding)(IMkvWriter* writer,
|
||||||
|
const uint8* data,
|
||||||
|
uint64 length,
|
||||||
|
int64 discard_padding,
|
||||||
|
uint64 track_number,
|
||||||
|
int64 timecode,
|
||||||
|
uint64 is_key);
|
||||||
|
|
||||||
|
// Utility method that confirms that blocks can still be added, and that the
|
||||||
|
// cluster header has been written. Used by |DoWriteBlock*|. Returns true
|
||||||
|
// when successful.
|
||||||
|
template <typename Type>
|
||||||
|
bool PreWriteBlock(Type* write_function);
|
||||||
|
|
||||||
|
// Utility method used by the |DoWriteBlock*| methods that handles the book
|
||||||
|
// keeping required after each block is written.
|
||||||
|
void PostWriteBlock(uint64 element_size);
|
||||||
|
|
||||||
|
// To simplify things, we require that there be fewer than 127
|
||||||
|
// tracks -- this allows us to serialize the track number value for
|
||||||
|
// a stream using a single byte, per the Matroska encoding.
|
||||||
|
bool IsValidTrackNumber(uint64 track_number) const;
|
||||||
|
|
||||||
|
// Given |abs_timecode|, calculates timecode relative to most recent timecode.
|
||||||
|
// Returns -1 on failure, or a relative timecode.
|
||||||
|
int64 GetRelativeTimecode(int64 abs_timecode) const;
|
||||||
|
|
||||||
// Used to implement AddFrame and AddMetadata.
|
// Used to implement AddFrame and AddMetadata.
|
||||||
bool DoWriteBlock(const uint8* frame,
|
bool DoWriteBlock(const uint8* frame,
|
||||||
uint64 length,
|
uint64 length,
|
||||||
@@ -822,6 +876,15 @@ class Cluster {
|
|||||||
uint64 generic_arg,
|
uint64 generic_arg,
|
||||||
WriteBlockAdditional write_block);
|
WriteBlockAdditional write_block);
|
||||||
|
|
||||||
|
// Used to implement AddFrameWithDiscardPadding
|
||||||
|
bool DoWriteBlockWithDiscardPadding(const uint8* frame,
|
||||||
|
uint64 length,
|
||||||
|
int64 discard_padding,
|
||||||
|
uint64 track_number,
|
||||||
|
uint64 absolute_timecode,
|
||||||
|
uint64 generic_arg,
|
||||||
|
WriteBlockDiscardPadding write_block);
|
||||||
|
|
||||||
// Outputs the Cluster header to |writer_|. Returns true on success.
|
// Outputs the Cluster header to |writer_|. Returns true on success.
|
||||||
bool WriteClusterHeader();
|
bool WriteClusterHeader();
|
||||||
|
|
||||||
@@ -1055,6 +1118,24 @@ class Segment {
|
|||||||
uint64 timestamp,
|
uint64 timestamp,
|
||||||
bool is_key);
|
bool is_key);
|
||||||
|
|
||||||
|
// Writes a frame with DiscardPadding to the output medium; returns true on
|
||||||
|
// success.
|
||||||
|
// Inputs:
|
||||||
|
// frame: Pointer to the data.
|
||||||
|
// length: Length of the data.
|
||||||
|
// discard_padding: DiscardPadding element value.
|
||||||
|
// track_number: Track to add the data to. Value returned by Add track
|
||||||
|
// functions.
|
||||||
|
// timestamp: Absolute timestamp of the frame, expressed in nanosecond
|
||||||
|
// units.
|
||||||
|
// is_key: Flag telling whether or not this frame is a key frame.
|
||||||
|
bool AddFrameWithDiscardPadding(const uint8* frame,
|
||||||
|
uint64 length,
|
||||||
|
int64 discard_padding,
|
||||||
|
uint64 track_number,
|
||||||
|
uint64 timestamp,
|
||||||
|
bool is_key);
|
||||||
|
|
||||||
// Writes a Frame to the output medium. Chooses the correct way of writing
|
// Writes a Frame to the output medium. Chooses the correct way of writing
|
||||||
// the frame (Block vs SimpleBlock) based on the parameters passed.
|
// the frame (Block vs SimpleBlock) based on the parameters passed.
|
||||||
// Inputs:
|
// Inputs:
|
||||||
|
|||||||
@@ -74,6 +74,10 @@ uint64 EbmlMasterElementSize(uint64 type, uint64 value) {
|
|||||||
return ebml_size;
|
return ebml_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64 EbmlElementSize(uint64 type, int64 value) {
|
||||||
|
return EbmlElementSize(type, static_cast<uint64>(value));
|
||||||
|
}
|
||||||
|
|
||||||
uint64 EbmlElementSize(uint64 type, uint64 value) {
|
uint64 EbmlElementSize(uint64 type, uint64 value) {
|
||||||
// Size of EBML ID
|
// Size of EBML ID
|
||||||
int32 ebml_size = GetUIntSize(type);
|
int32 ebml_size = GetUIntSize(type);
|
||||||
@@ -464,7 +468,8 @@ uint64 WriteMetadataBlock(IMkvWriter* writer,
|
|||||||
return blockg_elem_size;
|
return blockg_elem_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes a WebM Block with Additional. The structure is as follows
|
// Writes a WebM BlockGroup with BlockAdditional data. The structure is as
|
||||||
|
// follows:
|
||||||
// Indentation shows sub-levels
|
// Indentation shows sub-levels
|
||||||
// BlockGroup
|
// BlockGroup
|
||||||
// Block
|
// Block
|
||||||
@@ -553,6 +558,70 @@ uint64 WriteBlockWithAdditional(IMkvWriter* writer,
|
|||||||
return block_group_elem_size;
|
return block_group_elem_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Writes a WebM BlockGroup with DiscardPadding. The structure is as follows:
|
||||||
|
// Indentation shows sub-levels
|
||||||
|
// BlockGroup
|
||||||
|
// Block
|
||||||
|
// Data
|
||||||
|
// DiscardPadding
|
||||||
|
uint64 WriteBlockWithDiscardPadding(IMkvWriter* writer,
|
||||||
|
const uint8* data,
|
||||||
|
uint64 length,
|
||||||
|
int64 discard_padding,
|
||||||
|
uint64 track_number,
|
||||||
|
int64 timecode,
|
||||||
|
uint64 is_key) {
|
||||||
|
if (!data || length < 1 || discard_padding <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const uint64 block_payload_size = 4 + length;
|
||||||
|
const uint64 block_elem_size = EbmlMasterElementSize(kMkvBlock,
|
||||||
|
block_payload_size) +
|
||||||
|
block_payload_size;
|
||||||
|
const uint64 discard_padding_elem_size = EbmlElementSize(kMkvDiscardPadding,
|
||||||
|
discard_padding);
|
||||||
|
const uint64 block_group_payload_size = block_elem_size +
|
||||||
|
discard_padding_elem_size;
|
||||||
|
const uint64 block_group_elem_size = EbmlMasterElementSize(
|
||||||
|
kMkvBlockGroup,
|
||||||
|
block_group_payload_size) +
|
||||||
|
block_group_payload_size;
|
||||||
|
|
||||||
|
if (!WriteEbmlMasterElement(writer, kMkvBlockGroup,
|
||||||
|
block_group_payload_size))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!WriteEbmlMasterElement(writer, kMkvBlock, block_payload_size))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (WriteUInt(writer, track_number))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (SerializeInt(writer, timecode, 2))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint64 flags = 0;
|
||||||
|
if (is_key)
|
||||||
|
flags |= 0x80;
|
||||||
|
if (SerializeInt(writer, flags, 1))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (writer->Write(data, static_cast<uint32>(length)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (WriteID(writer, kMkvDiscardPadding))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const uint64 size = GetUIntSize(discard_padding);
|
||||||
|
if (WriteUInt(writer, size))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (SerializeInt(writer, discard_padding, static_cast<int32>(size)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return block_group_elem_size;
|
||||||
|
}
|
||||||
|
|
||||||
uint64 WriteVoidElement(IMkvWriter* writer, uint64 size) {
|
uint64 WriteVoidElement(IMkvWriter* writer, uint64 size) {
|
||||||
if (!writer)
|
if (!writer)
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size);
|
|||||||
int32 GetUIntSize(uint64 value);
|
int32 GetUIntSize(uint64 value);
|
||||||
int32 GetCodedUIntSize(uint64 value);
|
int32 GetCodedUIntSize(uint64 value);
|
||||||
uint64 EbmlMasterElementSize(uint64 type, uint64 value);
|
uint64 EbmlMasterElementSize(uint64 type, uint64 value);
|
||||||
|
uint64 EbmlElementSize(uint64 type, int64 value);
|
||||||
uint64 EbmlElementSize(uint64 type, uint64 value);
|
uint64 EbmlElementSize(uint64 type, uint64 value);
|
||||||
uint64 EbmlElementSize(uint64 type, float value);
|
uint64 EbmlElementSize(uint64 type, float value);
|
||||||
uint64 EbmlElementSize(uint64 type, const char* value);
|
uint64 EbmlElementSize(uint64 type, const char* value);
|
||||||
@@ -113,6 +114,25 @@ uint64 WriteBlockWithAdditional(IMkvWriter* writer,
|
|||||||
int64 timecode,
|
int64 timecode,
|
||||||
uint64 is_key);
|
uint64 is_key);
|
||||||
|
|
||||||
|
// Output an Mkv Block with a DiscardPadding element.
|
||||||
|
// Inputs:
|
||||||
|
// data: Pointer to the data.
|
||||||
|
// length: Length of the data.
|
||||||
|
// discard_padding: DiscardPadding value.
|
||||||
|
// track_number: Track to add the data to. Value returned by Add track
|
||||||
|
// functions. Only values in the range [1, 126] are
|
||||||
|
// permitted.
|
||||||
|
// timecode: Relative timecode of the Block. Only values in the
|
||||||
|
// range [0, 2^15) are permitted.
|
||||||
|
// is_key: Non-zero value specifies that frame is a key frame.
|
||||||
|
uint64 WriteBlockWithDiscardPadding(IMkvWriter* writer,
|
||||||
|
const uint8* data,
|
||||||
|
uint64 length,
|
||||||
|
int64 discard_padding,
|
||||||
|
uint64 track_number,
|
||||||
|
int64 timecode,
|
||||||
|
uint64 is_key);
|
||||||
|
|
||||||
// Output a void element. |size| must be the entire size in bytes that will be
|
// Output a void element. |size| must be the entire size in bytes that will be
|
||||||
// void. The function will calculate the size of the void header and subtract
|
// void. The function will calculate the size of the void header and subtract
|
||||||
// it from |size|.
|
// it from |size|.
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include "sample_muxer_metadata.h"
|
#include "sample_muxer_metadata.h"
|
||||||
|
|
||||||
|
using mkvmuxer::int64;
|
||||||
using mkvmuxer::uint64;
|
using mkvmuxer::uint64;
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
@@ -475,6 +476,7 @@ int main(int argc, char* argv[]) {
|
|||||||
(track_type == Track::kVideo && output_video)) {
|
(track_type == Track::kVideo && output_video)) {
|
||||||
const int frame_count = block->GetFrameCount();
|
const int frame_count = block->GetFrameCount();
|
||||||
const bool is_key = block->IsKey();
|
const bool is_key = block->IsKey();
|
||||||
|
const int64 discard_padding = block->GetDiscardPadding();
|
||||||
|
|
||||||
for (int i = 0; i < frame_count; ++i) {
|
for (int i = 0; i < frame_count; ++i) {
|
||||||
const mkvparser::Block::Frame& frame = block->GetFrame(i);
|
const mkvparser::Block::Frame& frame = block->GetFrame(i);
|
||||||
@@ -494,11 +496,21 @@ int main(int argc, char* argv[]) {
|
|||||||
if (track_type == Track::kAudio)
|
if (track_type == Track::kAudio)
|
||||||
track_num = aud_track;
|
track_num = aud_track;
|
||||||
|
|
||||||
if (!muxer_segment.AddFrame(data,
|
bool frame_added = false;
|
||||||
frame.len,
|
if (discard_padding) {
|
||||||
track_num,
|
frame_added =
|
||||||
time_ns,
|
muxer_segment.AddFrameWithDiscardPadding(data, frame.len,
|
||||||
is_key)) {
|
discard_padding,
|
||||||
|
track_num,
|
||||||
|
time_ns,
|
||||||
|
is_key);
|
||||||
|
} else {
|
||||||
|
frame_added = muxer_segment.AddFrame(data, frame.len,
|
||||||
|
track_num,
|
||||||
|
time_ns,
|
||||||
|
is_key);
|
||||||
|
}
|
||||||
|
if (!frame_added) {
|
||||||
printf("\n Could not add frame.\n");
|
printf("\n Could not add frame.\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ enum MkvId {
|
|||||||
kMkvBlockMore = 0xA6,
|
kMkvBlockMore = 0xA6,
|
||||||
kMkvBlockAddID = 0xEE,
|
kMkvBlockAddID = 0xEE,
|
||||||
kMkvBlockAdditional = 0xA5,
|
kMkvBlockAdditional = 0xA5,
|
||||||
|
kMkvDiscardPadding = 0x75A2,
|
||||||
//Track
|
//Track
|
||||||
kMkvTracks = 0x1654AE6B,
|
kMkvTracks = 0x1654AE6B,
|
||||||
kMkvTrackEntry = 0xAE,
|
kMkvTrackEntry = 0xAE,
|
||||||
|
|||||||
Reference in New Issue
Block a user