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),
|
length_(0),
|
||||||
track_number_(0),
|
track_number_(0),
|
||||||
timestamp_(0),
|
timestamp_(0),
|
||||||
discard_padding_(0) {}
|
discard_padding_(0),
|
||||||
|
reference_block_timestamp_(0),
|
||||||
|
reference_block_timestamp_set_(false) {}
|
||||||
|
|
||||||
Frame::~Frame() {
|
Frame::~Frame() {
|
||||||
delete[] frame_;
|
delete[] frame_;
|
||||||
@ -204,6 +206,9 @@ bool Frame::IsValid() const {
|
|||||||
if (track_number_ == 0 || track_number_ > kMaxTrackNumber) {
|
if (track_number_ == 0 || track_number_ > kMaxTrackNumber) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!CanBeSimpleBlock() && !is_key_ && !reference_block_timestamp_set_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,6 +216,11 @@ bool Frame::CanBeSimpleBlock() const {
|
|||||||
return additional_ == NULL && discard_padding_ == 0 && duration_ == 0;
|
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
|
// CuePoint Class
|
||||||
@ -2426,6 +2436,20 @@ bool Segment::AddGenericFrame(const Frame* frame) {
|
|||||||
if (!cluster)
|
if (!cluster)
|
||||||
return false;
|
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))
|
if (!cluster->AddFrame(frame))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -2435,8 +2459,12 @@ bool Segment::AddGenericFrame(const Frame* frame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
last_timestamp_ = frame->timestamp();
|
last_timestamp_ = frame->timestamp();
|
||||||
|
last_track_timestamp_[frame->track_number() - 1] = frame->timestamp();
|
||||||
last_block_duration_ = frame->duration();
|
last_block_duration_ = frame->duration();
|
||||||
|
|
||||||
|
if (frame_created)
|
||||||
|
delete frame;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2947,8 +2975,10 @@ int Segment::WriteFramesAll() {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame_timestamp > last_timestamp_)
|
if (frame_timestamp > last_timestamp_) {
|
||||||
last_timestamp_ = frame_timestamp;
|
last_timestamp_ = frame_timestamp;
|
||||||
|
last_track_timestamp_[frame->track_number() - 1] = frame_timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
delete frame;
|
delete frame;
|
||||||
frame = NULL;
|
frame = NULL;
|
||||||
@ -3010,8 +3040,10 @@ bool Segment::WriteFramesLessThan(uint64 timestamp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
++shift_left;
|
++shift_left;
|
||||||
if (frame_timestamp > last_timestamp_)
|
if (frame_timestamp > last_timestamp_) {
|
||||||
last_timestamp_ = frame_timestamp;
|
last_timestamp_ = frame_timestamp;
|
||||||
|
last_track_timestamp_[frame_prev->track_number() - 1] = frame_timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
delete frame_prev;
|
delete frame_prev;
|
||||||
}
|
}
|
||||||
|
16
mkvmuxer.hpp
16
mkvmuxer.hpp
@ -23,6 +23,8 @@ namespace mkvmuxer {
|
|||||||
class MkvWriter;
|
class MkvWriter;
|
||||||
class Segment;
|
class Segment;
|
||||||
|
|
||||||
|
const uint64 kMaxTrackNumber = 126;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
// Interface used by the mkvmuxer to write out the Mkv data.
|
// Interface used by the mkvmuxer to write out the Mkv data.
|
||||||
class IMkvWriter {
|
class IMkvWriter {
|
||||||
@ -108,6 +110,11 @@ class Frame {
|
|||||||
discard_padding_ = discard_padding;
|
discard_padding_ = discard_padding;
|
||||||
}
|
}
|
||||||
int64 discard_padding() const { return 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:
|
private:
|
||||||
// Id of the Additional data.
|
// Id of the Additional data.
|
||||||
@ -140,6 +147,12 @@ class Frame {
|
|||||||
// Discard padding for the frame.
|
// Discard padding for the frame.
|
||||||
int64 discard_padding_;
|
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);
|
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Frame);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1312,6 +1325,9 @@ class Segment {
|
|||||||
// Last timestamp in nanoseconds added to a cluster.
|
// Last timestamp in nanoseconds added to a cluster.
|
||||||
uint64 last_timestamp_;
|
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
|
// Maximum time in nanoseconds for a cluster duration. This variable is a
|
||||||
// guideline and some clusters may have a longer duration. Default is 30
|
// guideline and some clusters may have a longer duration. Default is 30
|
||||||
// seconds.
|
// seconds.
|
||||||
|
@ -36,7 +36,7 @@ namespace {
|
|||||||
const int kDateElementSize = 8;
|
const int kDateElementSize = 8;
|
||||||
|
|
||||||
uint64 WriteBlock(IMkvWriter* writer, const Frame* const frame, int64 timecode,
|
uint64 WriteBlock(IMkvWriter* writer, const Frame* const frame, int64 timecode,
|
||||||
uint64 duration) {
|
uint64 timecode_scale) {
|
||||||
uint64 block_additional_elem_size = 0;
|
uint64 block_additional_elem_size = 0;
|
||||||
uint64 block_addid_elem_size = 0;
|
uint64 block_addid_elem_size = 0;
|
||||||
uint64 block_more_payload_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());
|
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;
|
uint64 block_duration_elem_size = 0;
|
||||||
if (duration > 0)
|
if (duration > 0)
|
||||||
block_duration_elem_size = EbmlElementSize(kMkvBlockDuration, duration);
|
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 =
|
const uint64 block_group_payload_size =
|
||||||
block_elem_size + block_additions_elem_size + block_duration_elem_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,
|
if (!WriteEbmlMasterElement(writer, kMkvBlockGroup,
|
||||||
block_group_payload_size)) {
|
block_group_payload_size)) {
|
||||||
@ -92,10 +101,8 @@ uint64 WriteBlock(IMkvWriter* writer, const Frame* const frame, int64 timecode,
|
|||||||
if (SerializeInt(writer, timecode, 2))
|
if (SerializeInt(writer, timecode, 2))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
uint64 flags = 0;
|
// For a Block, flags is always 0.
|
||||||
if (frame->is_key())
|
if (SerializeInt(writer, 0, 1))
|
||||||
flags |= 0x80;
|
|
||||||
if (SerializeInt(writer, flags, 1))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (writer->Write(frame->frame(), static_cast<uint32>(frame->length())))
|
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 (frame->discard_padding() != 0 &&
|
||||||
if (WriteID(writer, kMkvDiscardPadding))
|
!WriteEbmlElement(writer, kMkvDiscardPadding, frame->discard_padding())) {
|
||||||
return 0;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const uint64 size = GetIntSize(frame->discard_padding());
|
if (!frame->is_key() &&
|
||||||
if (WriteUInt(writer, size))
|
!WriteEbmlElement(writer, kMkvReferenceBlock,
|
||||||
return false;
|
reference_block_timestamp)) {
|
||||||
|
return false;
|
||||||
if (SerializeInt(writer, frame->discard_padding(),
|
|
||||||
static_cast<int32>(size))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (duration > 0 && !WriteEbmlElement(writer, kMkvBlockDuration, duration)) {
|
if (duration > 0 && !WriteEbmlElement(writer, kMkvBlockDuration, duration)) {
|
||||||
@ -440,6 +444,23 @@ bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value) {
|
|||||||
return true;
|
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) {
|
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, float value) {
|
||||||
if (!writer)
|
if (!writer)
|
||||||
return false;
|
return false;
|
||||||
@ -524,7 +545,7 @@ uint64 WriteFrame(IMkvWriter* writer, const Frame* const frame,
|
|||||||
return frame->CanBeSimpleBlock()
|
return frame->CanBeSimpleBlock()
|
||||||
? WriteSimpleBlock(writer, frame, relative_timecode)
|
? WriteSimpleBlock(writer, frame, relative_timecode)
|
||||||
: WriteBlock(writer, frame, relative_timecode,
|
: WriteBlock(writer, frame, relative_timecode,
|
||||||
frame->duration() / cluster->timecode_scale());
|
cluster->timecode_scale());
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 WriteVoidElement(IMkvWriter* writer, uint64 size) {
|
uint64 WriteVoidElement(IMkvWriter* writer, uint64 size) {
|
||||||
|
@ -18,7 +18,6 @@ class IMkvWriter;
|
|||||||
|
|
||||||
const uint64 kEbmlUnknownValue = 0x01FFFFFFFFFFFFFFULL;
|
const uint64 kEbmlUnknownValue = 0x01FFFFFFFFFFFFFFULL;
|
||||||
const int64 kMaxBlockTimecode = 0x07FFFLL;
|
const int64 kMaxBlockTimecode = 0x07FFFLL;
|
||||||
const uint64 kMaxTrackNumber = 126;
|
|
||||||
|
|
||||||
// Writes out |value| in Big Endian order. Returns 0 on success.
|
// Writes out |value| in Big Endian order. Returns 0 on success.
|
||||||
int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size);
|
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.
|
// 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, uint64 value);
|
||||||
|
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, int64 value);
|
||||||
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, float 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 char* value);
|
||||||
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const uint8* value,
|
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const uint8* value,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user