1493 строки
51 KiB
C++
1493 строки
51 KiB
C++
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
|
//
|
|
// Use of this source code is governed by a BSD-style license
|
|
// that can be found in the LICENSE file in the root of the source
|
|
// tree. An additional intellectual property rights grant can be found
|
|
// in the file PATENTS. All contributing project authors may
|
|
// be found in the AUTHORS file in the root of the source tree.
|
|
|
|
#ifndef MKVMUXER_HPP
|
|
#define MKVMUXER_HPP
|
|
|
|
#include "mkvmuxertypes.hpp"
|
|
|
|
// For a description of the WebM elements see
|
|
// http://www.webmproject.org/code/specs/container/.
|
|
|
|
namespace mkvparser {
|
|
class IMkvReader;
|
|
} // end namespace
|
|
|
|
namespace mkvmuxer {
|
|
|
|
class MkvWriter;
|
|
class Segment;
|
|
|
|
const uint64 kMaxTrackNumber = 126;
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Interface used by the mkvmuxer to write out the Mkv data.
|
|
class IMkvWriter {
|
|
public:
|
|
// Writes out |len| bytes of |buf|. Returns 0 on success.
|
|
virtual int32 Write(const void* buf, uint32 len) = 0;
|
|
|
|
// Returns the offset of the output position from the beginning of the
|
|
// output.
|
|
virtual int64 Position() const = 0;
|
|
|
|
// Set the current File position. Returns 0 on success.
|
|
virtual int32 Position(int64 position) = 0;
|
|
|
|
// Returns true if the writer is seekable.
|
|
virtual bool Seekable() const = 0;
|
|
|
|
// Element start notification. Called whenever an element identifier is about
|
|
// to be written to the stream. |element_id| is the element identifier, and
|
|
// |position| is the location in the WebM stream where the first octet of the
|
|
// element identifier will be written.
|
|
// Note: the |MkvId| enumeration in webmids.hpp defines element values.
|
|
virtual void ElementStartNotify(uint64 element_id, int64 position) = 0;
|
|
|
|
protected:
|
|
IMkvWriter();
|
|
virtual ~IMkvWriter();
|
|
|
|
private:
|
|
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(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
|
|
bool ChunkedCopy(mkvparser::IMkvReader* source, IMkvWriter* dst, int64 start,
|
|
int64 size);
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Class to hold data the will be written to a block.
|
|
class Frame {
|
|
public:
|
|
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_; }
|
|
void set_duration(uint64 duration) { duration_ = duration; }
|
|
uint64 duration() const { return duration_; }
|
|
const uint8* frame() const { return frame_; }
|
|
void set_is_key(bool key) { is_key_ = key; }
|
|
bool is_key() const { return is_key_; }
|
|
uint64 length() const { return length_; }
|
|
void set_track_number(uint64 track_number) { track_number_ = track_number; }
|
|
uint64 track_number() const { return track_number_; }
|
|
void set_timestamp(uint64 timestamp) { timestamp_ = timestamp; }
|
|
uint64 timestamp() const { return timestamp_; }
|
|
void set_discard_padding(int64 discard_padding) {
|
|
discard_padding_ = discard_padding;
|
|
}
|
|
int64 discard_padding() const { return discard_padding_; }
|
|
void set_reference_block_timestamp(int64 reference_block_timestamp);
|
|
int64 reference_block_timestamp() const { return reference_block_timestamp_; }
|
|
bool reference_block_timestamp_set() const {
|
|
return reference_block_timestamp_set_;
|
|
}
|
|
|
|
private:
|
|
// Id of the Additional data.
|
|
uint64 add_id_;
|
|
|
|
// Pointer to additional data. Owned by this class.
|
|
uint8* additional_;
|
|
|
|
// Length of the additional data.
|
|
uint64 additional_length_;
|
|
|
|
// Duration of the frame in nanoseconds.
|
|
uint64 duration_;
|
|
|
|
// Pointer to the data. Owned by this class.
|
|
uint8* frame_;
|
|
|
|
// Flag telling if the data should set the key flag of a block.
|
|
bool is_key_;
|
|
|
|
// Length of the data.
|
|
uint64 length_;
|
|
|
|
// Mkv track number the data is associated with.
|
|
uint64 track_number_;
|
|
|
|
// Timestamp of the data in nanoseconds.
|
|
uint64 timestamp_;
|
|
|
|
// 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);
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Class to hold one cue point in a Cues element.
|
|
class CuePoint {
|
|
public:
|
|
CuePoint();
|
|
~CuePoint();
|
|
|
|
// Returns the size in bytes for the entire CuePoint element.
|
|
uint64 Size() const;
|
|
|
|
// Output the CuePoint element to the writer. Returns true on success.
|
|
bool Write(IMkvWriter* writer) const;
|
|
|
|
void set_time(uint64 time) { time_ = time; }
|
|
uint64 time() const { return time_; }
|
|
void set_track(uint64 track) { track_ = track; }
|
|
uint64 track() const { return track_; }
|
|
void set_cluster_pos(uint64 cluster_pos) { cluster_pos_ = cluster_pos; }
|
|
uint64 cluster_pos() const { return cluster_pos_; }
|
|
void set_block_number(uint64 block_number) { block_number_ = block_number; }
|
|
uint64 block_number() const { return block_number_; }
|
|
void set_output_block_number(bool output_block_number) {
|
|
output_block_number_ = output_block_number;
|
|
}
|
|
bool output_block_number() const { return output_block_number_; }
|
|
|
|
private:
|
|
// Returns the size in bytes for the payload of the CuePoint element.
|
|
uint64 PayloadSize() const;
|
|
|
|
// Absolute timecode according to the segment time base.
|
|
uint64 time_;
|
|
|
|
// The Track element associated with the CuePoint.
|
|
uint64 track_;
|
|
|
|
// The position of the Cluster containing the Block.
|
|
uint64 cluster_pos_;
|
|
|
|
// Number of the Block within the Cluster, starting from 1.
|
|
uint64 block_number_;
|
|
|
|
// If true the muxer will write out the block number for the cue if the
|
|
// block number is different than the default of 1. Default is set to true.
|
|
bool output_block_number_;
|
|
|
|
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(CuePoint);
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Cues element.
|
|
class Cues {
|
|
public:
|
|
Cues();
|
|
~Cues();
|
|
|
|
// Adds a cue point to the Cues element. Returns true on success.
|
|
bool AddCue(CuePoint* cue);
|
|
|
|
// Returns the cue point by index. Returns NULL if there is no cue point
|
|
// match.
|
|
CuePoint* GetCueByIndex(int32 index) const;
|
|
|
|
// Returns the total size of the Cues element
|
|
uint64 Size();
|
|
|
|
// Output the Cues element to the writer. Returns true on success.
|
|
bool Write(IMkvWriter* writer) const;
|
|
|
|
int32 cue_entries_size() const { return cue_entries_size_; }
|
|
void set_output_block_number(bool output_block_number) {
|
|
output_block_number_ = output_block_number;
|
|
}
|
|
bool output_block_number() const { return output_block_number_; }
|
|
|
|
private:
|
|
// Number of allocated elements in |cue_entries_|.
|
|
int32 cue_entries_capacity_;
|
|
|
|
// Number of CuePoints in |cue_entries_|.
|
|
int32 cue_entries_size_;
|
|
|
|
// CuePoint list.
|
|
CuePoint** cue_entries_;
|
|
|
|
// If true the muxer will write out the block number for the cue if the
|
|
// block number is different than the default of 1. Default is set to true.
|
|
bool output_block_number_;
|
|
|
|
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Cues);
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// ContentEncAESSettings element
|
|
class ContentEncAESSettings {
|
|
public:
|
|
enum { kCTR = 1 };
|
|
|
|
ContentEncAESSettings();
|
|
~ContentEncAESSettings() {}
|
|
|
|
// Returns the size in bytes for the ContentEncAESSettings element.
|
|
uint64 Size() const;
|
|
|
|
// Writes out the ContentEncAESSettings element to |writer|. Returns true on
|
|
// success.
|
|
bool Write(IMkvWriter* writer) const;
|
|
|
|
uint64 cipher_mode() const { return cipher_mode_; }
|
|
|
|
private:
|
|
// Returns the size in bytes for the payload of the ContentEncAESSettings
|
|
// element.
|
|
uint64 PayloadSize() const;
|
|
|
|
// Sub elements
|
|
uint64 cipher_mode_;
|
|
|
|
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncAESSettings);
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// ContentEncoding element
|
|
// Elements used to describe if the track data has been encrypted or
|
|
// compressed with zlib or header stripping.
|
|
// Currently only whole frames can be encrypted with AES. This dictates that
|
|
// ContentEncodingOrder will be 0, ContentEncodingScope will be 1,
|
|
// ContentEncodingType will be 1, and ContentEncAlgo will be 5.
|
|
class ContentEncoding {
|
|
public:
|
|
ContentEncoding();
|
|
~ContentEncoding();
|
|
|
|
// Sets the content encryption id. Copies |length| bytes from |id| to
|
|
// |enc_key_id_|. Returns true on success.
|
|
bool SetEncryptionID(const uint8* id, uint64 length);
|
|
|
|
// Returns the size in bytes for the ContentEncoding element.
|
|
uint64 Size() const;
|
|
|
|
// Writes out the ContentEncoding element to |writer|. Returns true on
|
|
// success.
|
|
bool Write(IMkvWriter* writer) const;
|
|
|
|
uint64 enc_algo() const { return enc_algo_; }
|
|
uint64 encoding_order() const { return encoding_order_; }
|
|
uint64 encoding_scope() const { return encoding_scope_; }
|
|
uint64 encoding_type() const { return encoding_type_; }
|
|
ContentEncAESSettings* enc_aes_settings() { return &enc_aes_settings_; }
|
|
|
|
private:
|
|
// Returns the size in bytes for the encoding elements.
|
|
uint64 EncodingSize(uint64 compresion_size, uint64 encryption_size) const;
|
|
|
|
// Returns the size in bytes for the encryption elements.
|
|
uint64 EncryptionSize() const;
|
|
|
|
// Track element names
|
|
uint64 enc_algo_;
|
|
uint8* enc_key_id_;
|
|
uint64 encoding_order_;
|
|
uint64 encoding_scope_;
|
|
uint64 encoding_type_;
|
|
|
|
// ContentEncAESSettings element.
|
|
ContentEncAESSettings enc_aes_settings_;
|
|
|
|
// Size of the ContentEncKeyID data in bytes.
|
|
uint64 enc_key_id_length_;
|
|
|
|
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncoding);
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Track element.
|
|
class Track {
|
|
public:
|
|
// The |seed| parameter is used to synthesize a UID for the track.
|
|
explicit Track(unsigned int* seed);
|
|
virtual ~Track();
|
|
|
|
// Adds a ContentEncoding element to the Track. Returns true on success.
|
|
virtual bool AddContentEncoding();
|
|
|
|
// Returns the ContentEncoding by index. Returns NULL if there is no
|
|
// ContentEncoding match.
|
|
ContentEncoding* GetContentEncodingByIndex(uint32 index) const;
|
|
|
|
// Returns the size in bytes for the payload of the Track element.
|
|
virtual uint64 PayloadSize() const;
|
|
|
|
// Returns the size in bytes of the Track element.
|
|
virtual uint64 Size() const;
|
|
|
|
// Output the Track element to the writer. Returns true on success.
|
|
virtual bool Write(IMkvWriter* writer) const;
|
|
|
|
// Sets the CodecPrivate element of the Track element. Copies |length|
|
|
// bytes from |codec_private| to |codec_private_|. Returns true on success.
|
|
bool SetCodecPrivate(const uint8* codec_private, uint64 length);
|
|
|
|
void set_codec_id(const char* codec_id);
|
|
const char* codec_id() const { return codec_id_; }
|
|
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; }
|
|
uint64 number() const { return number_; }
|
|
void set_type(uint64 type) { type_ = type; }
|
|
uint64 type() const { return type_; }
|
|
void set_uid(uint64 uid) { uid_ = uid; }
|
|
uint64 uid() const { return uid_; }
|
|
void set_codec_delay(uint64 codec_delay) { codec_delay_ = codec_delay; }
|
|
uint64 codec_delay() const { return codec_delay_; }
|
|
void set_seek_pre_roll(uint64 seek_pre_roll) {
|
|
seek_pre_roll_ = seek_pre_roll;
|
|
}
|
|
uint64 seek_pre_roll() const { return seek_pre_roll_; }
|
|
void set_default_duration(uint64 default_duration) {
|
|
default_duration_ = default_duration;
|
|
}
|
|
uint64 default_duration() const { return default_duration_; }
|
|
|
|
uint64 codec_private_length() const { return codec_private_length_; }
|
|
uint32 content_encoding_entries_size() const {
|
|
return content_encoding_entries_size_;
|
|
}
|
|
|
|
private:
|
|
// Track element names.
|
|
char* codec_id_;
|
|
uint8* codec_private_;
|
|
char* language_;
|
|
uint64 max_block_additional_id_;
|
|
char* name_;
|
|
uint64 number_;
|
|
uint64 type_;
|
|
uint64 uid_;
|
|
uint64 codec_delay_;
|
|
uint64 seek_pre_roll_;
|
|
uint64 default_duration_;
|
|
|
|
// Size of the CodecPrivate data in bytes.
|
|
uint64 codec_private_length_;
|
|
|
|
// ContentEncoding element list.
|
|
ContentEncoding** content_encoding_entries_;
|
|
|
|
// Number of ContentEncoding elements added.
|
|
uint32 content_encoding_entries_size_;
|
|
|
|
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Track);
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Track that has video specific elements.
|
|
class VideoTrack : public Track {
|
|
public:
|
|
// Supported modes for stereo 3D.
|
|
enum StereoMode {
|
|
kMono = 0,
|
|
kSideBySideLeftIsFirst = 1,
|
|
kTopBottomRightIsFirst = 2,
|
|
kTopBottomLeftIsFirst = 3,
|
|
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();
|
|
|
|
// Returns the size in bytes for the payload of the Track element plus the
|
|
// video specific elements.
|
|
virtual uint64 PayloadSize() const;
|
|
|
|
// Output the VideoTrack element to the writer. Returns true on success.
|
|
virtual bool Write(IMkvWriter* writer) const;
|
|
|
|
// 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; }
|
|
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; }
|
|
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_; }
|
|
|
|
private:
|
|
// Returns the size in bytes of the Video element.
|
|
uint64 VideoPayloadSize() const;
|
|
|
|
// 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_;
|
|
uint64 alpha_mode_;
|
|
uint64 width_;
|
|
|
|
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(VideoTrack);
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Track that has audio specific elements.
|
|
class AudioTrack : public Track {
|
|
public:
|
|
// The |seed| parameter is used to synthesize a UID for the track.
|
|
explicit AudioTrack(unsigned int* seed);
|
|
virtual ~AudioTrack();
|
|
|
|
// Returns the size in bytes for the payload of the Track element plus the
|
|
// audio specific elements.
|
|
virtual uint64 PayloadSize() const;
|
|
|
|
// Output the AudioTrack element to the writer. Returns true on success.
|
|
virtual bool Write(IMkvWriter* writer) const;
|
|
|
|
void set_bit_depth(uint64 bit_depth) { bit_depth_ = bit_depth; }
|
|
uint64 bit_depth() const { return bit_depth_; }
|
|
void set_channels(uint64 channels) { channels_ = channels; }
|
|
uint64 channels() const { return channels_; }
|
|
void set_sample_rate(double sample_rate) { sample_rate_ = sample_rate; }
|
|
double sample_rate() const { return sample_rate_; }
|
|
|
|
private:
|
|
// Audio track element names.
|
|
uint64 bit_depth_;
|
|
uint64 channels_;
|
|
double sample_rate_;
|
|
|
|
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(AudioTrack);
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Tracks element
|
|
class Tracks {
|
|
public:
|
|
// Audio and video type defined by the Matroska specs.
|
|
enum { kVideo = 0x1, kAudio = 0x2 };
|
|
|
|
static const char kOpusCodecId[];
|
|
static const char kVorbisCodecId[];
|
|
static const char kVp8CodecId[];
|
|
static const char kVp9CodecId[];
|
|
static const char kVp10CodecId[];
|
|
|
|
Tracks();
|
|
~Tracks();
|
|
|
|
// Adds a Track element to the Tracks object. |track| will be owned and
|
|
// deleted by the Tracks object. Returns true on success. |number| is the
|
|
// number to use for the track. |number| must be >= 0. If |number| == 0
|
|
// then the muxer will decide on the track number.
|
|
bool AddTrack(Track* track, int32 number);
|
|
|
|
// Returns the track by index. Returns NULL if there is no track match.
|
|
const Track* GetTrackByIndex(uint32 idx) const;
|
|
|
|
// Search the Tracks and return the track that matches |tn|. Returns NULL
|
|
// if there is no track match.
|
|
Track* GetTrackByNumber(uint64 track_number) const;
|
|
|
|
// Returns true if the track number is an audio track.
|
|
bool TrackIsAudio(uint64 track_number) const;
|
|
|
|
// Returns true if the track number is a video track.
|
|
bool TrackIsVideo(uint64 track_number) const;
|
|
|
|
// Output the Tracks element to the writer. Returns true on success.
|
|
bool Write(IMkvWriter* writer) const;
|
|
|
|
uint32 track_entries_size() const { return track_entries_size_; }
|
|
|
|
private:
|
|
// Track element list.
|
|
Track** track_entries_;
|
|
|
|
// Number of Track elements added.
|
|
uint32 track_entries_size_;
|
|
|
|
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Tracks);
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Chapter element
|
|
//
|
|
class Chapter {
|
|
public:
|
|
// Set the identifier for this chapter. (This corresponds to the
|
|
// Cue Identifier line in WebVTT.)
|
|
// TODO(matthewjheaney): the actual serialization of this item in
|
|
// MKV is pending.
|
|
bool set_id(const char* id);
|
|
|
|
// Converts the nanosecond start and stop times of this chapter to
|
|
// their corresponding timecode values, and stores them that way.
|
|
void set_time(const Segment& segment, uint64 start_time_ns,
|
|
uint64 end_time_ns);
|
|
|
|
// Sets the uid for this chapter. Primarily used to enable
|
|
// deterministic output from the muxer.
|
|
void set_uid(const uint64 uid) { uid_ = uid; }
|
|
|
|
// Add a title string to this chapter, per the semantics described
|
|
// here:
|
|
// http://www.matroska.org/technical/specs/index.html
|
|
//
|
|
// The title ("chapter string") is a UTF-8 string.
|
|
//
|
|
// The language has ISO 639-2 representation, described here:
|
|
// http://www.loc.gov/standards/iso639-2/englangn.html
|
|
// http://www.loc.gov/standards/iso639-2/php/English_list.php
|
|
// If you specify NULL as the language value, this implies
|
|
// English ("eng").
|
|
//
|
|
// The country value corresponds to the codes listed here:
|
|
// http://www.iana.org/domains/root/db/
|
|
//
|
|
// The function returns false if the string could not be allocated.
|
|
bool add_string(const char* title, const char* language, const char* country);
|
|
|
|
private:
|
|
friend class Chapters;
|
|
|
|
// For storage of chapter titles that differ by language.
|
|
class Display {
|
|
public:
|
|
// Establish representation invariant for new Display object.
|
|
void Init();
|
|
|
|
// Reclaim resources, in anticipation of destruction.
|
|
void Clear();
|
|
|
|
// Copies the title to the |title_| member. Returns false on
|
|
// error.
|
|
bool set_title(const char* title);
|
|
|
|
// Copies the language to the |language_| member. Returns false
|
|
// on error.
|
|
bool set_language(const char* language);
|
|
|
|
// Copies the country to the |country_| member. Returns false on
|
|
// error.
|
|
bool set_country(const char* country);
|
|
|
|
// If |writer| is non-NULL, serialize the Display sub-element of
|
|
// the Atom into the stream. Returns the Display element size on
|
|
// success, 0 if error.
|
|
uint64 WriteDisplay(IMkvWriter* writer) const;
|
|
|
|
private:
|
|
char* title_;
|
|
char* language_;
|
|
char* country_;
|
|
};
|
|
|
|
Chapter();
|
|
~Chapter();
|
|
|
|
// Establish the representation invariant for a newly-created
|
|
// Chapter object. The |seed| parameter is used to create the UID
|
|
// for this chapter atom.
|
|
void Init(unsigned int* seed);
|
|
|
|
// Copies this Chapter object to a different one. This is used when
|
|
// expanding a plain array of Chapter objects (see Chapters).
|
|
void ShallowCopy(Chapter* dst) const;
|
|
|
|
// Reclaim resources used by this Chapter object, pending its
|
|
// destruction.
|
|
void Clear();
|
|
|
|
// If there is no storage remaining on the |displays_| array for a
|
|
// new display object, creates a new, longer array and copies the
|
|
// existing Display objects to the new array. Returns false if the
|
|
// array cannot be expanded.
|
|
bool ExpandDisplaysArray();
|
|
|
|
// If |writer| is non-NULL, serialize the Atom sub-element into the
|
|
// stream. Returns the total size of the element on success, 0 if
|
|
// error.
|
|
uint64 WriteAtom(IMkvWriter* writer) const;
|
|
|
|
// The string identifier for this chapter (corresponds to WebVTT cue
|
|
// identifier).
|
|
char* id_;
|
|
|
|
// Start timecode of the chapter.
|
|
uint64 start_timecode_;
|
|
|
|
// Stop timecode of the chapter.
|
|
uint64 end_timecode_;
|
|
|
|
// The binary identifier for this chapter.
|
|
uint64 uid_;
|
|
|
|
// The Atom element can contain multiple Display sub-elements, as
|
|
// the same logical title can be rendered in different languages.
|
|
Display* displays_;
|
|
|
|
// The physical length (total size) of the |displays_| array.
|
|
int displays_size_;
|
|
|
|
// The logical length (number of active elements) on the |displays_|
|
|
// array.
|
|
int displays_count_;
|
|
|
|
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Chapter);
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Chapters element
|
|
//
|
|
class Chapters {
|
|
public:
|
|
Chapters();
|
|
~Chapters();
|
|
|
|
Chapter* AddChapter(unsigned int* seed);
|
|
|
|
// Returns the number of chapters that have been added.
|
|
int Count() const;
|
|
|
|
// Output the Chapters element to the writer. Returns true on success.
|
|
bool Write(IMkvWriter* writer) const;
|
|
|
|
private:
|
|
// Expands the chapters_ array if there is not enough space to contain
|
|
// another chapter object. Returns true on success.
|
|
bool ExpandChaptersArray();
|
|
|
|
// If |writer| is non-NULL, serialize the Edition sub-element of the
|
|
// Chapters element into the stream. Returns the Edition element
|
|
// size on success, 0 if error.
|
|
uint64 WriteEdition(IMkvWriter* writer) const;
|
|
|
|
// Total length of the chapters_ array.
|
|
int chapters_size_;
|
|
|
|
// Number of active chapters on the chapters_ array.
|
|
int chapters_count_;
|
|
|
|
// Array for storage of chapter objects.
|
|
Chapter* 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
|
|
//
|
|
// Notes:
|
|
// |Init| must be called before any other method in this class.
|
|
class Cluster {
|
|
public:
|
|
// |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. |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:
|
|
// 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* 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:
|
|
// 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. 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* data, uint64 length,
|
|
const uint8* additional, uint64 additional_length,
|
|
uint64 add_id, uint64 track_number,
|
|
uint64 abs_timecode, 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:
|
|
// 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
|
|
// 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 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:
|
|
// 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
|
|
// metadata frame, expressed in timecode units.
|
|
// duration: Duration of metadata frame, in timecode units.
|
|
//
|
|
// 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* data, uint64 length, uint64 track_number,
|
|
uint64 timecode, uint64 duration);
|
|
|
|
// Increments the size of the cluster's data in bytes.
|
|
void AddPayloadSize(uint64 size);
|
|
|
|
// Closes the cluster so no more data can be written to it. Will update the
|
|
// cluster's size if |writer_| is seekable. Returns true on success.
|
|
bool Finalize();
|
|
|
|
// 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:
|
|
// Utility method that confirms that blocks can still be added, and that the
|
|
// cluster header has been written. Used by |DoWriteFrame*|. Returns true
|
|
// when successful.
|
|
bool PreWriteBlock();
|
|
|
|
// Utility method used by the |DoWriteFrame*| methods that handles the book
|
|
// keeping required after each block is written.
|
|
void PostWriteBlock(uint64 element_size);
|
|
|
|
// Does some verification and calls WriteFrame.
|
|
bool DoWriteFrame(const Frame* const frame);
|
|
|
|
// Outputs the Cluster header to |writer_|. Returns true on success.
|
|
bool WriteClusterHeader();
|
|
|
|
// Number of blocks added to the cluster.
|
|
int32 blocks_added_;
|
|
|
|
// Flag telling if the cluster has been closed.
|
|
bool finalized_;
|
|
|
|
// Flag telling if the cluster's header has been written.
|
|
bool header_written_;
|
|
|
|
// The size of the cluster elements in bytes.
|
|
uint64 payload_size_;
|
|
|
|
// The file position used for cue points.
|
|
const int64 position_for_cues_;
|
|
|
|
// The file position of the cluster's size element.
|
|
int64 size_position_;
|
|
|
|
// 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_;
|
|
|
|
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Cluster);
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// SeekHead element
|
|
class SeekHead {
|
|
public:
|
|
SeekHead();
|
|
~SeekHead();
|
|
|
|
// TODO(fgalligan): Change this to reserve a certain size. Then check how
|
|
// big the seek entry to be added is as not every seek entry will be the
|
|
// maximum size it could be.
|
|
// Adds a seek entry to be written out when the element is finalized. |id|
|
|
// must be the coded mkv element id. |pos| is the file position of the
|
|
// element. Returns true on success.
|
|
bool AddSeekEntry(uint32 id, uint64 pos);
|
|
|
|
// Writes out SeekHead and SeekEntry elements. Returns true on success.
|
|
bool Finalize(IMkvWriter* writer) const;
|
|
|
|
// Returns the id of the Seek Entry at the given index. Returns -1 if index is
|
|
// out of range.
|
|
uint32 GetId(int index) const;
|
|
|
|
// Returns the position of the Seek Entry at the given index. Returns -1 if
|
|
// index is out of range.
|
|
uint64 GetPosition(int index) const;
|
|
|
|
// Sets the Seek Entry id and position at given index.
|
|
// Returns true on success.
|
|
bool SetSeekEntry(int index, uint32 id, uint64 position);
|
|
|
|
// Reserves space by writing out a Void element which will be updated with
|
|
// a SeekHead element later. Returns true on success.
|
|
bool Write(IMkvWriter* writer);
|
|
|
|
// We are going to put a cap on the number of Seek Entries.
|
|
const static int32 kSeekEntryCount = 5;
|
|
|
|
private:
|
|
// Returns the maximum size in bytes of one seek entry.
|
|
uint64 MaxEntrySize() const;
|
|
|
|
// Seek entry id element list.
|
|
uint32 seek_entry_id_[kSeekEntryCount];
|
|
|
|
// Seek entry pos element list.
|
|
uint64 seek_entry_pos_[kSeekEntryCount];
|
|
|
|
// The file position of SeekHead element.
|
|
int64 start_pos_;
|
|
|
|
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(SeekHead);
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Segment Information element
|
|
class SegmentInfo {
|
|
public:
|
|
SegmentInfo();
|
|
~SegmentInfo();
|
|
|
|
// Will update the duration if |duration_| is > 0.0. Returns true on success.
|
|
bool Finalize(IMkvWriter* writer) const;
|
|
|
|
// Sets |muxing_app_| and |writing_app_|.
|
|
bool Init();
|
|
|
|
// Output the Segment Information element to the writer. Returns true on
|
|
// success.
|
|
bool Write(IMkvWriter* writer);
|
|
|
|
void set_duration(double duration) { duration_ = duration; }
|
|
double duration() const { return duration_; }
|
|
void set_muxing_app(const char* app);
|
|
const char* muxing_app() const { return muxing_app_; }
|
|
void set_timecode_scale(uint64 scale) { timecode_scale_ = scale; }
|
|
uint64 timecode_scale() const { return timecode_scale_; }
|
|
void set_writing_app(const char* app);
|
|
const char* writing_app() const { return writing_app_; }
|
|
void set_date_utc(int64 date_utc) { date_utc_ = date_utc; }
|
|
int64 date_utc() const { return date_utc_; }
|
|
|
|
private:
|
|
// Segment Information element names.
|
|
// Initially set to -1 to signify that a duration has not been set and should
|
|
// not be written out.
|
|
double duration_;
|
|
// Set to libwebm-%d.%d.%d.%d, major, minor, build, revision.
|
|
char* muxing_app_;
|
|
uint64 timecode_scale_;
|
|
// Initially set to libwebm-%d.%d.%d.%d, major, minor, build, revision.
|
|
char* writing_app_;
|
|
// LLONG_MIN when DateUTC is not set.
|
|
int64 date_utc_;
|
|
|
|
// The file position of the duration element.
|
|
int64 duration_pos_;
|
|
|
|
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(SegmentInfo);
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// This class represents the main segment in a WebM file. Currently only
|
|
// supports one Segment element.
|
|
//
|
|
// Notes:
|
|
// |Init| must be called before any other method in this class.
|
|
class Segment {
|
|
public:
|
|
enum Mode { kLive = 0x1, kFile = 0x2 };
|
|
|
|
enum CuesPosition {
|
|
kAfterClusters = 0x0, // Position Cues after Clusters - Default
|
|
kBeforeClusters = 0x1 // Position Cues before Clusters
|
|
};
|
|
|
|
const static uint32 kDefaultDocTypeVersion = 2;
|
|
const static uint64 kDefaultMaxClusterDuration = 30000000000ULL;
|
|
|
|
Segment();
|
|
~Segment();
|
|
|
|
// Initializes |SegmentInfo| and returns result. Always returns false when
|
|
// |ptr_writer| is NULL.
|
|
bool Init(IMkvWriter* ptr_writer);
|
|
|
|
// Adds a generic track to the segment. Returns the newly-allocated
|
|
// track object (which is owned by the segment) on success, NULL on
|
|
// error. |number| is the number to use for the track. |number|
|
|
// must be >= 0. If |number| == 0 then the muxer will decide on the
|
|
// track number.
|
|
Track* AddTrack(int32 number);
|
|
|
|
// Adds a Vorbis audio track to the segment. Returns the number of the track
|
|
// on success, 0 on error. |number| is the number to use for the audio track.
|
|
// |number| must be >= 0. If |number| == 0 then the muxer will decide on
|
|
// the track number.
|
|
uint64 AddAudioTrack(int32 sample_rate, int32 channels, int32 number);
|
|
|
|
// Adds an empty chapter to the chapters of this segment. Returns
|
|
// non-NULL on success. After adding the chapter, the caller should
|
|
// 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
|
|
// BlockNumber for the CuePoint. Returns true on success.
|
|
bool AddCuePoint(uint64 timestamp, uint64 track);
|
|
|
|
// Adds a frame to be output in the file. Returns true on success.
|
|
// 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.
|
|
// 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* 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:
|
|
// data: Pointer to the data
|
|
// length: Length of the data
|
|
// track_number: Track to add the data to. Value returned by Add track
|
|
// functions.
|
|
// timecode: Absolute timestamp of the metadata frame, expressed
|
|
// in nanosecond units.
|
|
// duration: Duration of metadata frame, in nanosecond units.
|
|
//
|
|
// 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* 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:
|
|
// data: Pointer to the data.
|
|
// length: Length of the data.
|
|
// additional: Pointer to additional data.
|
|
// additional_length: Length of additional data.
|
|
// add_id: Additional ID which identifies the type of additional data.
|
|
// track_number: Track to add the data to. Value returned by Add track
|
|
// functions.
|
|
// 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* data, uint64 length,
|
|
const uint8* additional, uint64 additional_length,
|
|
uint64 add_id, uint64 track_number,
|
|
uint64 timestamp, bool is_key);
|
|
|
|
// Writes a frame with DiscardPadding to the output medium; returns true on
|
|
// success.
|
|
// Inputs:
|
|
// 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
|
|
// functions.
|
|
// 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* data, uint64 length,
|
|
int64 discard_padding, uint64 track_number,
|
|
uint64 timestamp, bool is_key);
|
|
|
|
// Writes a Frame to the output medium. Chooses the correct way of writing
|
|
// the frame (Block vs SimpleBlock) based on the parameters passed.
|
|
// Inputs:
|
|
// frame: frame object
|
|
bool AddGenericFrame(const Frame* frame);
|
|
|
|
// Adds a VP8 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
|
|
// the track number.
|
|
uint64 AddVideoTrack(int32 width, int32 height, int32 number);
|
|
|
|
// This function must be called after Finalize() if you need a copy of the
|
|
// output with Cues written before the Clusters. It will return false if the
|
|
// writer is not seekable of if chunking is set to true.
|
|
// Input parameters:
|
|
// reader - an IMkvReader object created with the same underlying file of the
|
|
// current writer object. Make sure to close the existing writer
|
|
// object before creating this so that all the data is properly
|
|
// flushed and available for reading.
|
|
// writer - an IMkvWriter object pointing to a *different* file than the one
|
|
// pointed by the current writer object. This file will contain the
|
|
// Cues element before the Clusters.
|
|
bool CopyAndMoveCuesBeforeClusters(mkvparser::IMkvReader* reader,
|
|
IMkvWriter* writer);
|
|
|
|
// Sets which track to use for the Cues element. Must have added the track
|
|
// before calling this function. Returns true on success. |track_number| is
|
|
// returned by the Add track functions.
|
|
bool CuesTrack(uint64 track_number);
|
|
|
|
// This will force the muxer to create a new Cluster when the next frame is
|
|
// added.
|
|
void ForceNewClusterOnNextFrame();
|
|
|
|
// Writes out any frames that have not been written out. Finalizes the last
|
|
// cluster. May update the size and duration of the segment. May output the
|
|
// Cues element. May finalize the SeekHead element. Returns true on success.
|
|
bool Finalize();
|
|
|
|
// Returns the Cues object.
|
|
Cues* GetCues() { return &cues_; }
|
|
|
|
// Returns the Segment Information object.
|
|
const SegmentInfo* GetSegmentInfo() const { return &segment_info_; }
|
|
SegmentInfo* GetSegmentInfo() { return &segment_info_; }
|
|
|
|
// Search the Tracks and return the track that matches |track_number|.
|
|
// Returns NULL if there is no track match.
|
|
Track* GetTrackByNumber(uint64 track_number) const;
|
|
|
|
// Toggles whether to output a cues element.
|
|
void OutputCues(bool output_cues);
|
|
|
|
// Sets if the muxer will output files in chunks or not. |chunking| is a
|
|
// flag telling whether or not to turn on chunking. |filename| is the base
|
|
// filename for the chunk files. The header chunk file will be named
|
|
// |filename|.hdr and the data chunks will be named
|
|
// |filename|_XXXXXX.chk. Chunking implies that the muxer will be writing
|
|
// to files so the muxer will use the default MkvWriter class to control
|
|
// what data is written to what files. Returns true on success.
|
|
// TODO: Should we change the IMkvWriter Interface to add Open and Close?
|
|
// That will force the interface to be dependent on files.
|
|
bool SetChunking(bool chunking, const char* filename);
|
|
|
|
bool chunking() const { return chunking_; }
|
|
uint64 cues_track() const { return cues_track_; }
|
|
void set_max_cluster_duration(uint64 max_cluster_duration) {
|
|
max_cluster_duration_ = max_cluster_duration;
|
|
}
|
|
uint64 max_cluster_duration() const { return max_cluster_duration_; }
|
|
void set_max_cluster_size(uint64 max_cluster_size) {
|
|
max_cluster_size_ = max_cluster_size;
|
|
}
|
|
uint64 max_cluster_size() const { return max_cluster_size_; }
|
|
void set_mode(Mode mode) { mode_ = mode; }
|
|
Mode mode() const { return mode_; }
|
|
CuesPosition cues_position() const { return cues_position_; }
|
|
bool output_cues() const { return output_cues_; }
|
|
const SegmentInfo* segment_info() const { return &segment_info_; }
|
|
|
|
private:
|
|
// Checks if header information has been output and initialized. If not it
|
|
// will output the Segment element and initialize the SeekHead elment and
|
|
// 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.
|
|
bool UpdateChunkName(const char* ext, char** name) const;
|
|
|
|
// Returns the maximum offset within the segment's payload. When chunking
|
|
// this function is needed to determine offsets of elements within the
|
|
// chunked files. Returns -1 on error.
|
|
int64 MaxOffset();
|
|
|
|
// Adds the frame to our frame array.
|
|
bool QueueFrame(Frame* frame);
|
|
|
|
// Output all frames that are queued. Returns -1 on error, otherwise
|
|
// it returns the number of frames written.
|
|
int WriteFramesAll();
|
|
|
|
// Output all frames that are queued that have an end time that is less
|
|
// then |timestamp|. Returns true on success and if there are no frames
|
|
// queued.
|
|
bool WriteFramesLessThan(uint64 timestamp);
|
|
|
|
// Outputs the segment header, Segment Information element, SeekHead element,
|
|
// and Tracks element to |writer_|.
|
|
bool WriteSegmentHeader();
|
|
|
|
// Given a frame with the specified timestamp (nanosecond units) and
|
|
// keyframe status, determine whether a new cluster should be
|
|
// created, before writing enqueued frames and the frame itself. The
|
|
// function returns one of the following values:
|
|
// -1 = error: an out-of-order frame was detected
|
|
// 0 = do not create a new cluster, and write frame to the existing cluster
|
|
// 1 = create a new cluster, and write frame to that new cluster
|
|
// 2 = create a new cluster, and re-run test
|
|
int TestFrame(uint64 track_num, uint64 timestamp_ns, bool key) const;
|
|
|
|
// Create a new cluster, using the earlier of the first enqueued
|
|
// frame, or the indicated time. Returns true on success.
|
|
bool MakeNewCluster(uint64 timestamp_ns);
|
|
|
|
// Checks whether a new cluster needs to be created, and if so
|
|
// creates a new cluster. Returns false if creation of a new cluster
|
|
// was necessary but creation was not successful.
|
|
bool DoNewClusterProcessing(uint64 track_num, uint64 timestamp_ns, bool key);
|
|
|
|
// Adjusts Cue Point values (to place Cues before Clusters) so that they
|
|
// reflect the correct offsets.
|
|
void MoveCuesBeforeClusters();
|
|
|
|
// This function recursively computes the correct cluster offsets (this is
|
|
// done to move the Cues before Clusters). It recursively updates the change
|
|
// in size (which indicates a change in cluster offset) until no sizes change.
|
|
// Parameters:
|
|
// 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 - 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.
|
|
unsigned int seed_;
|
|
|
|
// WebM elements
|
|
Cues cues_;
|
|
SeekHead seek_head_;
|
|
SegmentInfo segment_info_;
|
|
Tracks tracks_;
|
|
Chapters chapters_;
|
|
Tags tags_;
|
|
|
|
// Number of chunks written.
|
|
int chunk_count_;
|
|
|
|
// Current chunk filename.
|
|
char* chunk_name_;
|
|
|
|
// Default MkvWriter object created by this class used for writing clusters
|
|
// out in separate files.
|
|
MkvWriter* chunk_writer_cluster_;
|
|
|
|
// Default MkvWriter object created by this class used for writing Cues
|
|
// element out to a file.
|
|
MkvWriter* chunk_writer_cues_;
|
|
|
|
// Default MkvWriter object created by this class used for writing the
|
|
// Matroska header out to a file.
|
|
MkvWriter* chunk_writer_header_;
|
|
|
|
// Flag telling whether or not the muxer is chunking output to multiple
|
|
// files.
|
|
bool chunking_;
|
|
|
|
// Base filename for the chunked files.
|
|
char* chunking_base_name_;
|
|
|
|
// File position offset where the Clusters end.
|
|
int64 cluster_end_offset_;
|
|
|
|
// List of clusters.
|
|
Cluster** cluster_list_;
|
|
|
|
// Number of cluster pointers allocated in the cluster list.
|
|
int32 cluster_list_capacity_;
|
|
|
|
// Number of clusters in the cluster list.
|
|
int32 cluster_list_size_;
|
|
|
|
// Indicates whether Cues should be written before or after Clusters
|
|
CuesPosition cues_position_;
|
|
|
|
// Track number that is associated with the cues element for this segment.
|
|
uint64 cues_track_;
|
|
|
|
// Tells the muxer to force a new cluster on the next Block.
|
|
bool force_new_cluster_;
|
|
|
|
// List of stored audio frames. These variables are used to store frames so
|
|
// the muxer can follow the guideline "Audio blocks that contain the video
|
|
// key frame's timecode should be in the same cluster as the video key frame
|
|
// block."
|
|
Frame** frames_;
|
|
|
|
// Number of frame pointers allocated in the frame list.
|
|
int32 frames_capacity_;
|
|
|
|
// Number of frames in the frame list.
|
|
int32 frames_size_;
|
|
|
|
// Flag telling if a video track has been added to the segment.
|
|
bool has_video_;
|
|
|
|
// Flag telling if the segment's header has been written.
|
|
bool header_written_;
|
|
|
|
// Duration of the last block in nanoseconds.
|
|
uint64 last_block_duration_;
|
|
|
|
// 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.
|
|
uint64 max_cluster_duration_;
|
|
|
|
// Maximum size in bytes for a cluster. This variable is a guideline and
|
|
// some clusters may have a larger size. Default is 0 which signifies that
|
|
// the muxer will decide the size.
|
|
uint64 max_cluster_size_;
|
|
|
|
// The mode that segment is in. If set to |kLive| the writer must not
|
|
// seek backwards.
|
|
Mode mode_;
|
|
|
|
// Flag telling the muxer that a new cue point should be added.
|
|
bool new_cuepoint_;
|
|
|
|
// TODO(fgalligan): Should we add support for more than one Cues element?
|
|
// 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_;
|
|
IMkvWriter* writer_header_;
|
|
|
|
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Segment);
|
|
};
|
|
|
|
} // end namespace mkvmuxer
|
|
|
|
#endif // MKVMUXER_HPP
|