Merge "mkvmuxer: Write Block key frames correctly."

This commit is contained in:
Vignesh Venkatasubramanian 2015-06-04 23:32:33 +00:00 committed by Gerrit Code Review
commit 4928b0bd5f
4 changed files with 91 additions and 22 deletions

View File

@ -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;
}

View File

@ -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.

View File

@ -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) {

View File

@ -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,