Merge "third_party/libwebm: pull from upstream"
This commit is contained in:
Коммит
16c0ec711c
|
@ -1,11 +1,10 @@
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
LOCAL_CPP_EXTENSION := .cpp
|
||||
LOCAL_SRC_FILES := mkvmuxer.cpp \
|
||||
mkvmuxerutil.cpp \
|
||||
mkvparser.cpp \
|
||||
mkvreader.cpp \
|
||||
mkvwriter.cpp
|
||||
LOCAL_MODULE := libwebm
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:= libwebm
|
||||
LOCAL_SRC_FILES:= mkvparser.cpp \
|
||||
mkvreader.cpp \
|
||||
mkvmuxer.cpp \
|
||||
mkvmuxerutil.cpp \
|
||||
mkvwriter.cpp
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
|
|
@ -17,7 +17,7 @@ or agree to the institution of patent litigation or any other patent
|
|||
enforcement activity against any entity (including a cross-claim or
|
||||
counterclaim in a lawsuit) alleging that any of these implementations of WebM
|
||||
or any code incorporated within any of these implementations of WebM
|
||||
constitutes direct or contributory patent infringement, or inducement of
|
||||
constitute direct or contributory patent infringement, or inducement of
|
||||
patent infringement, then any patent rights granted to you under this License
|
||||
for these implementations of WebM shall terminate as of the date such
|
||||
litigation is filed.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
URL: https://chromium.googlesource.com/webm/libwebm
|
||||
Version: 249629d46c6e9391f25a90cff6d19075f47474cb
|
||||
Version: b6de61a5c0d441c91afb0785e3b26efd2f9e7337
|
||||
License: BSD
|
||||
License File: LICENSE.txt
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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 {
|
||||
|
@ -57,6 +59,10 @@ class IMkvWriter {
|
|||
|
||||
// Writes out the EBML header for a WebM file. This function must be called
|
||||
// before any other libwebm writing functions are called.
|
||||
bool WriteEbmlHeader(IMkvWriter* writer, uint64 doc_type_version);
|
||||
|
||||
// Deprecated. Writes out EBML header with doc_type_version as
|
||||
// kDefaultDocTypeVersion. Exists for backward compatibility.
|
||||
bool WriteEbmlHeader(IMkvWriter* writer);
|
||||
|
||||
// Copies in Chunk from source to destination between the given byte positions
|
||||
|
@ -70,12 +76,23 @@ class Frame {
|
|||
Frame();
|
||||
~Frame();
|
||||
|
||||
// Sets this frame's contents based on |frame|. Returns true on success. On
|
||||
// failure, this frame's existing contents may be lost.
|
||||
bool CopyFrom(const Frame& frame);
|
||||
|
||||
// Copies |frame| data into |frame_|. Returns true on success.
|
||||
bool Init(const uint8* frame, uint64 length);
|
||||
|
||||
// Copies |additional| data into |additional_|. Returns true on success.
|
||||
bool AddAdditionalData(const uint8* additional, uint64 length, uint64 add_id);
|
||||
|
||||
// Returns true if the frame has valid parameters.
|
||||
bool IsValid() const;
|
||||
|
||||
// Returns true if the frame can be written as a SimpleBlock based on current
|
||||
// parameters.
|
||||
bool CanBeSimpleBlock() const;
|
||||
|
||||
uint64 add_id() const { return add_id_; }
|
||||
const uint8* additional() const { return additional_; }
|
||||
uint64 additional_length() const { return additional_length_; }
|
||||
|
@ -89,10 +106,15 @@ class Frame {
|
|||
uint64 track_number() const { return track_number_; }
|
||||
void set_timestamp(uint64 timestamp) { timestamp_ = timestamp; }
|
||||
uint64 timestamp() const { return timestamp_; }
|
||||
void set_discard_padding(uint64 discard_padding) {
|
||||
void set_discard_padding(int64 discard_padding) {
|
||||
discard_padding_ = discard_padding;
|
||||
}
|
||||
uint64 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:
|
||||
// Id of the Additional data.
|
||||
|
@ -124,6 +146,14 @@ 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);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
@ -422,6 +452,16 @@ class VideoTrack : public Track {
|
|||
uint64 display_height() const { return display_height_; }
|
||||
void set_display_width(uint64 width) { display_width_ = width; }
|
||||
uint64 display_width() const { return display_width_; }
|
||||
|
||||
void set_crop_left(uint64 crop_left) { crop_left_ = crop_left; }
|
||||
uint64 crop_left() const { return crop_left_; }
|
||||
void set_crop_right(uint64 crop_right) { crop_right_ = crop_right; }
|
||||
uint64 crop_right() const { return crop_right_; }
|
||||
void set_crop_top(uint64 crop_top) { crop_top_ = crop_top; }
|
||||
uint64 crop_top() const { return crop_top_; }
|
||||
void set_crop_bottom(uint64 crop_bottom) { crop_bottom_ = crop_bottom; }
|
||||
uint64 crop_bottom() const { return crop_bottom_; }
|
||||
|
||||
void set_frame_rate(double frame_rate) { frame_rate_ = frame_rate; }
|
||||
double frame_rate() const { return frame_rate_; }
|
||||
void set_height(uint64 height) { height_ = height; }
|
||||
|
@ -438,6 +478,10 @@ class VideoTrack : public Track {
|
|||
// Video track element names.
|
||||
uint64 display_height_;
|
||||
uint64 display_width_;
|
||||
uint64 crop_left_;
|
||||
uint64 crop_right_;
|
||||
uint64 crop_top_;
|
||||
uint64 crop_bottom_;
|
||||
double frame_rate_;
|
||||
uint64 height_;
|
||||
uint64 stereo_mode_;
|
||||
|
@ -692,6 +736,112 @@ class Chapters {
|
|||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Chapters);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Tag element
|
||||
//
|
||||
class Tag {
|
||||
public:
|
||||
bool add_simple_tag(const char* tag_name, const char* tag_string);
|
||||
|
||||
private:
|
||||
// Tags calls Clear and the destructor of Tag
|
||||
friend class Tags;
|
||||
|
||||
// For storage of simple tags
|
||||
class SimpleTag {
|
||||
public:
|
||||
// Establish representation invariant for new SimpleTag object.
|
||||
void Init();
|
||||
|
||||
// Reclaim resources, in anticipation of destruction.
|
||||
void Clear();
|
||||
|
||||
// Copies the title to the |tag_name_| member. Returns false on
|
||||
// error.
|
||||
bool set_tag_name(const char* tag_name);
|
||||
|
||||
// Copies the language to the |tag_string_| member. Returns false
|
||||
// on error.
|
||||
bool set_tag_string(const char* tag_string);
|
||||
|
||||
// If |writer| is non-NULL, serialize the SimpleTag sub-element of
|
||||
// the Atom into the stream. Returns the SimpleTag element size on
|
||||
// success, 0 if error.
|
||||
uint64 Write(IMkvWriter* writer) const;
|
||||
|
||||
private:
|
||||
char* tag_name_;
|
||||
char* tag_string_;
|
||||
};
|
||||
|
||||
Tag();
|
||||
~Tag();
|
||||
|
||||
// Copies this Tag object to a different one. This is used when
|
||||
// expanding a plain array of Tag objects (see Tags).
|
||||
void ShallowCopy(Tag* dst) const;
|
||||
|
||||
// Reclaim resources used by this Tag object, pending its
|
||||
// destruction.
|
||||
void Clear();
|
||||
|
||||
// If there is no storage remaining on the |simple_tags_| array for a
|
||||
// new display object, creates a new, longer array and copies the
|
||||
// existing SimpleTag objects to the new array. Returns false if the
|
||||
// array cannot be expanded.
|
||||
bool ExpandSimpleTagsArray();
|
||||
|
||||
// If |writer| is non-NULL, serialize the Tag sub-element into the
|
||||
// stream. Returns the total size of the element on success, 0 if
|
||||
// error.
|
||||
uint64 Write(IMkvWriter* writer) const;
|
||||
|
||||
// The Atom element can contain multiple SimpleTag sub-elements
|
||||
SimpleTag* simple_tags_;
|
||||
|
||||
// The physical length (total size) of the |simple_tags_| array.
|
||||
int simple_tags_size_;
|
||||
|
||||
// The logical length (number of active elements) on the |simple_tags_|
|
||||
// array.
|
||||
int simple_tags_count_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Tag);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Tags element
|
||||
//
|
||||
class Tags {
|
||||
public:
|
||||
Tags();
|
||||
~Tags();
|
||||
|
||||
Tag* AddTag();
|
||||
|
||||
// Returns the number of tags that have been added.
|
||||
int Count() const;
|
||||
|
||||
// Output the Tags element to the writer. Returns true on success.
|
||||
bool Write(IMkvWriter* writer) const;
|
||||
|
||||
private:
|
||||
// Expands the tags_ array if there is not enough space to contain
|
||||
// another tag object. Returns true on success.
|
||||
bool ExpandTagsArray();
|
||||
|
||||
// Total length of the tags_ array.
|
||||
int tags_size_;
|
||||
|
||||
// Number of active tags on the tags_ array.
|
||||
int tags_count_;
|
||||
|
||||
// Array for storage of tag objects.
|
||||
Tag* tags_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Tags);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Cluster element
|
||||
//
|
||||
|
@ -699,32 +849,36 @@ class Chapters {
|
|||
// |Init| must be called before any other method in this class.
|
||||
class Cluster {
|
||||
public:
|
||||
Cluster(uint64 timecode, int64 cues_pos);
|
||||
~Cluster();
|
||||
|
||||
// |timecode| is the absolute timecode of the cluster. |cues_pos| is the
|
||||
// position for the cluster within the segment that should be written in
|
||||
// the cues element.
|
||||
// the cues element. |timecode_scale| is the timecode scale of the segment.
|
||||
Cluster(uint64 timecode, int64 cues_pos, uint64 timecode_scale);
|
||||
~Cluster();
|
||||
|
||||
bool Init(IMkvWriter* ptr_writer);
|
||||
|
||||
// Adds a frame to be output in the file. The frame is written out through
|
||||
// |writer_| if successful. Returns true on success.
|
||||
bool AddFrame(const Frame* frame);
|
||||
|
||||
// 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
|
||||
// data: Pointer to the data
|
||||
// length: Length of the data
|
||||
// track_number: Track to add the data to. Value returned by Add track
|
||||
// functions. The range of allowed values is [1, 126].
|
||||
// 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 AddFrame(const uint8* frame, uint64 length, uint64 track_number,
|
||||
bool AddFrame(const uint8* data, uint64 length, uint64 track_number,
|
||||
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
|
||||
// data: Pointer to the data
|
||||
// length: Length of the data
|
||||
// additional: Pointer to the additional data
|
||||
// additional_length: Length of the additional data
|
||||
|
@ -734,7 +888,7 @@ class Cluster {
|
|||
// 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,
|
||||
bool AddFrameWithAdditional(const uint8* data, uint64 length,
|
||||
const uint8* additional, uint64 additional_length,
|
||||
uint64 add_id, uint64 track_number,
|
||||
uint64 abs_timecode, bool is_key);
|
||||
|
@ -742,7 +896,7 @@ class Cluster {
|
|||
// 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.
|
||||
// data: Pointer to the data.
|
||||
// length: Length of the data.
|
||||
// discard_padding: DiscardPadding element value.
|
||||
// track_number: Track to add the data to. Value returned by Add track
|
||||
|
@ -750,14 +904,14 @@ class Cluster {
|
|||
// 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 AddFrameWithDiscardPadding(const uint8* frame, uint64 length,
|
||||
bool AddFrameWithDiscardPadding(const uint8* data, uint64 length,
|
||||
int64 discard_padding, uint64 track_number,
|
||||
uint64 abs_timecode, bool is_key);
|
||||
|
||||
// Writes a frame of metadata to the output medium; returns true on
|
||||
// success.
|
||||
// Inputs:
|
||||
// frame: Pointer to the data
|
||||
// data: Pointer to the data
|
||||
// length: Length of the data
|
||||
// track_number: Track to add the data to. Value returned by Add track
|
||||
// functions. The range of allowed values is [1, 126].
|
||||
|
@ -768,7 +922,7 @@ class Cluster {
|
|||
// The metadata frame is written as a block group, with a duration
|
||||
// sub-element but no reference time sub-elements (indicating that
|
||||
// it is considered a keyframe, per Matroska semantics).
|
||||
bool AddMetadata(const uint8* frame, uint64 length, uint64 track_number,
|
||||
bool AddMetadata(const uint8* data, uint64 length, uint64 track_number,
|
||||
uint64 timecode, uint64 duration);
|
||||
|
||||
// Increments the size of the cluster's data in bytes.
|
||||
|
@ -781,75 +935,29 @@ class Cluster {
|
|||
// Returns the size in bytes for the entire Cluster element.
|
||||
uint64 Size() const;
|
||||
|
||||
// Given |abs_timecode|, calculates timecode relative to most recent timecode.
|
||||
// Returns -1 on failure, or a relative timecode.
|
||||
int64 GetRelativeTimecode(int64 abs_timecode) const;
|
||||
|
||||
int64 size_position() const { return size_position_; }
|
||||
int32 blocks_added() const { return blocks_added_; }
|
||||
uint64 payload_size() const { return payload_size_; }
|
||||
int64 position_for_cues() const { return position_for_cues_; }
|
||||
uint64 timecode() const { return timecode_; }
|
||||
uint64 timecode_scale() const { return timecode_scale_; }
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
// Signature that matches WriteBlockWithDiscardPadding
|
||||
// in the muxer utilities package.
|
||||
typedef uint64 (*WriteBlockDiscardPadding)(IMkvWriter* writer,
|
||||
const uint8* data, uint64 length,
|
||||
int64 discard_padding,
|
||||
uint64 track_number,
|
||||
int64 timecode, uint64 is_key);
|
||||
|
||||
// Utility method that confirms that blocks can still be added, and that the
|
||||
// cluster header has been written. Used by |DoWriteBlock*|. Returns true
|
||||
// cluster header has been written. Used by |DoWriteFrame*|. Returns true
|
||||
// when successful.
|
||||
template <typename Type>
|
||||
bool PreWriteBlock(Type* write_function);
|
||||
bool PreWriteBlock();
|
||||
|
||||
// Utility method used by the |DoWriteBlock*| methods that handles the book
|
||||
// Utility method used by the |DoWriteFrame*| methods that handles the book
|
||||
// keeping required after each block is written.
|
||||
void PostWriteBlock(uint64 element_size);
|
||||
|
||||
// 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.
|
||||
bool IsValidTrackNumber(uint64 track_number) const;
|
||||
|
||||
// Given |abs_timecode|, calculates timecode relative to most recent timecode.
|
||||
// Returns -1 on failure, or a relative timecode.
|
||||
int64 GetRelativeTimecode(int64 abs_timecode) const;
|
||||
|
||||
// Used to implement AddFrame and AddMetadata.
|
||||
bool DoWriteBlock(const uint8* frame, uint64 length, uint64 track_number,
|
||||
uint64 absolute_timecode, 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);
|
||||
|
||||
// Used to implement AddFrameWithDiscardPadding
|
||||
bool DoWriteBlockWithDiscardPadding(const uint8* frame, uint64 length,
|
||||
int64 discard_padding,
|
||||
uint64 track_number,
|
||||
uint64 absolute_timecode,
|
||||
uint64 generic_arg,
|
||||
WriteBlockDiscardPadding write_block);
|
||||
// Does some verification and calls WriteFrame.
|
||||
bool DoWriteFrame(const Frame* const frame);
|
||||
|
||||
// Outputs the Cluster header to |writer_|. Returns true on success.
|
||||
bool WriteClusterHeader();
|
||||
|
@ -875,6 +983,9 @@ class Cluster {
|
|||
// The absolute timecode of the cluster.
|
||||
const uint64 timecode_;
|
||||
|
||||
// The timecode scale of the Segment containing the cluster.
|
||||
const uint64 timecode_scale_;
|
||||
|
||||
// Pointer to the writer object. Not owned by this class.
|
||||
IMkvWriter* writer_;
|
||||
|
||||
|
@ -996,6 +1107,7 @@ class Segment {
|
|||
kBeforeClusters = 0x1 // Position Cues before Clusters
|
||||
};
|
||||
|
||||
const static uint32 kDefaultDocTypeVersion = 2;
|
||||
const static uint64 kDefaultMaxClusterDuration = 30000000000ULL;
|
||||
|
||||
Segment();
|
||||
|
@ -1023,6 +1135,11 @@ class Segment {
|
|||
// populate its fields via the Chapter member functions.
|
||||
Chapter* AddChapter();
|
||||
|
||||
// Adds an empty tag to the tags of this segment. Returns
|
||||
// non-NULL on success. After adding the tag, the caller should
|
||||
// populate its fields via the Tag member functions.
|
||||
Tag* AddTag();
|
||||
|
||||
// Adds a cue point to the Cues element. |timestamp| is the time in
|
||||
// nanoseconds of the cue's time. |track| is the Track of the Cue. This
|
||||
// function must be called after AddFrame to calculate the correct
|
||||
|
@ -1031,19 +1148,19 @@ class Segment {
|
|||
|
||||
// Adds a frame to be output in the file. Returns true on success.
|
||||
// Inputs:
|
||||
// frame: Pointer to the data
|
||||
// data: Pointer to the data
|
||||
// length: Length of the data
|
||||
// track_number: Track to add the data to. Value returned by Add track
|
||||
// functions.
|
||||
// timestamp: Timestamp of the frame in nanoseconds from 0.
|
||||
// is_key: Flag telling whether or not this frame is a key frame.
|
||||
bool AddFrame(const uint8* frame, uint64 length, uint64 track_number,
|
||||
bool AddFrame(const uint8* data, uint64 length, uint64 track_number,
|
||||
uint64 timestamp_ns, bool is_key);
|
||||
|
||||
// Writes a frame of metadata to the output medium; returns true on
|
||||
// success.
|
||||
// Inputs:
|
||||
// frame: Pointer to the data
|
||||
// data: Pointer to the data
|
||||
// length: Length of the data
|
||||
// track_number: Track to add the data to. Value returned by Add track
|
||||
// functions.
|
||||
|
@ -1054,13 +1171,13 @@ class Segment {
|
|||
// The metadata frame is written as a block group, with a duration
|
||||
// sub-element but no reference time sub-elements (indicating that
|
||||
// it is considered a keyframe, per Matroska semantics).
|
||||
bool AddMetadata(const uint8* frame, uint64 length, uint64 track_number,
|
||||
bool AddMetadata(const uint8* data, uint64 length, uint64 track_number,
|
||||
uint64 timestamp_ns, uint64 duration_ns);
|
||||
|
||||
// Writes a frame with additional data to the output medium; returns true on
|
||||
// success.
|
||||
// Inputs:
|
||||
// frame: Pointer to the data.
|
||||
// data: Pointer to the data.
|
||||
// length: Length of the data.
|
||||
// additional: Pointer to additional data.
|
||||
// additional_length: Length of additional data.
|
||||
|
@ -1070,7 +1187,7 @@ class Segment {
|
|||
// timestamp: Absolute timestamp of the frame, expressed in nanosecond
|
||||
// units.
|
||||
// is_key: Flag telling whether or not this frame is a key frame.
|
||||
bool AddFrameWithAdditional(const uint8* frame, uint64 length,
|
||||
bool AddFrameWithAdditional(const uint8* data, uint64 length,
|
||||
const uint8* additional, uint64 additional_length,
|
||||
uint64 add_id, uint64 track_number,
|
||||
uint64 timestamp, bool is_key);
|
||||
|
@ -1078,7 +1195,7 @@ class Segment {
|
|||
// Writes a frame with DiscardPadding to the output medium; returns true on
|
||||
// success.
|
||||
// Inputs:
|
||||
// frame: Pointer to the data.
|
||||
// data: Pointer to the data.
|
||||
// length: Length of the data.
|
||||
// discard_padding: DiscardPadding element value.
|
||||
// track_number: Track to add the data to. Value returned by Add track
|
||||
|
@ -1086,7 +1203,7 @@ class Segment {
|
|||
// timestamp: Absolute timestamp of the frame, expressed in nanosecond
|
||||
// units.
|
||||
// is_key: Flag telling whether or not this frame is a key frame.
|
||||
bool AddFrameWithDiscardPadding(const uint8* frame, uint64 length,
|
||||
bool AddFrameWithDiscardPadding(const uint8* data, uint64 length,
|
||||
int64 discard_padding, uint64 track_number,
|
||||
uint64 timestamp, bool is_key);
|
||||
|
||||
|
@ -1177,6 +1294,9 @@ class Segment {
|
|||
// Cues elements.
|
||||
bool CheckHeaderInfo();
|
||||
|
||||
// Sets |doc_type_version_| based on the current element requirements.
|
||||
void UpdateDocTypeVersion();
|
||||
|
||||
// Sets |name| according to how many chunks have been written. |ext| is the
|
||||
// file extension. |name| must be deleted by the calling app. Returns true
|
||||
// on success.
|
||||
|
@ -1233,7 +1353,7 @@ class Segment {
|
|||
// diff - indicates the difference in size of the Cues element that needs to
|
||||
// accounted for.
|
||||
// index - index in the list of Cues which is currently being adjusted.
|
||||
// cue_size - size of the Cues element.
|
||||
// cue_size - sum of size of all the CuePoint elements.
|
||||
void MoveCuesBeforeClustersHelper(uint64 diff, int index, uint64* cue_size);
|
||||
|
||||
// Seeds the random number generator used to make UIDs.
|
||||
|
@ -1245,6 +1365,7 @@ class Segment {
|
|||
SegmentInfo segment_info_;
|
||||
Tracks tracks_;
|
||||
Chapters chapters_;
|
||||
Tags tags_;
|
||||
|
||||
// Number of chunks written.
|
||||
int chunk_count_;
|
||||
|
@ -1316,6 +1437,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.
|
||||
|
@ -1337,12 +1461,23 @@ class Segment {
|
|||
// Flag whether or not the muxer should output a Cues element.
|
||||
bool output_cues_;
|
||||
|
||||
// The size of the EBML header, used to validate the header if
|
||||
// WriteEbmlHeader() is called more than once.
|
||||
int32 ebml_header_size_;
|
||||
|
||||
// The file position of the segment's payload.
|
||||
int64 payload_pos_;
|
||||
|
||||
// The file position of the element's size.
|
||||
int64 size_position_;
|
||||
|
||||
// Current DocTypeVersion (|doc_type_version_|) and that written in
|
||||
// WriteSegmentHeader().
|
||||
// WriteEbmlHeader() will be called from Finalize() if |doc_type_version_|
|
||||
// differs from |doc_type_version_written_|.
|
||||
uint32 doc_type_version_;
|
||||
uint32 doc_type_version_written_;
|
||||
|
||||
// Pointer to the writer objects. Not owned by this class.
|
||||
IMkvWriter* writer_cluster_;
|
||||
IMkvWriter* writer_cues_;
|
||||
|
|
|
@ -15,18 +15,19 @@
|
|||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#ifdef _MSC_VER
|
||||
#define _CRT_RAND_S
|
||||
#endif
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "mkvwriter.hpp"
|
||||
#include "webmids.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Disable MSVC warnings that suggest making code non-portable.
|
||||
#pragma warning(disable : 4996)
|
||||
#endif
|
||||
|
||||
namespace mkvmuxer {
|
||||
|
||||
namespace {
|
||||
|
@ -34,6 +35,144 @@ namespace {
|
|||
// Date elements are always 8 octets in size.
|
||||
const int kDateElementSize = 8;
|
||||
|
||||
uint64 WriteBlock(IMkvWriter* writer, const Frame* const frame, int64 timecode,
|
||||
uint64 timecode_scale) {
|
||||
uint64 block_additional_elem_size = 0;
|
||||
uint64 block_addid_elem_size = 0;
|
||||
uint64 block_more_payload_size = 0;
|
||||
uint64 block_more_elem_size = 0;
|
||||
uint64 block_additions_payload_size = 0;
|
||||
uint64 block_additions_elem_size = 0;
|
||||
if (frame->additional()) {
|
||||
block_additional_elem_size = EbmlElementSize(
|
||||
kMkvBlockAdditional, frame->additional(), frame->additional_length());
|
||||
block_addid_elem_size = EbmlElementSize(kMkvBlockAddID, frame->add_id());
|
||||
|
||||
block_more_payload_size =
|
||||
block_addid_elem_size + block_additional_elem_size;
|
||||
block_more_elem_size =
|
||||
EbmlMasterElementSize(kMkvBlockMore, block_more_payload_size) +
|
||||
block_more_payload_size;
|
||||
block_additions_payload_size = block_more_elem_size;
|
||||
block_additions_elem_size =
|
||||
EbmlMasterElementSize(kMkvBlockAdditions,
|
||||
block_additions_payload_size) +
|
||||
block_additions_payload_size;
|
||||
}
|
||||
|
||||
uint64 discard_padding_elem_size = 0;
|
||||
if (frame->discard_padding() != 0) {
|
||||
discard_padding_elem_size =
|
||||
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);
|
||||
|
||||
const uint64 block_payload_size = 4 + frame->length();
|
||||
const uint64 block_elem_size =
|
||||
EbmlMasterElementSize(kMkvBlock, block_payload_size) + block_payload_size;
|
||||
|
||||
const uint64 block_group_payload_size =
|
||||
block_elem_size + block_additions_elem_size + block_duration_elem_size +
|
||||
discard_padding_elem_size + reference_block_elem_size;
|
||||
|
||||
if (!WriteEbmlMasterElement(writer, kMkvBlockGroup,
|
||||
block_group_payload_size)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!WriteEbmlMasterElement(writer, kMkvBlock, block_payload_size))
|
||||
return 0;
|
||||
|
||||
if (WriteUInt(writer, frame->track_number()))
|
||||
return 0;
|
||||
|
||||
if (SerializeInt(writer, timecode, 2))
|
||||
return 0;
|
||||
|
||||
// For a Block, flags is always 0.
|
||||
if (SerializeInt(writer, 0, 1))
|
||||
return 0;
|
||||
|
||||
if (writer->Write(frame->frame(), static_cast<uint32>(frame->length())))
|
||||
return 0;
|
||||
|
||||
if (frame->additional()) {
|
||||
if (!WriteEbmlMasterElement(writer, kMkvBlockAdditions,
|
||||
block_additions_payload_size)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!WriteEbmlMasterElement(writer, kMkvBlockMore, block_more_payload_size))
|
||||
return 0;
|
||||
|
||||
if (!WriteEbmlElement(writer, kMkvBlockAddID, frame->add_id()))
|
||||
return 0;
|
||||
|
||||
if (!WriteEbmlElement(writer, kMkvBlockAdditional, frame->additional(),
|
||||
frame->additional_length())) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (frame->discard_padding() != 0 &&
|
||||
!WriteEbmlElement(writer, kMkvDiscardPadding, frame->discard_padding())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!frame->is_key() &&
|
||||
!WriteEbmlElement(writer, kMkvReferenceBlock,
|
||||
reference_block_timestamp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (duration > 0 && !WriteEbmlElement(writer, kMkvBlockDuration, duration)) {
|
||||
return false;
|
||||
}
|
||||
return EbmlMasterElementSize(kMkvBlockGroup, block_group_payload_size) +
|
||||
block_group_payload_size;
|
||||
}
|
||||
|
||||
uint64 WriteSimpleBlock(IMkvWriter* writer, const Frame* const frame,
|
||||
int64 timecode) {
|
||||
if (WriteID(writer, kMkvSimpleBlock))
|
||||
return 0;
|
||||
|
||||
const int32 size = static_cast<int32>(frame->length()) + 4;
|
||||
if (WriteUInt(writer, size))
|
||||
return 0;
|
||||
|
||||
if (WriteUInt(writer, static_cast<uint64>(frame->track_number())))
|
||||
return 0;
|
||||
|
||||
if (SerializeInt(writer, timecode, 2))
|
||||
return 0;
|
||||
|
||||
uint64 flags = 0;
|
||||
if (frame->is_key())
|
||||
flags |= 0x80;
|
||||
|
||||
if (SerializeInt(writer, flags, 1))
|
||||
return 0;
|
||||
|
||||
if (writer->Write(frame->frame(), static_cast<uint32>(frame->length())))
|
||||
return 0;
|
||||
|
||||
return GetUIntSize(kMkvSimpleBlock) + GetCodedUIntSize(size) + 4 +
|
||||
frame->length();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int32 GetCodedUIntSize(uint64 value) {
|
||||
|
@ -72,6 +211,13 @@ int32 GetUIntSize(uint64 value) {
|
|||
return 8;
|
||||
}
|
||||
|
||||
int32 GetIntSize(int64 value) {
|
||||
// Doubling the requested value ensures positive values with their high bit
|
||||
// set are written with 0-padding to avoid flipping the signedness.
|
||||
const uint64 v = (value < 0) ? value ^ -1LL : value;
|
||||
return GetUIntSize(2 * v);
|
||||
}
|
||||
|
||||
uint64 EbmlMasterElementSize(uint64 type, uint64 value) {
|
||||
// Size of EBML ID
|
||||
int32 ebml_size = GetUIntSize(type);
|
||||
|
@ -83,7 +229,16 @@ uint64 EbmlMasterElementSize(uint64 type, uint64 value) {
|
|||
}
|
||||
|
||||
uint64 EbmlElementSize(uint64 type, int64 value) {
|
||||
return EbmlElementSize(type, static_cast<uint64>(value));
|
||||
// Size of EBML ID
|
||||
int32 ebml_size = GetUIntSize(type);
|
||||
|
||||
// Datasize
|
||||
ebml_size += GetIntSize(value);
|
||||
|
||||
// Size of Datasize
|
||||
ebml_size++;
|
||||
|
||||
return ebml_size;
|
||||
}
|
||||
|
||||
uint64 EbmlElementSize(uint64 type, uint64 value) {
|
||||
|
@ -144,7 +299,7 @@ uint64 EbmlElementSize(uint64 type, const uint8* value, uint64 size) {
|
|||
return ebml_size;
|
||||
}
|
||||
|
||||
uint64 EbmlDateElementSize(uint64 type, int64 value) {
|
||||
uint64 EbmlDateElementSize(uint64 type) {
|
||||
// Size of EBML ID
|
||||
uint64 ebml_size = GetUIntSize(type);
|
||||
|
||||
|
@ -289,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;
|
||||
|
@ -355,289 +527,25 @@ bool WriteEbmlDateElement(IMkvWriter* writer, uint64 type, int64 value) {
|
|||
return true;
|
||||
}
|
||||
|
||||
uint64 WriteSimpleBlock(IMkvWriter* writer, const uint8* data, uint64 length,
|
||||
uint64 track_number, int64 timecode, uint64 is_key) {
|
||||
if (!writer)
|
||||
return false;
|
||||
uint64 WriteFrame(IMkvWriter* writer, const Frame* const frame,
|
||||
Cluster* cluster) {
|
||||
if (!writer || !frame || !frame->IsValid() || !cluster ||
|
||||
!cluster->timecode_scale())
|
||||
return 0;
|
||||
|
||||
if (!data || length < 1)
|
||||
return false;
|
||||
|
||||
// Here we only permit track number values to be no greater than
|
||||
// 126, which the largest value we can store having a Matroska
|
||||
// integer representation of only 1 byte.
|
||||
|
||||
if (track_number < 1 || track_number > 126)
|
||||
return false;
|
||||
|
||||
// Technically the timestamp for a block can be less than the
|
||||
// timestamp for the cluster itself (remember that block timestamp
|
||||
// Technically the timecode for a block can be less than the
|
||||
// timecode for the cluster itself (remember that block timecode
|
||||
// is a signed, 16-bit integer). However, as a simplification we
|
||||
// only permit non-negative cluster-relative timestamps for blocks.
|
||||
|
||||
if (timecode < 0 || timecode > kMaxBlockTimecode)
|
||||
return false;
|
||||
|
||||
if (WriteID(writer, kMkvSimpleBlock))
|
||||
// only permit non-negative cluster-relative timecodes for blocks.
|
||||
const int64 relative_timecode = cluster->GetRelativeTimecode(
|
||||
frame->timestamp() / cluster->timecode_scale());
|
||||
if (relative_timecode < 0 || relative_timecode > kMaxBlockTimecode)
|
||||
return 0;
|
||||
|
||||
const int32 size = static_cast<int32>(length) + 4;
|
||||
if (WriteUInt(writer, size))
|
||||
return 0;
|
||||
|
||||
if (WriteUInt(writer, static_cast<uint64>(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;
|
||||
|
||||
const uint64 element_size =
|
||||
GetUIntSize(kMkvSimpleBlock) + GetCodedUIntSize(size) + 4 + length;
|
||||
|
||||
return element_size;
|
||||
}
|
||||
|
||||
// We must write the metadata (key)frame as a BlockGroup element,
|
||||
// because we need to specify a duration for the frame. The
|
||||
// BlockGroup element comprises the frame itself and its duration,
|
||||
// and is laid out as follows:
|
||||
//
|
||||
// BlockGroup tag
|
||||
// BlockGroup size
|
||||
// Block tag
|
||||
// Block size
|
||||
// (the frame is the block payload)
|
||||
// Duration tag
|
||||
// Duration size
|
||||
// (duration payload)
|
||||
//
|
||||
uint64 WriteMetadataBlock(IMkvWriter* writer, const uint8* data, uint64 length,
|
||||
uint64 track_number, int64 timecode,
|
||||
uint64 duration) {
|
||||
// We don't backtrack when writing to the stream, so we must
|
||||
// pre-compute the BlockGroup size, by summing the sizes of each
|
||||
// sub-element (the block and the duration).
|
||||
|
||||
// We use a single byte for the track number of the block, which
|
||||
// means the block header is exactly 4 bytes.
|
||||
|
||||
// TODO(matthewjheaney): use EbmlMasterElementSize and WriteEbmlMasterElement
|
||||
|
||||
const uint64 block_payload_size = 4 + length;
|
||||
const int32 block_size = GetCodedUIntSize(block_payload_size);
|
||||
const uint64 block_elem_size = 1 + block_size + block_payload_size;
|
||||
|
||||
const int32 duration_payload_size = GetUIntSize(duration);
|
||||
const int32 duration_size = GetCodedUIntSize(duration_payload_size);
|
||||
const uint64 duration_elem_size = 1 + duration_size + duration_payload_size;
|
||||
|
||||
const uint64 blockg_payload_size = block_elem_size + duration_elem_size;
|
||||
const int32 blockg_size = GetCodedUIntSize(blockg_payload_size);
|
||||
const uint64 blockg_elem_size = 1 + blockg_size + blockg_payload_size;
|
||||
|
||||
if (WriteID(writer, kMkvBlockGroup)) // 1-byte ID size
|
||||
return 0;
|
||||
|
||||
if (WriteUInt(writer, blockg_payload_size))
|
||||
return 0;
|
||||
|
||||
// Write Block element
|
||||
|
||||
if (WriteID(writer, kMkvBlock)) // 1-byte ID size
|
||||
return 0;
|
||||
|
||||
if (WriteUInt(writer, block_payload_size))
|
||||
return 0;
|
||||
|
||||
// Byte 1 of 4
|
||||
|
||||
if (WriteUInt(writer, track_number))
|
||||
return 0;
|
||||
|
||||
// Bytes 2 & 3 of 4
|
||||
|
||||
if (SerializeInt(writer, timecode, 2))
|
||||
return 0;
|
||||
|
||||
// Byte 4 of 4
|
||||
|
||||
const uint64 flags = 0;
|
||||
|
||||
if (SerializeInt(writer, flags, 1))
|
||||
return 0;
|
||||
|
||||
// Now write the actual frame (of metadata)
|
||||
|
||||
if (writer->Write(data, static_cast<uint32>(length)))
|
||||
return 0;
|
||||
|
||||
// Write Duration element
|
||||
|
||||
if (WriteID(writer, kMkvBlockDuration)) // 1-byte ID size
|
||||
return 0;
|
||||
|
||||
if (WriteUInt(writer, duration_payload_size))
|
||||
return 0;
|
||||
|
||||
if (SerializeInt(writer, duration, duration_payload_size))
|
||||
return 0;
|
||||
|
||||
// Note that we don't write a reference time as part of the block
|
||||
// group; no reference time(s) indicates that this block is a
|
||||
// keyframe. (Unlike the case for a SimpleBlock element, the header
|
||||
// bits of the Block sub-element of a BlockGroup element do not
|
||||
// indicate keyframe status. The keyframe status is inferred from
|
||||
// the absence of reference time sub-elements.)
|
||||
|
||||
return blockg_elem_size;
|
||||
}
|
||||
|
||||
// Writes a WebM BlockGroup with BlockAdditional data. 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(kMkvBlockAdditions, 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;
|
||||
}
|
||||
|
||||
// Writes a WebM BlockGroup with DiscardPadding. The structure is as follows:
|
||||
// Indentation shows sub-levels
|
||||
// BlockGroup
|
||||
// Block
|
||||
// Data
|
||||
// DiscardPadding
|
||||
uint64 WriteBlockWithDiscardPadding(IMkvWriter* writer, const uint8* data,
|
||||
uint64 length, int64 discard_padding,
|
||||
uint64 track_number, int64 timecode,
|
||||
uint64 is_key) {
|
||||
if (!data || length < 1 || discard_padding <= 0)
|
||||
return 0;
|
||||
|
||||
const uint64 block_payload_size = 4 + length;
|
||||
const uint64 block_elem_size =
|
||||
EbmlMasterElementSize(kMkvBlock, block_payload_size) + block_payload_size;
|
||||
const uint64 discard_padding_elem_size =
|
||||
EbmlElementSize(kMkvDiscardPadding, discard_padding);
|
||||
const uint64 block_group_payload_size =
|
||||
block_elem_size + discard_padding_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 (WriteID(writer, kMkvDiscardPadding))
|
||||
return 0;
|
||||
|
||||
const uint64 size = GetUIntSize(discard_padding);
|
||||
if (WriteUInt(writer, size))
|
||||
return false;
|
||||
|
||||
if (SerializeInt(writer, discard_padding, static_cast<int32>(size)))
|
||||
return false;
|
||||
|
||||
return block_group_elem_size;
|
||||
return frame->CanBeSimpleBlock() ?
|
||||
WriteSimpleBlock(writer, frame, relative_timecode) :
|
||||
WriteBlock(writer, frame, relative_timecode,
|
||||
cluster->timecode_scale());
|
||||
}
|
||||
|
||||
uint64 WriteVoidElement(IMkvWriter* writer, uint64 size) {
|
||||
|
@ -698,10 +606,7 @@ mkvmuxer::uint64 mkvmuxer::MakeUID(unsigned int* seed) {
|
|||
// TODO(fgalligan): Move random number generation to platform specific code.
|
||||
#ifdef _MSC_VER
|
||||
(void)seed;
|
||||
unsigned int random_value;
|
||||
const errno_t e = rand_s(&random_value);
|
||||
(void)e;
|
||||
const int32 nn = random_value;
|
||||
const int32 nn = rand();
|
||||
#elif __ANDROID__
|
||||
int32 temp_num = 1;
|
||||
int fd = open("/dev/urandom", O_RDONLY);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#ifndef MKVMUXERUTIL_HPP
|
||||
#define MKVMUXERUTIL_HPP
|
||||
|
||||
#include "mkvmuxer.hpp"
|
||||
#include "mkvmuxertypes.hpp"
|
||||
|
||||
namespace mkvmuxer {
|
||||
|
@ -23,6 +24,7 @@ int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size);
|
|||
|
||||
// Returns the size in bytes of the element.
|
||||
int32 GetUIntSize(uint64 value);
|
||||
int32 GetIntSize(int64 value);
|
||||
int32 GetCodedUIntSize(uint64 value);
|
||||
uint64 EbmlMasterElementSize(uint64 type, uint64 value);
|
||||
uint64 EbmlElementSize(uint64 type, int64 value);
|
||||
|
@ -30,7 +32,7 @@ uint64 EbmlElementSize(uint64 type, uint64 value);
|
|||
uint64 EbmlElementSize(uint64 type, float value);
|
||||
uint64 EbmlElementSize(uint64 type, const char* value);
|
||||
uint64 EbmlElementSize(uint64 type, const uint8* value, uint64 size);
|
||||
uint64 EbmlDateElementSize(uint64 type, int64 value);
|
||||
uint64 EbmlDateElementSize(uint64 type);
|
||||
|
||||
// Creates an EBML coded number from |value| and writes it out. The size of
|
||||
// the coded number is determined by the value of |value|. |value| must not
|
||||
|
@ -51,73 +53,17 @@ 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,
|
||||
uint64 size);
|
||||
bool WriteEbmlDateElement(IMkvWriter* writer, uint64 type, int64 value);
|
||||
|
||||
// Output an Mkv Simple Block.
|
||||
// Inputs:
|
||||
// data: Pointer to the data.
|
||||
// length: Length of the data.
|
||||
// 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 WriteSimpleBlock(IMkvWriter* writer, const uint8* data, uint64 length,
|
||||
uint64 track_number, int64 timecode, uint64 is_key);
|
||||
|
||||
// Output a metadata keyframe, using a Block Group element.
|
||||
// Inputs:
|
||||
// data: Pointer to the (meta)data.
|
||||
// length: Length of the (meta)data.
|
||||
// track_number: Track to add the data to. Value returned by Add track
|
||||
// functions. Only values in the range [1, 126] are
|
||||
// permitted.
|
||||
// timecode Timecode of frame, relative to cluster timecode. Only
|
||||
// values in the range [0, 2^15) are permitted.
|
||||
// duration_timecode Duration of frame, using timecode units.
|
||||
uint64 WriteMetadataBlock(IMkvWriter* writer, const uint8* data, uint64 length,
|
||||
uint64 track_number, 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 an Mkv Block with a DiscardPadding element.
|
||||
// Inputs:
|
||||
// data: Pointer to the data.
|
||||
// length: Length of the data.
|
||||
// discard_padding: DiscardPadding value.
|
||||
// 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 WriteBlockWithDiscardPadding(IMkvWriter* writer, const uint8* data,
|
||||
uint64 length, int64 discard_padding,
|
||||
uint64 track_number, int64 timecode,
|
||||
uint64 is_key);
|
||||
// Output a Mkv Frame. It decides the correct element to write (Block vs
|
||||
// SimpleBlock) based on the parameters of the Frame.
|
||||
uint64 WriteFrame(IMkvWriter* writer, const Frame* const frame,
|
||||
Cluster* cluster);
|
||||
|
||||
// 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
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -398,6 +398,10 @@ class VideoTrack : public Track {
|
|||
|
||||
long long GetWidth() const;
|
||||
long long GetHeight() const;
|
||||
long long GetDisplayWidth() const;
|
||||
long long GetDisplayHeight() const;
|
||||
long long GetDisplayUnit() const;
|
||||
long long GetStereoMode() const;
|
||||
double GetFrameRate() const;
|
||||
|
||||
bool VetEntry(const BlockEntry*) const;
|
||||
|
@ -406,6 +410,11 @@ class VideoTrack : public Track {
|
|||
private:
|
||||
long long m_width;
|
||||
long long m_height;
|
||||
long long m_display_width;
|
||||
long long m_display_height;
|
||||
long long m_display_unit;
|
||||
long long m_stereo_mode;
|
||||
|
||||
double m_rate;
|
||||
};
|
||||
|
||||
|
@ -582,6 +591,85 @@ class Chapters {
|
|||
int m_editions_count;
|
||||
};
|
||||
|
||||
class Tags {
|
||||
Tags(const Tags&);
|
||||
Tags& operator=(const Tags&);
|
||||
|
||||
public:
|
||||
Segment* const m_pSegment;
|
||||
const long long m_start;
|
||||
const long long m_size;
|
||||
const long long m_element_start;
|
||||
const long long m_element_size;
|
||||
|
||||
Tags(Segment*, long long payload_start, long long payload_size,
|
||||
long long element_start, long long element_size);
|
||||
|
||||
~Tags();
|
||||
|
||||
long Parse();
|
||||
|
||||
class Tag;
|
||||
class SimpleTag;
|
||||
|
||||
class SimpleTag {
|
||||
friend class Tag;
|
||||
SimpleTag();
|
||||
SimpleTag(const SimpleTag&);
|
||||
~SimpleTag();
|
||||
SimpleTag& operator=(const SimpleTag&);
|
||||
|
||||
public:
|
||||
const char* GetTagName() const;
|
||||
const char* GetTagString() const;
|
||||
|
||||
private:
|
||||
void Init();
|
||||
void ShallowCopy(SimpleTag&) const;
|
||||
void Clear();
|
||||
long Parse(IMkvReader*, long long pos, long long size);
|
||||
|
||||
char* m_tag_name;
|
||||
char* m_tag_string;
|
||||
};
|
||||
|
||||
class Tag {
|
||||
friend class Tags;
|
||||
Tag();
|
||||
Tag(const Tag&);
|
||||
~Tag();
|
||||
Tag& operator=(const Tag&);
|
||||
|
||||
public:
|
||||
int GetSimpleTagCount() const;
|
||||
const SimpleTag* GetSimpleTag(int index) const;
|
||||
|
||||
private:
|
||||
void Init();
|
||||
void ShallowCopy(Tag&) const;
|
||||
void Clear();
|
||||
long Parse(IMkvReader*, long long pos, long long size);
|
||||
|
||||
long ParseSimpleTag(IMkvReader*, long long pos, long long size);
|
||||
bool ExpandSimpleTagsArray();
|
||||
|
||||
SimpleTag* m_simple_tags;
|
||||
int m_simple_tags_size;
|
||||
int m_simple_tags_count;
|
||||
};
|
||||
|
||||
int GetTagCount() const;
|
||||
const Tag* GetTag(int index) const;
|
||||
|
||||
private:
|
||||
long ParseTag(long long pos, long long size);
|
||||
bool ExpandTagsArray();
|
||||
|
||||
Tag* m_tags;
|
||||
int m_tags_size;
|
||||
int m_tags_count;
|
||||
};
|
||||
|
||||
class SegmentInfo {
|
||||
SegmentInfo(const SegmentInfo&);
|
||||
SegmentInfo& operator=(const SegmentInfo&);
|
||||
|
@ -684,7 +772,7 @@ class CuePoint {
|
|||
long long m_element_start;
|
||||
long long m_element_size;
|
||||
|
||||
void Load(IMkvReader*);
|
||||
bool Load(IMkvReader*);
|
||||
|
||||
long long GetTimeCode() const; // absolute but unscaled
|
||||
long long GetTime(const Segment*) const; // absolute and scaled (ns units)
|
||||
|
@ -697,7 +785,7 @@ class CuePoint {
|
|||
// reference = clusters containing req'd referenced blocks
|
||||
// reftime = timecode of the referenced block
|
||||
|
||||
void Parse(IMkvReader*, long long, long long);
|
||||
bool Parse(IMkvReader*, long long, long long);
|
||||
};
|
||||
|
||||
const TrackPosition* Find(const Track*) const;
|
||||
|
@ -730,14 +818,6 @@ class Cues {
|
|||
long long time_ns, const Track*, const CuePoint*&,
|
||||
const CuePoint::TrackPosition*&) const;
|
||||
|
||||
#if 0
|
||||
bool FindNext( //upper_bound of time_ns
|
||||
long long time_ns,
|
||||
const Track*,
|
||||
const CuePoint*&,
|
||||
const CuePoint::TrackPosition*&) const;
|
||||
#endif
|
||||
|
||||
const CuePoint* GetFirst() const;
|
||||
const CuePoint* GetLast() const;
|
||||
const CuePoint* GetNext(const CuePoint*) const;
|
||||
|
@ -751,7 +831,7 @@ class Cues {
|
|||
bool DoneParsing() const;
|
||||
|
||||
private:
|
||||
void Init() const;
|
||||
bool Init() const;
|
||||
void PreloadCuePoint(long&, long long) const;
|
||||
|
||||
mutable CuePoint** m_cue_points;
|
||||
|
@ -877,18 +957,12 @@ class Segment {
|
|||
long ParseNext(const Cluster* pCurr, const Cluster*& pNext, long long& pos,
|
||||
long& size);
|
||||
|
||||
#if 0
|
||||
//This pair parses one cluster, but only changes the state of the
|
||||
//segment object when the cluster is actually added to the index.
|
||||
long ParseCluster(long long& cluster_pos, long long& new_pos) const;
|
||||
bool AddCluster(long long cluster_pos, long long new_pos);
|
||||
#endif
|
||||
|
||||
const SeekHead* GetSeekHead() const;
|
||||
const Tracks* GetTracks() const;
|
||||
const SegmentInfo* GetInfo() const;
|
||||
const Cues* GetCues() const;
|
||||
const Chapters* GetChapters() const;
|
||||
const Tags* GetTags() const;
|
||||
|
||||
long long GetDuration() const;
|
||||
|
||||
|
@ -914,6 +988,7 @@ class Segment {
|
|||
Tracks* m_pTracks;
|
||||
Cues* m_pCues;
|
||||
Chapters* m_pChapters;
|
||||
Tags* m_pTags;
|
||||
Cluster** m_clusters;
|
||||
long m_clusterCount; // number of entries for which m_index >= 0
|
||||
long m_clusterPreloadCount; // number of entries for which m_index < 0
|
||||
|
|
|
@ -133,7 +133,13 @@ enum MkvId {
|
|||
kMkvChapterDisplay = 0x80,
|
||||
kMkvChapString = 0x85,
|
||||
kMkvChapLanguage = 0x437C,
|
||||
kMkvChapCountry = 0x437E
|
||||
kMkvChapCountry = 0x437E,
|
||||
// Tags
|
||||
kMkvTags = 0x1254C367,
|
||||
kMkvTag = 0x7373,
|
||||
kMkvSimpleTag = 0x67C8,
|
||||
kMkvTagName = 0x45A3,
|
||||
kMkvTagString = 0x4487
|
||||
};
|
||||
|
||||
} // end namespace mkvmuxer
|
||||
|
|
Загрузка…
Ссылка в новой задаче