Refactor Cluster::AddFrame member function

Change-Id: Ibff460918243647eb76785508bb50490bc1d8561
This commit is contained in:
Matthew Heaney 2012-09-06 10:33:27 -07:00
parent c425e965aa
commit 0edf087bbb
4 changed files with 118 additions and 70 deletions

View File

@ -12,6 +12,7 @@
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <ctime> #include <ctime>
#include <limits>
#include <new> #include <new>
#include "mkvmuxerutil.hpp" #include "mkvmuxerutil.hpp"
@ -1024,28 +1025,14 @@ bool Cluster::Init(IMkvWriter* ptr_writer) {
bool Cluster::AddFrame(const uint8* frame, bool Cluster::AddFrame(const uint8* frame,
uint64 length, uint64 length,
uint64 track_number, uint64 track_number,
int16 timecode, uint64 abs_timecode,
bool is_key) { bool is_key) {
if (finalized_) return DoWriteBlock(frame,
return false; length,
track_number,
if (!header_written_) abs_timecode,
if (!WriteClusterHeader()) is_key ? 1 : 0,
return false; &WriteSimpleBlock);
const uint64 element_size = WriteSimpleBlock(writer_,
frame,
length,
static_cast<char>(track_number),
timecode,
is_key);
if (!element_size)
return false;
AddPayloadSize(element_size);
blocks_added_++;
return true;
} }
void Cluster::AddPayloadSize(uint64 size) { void Cluster::AddPayloadSize(uint64 size) {
@ -1081,6 +1068,59 @@ uint64 Cluster::Size() const {
return element_size; return element_size;
} }
bool Cluster::DoWriteBlock(
const uint8* frame,
uint64 length,
uint64 track_number,
uint64 abs_timecode,
uint64 generic_arg,
WriteBlock write_block) {
if (frame == NULL || length == 0)
return false;
// 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.
if (track_number == 0 || track_number > 0x7E)
return false;
const int64 cluster_timecode = this->Cluster::timecode();
const int64 rel_timecode =
static_cast<int64>(abs_timecode) - cluster_timecode;
if (rel_timecode < 0)
return false;
if (rel_timecode > std::numeric_limits<int16>::max())
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_,
frame,
length,
track_number,
rel_timecode,
generic_arg);
if (element_size == 0)
return false;
AddPayloadSize(element_size);
blocks_added_++;
return true;
}
bool Cluster::WriteClusterHeader() { bool Cluster::WriteClusterHeader() {
if (finalized_) if (finalized_)
return false; return false;
@ -1710,10 +1750,14 @@ bool Segment::AddFrame(const uint8* frame,
if (!cluster) if (!cluster)
return false; return false;
int64 block_timecode = timestamp / segment_info_.timecode_scale(); const uint64 timecode_scale = segment_info_.timecode_scale();
block_timecode -= static_cast<int64>(cluster->timecode()); const uint64 abs_timecode = timestamp / timecode_scale;
if (block_timecode < 0) if (!cluster->AddFrame(frame,
length,
track_number,
abs_timecode,
is_key))
return false; return false;
if (new_cuepoint_ && cues_track_ == track_number) { if (new_cuepoint_ && cues_track_ == track_number) {
@ -1721,13 +1765,6 @@ bool Segment::AddFrame(const uint8* frame,
return false; return false;
} }
if (!cluster->AddFrame(frame,
length,
track_number,
static_cast<int16>(block_timecode),
is_key))
return false;
if (timestamp > last_timestamp_) if (timestamp > last_timestamp_)
last_timestamp_ = timestamp; last_timestamp_ = timestamp;
@ -2027,32 +2064,30 @@ bool Segment::WriteFramesAll() {
if (!cluster) if (!cluster)
return false; return false;
const uint64 timecode_scale = segment_info_.timecode_scale();
for (int32 i = 0; i < frames_size_; ++i) { for (int32 i = 0; i < frames_size_; ++i) {
Frame* const frame = frames_[i]; Frame*& frame = frames_[i];
const uint64 frame_timestamp = frame->timestamp(); // ns
int64 block_timecode = const uint64 frame_timecode = frame_timestamp / timecode_scale;
frame->timestamp() / segment_info_.timecode_scale();
block_timecode -= static_cast<int64>(cluster->timecode());
if (block_timecode < 0)
return false;
if (new_cuepoint_ && cues_track_ == frame->track_number()) {
if (!AddCuePoint(frame->timestamp()))
return false;
}
if (!cluster->AddFrame(frame->frame(), if (!cluster->AddFrame(frame->frame(),
frame->length(), frame->length(),
frame->track_number(), frame->track_number(),
static_cast<int16>(block_timecode), frame_timecode,
frame->is_key())) frame->is_key()))
return false; return false;
if (frame->timestamp() > last_timestamp_) if (new_cuepoint_ && cues_track_ == frame->track_number()) {
last_timestamp_ = frame->timestamp(); if (!AddCuePoint(frame_timestamp))
return false;
}
if (frame_timestamp > last_timestamp_)
last_timestamp_ = frame_timestamp;
delete frame; delete frame;
frame = NULL;
} }
frames_size_ = 0; frames_size_ = 0;
@ -2070,10 +2105,10 @@ bool Segment::WriteFramesLessThan(uint64 timestamp) {
return false; return false;
Cluster* const cluster = cluster_list_[cluster_list_size_-1]; Cluster* const cluster = cluster_list_[cluster_list_size_-1];
if (!cluster) if (!cluster)
return false; return false;
const uint64 timecode_scale = segment_info_.timecode_scale();
int32 shift_left = 0; int32 shift_left = 0;
// TODO(fgalligan): Change this to use the durations of frames instead of // TODO(fgalligan): Change this to use the durations of frames instead of
@ -2085,29 +2120,24 @@ bool Segment::WriteFramesLessThan(uint64 timestamp) {
break; break;
const Frame* const frame_prev = frames_[i-1]; const Frame* const frame_prev = frames_[i-1];
const uint64 frame_timestamp = frame_prev->timestamp();
int64 block_timecode = const uint64 frame_timecode = frame_timestamp / timecode_scale;
frame_prev->timestamp() / segment_info_.timecode_scale();
block_timecode -= static_cast<int64>(cluster->timecode());
if (block_timecode < 0)
return false;
if (new_cuepoint_ && cues_track_ == frame_prev->track_number()) {
if (!AddCuePoint(frame_prev->timestamp()))
return false;
}
if (!cluster->AddFrame(frame_prev->frame(), if (!cluster->AddFrame(frame_prev->frame(),
frame_prev->length(), frame_prev->length(),
frame_prev->track_number(), frame_prev->track_number(),
static_cast<int16>(block_timecode), frame_timecode,
frame_prev->is_key())) frame_prev->is_key()))
return false; return false;
if (new_cuepoint_ && cues_track_ == frame_prev->track_number()) {
if (!AddCuePoint(frame_timestamp))
return false;
}
++shift_left; ++shift_left;
if (frame_prev->timestamp() > last_timestamp_) if (frame_timestamp > last_timestamp_)
last_timestamp_ = frame_prev->timestamp(); last_timestamp_ = frame_timestamp;
delete frame_prev; delete frame_prev;
} }

View File

@ -489,13 +489,14 @@ class Cluster {
// frame: Pointer to the data // frame: Pointer to the data
// length: Length of the data // length: Length of the data
// track_number: Track to add the data to. Value returned by Add track // track_number: Track to add the data to. Value returned by Add track
// functions. // functions. The range of allowed values is [1, 126].
// timestamp: Timecode of the frame relative to the cluster timecode. // 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. // is_key: Flag telling whether or not this frame is a key frame.
bool AddFrame(const uint8* frame, bool AddFrame(const uint8* frame,
uint64 length, uint64 length,
uint64 track_number, uint64 track_number,
short timecode, uint64 timecode, // timecode units (absolute)
bool is_key); bool is_key);
// Increments the size of the cluster's data in bytes. // Increments the size of the cluster's data in bytes.
@ -514,6 +515,23 @@ class Cluster {
uint64 timecode() const { return timecode_; } uint64 timecode() const { return timecode_; }
private: private:
// Signature that matches either of WriteSimpleBlock or WriteMetadataBlock
// in the muxer utilities package.
typedef uint64 (*WriteBlock)(IMkvWriter* writer,
const uint8* data,
uint64 length,
uint64 track_number,
int64 timecode,
uint64 generic_arg);
// Used to implement AddFrame.
bool DoWriteBlock(const uint8* frame,
uint64 length,
uint64 track_number,
uint64 absolute_timecode,
uint64 generic_arg,
WriteBlock 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();
@ -670,7 +688,7 @@ class Segment {
bool AddFrame(const uint8* frame, bool AddFrame(const uint8* frame,
uint64 length, uint64 length,
uint64 track_number, uint64 track_number,
uint64 timestamp, uint64 timestamp_ns,
bool is_key); bool is_key);
// Adds a video track to the segment. Returns the number of the track on // Adds a video track to the segment. Returns the number of the track on

View File

@ -309,7 +309,7 @@ uint64 WriteSimpleBlock(IMkvWriter* writer,
uint64 length, uint64 length,
uint64 track_number, uint64 track_number,
int64 timecode, int64 timecode,
bool is_key) { uint64 is_key) {
if (!writer) if (!writer)
return false; return false;

View File

@ -62,13 +62,13 @@ bool WriteEbmlElement(IMkvWriter* writer,
// permitted. // permitted.
// timecode: Relative timecode of the Block. Only values in the // timecode: Relative timecode of the Block. Only values in the
// range [0, 2^15) are permitted. // range [0, 2^15) are permitted.
// is_key: Flag telling whether or not this frame is a key frame. // is_key: Non-zero value specifies that frame is a key frame.
uint64 WriteSimpleBlock(IMkvWriter* writer, uint64 WriteSimpleBlock(IMkvWriter* writer,
const uint8* data, const uint8* data,
uint64 length, uint64 length,
uint64 track_number, uint64 track_number,
int64 timecode, int64 timecode,
bool is_key); uint64 is_key);
// Output a metadata keyframe, using a Block Group element. // Output a metadata keyframe, using a Block Group element.
// Inputs: // Inputs: