Add support for muxing to libwebm.
Squashed commit of the following: 9f73b86 Updated code to Google C++ style guide. 8580901 Added support for linux. fd0b59c Fixed segment size issue. d51d5ef Added more Track and Video options. 0fc73fd Fixed issue where cue point was being written out on wrong track. fcfdd07 Updated sample_muxer to read in a webm and output a webm file. Added some options to sample_muxer. Fixed writing out unknown size. 285c558 Added support for muxer guideline "Audio that matches video key frame should be in the same cluster." Added support for block_number in cue points. Added support for setting max cluster size. f956dec Add support for setting the max duration for all clusters. 92ca53e Add support for Cues element. d6b4cba Added typedefs for unsigned long long, long long, and unsigned char. Reformated some code. 1b1f8b2 Added support for SeekHead element. Added WriteVoidElement function. 8faa187 Add support for CodecPrivate. Add support for updating SegmentInfo duration. Add support for updating Segment size. Added new sample that swicthes the tracks. 1dd3555 Refactored some code. Check to see if track is a video track if starting a new cluster on a key-frame. 1bc8374 Refacotrs code so Cluster is in charge of wirting out its own data. 836cd74 Added basic cluster and simple_block support for writing frames. cc48cc2 Add simple support for Audio tracks. 4efd614 Added support for using the encoded ID value for the elements. fb8b5a6 Initial commit of libwebm muxer. Removed switch_sample project. Fixed initialization order warnings on Linux. Reformatted code to follow Google C++ style guide. Fixed Makefile. Removed tester.cpp. Change-Id: I4857042f804edb834be52787a7d5ccdd578b7275
This commit is contained in:
parent
18ac83d501
commit
a3dd40877d
37
Makefile
37
Makefile
@ -1,20 +1,29 @@
|
||||
LIB = libmkvparser.a
|
||||
OBJECTS = mkvparser.o mkvreader.o sample.o
|
||||
EXE = sample
|
||||
CFLAGS = -W -Wall -g
|
||||
CXX := g++
|
||||
CXXFLAGS := -W -Wall -g
|
||||
LIBS := libmkvparser.a libmkvmuxer.a
|
||||
PARSEOBJ := mkvparser.o mkvreader.o
|
||||
MUXEROBJ := mkvmuxer.o mkvmuxerutil.o mkvwriter.o
|
||||
OBJECTS1 := $(PARSEOBJ) sample.o
|
||||
OBJECTS2 := $(PARSEOBJ) $(MUXEROBJ) sample_muxer/sample_muxer.o
|
||||
INCLUDES := -I.
|
||||
EXES := samplemuxer sample
|
||||
|
||||
$(EXE): $(OBJECTS)
|
||||
$(AR) rcs $(LIB) mkvparser.o mkvreader.o
|
||||
$(CXX) $(OBJECTS) -L./ -lmkvparser -o $(EXE)
|
||||
all: $(EXES)
|
||||
|
||||
mkvparser.o: mkvparser.cpp
|
||||
$(CXX) -c $(CFLAGS) mkvparser.cpp -o mkvparser.o
|
||||
sample: sample.o libmkvparser.a
|
||||
$(CXX) $^ -o $@
|
||||
|
||||
mkvreader.o: mkvreader.cpp
|
||||
$(CXX) -c $(CFLAGS) mkvreader.cpp -o mkvreader.o
|
||||
samplemuxer: sample_muxer/sample_muxer.o $(LIBS)
|
||||
$(CXX) $^ -o $@
|
||||
|
||||
sample.o: sample.cpp
|
||||
$(CXX) -c $(CFLAGS) sample.cpp -o sample.o
|
||||
libmkvparser.a: $(PARSEOBJ)
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
libmkvmuxer.a: $(MUXEROBJ)
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) -c $(CXXFLAGS) $(INCLUDES) $< -o $@
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJECTS) $(LIB) $(EXE) Makefile.bak
|
||||
$(RM) -f $(OBJECTS1) $(OBJECTS2) $(LIBS) $(EXES) Makefile.bak
|
||||
|
1617
mkvmuxer.cpp
Normal file
1617
mkvmuxer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
689
mkvmuxer.hpp
Normal file
689
mkvmuxer.hpp
Normal file
@ -0,0 +1,689 @@
|
||||
// Copyright (c) 2011 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 mkvmuxer {
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// 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;
|
||||
|
||||
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);
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Class to hold data the will be written to a block.
|
||||
class Frame {
|
||||
public:
|
||||
Frame();
|
||||
~Frame();
|
||||
|
||||
// Copies |frame| data into |frame_|. Returns true on success.
|
||||
bool Init(const uint8* frame, uint64 length);
|
||||
|
||||
const uint8* frame() const { return frame_; }
|
||||
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_is_key(bool key) { is_key_ = key; }
|
||||
bool is_key() const { return is_key_; }
|
||||
|
||||
private:
|
||||
// Pointer to the data. Owned by this class.
|
||||
uint8* frame_;
|
||||
|
||||
// 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_;
|
||||
|
||||
// Flag telling if the data should set the key flag of a block.
|
||||
bool is_key_;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// 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.
|
||||
const CuePoint* GetCueByIndex(int32 index) const;
|
||||
|
||||
// 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);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Track element.
|
||||
class Track {
|
||||
public:
|
||||
Track();
|
||||
virtual ~Track();
|
||||
|
||||
// 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_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_; }
|
||||
uint64 uid() const { return uid_; }
|
||||
|
||||
uint64 codec_private_length() const { return codec_private_length_; }
|
||||
|
||||
private:
|
||||
// Returns a random number to be used for the Track UID.
|
||||
static uint64 MakeUID();
|
||||
|
||||
// Track element names
|
||||
char* codec_id_;
|
||||
uint8* codec_private_;
|
||||
char* language_;
|
||||
char* name_;
|
||||
uint64 number_;
|
||||
uint64 type_;
|
||||
const uint64 uid_;
|
||||
|
||||
// Size of the CodecPrivate data in bytes.
|
||||
uint64 codec_private_length_;
|
||||
|
||||
// Flag telling if the rand call was seeded.
|
||||
static bool is_seeded_;
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
VideoTrack();
|
||||
virtual ~VideoTrack();
|
||||
|
||||
// Returns the size in bytes for the payload of the Track element plus the
|
||||
// video specific elements.
|
||||
virtual uint64 PayloadSize() const;
|
||||
|
||||
// Returns the size in bytes of the Track element plus the video specific
|
||||
// elements.
|
||||
virtual uint64 Size() 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);
|
||||
|
||||
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_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_; }
|
||||
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_;
|
||||
double frame_rate_;
|
||||
uint64 height_;
|
||||
uint64 stereo_mode_;
|
||||
uint64 width_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(VideoTrack);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Track that has audio specific elements.
|
||||
class AudioTrack : public Track {
|
||||
public:
|
||||
AudioTrack();
|
||||
virtual ~AudioTrack();
|
||||
|
||||
// Returns the size in bytes for the payload of the Track element plus the
|
||||
// audio specific elements.
|
||||
virtual uint64 PayloadSize() const;
|
||||
|
||||
// Returns the size in bytes of the Track element plus the audio specific
|
||||
// elements.
|
||||
virtual uint64 Size() 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
|
||||
};
|
||||
// Vorbis and VP8 coded id defined by the Matroska specs.
|
||||
static const char* const kVorbisCodecId;
|
||||
static const char* const kVp8CodecId;
|
||||
|
||||
Tracks();
|
||||
~Tracks();
|
||||
|
||||
// Adds a Track element to the Tracks object. |track| will be owned and
|
||||
// deleted by the Tracks object. Returns true on success.
|
||||
bool AddTrack(Track* track);
|
||||
|
||||
// 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);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Cluster element
|
||||
class Cluster {
|
||||
public:
|
||||
// |timecode| is the absolute timecode of the cluster.
|
||||
Cluster(uint64 timecode, IMkvWriter* writer);
|
||||
~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
|
||||
// length: Length of the data
|
||||
// track_number: Track to add the data to. Value returned by Add track
|
||||
// functions.
|
||||
// timestamp: Timecode of the frame relative to the cluster timecode.
|
||||
// is_key: Flag telling whether or not this frame is a key frame.
|
||||
bool AddFrame(const uint8* frame,
|
||||
uint64 length,
|
||||
uint64 track_number,
|
||||
short timecode,
|
||||
bool is_key);
|
||||
|
||||
// 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();
|
||||
|
||||
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_; }
|
||||
|
||||
private:
|
||||
// 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.
|
||||
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_;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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);
|
||||
|
||||
private:
|
||||
// We are going to put a cap on the number of Seek Entries.
|
||||
const static int32 kSeekEntryCount = 4;
|
||||
|
||||
// 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_; }
|
||||
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_; }
|
||||
|
||||
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_;
|
||||
|
||||
// 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.
|
||||
class Segment {
|
||||
public:
|
||||
enum Mode {
|
||||
kLive = 0x1,
|
||||
kFile = 0x2
|
||||
};
|
||||
|
||||
explicit Segment(IMkvWriter* writer);
|
||||
virtual ~Segment();
|
||||
|
||||
// Adds an audio track to the segment. Returns the number of the track on
|
||||
// success, 0 on error.
|
||||
uint64 AddAudioTrack(int32 sample_rate, int32 channels);
|
||||
|
||||
// Adds a frame to be output in the file. Returns true on success.
|
||||
// Inputs:
|
||||
// frame: 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(uint8* frame,
|
||||
uint64 length,
|
||||
uint64 track_number,
|
||||
uint64 timestamp,
|
||||
bool is_key);
|
||||
|
||||
// Adds a video track to the segment. Returns the number of the track on
|
||||
// success, 0 on error.
|
||||
uint64 AddVideoTrack(int32 width, int32 height);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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.
|
||||
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);
|
||||
|
||||
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_; }
|
||||
bool output_cues() const { return output_cues_; }
|
||||
const SegmentInfo* segment_info() const { return &segment_info_; }
|
||||
|
||||
private:
|
||||
// Adds a cue point to the Cues element. |timestamp| is the time in
|
||||
// nanoseconds of the cue's time. Returns true on success.
|
||||
bool AddCuePoint(uint64 timestamp);
|
||||
|
||||
// Adds the frame to our frame array.
|
||||
bool QueueFrame(Frame* frame);
|
||||
|
||||
// Output all frames that are queued. Returns true on success and if there
|
||||
// are no frames queued.
|
||||
bool 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();
|
||||
|
||||
// WebM elements
|
||||
Cues cues_;
|
||||
SeekHead seek_head_;
|
||||
SegmentInfo segment_info_;
|
||||
Tracks tracks_;
|
||||
|
||||
// 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_;
|
||||
|
||||
// Track number that is associated with the cues element for this segment.
|
||||
uint64 cues_track_;
|
||||
|
||||
// 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_;
|
||||
|
||||
// Last timestamp in nanoseconds added to a cluster.
|
||||
uint64 last_timestamp_;
|
||||
|
||||
// Maximum time in nanoseconds for a cluster duration. This variable is a
|
||||
// guideline and some clusters may have a longer duration. Default is 0
|
||||
// which signifies that the muxer will decide.
|
||||
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 cluster should be started with the next
|
||||
// frame.
|
||||
bool new_cluster_;
|
||||
|
||||
// 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 file position of the segment's payload.
|
||||
int64 payload_pos_;
|
||||
|
||||
// The file position of the element's size.
|
||||
int64 size_position_;
|
||||
|
||||
// Pointer to the writer object. Not owned by this class.
|
||||
IMkvWriter* writer_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Segment);
|
||||
};
|
||||
|
||||
} //end namespace mkvmuxer
|
||||
|
||||
#endif //MKVMUXER_HPP
|
199
mkvmuxer_2008.vcproj
Normal file
199
mkvmuxer_2008.vcproj
Normal file
@ -0,0 +1,199 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="mkvmuxer"
|
||||
ProjectGUID="{7B1F12CA-0724-430B-B61A-1D357C912CBA}"
|
||||
RootNamespace="mkvmuxer"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\mkvmuxer.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mkvmuxerutil.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mkvwriter.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\mkvmuxer.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mkvmuxertypes.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mkvmuxerutil.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mkvwriter.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\webmids.hpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
29
mkvmuxertypes.hpp
Normal file
29
mkvmuxertypes.hpp
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2011 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 MKVMUXERTYPES_HPP
|
||||
#define MKVMUXERTYPES_HPP
|
||||
|
||||
// Copied from Chromium basictypes.h
|
||||
// A macro to disallow the copy constructor and operator= functions
|
||||
// This should be used in the private: declarations for a class
|
||||
#define LIBWEBM_DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||
TypeName(const TypeName&); \
|
||||
void operator=(const TypeName&)
|
||||
|
||||
namespace mkvmuxer {
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef int int32;
|
||||
typedef unsigned int uint32;
|
||||
typedef long long int64;
|
||||
typedef unsigned long long uint64;
|
||||
|
||||
} //end namespace mkvmuxer
|
||||
|
||||
#endif // MKVMUXERTYPES_HPP
|
375
mkvmuxerutil.cpp
Normal file
375
mkvmuxerutil.cpp
Normal file
@ -0,0 +1,375 @@
|
||||
// Copyright (c) 2011 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.
|
||||
|
||||
#include "mkvmuxerutil.hpp"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <new>
|
||||
|
||||
#include "mkvwriter.hpp"
|
||||
#include "webmids.hpp"
|
||||
|
||||
namespace mkvmuxer {
|
||||
|
||||
int32 GetCodedUIntSize(uint64 value) {
|
||||
|
||||
if (value < 0x000000000000007FULL)
|
||||
return 1;
|
||||
else if (value < 0x0000000000003FFFULL)
|
||||
return 2;
|
||||
else if (value < 0x00000000001FFFFFULL)
|
||||
return 3;
|
||||
else if (value < 0x000000000FFFFFFFULL)
|
||||
return 4;
|
||||
else if (value < 0x00000007FFFFFFFFULL)
|
||||
return 5;
|
||||
else if (value < 0x000003FFFFFFFFFFULL)
|
||||
return 6;
|
||||
else if (value < 0x0001FFFFFFFFFFFFULL)
|
||||
return 7;
|
||||
return 8;
|
||||
}
|
||||
|
||||
int32 GetUIntSize(uint64 value) {
|
||||
|
||||
if (value < 0x0000000000000100ULL)
|
||||
return 1;
|
||||
else if (value < 0x0000000000010000ULL)
|
||||
return 2;
|
||||
else if (value < 0x0000000001000000ULL)
|
||||
return 3;
|
||||
else if (value < 0x0000000100000000ULL)
|
||||
return 4;
|
||||
else if (value < 0x0000010000000000ULL)
|
||||
return 5;
|
||||
else if (value < 0x0001000000000000ULL)
|
||||
return 6;
|
||||
else if (value < 0x0100000000000000ULL)
|
||||
return 7;
|
||||
return 8;
|
||||
}
|
||||
|
||||
uint64 EbmlElementSize(uint64 type, uint64 value, bool master) {
|
||||
// Size of EBML ID
|
||||
int32 ebml_size = GetUIntSize(type);
|
||||
|
||||
// Datasize
|
||||
ebml_size += GetUIntSize(value);
|
||||
|
||||
// Size of Datasize
|
||||
if (!master)
|
||||
ebml_size++;
|
||||
|
||||
return ebml_size;
|
||||
}
|
||||
|
||||
uint64 EbmlElementSize(uint64 type, float value, bool master) {
|
||||
// Size of EBML ID
|
||||
uint64 ebml_size = GetUIntSize(type);
|
||||
|
||||
// Datasize
|
||||
ebml_size += sizeof(value);
|
||||
|
||||
// Size of Datasize
|
||||
if (!master)
|
||||
ebml_size++;
|
||||
|
||||
return ebml_size;
|
||||
}
|
||||
|
||||
uint64 EbmlElementSize(uint64 type, const char* value, bool master) {
|
||||
assert(value != NULL);
|
||||
|
||||
// Size of EBML ID
|
||||
uint64 ebml_size = GetUIntSize(type);
|
||||
|
||||
// Datasize
|
||||
ebml_size += strlen(value);
|
||||
|
||||
// Size of Datasize
|
||||
if (!master)
|
||||
ebml_size++;
|
||||
|
||||
return ebml_size;
|
||||
}
|
||||
|
||||
uint64 EbmlElementSize(uint64 type,
|
||||
const uint8* value,
|
||||
uint64 size,
|
||||
bool master) {
|
||||
assert(value != NULL);
|
||||
|
||||
// Size of EBML ID
|
||||
uint64 ebml_size = GetUIntSize(type);
|
||||
|
||||
// Datasize
|
||||
ebml_size += size;
|
||||
|
||||
// Size of Datasize
|
||||
if (!master)
|
||||
ebml_size += GetCodedUIntSize(size);
|
||||
|
||||
return ebml_size;
|
||||
}
|
||||
|
||||
int32 SerializeInt(
|
||||
IMkvWriter* writer,
|
||||
int64 value,
|
||||
int32 size) {
|
||||
assert(writer);
|
||||
assert(size >= 0);
|
||||
assert(size <= 8);
|
||||
|
||||
for (int32 i = 1; i <= size; ++i) {
|
||||
const int32 byte_count = size - i;
|
||||
const int32 bit_count = byte_count * 8;
|
||||
|
||||
const int64 bb = value >> bit_count;
|
||||
const uint8 b = static_cast<uint8>(bb);
|
||||
|
||||
const int32 status = writer->Write(&b, 1);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 SerializeFloat(IMkvWriter* writer, float f) {
|
||||
assert(writer);
|
||||
const uint32& val = reinterpret_cast<const uint32&>(f);
|
||||
|
||||
for (int32 i = 1; i <= 4; ++i) {
|
||||
const int32 byte_count = 4 - i;
|
||||
const int32 bit_count = byte_count * 8;
|
||||
|
||||
const uint32 bb = val >> bit_count;
|
||||
const uint8 b = static_cast<uint8>(bb);
|
||||
|
||||
const int32 status = writer->Write(&b, 1);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 WriteUInt(IMkvWriter* writer, uint64 value) {
|
||||
assert(writer);
|
||||
int32 size = GetCodedUIntSize(value);
|
||||
|
||||
return WriteUIntSize(writer, value, size);
|
||||
}
|
||||
|
||||
int32 WriteUIntSize(IMkvWriter* writer, uint64 value, int32 size) {
|
||||
assert(writer);
|
||||
assert(size >= 0);
|
||||
|
||||
if (size > 0) {
|
||||
assert(size <= 8);
|
||||
|
||||
const uint64 bit = 1LL << (size * 7);
|
||||
assert(value <= (bit - 2));
|
||||
|
||||
value |= bit;
|
||||
} else {
|
||||
size = 1;
|
||||
int64 bit;
|
||||
|
||||
for (;;) {
|
||||
bit = 1LL << (size * 7);
|
||||
const uint64 max = bit - 2;
|
||||
|
||||
if (value <= max)
|
||||
break;
|
||||
|
||||
++size;
|
||||
}
|
||||
|
||||
assert(size <= 8);
|
||||
value |= bit;
|
||||
}
|
||||
|
||||
return SerializeInt(writer, value, size);
|
||||
}
|
||||
|
||||
int32 WriteID(IMkvWriter* writer, uint64 type) {
|
||||
assert(writer);
|
||||
const int32 size = GetUIntSize(type);
|
||||
|
||||
return SerializeInt(writer, type, size);
|
||||
}
|
||||
|
||||
bool WriteEbmlMasterElement(IMkvWriter* writer, uint64 type, uint64 size) {
|
||||
assert(writer);
|
||||
|
||||
if (WriteID(writer, type))
|
||||
return false;
|
||||
|
||||
if (WriteUInt(writer, size))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value) {
|
||||
assert(writer);
|
||||
|
||||
if (WriteID(writer, type))
|
||||
return false;
|
||||
|
||||
const uint64 size = GetUIntSize(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) {
|
||||
assert(writer);
|
||||
|
||||
if (WriteID(writer, type))
|
||||
return false;
|
||||
|
||||
if (WriteUInt(writer, 4))
|
||||
return false;
|
||||
|
||||
if (SerializeFloat(writer, value))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const char* value) {
|
||||
assert(writer);
|
||||
assert(value != NULL);
|
||||
|
||||
if (WriteID(writer, type))
|
||||
return false;
|
||||
|
||||
const int32 length = strlen(value);
|
||||
if (WriteUInt(writer, length))
|
||||
return false;
|
||||
|
||||
if (writer->Write(value, length))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteEbmlElement(IMkvWriter* writer,
|
||||
uint64 type,
|
||||
const uint8* value,
|
||||
uint64 size) {
|
||||
assert(writer);
|
||||
assert(value != NULL);
|
||||
assert(size > 0);
|
||||
|
||||
if (WriteID(writer, type))
|
||||
return false;
|
||||
|
||||
if (WriteUInt(writer, size))
|
||||
return false;
|
||||
|
||||
if (writer->Write(value, static_cast<uint32>(size)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64 WriteSimpleBlock(IMkvWriter* writer,
|
||||
const uint8* data,
|
||||
uint64 length,
|
||||
char track_number,
|
||||
short timecode,
|
||||
bool is_key) {
|
||||
assert(writer);
|
||||
assert(data != NULL);
|
||||
assert(length > 0);
|
||||
assert(track_number > 0);
|
||||
assert(timecode >= 0);
|
||||
|
||||
if (WriteID(writer, kMkvSimpleBlock))
|
||||
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, static_cast<uint64>(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;
|
||||
}
|
||||
|
||||
uint64 WriteVoidElement(IMkvWriter* writer, uint64 size) {
|
||||
// Subtract one for the void ID and the coded size.
|
||||
uint64 void_entry_size = size - 1 - GetCodedUIntSize(size-1);
|
||||
uint64 void_size = EbmlElementSize(kMkvVoid, void_entry_size, true) +
|
||||
void_entry_size;
|
||||
assert(void_size == size);
|
||||
|
||||
const int64 payload_position = writer->Position();
|
||||
if (payload_position < 0)
|
||||
return 0;
|
||||
|
||||
if (WriteID(writer, kMkvVoid))
|
||||
return 0;
|
||||
|
||||
if (WriteUInt(writer, void_entry_size))
|
||||
return 0;
|
||||
|
||||
const uint8 value = 0;
|
||||
for (int32 i = 0; i < static_cast<int32>(void_entry_size); ++i) {
|
||||
if (writer->Write(&value, 1))
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int64 stop_position = writer->Position();
|
||||
if (stop_position < 0)
|
||||
return 0;
|
||||
assert(stop_position - payload_position == static_cast<int64>(void_size));
|
||||
|
||||
return void_size;
|
||||
}
|
||||
|
||||
void GetVersion(int32& major, int32& minor, int32& build, int32& revision) {
|
||||
major = 0;
|
||||
minor = 0;
|
||||
build = 0;
|
||||
revision = 1;
|
||||
}
|
||||
|
||||
} // namespace mkvmuxer
|
82
mkvmuxerutil.hpp
Normal file
82
mkvmuxerutil.hpp
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright (c) 2011 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 MKVMUXERUTIL_HPP
|
||||
#define MKVMUXERUTIL_HPP
|
||||
|
||||
#include "mkvmuxertypes.hpp"
|
||||
|
||||
namespace mkvmuxer {
|
||||
|
||||
class IMkvWriter;
|
||||
|
||||
const uint64 kEbmlUnknownValue = 0x01FFFFFFFFFFFFFFULL;
|
||||
|
||||
// Writes out |value| in Big Endian order. Returns 0 on success.
|
||||
int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size);
|
||||
|
||||
// Returns the size in bytes of the element. |master| must be set to true if
|
||||
// the element is an Mkv master element.
|
||||
// TODO(fgalligan): Change these functions so they are master element aware.
|
||||
uint64 EbmlElementSize(uint64 type, uint64 value, bool master);
|
||||
uint64 EbmlElementSize(uint64 type, float value, bool master);
|
||||
uint64 EbmlElementSize(uint64 type, const char* value, bool master);
|
||||
uint64 EbmlElementSize(uint64 type,
|
||||
const uint8* value,
|
||||
uint64 size,
|
||||
bool master);
|
||||
|
||||
// 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
|
||||
// be in a coded form. Returns 0 on success.
|
||||
int32 WriteUInt(IMkvWriter* writer, uint64 value);
|
||||
|
||||
// Creates an EBML coded number from |value| and writes it out. The size of
|
||||
// the coded number is determined by the value of |size|. |value| must not
|
||||
// be in a coded form. Returns 0 on success.
|
||||
int32 WriteUIntSize(IMkvWriter* writer, uint64 value, int32 size);
|
||||
|
||||
// Output an Mkv master element. Returns true if the element was written.
|
||||
bool WriteEbmlMasterElement(IMkvWriter* writer, uint64 value, uint64 size);
|
||||
|
||||
// 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, float value);
|
||||
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const char* value);
|
||||
bool WriteEbmlElement(IMkvWriter* writer,
|
||||
uint64 type,
|
||||
const uint8* value,
|
||||
uint64 size);
|
||||
|
||||
// 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.
|
||||
// timecode: Relative timecode of the Block.
|
||||
// is_key: Flag telling whether or not this frame is a key frame.
|
||||
uint64 WriteSimpleBlock(IMkvWriter* writer,
|
||||
const uint8* data,
|
||||
uint64 length,
|
||||
char track_number,
|
||||
short timecode,
|
||||
bool is_key);
|
||||
|
||||
// Output a void element. |size| must be the entire size in bytes that will be
|
||||
// void. The function will calculate the size of the void header and subtract
|
||||
// it from |size|.
|
||||
uint64 WriteVoidElement(IMkvWriter* writer, uint64 size);
|
||||
|
||||
// Returns the version number of the muxer in |major|, |minor|, |build|,
|
||||
// and |revision|.
|
||||
void GetVersion(int32& major, int32& minor, int32& build, int32& revision);
|
||||
|
||||
} //end namespace mkvmuxer
|
||||
|
||||
#endif // MKVMUXERUTIL_HPP
|
@ -8,6 +8,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample", "sample_2008.vcpro
|
||||
{F9128EC6-C008-41AD-B38F-0E70D549D9F4} = {F9128EC6-C008-41AD-B38F-0E70D549D9F4}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mkvmuxer", "mkvmuxer_2008.vcproj", "{7B1F12CA-0724-430B-B61A-1D357C912CBA}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_muxer", "sample_muxer\sample_muxer.vcproj", "{B407561F-1F5E-4798-B9C2-81AB09CFBC16}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{F9128EC6-C008-41AD-B38F-0E70D549D9F4} = {F9128EC6-C008-41AD-B38F-0E70D549D9F4}
|
||||
{7B1F12CA-0724-430B-B61A-1D357C912CBA} = {7B1F12CA-0724-430B-B61A-1D357C912CBA}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
@ -22,6 +30,14 @@ Global
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Release|Win32.Build.0 = Release|Win32
|
||||
{7B1F12CA-0724-430B-B61A-1D357C912CBA}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{7B1F12CA-0724-430B-B61A-1D357C912CBA}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{7B1F12CA-0724-430B-B61A-1D357C912CBA}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{7B1F12CA-0724-430B-B61A-1D357C912CBA}.Release|Win32.Build.0 = Release|Win32
|
||||
{B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
87
mkvwriter.cpp
Normal file
87
mkvwriter.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
// Copyright (c) 2011 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.
|
||||
|
||||
#include "mkvwriter.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <share.h> // for _SH_DENYWR
|
||||
#endif
|
||||
|
||||
#include <cassert>
|
||||
#include <new>
|
||||
|
||||
namespace mkvmuxer {
|
||||
|
||||
MkvWriter::MkvWriter() : file_(NULL) {
|
||||
}
|
||||
|
||||
MkvWriter::~MkvWriter() {
|
||||
Close();
|
||||
}
|
||||
|
||||
int32 MkvWriter::Write(const void* buffer, uint32 length) {
|
||||
assert(file_);
|
||||
|
||||
if (length == 0)
|
||||
return 0;
|
||||
|
||||
if (buffer == NULL)
|
||||
return -1;
|
||||
|
||||
const size_t bytes_written = fwrite(buffer, 1, length, file_);
|
||||
|
||||
return (bytes_written == length) ? 0 : -1;
|
||||
}
|
||||
|
||||
bool MkvWriter::Open(const char* filename) {
|
||||
if (filename == NULL)
|
||||
return false;
|
||||
|
||||
if (file_)
|
||||
return false;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
file_ = _fsopen(filename, "wb", _SH_DENYWR);
|
||||
#else
|
||||
file_ = fopen(filename, "wb");
|
||||
#endif
|
||||
if (file_ == NULL)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MkvWriter::Close() {
|
||||
if (file_) {
|
||||
fclose(file_);
|
||||
file_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int64 MkvWriter::Position() const {
|
||||
assert(file_);
|
||||
#ifdef _MSC_VER
|
||||
return _ftelli64(file_);
|
||||
#else
|
||||
return ftell(file_);
|
||||
#endif
|
||||
}
|
||||
|
||||
int32 MkvWriter::Position(int64 position) {
|
||||
assert(file_);
|
||||
#ifdef _MSC_VER
|
||||
return _fseeki64(file_, position, SEEK_SET);
|
||||
#else
|
||||
return fseek(file_, position, SEEK_SET);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MkvWriter::Seekable() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mkvmuxer
|
48
mkvwriter.hpp
Normal file
48
mkvwriter.hpp
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2011 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 MKVWRITER_HPP
|
||||
#define MKVWRITER_HPP
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mkvmuxer.hpp"
|
||||
#include "mkvmuxertypes.hpp"
|
||||
|
||||
namespace mkvmuxer {
|
||||
|
||||
// Default implementation of the IMkvWriter interface on Windows.
|
||||
class MkvWriter : public IMkvWriter {
|
||||
public:
|
||||
MkvWriter();
|
||||
virtual ~MkvWriter();
|
||||
|
||||
// IMkvWriter interface
|
||||
virtual int64 Position() const;
|
||||
virtual int32 Position(int64 position);
|
||||
virtual bool Seekable() const;
|
||||
virtual int32 Write(const void* buffer, uint32 length);
|
||||
|
||||
// Creates and opens a file for writing. |filename| is the name of the file
|
||||
// to open. This function will overwrite the contents of |filename|. Returns
|
||||
// true on success.
|
||||
bool Open(const char* filename);
|
||||
|
||||
// Closes an opened file.
|
||||
void Close();
|
||||
|
||||
private:
|
||||
// File handle to output file.
|
||||
FILE* file_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(MkvWriter);
|
||||
};
|
||||
|
||||
} //end namespace mkvmuxer
|
||||
|
||||
#endif // MKVWRITER_HPP
|
352
sample_muxer/sample_muxer.cpp
Normal file
352
sample_muxer/sample_muxer.cpp
Normal file
@ -0,0 +1,352 @@
|
||||
// Copyright (c) 2011 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.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// libwebm parser includes
|
||||
#include "mkvreader.hpp"
|
||||
#include "mkvparser.hpp"
|
||||
|
||||
// libwebm muxer includes
|
||||
#include "mkvmuxer.hpp"
|
||||
#include "mkvwriter.hpp"
|
||||
#include "mkvmuxerutil.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
void Usage() {
|
||||
printf("Usage: sample_muxer -i input -o output [options]\n");
|
||||
printf("\n");
|
||||
printf("Main options:\n");
|
||||
printf(" -h | -? show help\n");
|
||||
printf(" -video <int> >0 outputs video\n");
|
||||
printf(" -audio <int> >0 outputs audio\n");
|
||||
printf(" -live <int> >0 puts the muxer into live mode\n");
|
||||
printf(" 0 puts the muxer into file mode\n");
|
||||
printf(" -output_cues <int> >0 outputs cues element\n");
|
||||
printf(" -cues_on_video_track <int> >0 outputs cues on video track\n");
|
||||
printf(" 0 outputs cues on audio track\n");
|
||||
printf(" -max_cluster_duration <double> in seconds\n");
|
||||
printf(" -max_cluster_size <int> in bytes\n");
|
||||
printf(" -switch_tracks <int> >0 switches tracks in output\n");
|
||||
printf("\n");
|
||||
printf("Video options:\n");
|
||||
printf(" -display_width <int> Display width in pixels\n");
|
||||
printf(" -display_height <int> Display height in pixels\n");
|
||||
printf(" -stereo_mode <int> 3D video mode\n");
|
||||
printf("\n");
|
||||
printf("Cues options:\n");
|
||||
printf(" -output_cues_block_number <int> >0 outputs cue block number\n");
|
||||
}
|
||||
|
||||
} //end namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
using mkvmuxer::uint64;
|
||||
|
||||
char* input = NULL;
|
||||
char* output = NULL;
|
||||
|
||||
// Segment variables
|
||||
bool output_video = true;
|
||||
bool output_audio = true;
|
||||
bool live_mode = false;
|
||||
bool output_cues = true;
|
||||
bool cues_on_video_track = true;
|
||||
uint64 max_cluster_duration = 0;
|
||||
uint64 max_cluster_size = 0;
|
||||
bool switch_tracks = false;
|
||||
|
||||
bool output_cues_block_number = true;
|
||||
|
||||
uint64 display_width = 0;
|
||||
uint64 display_height = 0;
|
||||
uint64 stereo_mode = 0;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
char* end;
|
||||
|
||||
if (!strcmp("-h", argv[i]) || !strcmp("-?", argv[i])) {
|
||||
Usage();
|
||||
return 0;
|
||||
} else if (!strcmp("-i", argv[i])) {
|
||||
input = argv[++i];
|
||||
} else if (!strcmp("-o", argv[i])) {
|
||||
output = argv[++i];
|
||||
} else if (!strcmp("-video", argv[i])) {
|
||||
output_video = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||
} else if (!strcmp("-audio", argv[i])) {
|
||||
output_audio = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||
} else if (!strcmp("-live", argv[i])) {
|
||||
live_mode = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||
} else if (!strcmp("-output_cues", argv[i])) {
|
||||
output_cues = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||
} else if (!strcmp("-cues_on_video_track", argv[i])) {
|
||||
cues_on_video_track = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||
} else if (!strcmp("-max_cluster_duration", argv[i])) {
|
||||
const double seconds = strtod(argv[++i], &end);
|
||||
max_cluster_duration =
|
||||
static_cast<uint64>(seconds * 1000000000.0);
|
||||
} else if (!strcmp("-max_cluster_size", argv[i])) {
|
||||
max_cluster_size = strtol(argv[++i], &end, 10);
|
||||
} else if (!strcmp("-switch_tracks", argv[i])) {
|
||||
switch_tracks = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||
} else if (!strcmp("-display_width", argv[i])) {
|
||||
display_width = strtol(argv[++i], &end, 10);
|
||||
} else if (!strcmp("-display_height", argv[i])) {
|
||||
display_height = strtol(argv[++i], &end, 10);
|
||||
} else if (!strcmp("-stereo_mode", argv[i])) {
|
||||
stereo_mode = strtol(argv[++i], &end, 10);
|
||||
} else if (!strcmp("-output_cues_block_number", argv[i])) {
|
||||
output_cues_block_number =
|
||||
strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||
}
|
||||
}
|
||||
|
||||
if (input == NULL || output == NULL) {
|
||||
Usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get parser header info
|
||||
mkvparser::MkvReader reader;
|
||||
|
||||
if (reader.Open(input)) {
|
||||
printf("\n Filename is invalid or error while opening.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
long long pos = 0;
|
||||
mkvparser::EBMLHeader ebml_header;
|
||||
ebml_header.Parse(&reader, pos);
|
||||
|
||||
mkvparser::Segment* parser_segment;
|
||||
long long ret = mkvparser::Segment::CreateInstance(&reader,
|
||||
pos,
|
||||
parser_segment);
|
||||
if (ret) {
|
||||
printf("\n Segment::CreateInstance() failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = parser_segment->Load();
|
||||
if (ret < 0) {
|
||||
printf("\n Segment::Load() failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const mkvparser::SegmentInfo* const segment_info = parser_segment->GetInfo();
|
||||
const long long timeCodeScale = segment_info->GetTimeCodeScale();
|
||||
|
||||
// Set muxer header info
|
||||
mkvmuxer::MkvWriter writer;
|
||||
|
||||
if (!writer.Open(output)) {
|
||||
printf("\n Filename is invalid or error while opening.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set Segment element attributes
|
||||
mkvmuxer::Segment muxer_segment(&writer);
|
||||
if (live_mode)
|
||||
muxer_segment.set_mode(mkvmuxer::Segment::kLive);
|
||||
else
|
||||
muxer_segment.set_mode(mkvmuxer::Segment::kFile);
|
||||
|
||||
if (max_cluster_duration > 0)
|
||||
muxer_segment.set_max_cluster_duration(max_cluster_duration);
|
||||
if (max_cluster_size > 0)
|
||||
muxer_segment.set_max_cluster_size(max_cluster_size);
|
||||
muxer_segment.OutputCues(output_cues);
|
||||
|
||||
// Set SegmentInfo element attributes
|
||||
mkvmuxer::SegmentInfo* info = muxer_segment.GetSegmentInfo();
|
||||
info->set_timecode_scale(timeCodeScale);
|
||||
info->set_writing_app("sample_muxer");
|
||||
|
||||
// Set Tracks element attributes
|
||||
enum { kVideoTrack = 1, kAudioTrack = 2 };
|
||||
const mkvparser::Tracks* parser_tracks = parser_segment->GetTracks();
|
||||
unsigned long i = 0;
|
||||
uint64 vid_track = 0; // no track added
|
||||
uint64 aud_track = 0; // no track added
|
||||
|
||||
while (i != parser_tracks->GetTracksCount()) {
|
||||
int track_num = i++;
|
||||
if (switch_tracks)
|
||||
track_num = i % parser_tracks->GetTracksCount();
|
||||
|
||||
const mkvparser::Track* const parser_track =
|
||||
parser_tracks->GetTrackByIndex(track_num);
|
||||
|
||||
if (parser_track == NULL)
|
||||
continue;
|
||||
|
||||
// TODO(fgalligan): Add support for language to parser.
|
||||
const char* track_name = parser_track->GetNameAsUTF8();
|
||||
|
||||
const long long track_type = parser_track->GetType();
|
||||
|
||||
if (track_type == kVideoTrack && output_video) {
|
||||
// Get the video track from the parser
|
||||
const mkvparser::VideoTrack* const pVideoTrack =
|
||||
static_cast<const mkvparser::VideoTrack*>(parser_track);
|
||||
const long long width = pVideoTrack->GetWidth();
|
||||
const long long height = pVideoTrack->GetHeight();
|
||||
|
||||
// Add the video track to the muxer
|
||||
vid_track = muxer_segment.AddVideoTrack(static_cast<int>(width),
|
||||
static_cast<int>(height));
|
||||
if (!vid_track) {
|
||||
printf("\n Could not add video track.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mkvmuxer::VideoTrack* video =
|
||||
static_cast<mkvmuxer::VideoTrack*>(
|
||||
muxer_segment.GetTrackByNumber(vid_track));
|
||||
if (!video) {
|
||||
printf("\n Could not get video track.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (track_name)
|
||||
video->set_name(track_name);
|
||||
|
||||
if (display_width > 0)
|
||||
video->set_display_width(display_width);
|
||||
if (display_height > 0)
|
||||
video->set_display_height(display_height);
|
||||
if (stereo_mode > 0)
|
||||
video->SetStereoMode(stereo_mode);
|
||||
|
||||
const double rate = pVideoTrack->GetFrameRate();
|
||||
if (rate > 0.0) {
|
||||
video->set_frame_rate(rate);
|
||||
}
|
||||
} else if (track_type == kAudioTrack && output_audio) {
|
||||
// Get the audio track from the parser
|
||||
const mkvparser::AudioTrack* const pAudioTrack =
|
||||
static_cast<const mkvparser::AudioTrack*>(parser_track);
|
||||
const long long channels = pAudioTrack->GetChannels();
|
||||
const double sample_rate = pAudioTrack->GetSamplingRate();
|
||||
|
||||
// Add the audio track to the muxer
|
||||
aud_track = muxer_segment.AddAudioTrack(static_cast<int>(sample_rate),
|
||||
static_cast<int>(channels));
|
||||
if (!aud_track) {
|
||||
printf("\n Could not add audio track.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mkvmuxer::AudioTrack* audio =
|
||||
static_cast<mkvmuxer::AudioTrack*>(
|
||||
muxer_segment.GetTrackByNumber(aud_track));
|
||||
if (!audio) {
|
||||
printf("\n Could not get audio track.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (track_name)
|
||||
audio->set_name(track_name);
|
||||
|
||||
size_t private_size;
|
||||
const unsigned char* private_data =
|
||||
pAudioTrack->GetCodecPrivate(private_size);
|
||||
if (private_size > 0) {
|
||||
if (!audio->SetCodecPrivate(private_data, private_size)) {
|
||||
printf("\n Could not add audio private data.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
const long long bit_depth = pAudioTrack->GetBitDepth();
|
||||
if (bit_depth > 0)
|
||||
audio->set_bit_depth(bit_depth);
|
||||
}
|
||||
}
|
||||
|
||||
// Set Cues element attributes
|
||||
mkvmuxer::Cues* cues = muxer_segment.GetCues();
|
||||
cues->set_output_block_number(output_cues_block_number);
|
||||
if (cues_on_video_track) {
|
||||
if (vid_track)
|
||||
muxer_segment.CuesTrack(vid_track);
|
||||
} else {
|
||||
if (aud_track)
|
||||
muxer_segment.CuesTrack(aud_track);
|
||||
}
|
||||
|
||||
// Write clusters
|
||||
unsigned char* data = NULL;
|
||||
int data_len = 0;
|
||||
|
||||
const mkvparser::Cluster* cluster = parser_segment->GetFirst();
|
||||
|
||||
while ((cluster != NULL) && !cluster->EOS()) {
|
||||
const mkvparser::BlockEntry* block_entry = cluster->GetFirst();
|
||||
|
||||
while ((block_entry != NULL) && !block_entry->EOS()) {
|
||||
const mkvparser::Block* const block = block_entry->GetBlock();
|
||||
const long long trackNum = block->GetTrackNumber();
|
||||
const mkvparser::Track* const parser_track =
|
||||
parser_tracks->GetTrackByNumber(
|
||||
static_cast<unsigned long>(trackNum));
|
||||
const long long track_type = parser_track->GetType();
|
||||
|
||||
if ((track_type == kAudioTrack && output_audio) ||
|
||||
(track_type == kVideoTrack && output_video)) {
|
||||
const int frame_count = block->GetFrameCount();
|
||||
const long long time_ns = block->GetTime(cluster);
|
||||
const bool is_key = block->IsKey();
|
||||
|
||||
for (int i = 0; i < frame_count; ++i) {
|
||||
const mkvparser::Block::Frame& frame = block->GetFrame(i);
|
||||
|
||||
if (frame.len > data_len) {
|
||||
delete [] data;
|
||||
data = new unsigned char[frame.len];
|
||||
if (!data)
|
||||
return -1;
|
||||
data_len = frame.len;
|
||||
}
|
||||
|
||||
if (frame.Read(&reader, data))
|
||||
return -1;
|
||||
|
||||
uint64 track_num = vid_track;
|
||||
if (track_type == kAudioTrack)
|
||||
track_num = aud_track;
|
||||
|
||||
if (!muxer_segment.AddFrame(data,
|
||||
frame.len,
|
||||
track_num,
|
||||
time_ns,
|
||||
is_key)) {
|
||||
printf("\n Could not add frame.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
block_entry = cluster->GetNext(block_entry);
|
||||
}
|
||||
|
||||
cluster = parser_segment->GetNext(cluster);
|
||||
}
|
||||
|
||||
muxer_segment.Finalize();
|
||||
|
||||
delete [] data;
|
||||
delete parser_segment;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
197
sample_muxer/sample_muxer.vcproj
Normal file
197
sample_muxer/sample_muxer.vcproj
Normal file
@ -0,0 +1,197 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="sample_muxer"
|
||||
ProjectGUID="{B407561F-1F5E-4798-B9C2-81AB09CFBC16}"
|
||||
RootNamespace="sample_muxer"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="..\Debug\mkvparser.lib ..\Debug\mkvmuxer.lib"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
AdditionalIncludeDirectories="../"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="..\Release\mkvparser.lib ..\Release\mkvmuxer.lib"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\sample_muxer.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
107
webmids.hpp
Normal file
107
webmids.hpp
Normal file
@ -0,0 +1,107 @@
|
||||
// Copyright (c) 2011 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 WEBMIDS_HPP
|
||||
#define WEBMIDS_HPP
|
||||
|
||||
namespace mkvmuxer {
|
||||
|
||||
enum MkvId {
|
||||
kMkvEBML = 0x1A45DFA3,
|
||||
kMkvEBMLVersion = 0x4286,
|
||||
kMkvEBMLReadVersion = 0x42F7,
|
||||
kMkvEBMLMaxIDLength = 0x42F2,
|
||||
kMkvEBMLMaxSizeLength = 0x42F3,
|
||||
kMkvDocType = 0x4282,
|
||||
kMkvDocTypeVersion = 0x4287,
|
||||
kMkvDocTypeReadVersion = 0x4285,
|
||||
kMkvVoid = 0xEC,
|
||||
kMkvSignatureSlot = 0x1B538667,
|
||||
kMkvSignatureAlgo = 0x7E8A,
|
||||
kMkvSignatureHash = 0x7E9A,
|
||||
kMkvSignaturePublicKey = 0x7EA5,
|
||||
kMkvSignature = 0x7EB5,
|
||||
kMkvSignatureElements = 0x7E5B,
|
||||
kMkvSignatureElementList = 0x7E7B,
|
||||
kMkvSignedElement = 0x6532,
|
||||
//segment
|
||||
kMkvSegment = 0x18538067,
|
||||
//Meta Seek Information
|
||||
kMkvSeekHead = 0x114D9B74,
|
||||
kMkvSeek = 0x4DBB,
|
||||
kMkvSeekID = 0x53AB,
|
||||
kMkvSeekPosition = 0x53AC,
|
||||
//Segment Information
|
||||
kMkvInfo = 0x1549A966,
|
||||
kMkvTimecodeScale = 0x2AD7B1,
|
||||
kMkvDuration = 0x4489,
|
||||
kMkvDateUTC = 0x4461,
|
||||
kMkvMuxingApp = 0x4D80,
|
||||
kMkvWritingApp = 0x5741,
|
||||
//Cluster
|
||||
kMkvCluster = 0x1F43B675,
|
||||
kMkvTimecode = 0xE7,
|
||||
kMkvPrevSize = 0xAB,
|
||||
kMkvBlockGroup = 0xA0,
|
||||
kMkvBlock = 0xA1,
|
||||
kMkvBlockDuration = 0x9B,
|
||||
kMkvReferenceBlock = 0xFB,
|
||||
kMkvLaceNumber = 0xCC,
|
||||
kMkvSimpleBlock = 0xA3,
|
||||
//Track
|
||||
kMkvTracks = 0x1654AE6B,
|
||||
kMkvTrackEntry = 0xAE,
|
||||
kMkvTrackNumber = 0xD7,
|
||||
kMkvTrackUID = 0x73C5,
|
||||
kMkvTrackType = 0x83,
|
||||
kMkvFlagEnabled = 0xB9,
|
||||
kMkvFlagDefault = 0x88,
|
||||
kMkvFlagForced = 0x55AA,
|
||||
kMkvFlagLacing = 0x9C,
|
||||
kMkvDefaultDuration = 0x23E383,
|
||||
kMkvName = 0x536E,
|
||||
kMkvLanguage = 0x22B59C,
|
||||
kMkvCodecID = 0x86,
|
||||
kMkvCodecPrivate = 0x63A2,
|
||||
kMkvCodecName = 0x258688,
|
||||
//video
|
||||
kMkvVideo = 0xE0,
|
||||
kMkvFlagInterlaced = 0x9A,
|
||||
kMkvStereoMode = 0x53B8,
|
||||
kMkvPixelWidth = 0xB0,
|
||||
kMkvPixelHeight = 0xBA,
|
||||
kMkvPixelCropBottom = 0x54AA,
|
||||
kMkvPixelCropTop = 0x54BB,
|
||||
kMkvPixelCropLeft = 0x54CC,
|
||||
kMkvPixelCropRight = 0x54DD,
|
||||
kMkvDisplayWidth = 0x54B0,
|
||||
kMkvDisplayHeight = 0x54BA,
|
||||
kMkvDisplayUnit = 0x54B2,
|
||||
kMkvAspectRatioType = 0x54B3,
|
||||
kMkvFrameRate = 0x2383E3,
|
||||
//end video
|
||||
//audio
|
||||
kMkvAudio = 0xE1,
|
||||
kMkvSamplingFrequency = 0xB5,
|
||||
kMkvOutputSamplingFrequency = 0x78B5,
|
||||
kMkvChannels = 0x9F,
|
||||
kMkvBitDepth = 0x6264,
|
||||
//end audio
|
||||
//Cueing Data
|
||||
kMkvCues = 0x1C53BB6B,
|
||||
kMkvCuePoint = 0xBB,
|
||||
kMkvCueTime = 0xB3,
|
||||
kMkvCueTrackPositions = 0xB7,
|
||||
kMkvCueTrack = 0xF7,
|
||||
kMkvCueClusterPosition = 0xF1,
|
||||
kMkvCueBlockNumber = 0x5378,
|
||||
};
|
||||
|
||||
} // end namespace mkvmuxer
|
||||
|
||||
#endif // WEBMIDS_HPP
|
Loading…
Reference in New Issue
Block a user