Merge "Elements and functions to support BlockAdditional"
This commit is contained in:
committed by
Gerrit Code Review
commit
05912e8a96
173
mkvmuxer.cpp
173
mkvmuxer.cpp
@@ -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,
|
||||
|
||||
69
mkvmuxer.hpp
69
mkvmuxer.hpp
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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|.
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user