Merge "mkvmuxer: Write Block key frames correctly."
This commit is contained in:
commit
4928b0bd5f
38
mkvmuxer.cpp
38
mkvmuxer.cpp
@ -131,7 +131,9 @@ Frame::Frame()
|
||||
length_(0),
|
||||
track_number_(0),
|
||||
timestamp_(0),
|
||||
discard_padding_(0) {}
|
||||
discard_padding_(0),
|
||||
reference_block_timestamp_(0),
|
||||
reference_block_timestamp_set_(false) {}
|
||||
|
||||
Frame::~Frame() {
|
||||
delete[] frame_;
|
||||
@ -204,6 +206,9 @@ bool Frame::IsValid() const {
|
||||
if (track_number_ == 0 || track_number_ > kMaxTrackNumber) {
|
||||
return false;
|
||||
}
|
||||
if (!CanBeSimpleBlock() && !is_key_ && !reference_block_timestamp_set_) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -211,6 +216,11 @@ bool Frame::CanBeSimpleBlock() const {
|
||||
return additional_ == NULL && discard_padding_ == 0 && duration_ == 0;
|
||||
}
|
||||
|
||||
void Frame::set_reference_block_timestamp(int64 reference_block_timestamp) {
|
||||
reference_block_timestamp_ = reference_block_timestamp;
|
||||
reference_block_timestamp_set_ = true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CuePoint Class
|
||||
@ -2426,6 +2436,20 @@ bool Segment::AddGenericFrame(const Frame* frame) {
|
||||
if (!cluster)
|
||||
return false;
|
||||
|
||||
// If the Frame is not a SimpleBlock, then set the reference_block_timestamp
|
||||
// if it is not set already.
|
||||
bool frame_created = false;
|
||||
if (!frame->CanBeSimpleBlock() && !frame->is_key() &&
|
||||
!frame->reference_block_timestamp_set()) {
|
||||
Frame* const new_frame = new (std::nothrow) Frame();
|
||||
if (!new_frame->CopyFrom(*frame))
|
||||
return false;
|
||||
new_frame->set_reference_block_timestamp(
|
||||
last_track_timestamp_[frame->track_number() - 1]);
|
||||
frame = new_frame;
|
||||
frame_created = true;
|
||||
}
|
||||
|
||||
if (!cluster->AddFrame(frame))
|
||||
return false;
|
||||
|
||||
@ -2435,8 +2459,12 @@ bool Segment::AddGenericFrame(const Frame* frame) {
|
||||
}
|
||||
|
||||
last_timestamp_ = frame->timestamp();
|
||||
last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
|
||||
last_block_duration_ = frame->duration();
|
||||
|
||||
if (frame_created)
|
||||
delete frame;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2947,8 +2975,10 @@ int Segment::WriteFramesAll() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (frame_timestamp > last_timestamp_)
|
||||
if (frame_timestamp > last_timestamp_) {
|
||||
last_timestamp_ = frame_timestamp;
|
||||
last_track_timestamp_[frame->track_number() - 1] = frame_timestamp;
|
||||
}
|
||||
|
||||
delete frame;
|
||||
frame = NULL;
|
||||
@ -3010,8 +3040,10 @@ bool Segment::WriteFramesLessThan(uint64 timestamp) {
|
||||
}
|
||||
|
||||
++shift_left;
|
||||
if (frame_timestamp > last_timestamp_)
|
||||
if (frame_timestamp > last_timestamp_) {
|
||||
last_timestamp_ = frame_timestamp;
|
||||
last_track_timestamp_[frame_prev->track_number() - 1] = frame_timestamp;
|
||||
}
|
||||
|
||||
delete frame_prev;
|
||||
}
|
||||
|
16
mkvmuxer.hpp
16
mkvmuxer.hpp
@ -23,6 +23,8 @@ namespace mkvmuxer {
|
||||
class MkvWriter;
|
||||
class Segment;
|
||||
|
||||
const uint64 kMaxTrackNumber = 126;
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Interface used by the mkvmuxer to write out the Mkv data.
|
||||
class IMkvWriter {
|
||||
@ -108,6 +110,11 @@ class Frame {
|
||||
discard_padding_ = discard_padding;
|
||||
}
|
||||
int64 discard_padding() const { return discard_padding_; }
|
||||
void set_reference_block_timestamp(int64 reference_block_timestamp);
|
||||
int64 reference_block_timestamp() const { return reference_block_timestamp_; }
|
||||
bool reference_block_timestamp_set() const {
|
||||
return reference_block_timestamp_set_;
|
||||
}
|
||||
|
||||
private:
|
||||
// Id of the Additional data.
|
||||
@ -140,6 +147,12 @@ class Frame {
|
||||
// Discard padding for the frame.
|
||||
int64 discard_padding_;
|
||||
|
||||
// Reference block timestamp.
|
||||
int64 reference_block_timestamp_;
|
||||
|
||||
// Flag indicating if |reference_block_timestamp_| has been set.
|
||||
bool reference_block_timestamp_set_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Frame);
|
||||
};
|
||||
|
||||
@ -1312,6 +1325,9 @@ class Segment {
|
||||
// Last timestamp in nanoseconds added to a cluster.
|
||||
uint64 last_timestamp_;
|
||||
|
||||
// Last timestamp in nanoseconds by track number added to a cluster.
|
||||
uint64 last_track_timestamp_[kMaxTrackNumber];
|
||||
|
||||
// Maximum time in nanoseconds for a cluster duration. This variable is a
|
||||
// guideline and some clusters may have a longer duration. Default is 30
|
||||
// seconds.
|
||||
|
@ -36,7 +36,7 @@ namespace {
|
||||
const int kDateElementSize = 8;
|
||||
|
||||
uint64 WriteBlock(IMkvWriter* writer, const Frame* const frame, int64 timecode,
|
||||
uint64 duration) {
|
||||
uint64 timecode_scale) {
|
||||
uint64 block_additional_elem_size = 0;
|
||||
uint64 block_addid_elem_size = 0;
|
||||
uint64 block_more_payload_size = 0;
|
||||
@ -66,6 +66,15 @@ uint64 WriteBlock(IMkvWriter* writer, const Frame* const frame, int64 timecode,
|
||||
EbmlElementSize(kMkvDiscardPadding, frame->discard_padding());
|
||||
}
|
||||
|
||||
const uint64 reference_block_timestamp =
|
||||
frame->reference_block_timestamp() / timecode_scale;
|
||||
uint64 reference_block_elem_size = 0;
|
||||
if (!frame->is_key()) {
|
||||
reference_block_elem_size =
|
||||
EbmlElementSize(kMkvReferenceBlock, reference_block_timestamp);
|
||||
}
|
||||
|
||||
const uint64 duration = frame->duration() / timecode_scale;
|
||||
uint64 block_duration_elem_size = 0;
|
||||
if (duration > 0)
|
||||
block_duration_elem_size = EbmlElementSize(kMkvBlockDuration, duration);
|
||||
@ -76,7 +85,7 @@ uint64 WriteBlock(IMkvWriter* writer, const Frame* const frame, int64 timecode,
|
||||
|
||||
const uint64 block_group_payload_size =
|
||||
block_elem_size + block_additions_elem_size + block_duration_elem_size +
|
||||
discard_padding_elem_size;
|
||||
discard_padding_elem_size + reference_block_elem_size;
|
||||
|
||||
if (!WriteEbmlMasterElement(writer, kMkvBlockGroup,
|
||||
block_group_payload_size)) {
|
||||
@ -92,10 +101,8 @@ uint64 WriteBlock(IMkvWriter* writer, const Frame* const frame, int64 timecode,
|
||||
if (SerializeInt(writer, timecode, 2))
|
||||
return 0;
|
||||
|
||||
uint64 flags = 0;
|
||||
if (frame->is_key())
|
||||
flags |= 0x80;
|
||||
if (SerializeInt(writer, flags, 1))
|
||||
// For a Block, flags is always 0.
|
||||
if (SerializeInt(writer, 0, 1))
|
||||
return 0;
|
||||
|
||||
if (writer->Write(frame->frame(), static_cast<uint32>(frame->length())))
|
||||
@ -119,18 +126,15 @@ uint64 WriteBlock(IMkvWriter* writer, const Frame* const frame, int64 timecode,
|
||||
}
|
||||
}
|
||||
|
||||
if (frame->discard_padding() != 0) {
|
||||
if (WriteID(writer, kMkvDiscardPadding))
|
||||
return 0;
|
||||
if (frame->discard_padding() != 0 &&
|
||||
!WriteEbmlElement(writer, kMkvDiscardPadding, frame->discard_padding())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint64 size = GetIntSize(frame->discard_padding());
|
||||
if (WriteUInt(writer, size))
|
||||
return false;
|
||||
|
||||
if (SerializeInt(writer, frame->discard_padding(),
|
||||
static_cast<int32>(size))) {
|
||||
return false;
|
||||
}
|
||||
if (!frame->is_key() &&
|
||||
!WriteEbmlElement(writer, kMkvReferenceBlock,
|
||||
reference_block_timestamp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (duration > 0 && !WriteEbmlElement(writer, kMkvBlockDuration, duration)) {
|
||||
@ -440,6 +444,23 @@ bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, int64 value) {
|
||||
if (!writer)
|
||||
return false;
|
||||
|
||||
if (WriteID(writer, type))
|
||||
return 0;
|
||||
|
||||
const uint64 size = GetIntSize(value);
|
||||
if (WriteUInt(writer, size))
|
||||
return false;
|
||||
|
||||
if (SerializeInt(writer, value, static_cast<int32>(size)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, float value) {
|
||||
if (!writer)
|
||||
return false;
|
||||
@ -524,7 +545,7 @@ uint64 WriteFrame(IMkvWriter* writer, const Frame* const frame,
|
||||
return frame->CanBeSimpleBlock()
|
||||
? WriteSimpleBlock(writer, frame, relative_timecode)
|
||||
: WriteBlock(writer, frame, relative_timecode,
|
||||
frame->duration() / cluster->timecode_scale());
|
||||
cluster->timecode_scale());
|
||||
}
|
||||
|
||||
uint64 WriteVoidElement(IMkvWriter* writer, uint64 size) {
|
||||
|
@ -18,7 +18,6 @@ class IMkvWriter;
|
||||
|
||||
const uint64 kEbmlUnknownValue = 0x01FFFFFFFFFFFFFFULL;
|
||||
const int64 kMaxBlockTimecode = 0x07FFFLL;
|
||||
const uint64 kMaxTrackNumber = 126;
|
||||
|
||||
// Writes out |value| in Big Endian order. Returns 0 on success.
|
||||
int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size);
|
||||
@ -54,6 +53,7 @@ int32 WriteID(IMkvWriter* writer, uint64 type);
|
||||
|
||||
// Output an Mkv non-master element. Returns true if the element was written.
|
||||
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value);
|
||||
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, int64 value);
|
||||
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, float value);
|
||||
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const char* value);
|
||||
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const uint8* value,
|
||||
|
Loading…
x
Reference in New Issue
Block a user