Merge "Elements and functions to support BlockAdditional"

This commit is contained in:
Vignesh Venkatasubramanian
2013-05-07 14:17:43 -07:00
committed by Gerrit Code Review
5 changed files with 360 additions and 0 deletions

View File

@@ -460,6 +460,7 @@ Track::Track(unsigned int* seed)
: codec_id_(NULL),
codec_private_(NULL),
language_(NULL),
max_block_additional_id_(0),
name_(NULL),
number_(0),
type_(0),
@@ -535,6 +536,8 @@ uint64 Track::PayloadSize() const {
size += EbmlElementSize(kMkvLanguage, language_);
if (name_)
size += EbmlElementSize(kMkvName, name_);
if (max_block_additional_id_)
size += EbmlElementSize(kMkvMaxBlockAdditionID, max_block_additional_id_);
if (content_encoding_entries_size_ > 0) {
uint64 content_encodings_size = 0;
@@ -581,6 +584,8 @@ bool Track::Write(IMkvWriter* writer) const {
size += EbmlElementSize(kMkvLanguage, language_);
if (name_)
size += EbmlElementSize(kMkvName, name_);
if (max_block_additional_id_)
size += EbmlElementSize(kMkvMaxBlockAdditionID, max_block_additional_id_);
const int64 payload_position = writer->Position();
if (payload_position < 0)
@@ -592,6 +597,11 @@ bool Track::Write(IMkvWriter* writer) const {
return false;
if (!WriteEbmlElement(writer, kMkvTrackType, type_))
return false;
if (max_block_additional_id_)
if (!WriteEbmlElement(writer,
kMkvMaxBlockAdditionID,
max_block_additional_id_))
return false;
if (codec_id_) {
if (!WriteEbmlElement(writer, kMkvCodecID, codec_id_))
return false;
@@ -719,6 +729,7 @@ VideoTrack::VideoTrack(unsigned int* seed)
frame_rate_(0.0),
height_(0),
stereo_mode_(0),
alpha_mode_(0),
width_(0) {
}
@@ -737,6 +748,15 @@ bool VideoTrack::SetStereoMode(uint64 stereo_mode) {
return true;
}
bool VideoTrack::SetAlphaMode(uint64 alpha_mode) {
if (alpha_mode != kNoAlpha &&
alpha_mode != kAlpha)
return false;
alpha_mode_ = alpha_mode;
return true;
}
uint64 VideoTrack::PayloadSize() const {
const uint64 parent_size = Track::PayloadSize();
@@ -772,6 +792,9 @@ bool VideoTrack::Write(IMkvWriter* writer) const {
if (stereo_mode_ > kMono)
if (!WriteEbmlElement(writer, kMkvStereoMode, stereo_mode_))
return false;
if (alpha_mode_ > kNoAlpha)
if (!WriteEbmlElement(writer, kMkvAlphaMode, alpha_mode_))
return false;
if (frame_rate_ > 0.0)
if (!WriteEbmlElement(writer,
kMkvFrameRate,
@@ -795,6 +818,8 @@ uint64 VideoTrack::VideoPayloadSize() const {
size += EbmlElementSize(kMkvDisplayHeight, display_height_);
if (stereo_mode_ > kMono)
size += EbmlElementSize(kMkvStereoMode, stereo_mode_);
if (alpha_mode_ > kNoAlpha)
size += EbmlElementSize(kMkvAlphaMode, alpha_mode_);
if (frame_rate_ > 0.0)
size += EbmlElementSize(kMkvFrameRate, static_cast<float>(frame_rate_));
@@ -1395,6 +1420,25 @@ bool Cluster::AddFrame(const uint8* frame,
&WriteSimpleBlock);
}
bool Cluster::AddFrameWithAdditional(const uint8* frame,
uint64 length,
const uint8* additional,
uint64 additional_length,
uint64 add_id,
uint64 track_number,
uint64 abs_timecode,
bool is_key) {
return DoWriteBlockWithAdditional(frame,
length,
additional,
additional_length,
add_id,
track_number,
abs_timecode,
is_key ? 1 : 0,
&WriteBlockWithAdditional);
}
bool Cluster::AddMetadata(const uint8* frame,
uint64 length,
uint64 track_number,
@@ -1494,6 +1538,66 @@ bool Cluster::DoWriteBlock(
return true;
}
bool Cluster::DoWriteBlockWithAdditional(
const uint8* frame,
uint64 length,
const uint8* additional,
uint64 additional_length,
uint64 add_id,
uint64 track_number,
uint64 abs_timecode,
uint64 generic_arg,
WriteBlockAdditional write_block) {
if (frame == NULL || length == 0 ||
additional == NULL || additional_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 > kMaxBlockTimecode)
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,
additional,
additional_length,
add_id,
track_number,
rel_timecode,
generic_arg);
if (element_size == 0)
return false;
AddPayloadSize(element_size);
blocks_added_++;
return true;
}
bool Cluster::WriteClusterHeader() {
if (finalized_)
return false;
@@ -2100,6 +2204,75 @@ bool Segment::AddFrame(const uint8* frame,
return true;
}
bool Segment::AddFrameWithAdditional(const uint8* frame,
uint64 length,
const uint8* additional,
uint64 additional_length,
uint64 add_id,
uint64 track_number,
uint64 timestamp,
bool is_key) {
if (!frame || !additional)
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 Frame();
if (!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);
if (!QueueFrame(new_frame))
return false;
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)
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::AddMetadata(const uint8* frame,
uint64 length,
uint64 track_number,

View File

@@ -296,6 +296,10 @@ class Track {
const uint8* codec_private() const { return codec_private_; }
void set_language(const char* language);
const char* language() const { return language_; }
void set_max_block_additional_id(uint64 max_block_additional_id) {
max_block_additional_id_ = max_block_additional_id;
}
uint64 max_block_additional_id() const { return max_block_additional_id_; }
void set_name(const char* name);
const char* name() const { return name_; }
void set_number(uint64 number) { number_ = number; }
@@ -314,6 +318,7 @@ class Track {
char* codec_id_;
uint8* codec_private_;
char* language_;
uint64 max_block_additional_id_;
char* name_;
uint64 number_;
uint64 type_;
@@ -344,6 +349,11 @@ class VideoTrack : public Track {
kSideBySideRightIsFirst = 11
};
enum AlphaMode {
kNoAlpha = 0,
kAlpha = 1
};
// The |seed| parameter is used to synthesize a UID for the track.
explicit VideoTrack(unsigned int* seed);
virtual ~VideoTrack();
@@ -358,6 +368,9 @@ class VideoTrack : public Track {
// Sets the video's stereo mode. Returns true on success.
bool SetStereoMode(uint64 stereo_mode);
// Sets the video's alpha mode. Returns true on success.
bool SetAlphaMode(uint64 alpha_mode);
void set_display_height(uint64 height) { display_height_ = height; }
uint64 display_height() const { return display_height_; }
void set_display_width(uint64 width) { display_width_ = width; }
@@ -367,6 +380,7 @@ class VideoTrack : public Track {
void set_height(uint64 height) { height_ = height; }
uint64 height() const { return height_; }
uint64 stereo_mode() { return stereo_mode_; }
uint64 alpha_mode() { return alpha_mode_; }
void set_width(uint64 width) { width_ = width; }
uint64 width() const { return width_; }
@@ -380,6 +394,7 @@ class VideoTrack : public Track {
double frame_rate_;
uint64 height_;
uint64 stereo_mode_;
uint64 alpha_mode_;
uint64 width_;
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(VideoTrack);
@@ -661,6 +676,28 @@ class Cluster {
uint64 timecode, // timecode units (absolute)
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
// additional: Pointer to the additional data
// additional_length: Length of the additional data
// add_id: Value of BlockAddID element
// 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 AddFrameWithAdditional(const uint8* frame,
uint64 length,
const uint8* additional,
uint64 additional_length,
uint64 add_id,
uint64 track_number,
uint64 abs_timecode,
bool is_key);
// Writes a frame of metadata to the output medium; returns true on
// success.
// Inputs:
@@ -706,6 +743,18 @@ class Cluster {
int64 timecode,
uint64 generic_arg);
// Signature that matches WriteBlockWithAdditional
// in the muxer utilities package.
typedef uint64 (*WriteBlockAdditional)(IMkvWriter* writer,
const uint8* data,
uint64 length,
const uint8* additional,
uint64 add_id,
uint64 additional_length,
uint64 track_number,
int64 timecode,
uint64 is_key);
// Used to implement AddFrame and AddMetadata.
bool DoWriteBlock(const uint8* frame,
uint64 length,
@@ -714,6 +763,17 @@ class Cluster {
uint64 generic_arg,
WriteBlock write_block);
// Used to implement AddFrameWithAdditional
bool DoWriteBlockWithAdditional(const uint8* frame,
uint64 length,
const uint8* additional,
uint64 additional_length,
uint64 add_id,
uint64 track_number,
uint64 absolute_timecode,
uint64 generic_arg,
WriteBlockAdditional write_block);
// Outputs the Cluster header to |writer_|. Returns true on success.
bool WriteClusterHeader();
@@ -908,6 +968,15 @@ class Segment {
uint64 timestamp_ns,
uint64 duration_ns);
bool AddFrameWithAdditional(const uint8* frame,
uint64 length,
const uint8* additional,
uint64 additional_length,
uint64 add_id,
uint64 track_number,
uint64 timestamp,
bool is_key);
// Adds a video track to the segment. Returns the number of the track on
// success, 0 on error. |number| is the number to use for the video track.
// |number| must be >= 0. If |number| == 0 then the muxer will decide on

View File

@@ -464,6 +464,95 @@ uint64 WriteMetadataBlock(IMkvWriter* writer,
return blockg_elem_size;
}
// Writes a WebM Block with Additional. The structure is as follows
// Indentation shows sub-levels
// BlockGroup
// Block
// Data
// BlockAdditions
// BlockMore
// BlockAddID
// 1 (Denotes Alpha)
// BlockAdditional
// Data
uint64 WriteBlockWithAdditional(IMkvWriter* writer,
const uint8* data,
uint64 length,
const uint8* additional,
uint64 additional_length,
uint64 add_id,
uint64 track_number,
int64 timecode,
uint64 is_key) {
if (!data || !additional || length < 1 || additional_length < 1)
return 0;
const uint64 block_payload_size = 4 + length;
const uint64 block_elem_size = EbmlMasterElementSize(kMkvBlock,
block_payload_size) +
block_payload_size;
const uint64 block_additional_elem_size = EbmlElementSize(kMkvBlockAdditional,
additional,
additional_length);
const uint64 block_addid_elem_size = EbmlElementSize(kMkvBlockAddID, add_id);
const uint64 block_more_payload_size = block_addid_elem_size +
block_additional_elem_size;
const uint64 block_more_elem_size = EbmlMasterElementSize(
kMkvBlockMore,
block_more_payload_size) +
block_more_payload_size;
const uint64 block_additions_payload_size = block_more_elem_size;
const uint64 block_additions_elem_size = EbmlMasterElementSize(
kMkvBlockMore,
block_additions_payload_size) +
block_additions_payload_size;
const uint64 block_group_payload_size = block_elem_size +
block_additions_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 (!WriteEbmlMasterElement(writer, kMkvBlockAdditions,
block_additions_payload_size))
return 0;
if (!WriteEbmlMasterElement(writer, kMkvBlockMore, block_more_payload_size))
return 0;
if (!WriteEbmlElement(writer, kMkvBlockAddID, add_id))
return 0;
if (!WriteEbmlElement(writer, kMkvBlockAdditional,
additional, additional_length))
return 0;
return block_group_elem_size;
}
uint64 WriteVoidElement(IMkvWriter* writer, uint64 size) {
if (!writer)
return false;

View File

@@ -88,6 +88,29 @@ uint64 WriteMetadataBlock(IMkvWriter* writer,
int64 timecode,
uint64 duration_timecode);
// Output an Mkv Block with BlockAdditional data.
// Inputs:
// data: Pointer to the data.
// length: Length of the data.
// additional: Pointer to the additional data
// additional_length: Length of the additional data.
// add_id: Value of BlockAddID element.
// 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 WriteBlockWithAdditional(IMkvWriter* writer,
const uint8* data,
uint64 length,
const uint8* additional,
uint64 additional_length,
uint64 add_id,
uint64 track_number,
int64 timecode,
uint64 is_key);
// 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
// it from |size|.

View File

@@ -53,6 +53,10 @@ enum MkvId {
kMkvReferenceBlock = 0xFB,
kMkvLaceNumber = 0xCC,
kMkvSimpleBlock = 0xA3,
kMkvBlockAdditions = 0x75A1,
kMkvBlockMore = 0xA6,
kMkvBlockAddID = 0xEE,
kMkvBlockAdditional = 0xA5,
//Track
kMkvTracks = 0x1654AE6B,
kMkvTrackEntry = 0xAE,
@@ -69,10 +73,12 @@ enum MkvId {
kMkvCodecID = 0x86,
kMkvCodecPrivate = 0x63A2,
kMkvCodecName = 0x258688,
kMkvMaxBlockAdditionID = 0x55EE,
//video
kMkvVideo = 0xE0,
kMkvFlagInterlaced = 0x9A,
kMkvStereoMode = 0x53B8,
kMkvAlphaMode = 0x53C0,
kMkvPixelWidth = 0xB0,
kMkvPixelHeight = 0xBA,
kMkvPixelCropBottom = 0x54AA,