Support for placing Cues before Clusters
Adding support for placing Cues element before the Cluster element. We recompute the new offsets using a recursive algorithm and update the Cues and Seek Heads with the updates offsets. Change-Id: I038f1a403b1defa853b9026bd3e48f4ad1006866
This commit is contained in:
2
Makefile
2
Makefile
@@ -2,7 +2,7 @@ CXX := g++
|
|||||||
CXXFLAGS := -W -Wall -g
|
CXXFLAGS := -W -Wall -g
|
||||||
LIBWEBMA := libwebm.a
|
LIBWEBMA := libwebm.a
|
||||||
LIBWEBMSO := libwebm.so
|
LIBWEBMSO := libwebm.so
|
||||||
WEBMOBJS := mkvparser.o mkvreader.o mkvmuxer.o mkvmuxerutil.o mkvwriter.o
|
WEBMOBJS := mkvparser.o mkvreader.o mkvmuxer.o mkvmuxerutil.o mkvwriter.o mkvreadablewriter.o
|
||||||
OBJSA := $(WEBMOBJS:.o=_a.o)
|
OBJSA := $(WEBMOBJS:.o=_a.o)
|
||||||
OBJSSO := $(WEBMOBJS:.o=_so.o)
|
OBJSSO := $(WEBMOBJS:.o=_so.o)
|
||||||
OBJECTS1 := sample.o
|
OBJECTS1 := sample.o
|
||||||
|
|||||||
143
mkvmuxer.cpp
143
mkvmuxer.cpp
@@ -7,6 +7,7 @@
|
|||||||
// be found in the AUTHORS file in the root of the source tree.
|
// be found in the AUTHORS file in the root of the source tree.
|
||||||
|
|
||||||
#include "mkvmuxer.hpp"
|
#include "mkvmuxer.hpp"
|
||||||
|
#include "mkvreadablewriter.hpp"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@@ -90,6 +91,25 @@ bool WriteEbmlHeader(IMkvWriter* writer) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ChunkedCopy(mkvmuxer::IMkvReadableWriter* source,
|
||||||
|
mkvmuxer::IMkvWriter* dst,
|
||||||
|
mkvmuxer::int64 start, int64 size) {
|
||||||
|
// TODO(vigneshv): Check if this is a reasonable value.
|
||||||
|
const uint32 kBufSize = 2048;
|
||||||
|
uint8* buf = new uint8[kBufSize];
|
||||||
|
int64 offset = start;
|
||||||
|
while (size > 0) {
|
||||||
|
const int64 read_len = (size > kBufSize) ? kBufSize : size;
|
||||||
|
if (source->Read(offset, read_len, buf))
|
||||||
|
return false;
|
||||||
|
dst->Write(buf, read_len);
|
||||||
|
offset += read_len;
|
||||||
|
size -= read_len;
|
||||||
|
}
|
||||||
|
delete[] buf;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Frame Class
|
// Frame Class
|
||||||
@@ -249,7 +269,7 @@ bool Cues::AddCue(CuePoint* cue) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CuePoint* Cues::GetCueByIndex(int32 index) const {
|
CuePoint* Cues::GetCueByIndex(int32 index) const {
|
||||||
if (cue_entries_ == NULL)
|
if (cue_entries_ == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -259,6 +279,14 @@ const CuePoint* Cues::GetCueByIndex(int32 index) const {
|
|||||||
return cue_entries_[index];
|
return cue_entries_[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64 Cues::Size() {
|
||||||
|
uint64 size = 0;
|
||||||
|
for (int32 i = 0; i < cue_entries_size_; ++i)
|
||||||
|
size += GetCueByIndex(i)->Size();
|
||||||
|
size += EbmlMasterElementSize(kMkvCues, size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
bool Cues::Write(IMkvWriter* writer) const {
|
bool Cues::Write(IMkvWriter* writer) const {
|
||||||
if (!writer)
|
if (!writer)
|
||||||
return false;
|
return false;
|
||||||
@@ -1722,6 +1750,26 @@ bool SeekHead::AddSeekEntry(uint32 id, uint64 pos) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32 SeekHead::GetId(int index) const {
|
||||||
|
if (index < 0 || index >= kSeekEntryCount)
|
||||||
|
return -1;
|
||||||
|
return seek_entry_id_[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 SeekHead::GetPosition(int index) const {
|
||||||
|
if (index < 0 || index >= kSeekEntryCount)
|
||||||
|
return -1;
|
||||||
|
return seek_entry_pos_[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SeekHead::SetSeekEntry(int index, uint32 id, uint64 position) {
|
||||||
|
if (index < 0 || index >= kSeekEntryCount)
|
||||||
|
return false;
|
||||||
|
seek_entry_id_[index] = id;
|
||||||
|
seek_entry_pos_[index] = position;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
uint64 SeekHead::MaxEntrySize() const {
|
uint64 SeekHead::MaxEntrySize() const {
|
||||||
const uint64 max_entry_payload_size =
|
const uint64 max_entry_payload_size =
|
||||||
EbmlElementSize(kMkvSeekID, 0xffffffffULL) +
|
EbmlElementSize(kMkvSeekID, 0xffffffffULL) +
|
||||||
@@ -1914,6 +1962,7 @@ Segment::Segment()
|
|||||||
cluster_list_(NULL),
|
cluster_list_(NULL),
|
||||||
cluster_list_capacity_(0),
|
cluster_list_capacity_(0),
|
||||||
cluster_list_size_(0),
|
cluster_list_size_(0),
|
||||||
|
cues_position_(kAfterClusters),
|
||||||
cues_track_(0),
|
cues_track_(0),
|
||||||
force_new_cluster_(false),
|
force_new_cluster_(false),
|
||||||
frames_(NULL),
|
frames_(NULL),
|
||||||
@@ -1973,16 +2022,84 @@ Segment::~Segment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Segment::MoveCuesBeforeClustersHelper(uint64 diff,
|
||||||
|
int32 index,
|
||||||
|
uint64* cues_size) {
|
||||||
|
const uint64 old_cues_size = *cues_size;
|
||||||
|
CuePoint* const cue_point = cues_.GetCueByIndex(index);
|
||||||
|
if (cue_point == NULL)
|
||||||
|
return;
|
||||||
|
const uint64 old_cue_point_size = cue_point->Size();
|
||||||
|
const uint64 cluster_pos = cue_point->cluster_pos() + diff;
|
||||||
|
cue_point->set_cluster_pos(cluster_pos); // update the new cluster position
|
||||||
|
// New size of the cue is computed as follows
|
||||||
|
// Let a = current size of Cues Element
|
||||||
|
// Let b = Difference in Cue Point's size after this pass
|
||||||
|
// Let c = Difference in length of Cues Element's size
|
||||||
|
// (This is computed as CodedSize(a + b) - CodedSize(a)
|
||||||
|
// Let d = a + b + c. Now d is the new size of the Cues element which is
|
||||||
|
// passed on to the next recursive call.
|
||||||
|
const uint64 cue_point_size_diff = cue_point->Size() - old_cue_point_size;
|
||||||
|
const uint64 cue_size_diff = GetCodedUIntSize(*cues_size +
|
||||||
|
cue_point_size_diff) -
|
||||||
|
GetCodedUIntSize(*cues_size);
|
||||||
|
*cues_size += cue_point_size_diff + cue_size_diff;
|
||||||
|
diff = *cues_size - old_cues_size;
|
||||||
|
if (diff > 0) {
|
||||||
|
for (int32 i = 0; i < cues_.cue_entries_size(); ++i) {
|
||||||
|
MoveCuesBeforeClustersHelper(diff, i, cues_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Segment::MoveCuesBeforeClusters() {
|
||||||
|
const uint64 current_cue_size = cues_.Size();
|
||||||
|
uint64 cue_size = current_cue_size;
|
||||||
|
for (int32 i = 0; i < cues_.cue_entries_size(); i++)
|
||||||
|
MoveCuesBeforeClustersHelper(current_cue_size, i, &cue_size);
|
||||||
|
|
||||||
|
// Adjust the Seek Entry to reflect the change in position
|
||||||
|
// of Cluster and Cues
|
||||||
|
int32 cluster_index;
|
||||||
|
int32 cues_index;
|
||||||
|
for (int32 i = 0; i < SeekHead::kSeekEntryCount; ++i) {
|
||||||
|
if (seek_head_.GetId(i) == kMkvCluster)
|
||||||
|
cluster_index = i;
|
||||||
|
if (seek_head_.GetId(i) == kMkvCues)
|
||||||
|
cues_index = i;
|
||||||
|
}
|
||||||
|
seek_head_.SetSeekEntry(cues_index, kMkvCues,
|
||||||
|
seek_head_.GetPosition(cluster_index));
|
||||||
|
seek_head_.SetSeekEntry(cluster_index, kMkvCluster,
|
||||||
|
cues_.Size() + seek_head_.GetPosition(cues_index));
|
||||||
|
}
|
||||||
|
|
||||||
bool Segment::Init(IMkvWriter* ptr_writer) {
|
bool Segment::Init(IMkvWriter* ptr_writer) {
|
||||||
if (!ptr_writer) {
|
if (!ptr_writer) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
writer_cluster_ = ptr_writer;
|
writer_ = ptr_writer;
|
||||||
writer_cues_ = ptr_writer;
|
if (cues_position_ == kAfterClusters) {
|
||||||
writer_header_ = ptr_writer;
|
writer_cluster_ = writer_;
|
||||||
|
writer_cues_ = writer_;
|
||||||
|
writer_header_ = writer_;
|
||||||
|
} else {
|
||||||
|
writer_cluster_ = writer_temp_;
|
||||||
|
writer_cues_ = writer_temp_;
|
||||||
|
writer_header_ = writer_temp_;
|
||||||
|
}
|
||||||
return segment_info_.Init();
|
return segment_info_.Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Segment::WriteCuesBeforeClusters(IMkvReadableWriter* ptr_writer) {
|
||||||
|
if (!ptr_writer || writer_cluster_ || writer_cues_ || writer_header_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
writer_temp_ = ptr_writer;
|
||||||
|
cues_position_ = kBeforeClusters;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Segment::Finalize() {
|
bool Segment::Finalize() {
|
||||||
if (WriteFramesAll() < 0)
|
if (WriteFramesAll() < 0)
|
||||||
return false;
|
return false;
|
||||||
@@ -2007,7 +2124,6 @@ bool Segment::Finalize() {
|
|||||||
if (!segment_info_.Finalize(writer_header_))
|
if (!segment_info_.Finalize(writer_header_))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// TODO(fgalligan): Add support for putting the Cues at the front.
|
|
||||||
if (output_cues_)
|
if (output_cues_)
|
||||||
if (!seek_head_.AddSeekEntry(kMkvCues, MaxOffset()))
|
if (!seek_head_.AddSeekEntry(kMkvCues, MaxOffset()))
|
||||||
return false;
|
return false;
|
||||||
@@ -2026,6 +2142,18 @@ bool Segment::Finalize() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const int64 current_offset = writer_cluster_->Position();
|
||||||
|
const int64 cluster_offset = cluster_list_[0]->size_position() -
|
||||||
|
GetUIntSize(kMkvCluster);
|
||||||
|
if (cues_position_ == kBeforeClusters) {
|
||||||
|
writer_cluster_ = writer_;
|
||||||
|
writer_cues_ = writer_;
|
||||||
|
writer_header_ = writer_;
|
||||||
|
ChunkedCopy(writer_temp_, writer_cluster_, 0, cluster_offset);
|
||||||
|
MoveCuesBeforeClusters();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the seek headers and cues
|
||||||
if (output_cues_)
|
if (output_cues_)
|
||||||
if (!cues_.Write(writer_cues_))
|
if (!cues_.Write(writer_cues_))
|
||||||
return false;
|
return false;
|
||||||
@@ -2033,6 +2161,11 @@ bool Segment::Finalize() {
|
|||||||
if (!seek_head_.Finalize(writer_header_))
|
if (!seek_head_.Finalize(writer_header_))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (cues_position_ == kBeforeClusters) {
|
||||||
|
ChunkedCopy(writer_temp_, writer_cluster_,
|
||||||
|
cluster_offset, current_offset - cluster_offset);
|
||||||
|
}
|
||||||
|
|
||||||
if (writer_header_->Seekable()) {
|
if (writer_header_->Seekable()) {
|
||||||
if (size_position_ == -1)
|
if (size_position_ == -1)
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
64
mkvmuxer.hpp
64
mkvmuxer.hpp
@@ -51,10 +51,21 @@ class IMkvWriter {
|
|||||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(IMkvWriter);
|
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(IMkvWriter);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class IMkvReadableWriter : public IMkvWriter {
|
||||||
|
public:
|
||||||
|
virtual int Read(long long position, long length,
|
||||||
|
unsigned char* buffer) = 0;
|
||||||
|
virtual int Length(long long* total, long long* available) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// Writes out the EBML header for a WebM file. This function must be called
|
// Writes out the EBML header for a WebM file. This function must be called
|
||||||
// before any other libwebm writing functions are called.
|
// before any other libwebm writing functions are called.
|
||||||
bool WriteEbmlHeader(IMkvWriter* writer);
|
bool WriteEbmlHeader(IMkvWriter* writer);
|
||||||
|
|
||||||
|
// Copies in Chunk from source to destination between the given byte positions
|
||||||
|
bool ChunkedCopy(IMkvReadableWriter* source, IMkvWriter* dst,
|
||||||
|
int64 start, int64 size);
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
// Class to hold data the will be written to a block.
|
// Class to hold data the will be written to a block.
|
||||||
class Frame {
|
class Frame {
|
||||||
@@ -152,7 +163,10 @@ class Cues {
|
|||||||
|
|
||||||
// Returns the cue point by index. Returns NULL if there is no cue point
|
// Returns the cue point by index. Returns NULL if there is no cue point
|
||||||
// match.
|
// match.
|
||||||
const CuePoint* GetCueByIndex(int32 index) const;
|
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.
|
// Output the Cues element to the writer. Returns true on success.
|
||||||
bool Write(IMkvWriter* writer) const;
|
bool Write(IMkvWriter* writer) const;
|
||||||
@@ -728,6 +742,7 @@ class Cluster {
|
|||||||
// Returns the size in bytes for the entire Cluster element.
|
// Returns the size in bytes for the entire Cluster element.
|
||||||
uint64 Size() const;
|
uint64 Size() const;
|
||||||
|
|
||||||
|
int64 size_position() const { return size_position_; }
|
||||||
int32 blocks_added() const { return blocks_added_; }
|
int32 blocks_added() const { return blocks_added_; }
|
||||||
uint64 payload_size() const { return payload_size_; }
|
uint64 payload_size() const { return payload_size_; }
|
||||||
int64 position_for_cues() const { return position_for_cues_; }
|
int64 position_for_cues() const { return position_for_cues_; }
|
||||||
@@ -822,14 +837,26 @@ class SeekHead {
|
|||||||
// Writes out SeekHead and SeekEntry elements. Returns true on success.
|
// Writes out SeekHead and SeekEntry elements. Returns true on success.
|
||||||
bool Finalize(IMkvWriter* writer) const;
|
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
|
// Reserves space by writing out a Void element which will be updated with
|
||||||
// a SeekHead element later. Returns true on success.
|
// a SeekHead element later. Returns true on success.
|
||||||
bool Write(IMkvWriter* writer);
|
bool Write(IMkvWriter* writer);
|
||||||
|
|
||||||
private:
|
|
||||||
// We are going to put a cap on the number of Seek Entries.
|
// We are going to put a cap on the number of Seek Entries.
|
||||||
const static int32 kSeekEntryCount = 5;
|
const static int32 kSeekEntryCount = 5;
|
||||||
|
|
||||||
|
private:
|
||||||
// Returns the maximum size in bytes of one seek entry.
|
// Returns the maximum size in bytes of one seek entry.
|
||||||
uint64 MaxEntrySize() const;
|
uint64 MaxEntrySize() const;
|
||||||
|
|
||||||
@@ -901,6 +928,11 @@ class Segment {
|
|||||||
kFile = 0x2
|
kFile = 0x2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum CuesPosition {
|
||||||
|
kAfterClusters = 0x0, // Position Cues after Clusters - Default
|
||||||
|
kBeforeClusters = 0x1 // Position Cues before Clusters
|
||||||
|
};
|
||||||
|
|
||||||
const static uint64 kDefaultMaxClusterDuration = 30000000000ULL;
|
const static uint64 kDefaultMaxClusterDuration = 30000000000ULL;
|
||||||
|
|
||||||
Segment();
|
Segment();
|
||||||
@@ -910,6 +942,11 @@ class Segment {
|
|||||||
// |ptr_writer| is NULL.
|
// |ptr_writer| is NULL.
|
||||||
bool Init(IMkvWriter* ptr_writer);
|
bool Init(IMkvWriter* ptr_writer);
|
||||||
|
|
||||||
|
// This function must be called before Init() if Cues are to be written before
|
||||||
|
// the Clusters. Input parameter is a IMkvReadableWriter object which supports
|
||||||
|
// both writing and reading.
|
||||||
|
bool WriteCuesBeforeClusters(IMkvReadableWriter* ptr_writer);
|
||||||
|
|
||||||
// Adds a generic track to the segment. Returns the newly-allocated
|
// Adds a generic track to the segment. Returns the newly-allocated
|
||||||
// track object (which is owned by the segment) on success, NULL on
|
// track object (which is owned by the segment) on success, NULL on
|
||||||
// error. |number| is the number to use for the track. |number|
|
// error. |number| is the number to use for the track. |number|
|
||||||
@@ -1034,6 +1071,7 @@ class Segment {
|
|||||||
uint64 max_cluster_size() const { return max_cluster_size_; }
|
uint64 max_cluster_size() const { return max_cluster_size_; }
|
||||||
void set_mode(Mode mode) { mode_ = mode; }
|
void set_mode(Mode mode) { mode_ = mode; }
|
||||||
Mode mode() const { return mode_; }
|
Mode mode() const { return mode_; }
|
||||||
|
CuesPosition cues_position() const { return cues_position_; }
|
||||||
bool output_cues() const { return output_cues_; }
|
bool output_cues() const { return output_cues_; }
|
||||||
const SegmentInfo* segment_info() const { return &segment_info_; }
|
const SegmentInfo* segment_info() const { return &segment_info_; }
|
||||||
|
|
||||||
@@ -1088,6 +1126,21 @@ class Segment {
|
|||||||
// was necessary but creation was not successful.
|
// was necessary but creation was not successful.
|
||||||
bool DoNewClusterProcessing(uint64 track_num, uint64 timestamp_ns, bool key);
|
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 - size of the Cues element.
|
||||||
|
void MoveCuesBeforeClustersHelper(uint64 diff, int index, uint64* cue_size);
|
||||||
|
|
||||||
// Seeds the random number generator used to make UIDs.
|
// Seeds the random number generator used to make UIDs.
|
||||||
unsigned int seed_;
|
unsigned int seed_;
|
||||||
|
|
||||||
@@ -1132,6 +1185,9 @@ class Segment {
|
|||||||
// Number of clusters in the cluster list.
|
// Number of clusters in the cluster list.
|
||||||
int32 cluster_list_size_;
|
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.
|
// Track number that is associated with the cues element for this segment.
|
||||||
uint64 cues_track_;
|
uint64 cues_track_;
|
||||||
|
|
||||||
@@ -1191,6 +1247,10 @@ class Segment {
|
|||||||
IMkvWriter* writer_cues_;
|
IMkvWriter* writer_cues_;
|
||||||
IMkvWriter* writer_header_;
|
IMkvWriter* writer_header_;
|
||||||
|
|
||||||
|
// Pointer to actual writer object and temp writer object
|
||||||
|
IMkvWriter* writer_;
|
||||||
|
IMkvReadableWriter* writer_temp_;
|
||||||
|
|
||||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Segment);
|
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Segment);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ const int64 kMaxBlockTimecode = 0x07FFFLL;
|
|||||||
int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size);
|
int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size);
|
||||||
|
|
||||||
// Returns the size in bytes of the element.
|
// Returns the size in bytes of the element.
|
||||||
|
int32 GetUIntSize(uint64 value);
|
||||||
|
int32 GetCodedUIntSize(uint64 value);
|
||||||
uint64 EbmlMasterElementSize(uint64 type, uint64 value);
|
uint64 EbmlMasterElementSize(uint64 type, uint64 value);
|
||||||
uint64 EbmlElementSize(uint64 type, uint64 value);
|
uint64 EbmlElementSize(uint64 type, uint64 value);
|
||||||
uint64 EbmlElementSize(uint64 type, float value);
|
uint64 EbmlElementSize(uint64 type, float value);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
// libwebm muxer includes
|
// libwebm muxer includes
|
||||||
#include "mkvmuxer.hpp"
|
#include "mkvmuxer.hpp"
|
||||||
|
#include "mkvreadablewriter.hpp"
|
||||||
#include "mkvwriter.hpp"
|
#include "mkvwriter.hpp"
|
||||||
#include "mkvmuxerutil.hpp"
|
#include "mkvmuxerutil.hpp"
|
||||||
|
|
||||||
@@ -53,6 +54,7 @@ void Usage() {
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
printf("Cues options:\n");
|
printf("Cues options:\n");
|
||||||
printf(" -output_cues_block_number <int> >0 outputs cue block number\n");
|
printf(" -output_cues_block_number <int> >0 outputs cue block number\n");
|
||||||
|
printf(" -cues_before_clusters <int> >0 puts Cues before Clusters\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("Metadata options:\n");
|
printf("Metadata options:\n");
|
||||||
printf(" -webvtt-subtitles <vttfile> "
|
printf(" -webvtt-subtitles <vttfile> "
|
||||||
@@ -145,6 +147,7 @@ int main(int argc, char* argv[]) {
|
|||||||
bool output_audio = true;
|
bool output_audio = true;
|
||||||
bool live_mode = false;
|
bool live_mode = false;
|
||||||
bool output_cues = true;
|
bool output_cues = true;
|
||||||
|
bool cues_before_clusters = false;
|
||||||
bool cues_on_video_track = true;
|
bool cues_on_video_track = true;
|
||||||
bool cues_on_audio_track = false;
|
bool cues_on_audio_track = false;
|
||||||
uint64 max_cluster_duration = 0;
|
uint64 max_cluster_duration = 0;
|
||||||
@@ -182,6 +185,8 @@ int main(int argc, char* argv[]) {
|
|||||||
live_mode = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
live_mode = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||||
} else if (!strcmp("-output_cues", argv[i]) && i < argc_check) {
|
} else if (!strcmp("-output_cues", argv[i]) && i < argc_check) {
|
||||||
output_cues = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
output_cues = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||||
|
} else if (!strcmp("-cues_before_clusters", argv[i]) && i < argc_check) {
|
||||||
|
cues_before_clusters = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||||
} else if (!strcmp("-cues_on_video_track", argv[i]) && i < argc_check) {
|
} else if (!strcmp("-cues_on_video_track", argv[i]) && i < argc_check) {
|
||||||
cues_on_video_track = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
cues_on_video_track = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||||
if (cues_on_video_track)
|
if (cues_on_video_track)
|
||||||
@@ -267,6 +272,14 @@ int main(int argc, char* argv[]) {
|
|||||||
// Set Segment element attributes
|
// Set Segment element attributes
|
||||||
mkvmuxer::Segment muxer_segment;
|
mkvmuxer::Segment muxer_segment;
|
||||||
|
|
||||||
|
mkvmuxer::MkvReadableWriter writer_temp;
|
||||||
|
if (cues_before_clusters) {
|
||||||
|
if (!writer_temp.Open(NULL, true)) {
|
||||||
|
printf("\n Filename is invalid or error while opening.\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
muxer_segment.WriteCuesBeforeClusters(&writer_temp);
|
||||||
|
}
|
||||||
if (!muxer_segment.Init(&writer)) {
|
if (!muxer_segment.Init(&writer)) {
|
||||||
printf("\n Could not initialize muxer segment!\n");
|
printf("\n Could not initialize muxer segment!\n");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
@@ -511,6 +524,8 @@ int main(int argc, char* argv[]) {
|
|||||||
delete parser_segment;
|
delete parser_segment;
|
||||||
|
|
||||||
writer.Close();
|
writer.Close();
|
||||||
|
if (cues_before_clusters)
|
||||||
|
writer_temp.Close();
|
||||||
reader.Close();
|
reader.Close();
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|||||||
Reference in New Issue
Block a user