Adds support for simple tags
Change-Id: I285e4b73df0a7112bbde7ef13eddf8fdccf59178
This commit is contained in:
parent
75a6d2da8b
commit
b6de61a5c0
240
mkvmuxer.cpp
240
mkvmuxer.cpp
@ -1514,6 +1514,237 @@ uint64 Chapters::WriteEdition(IMkvWriter* writer) const {
|
||||
return edition_size;
|
||||
}
|
||||
|
||||
// Tag Class
|
||||
|
||||
bool Tag::add_simple_tag(const char* tag_name, const char* tag_string) {
|
||||
if (!ExpandSimpleTagsArray())
|
||||
return false;
|
||||
|
||||
SimpleTag& st = simple_tags_[simple_tags_count_++];
|
||||
st.Init();
|
||||
|
||||
if (!st.set_tag_name(tag_name))
|
||||
return false;
|
||||
|
||||
if (!st.set_tag_string(tag_string))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Tag::Tag() {
|
||||
simple_tags_ = NULL;
|
||||
simple_tags_size_ = 0;
|
||||
simple_tags_count_ = 0;
|
||||
}
|
||||
|
||||
Tag::~Tag() {}
|
||||
|
||||
void Tag::ShallowCopy(Tag* dst) const {
|
||||
dst->simple_tags_ = simple_tags_;
|
||||
dst->simple_tags_size_ = simple_tags_size_;
|
||||
dst->simple_tags_count_ = simple_tags_count_;
|
||||
}
|
||||
|
||||
void Tag::Clear() {
|
||||
while (simple_tags_count_ > 0) {
|
||||
SimpleTag& st = simple_tags_[--simple_tags_count_];
|
||||
st.Clear();
|
||||
}
|
||||
|
||||
delete[] simple_tags_;
|
||||
simple_tags_ = NULL;
|
||||
|
||||
simple_tags_size_ = 0;
|
||||
}
|
||||
|
||||
bool Tag::ExpandSimpleTagsArray() {
|
||||
if (simple_tags_size_ > simple_tags_count_)
|
||||
return true; // nothing to do yet
|
||||
|
||||
const int size = (simple_tags_size_ == 0) ? 1 : 2 * simple_tags_size_;
|
||||
|
||||
SimpleTag* const simple_tags = new (std::nothrow) SimpleTag[size]; // NOLINT
|
||||
if (simple_tags == NULL)
|
||||
return false;
|
||||
|
||||
for (int idx = 0; idx < simple_tags_count_; ++idx) {
|
||||
simple_tags[idx] = simple_tags_[idx]; // shallow copy
|
||||
}
|
||||
|
||||
delete[] simple_tags_;
|
||||
|
||||
simple_tags_ = simple_tags;
|
||||
simple_tags_size_ = size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64 Tag::Write(IMkvWriter* writer) const {
|
||||
uint64 payload_size = 0;
|
||||
|
||||
for (int idx = 0; idx < simple_tags_count_; ++idx) {
|
||||
const SimpleTag& st = simple_tags_[idx];
|
||||
payload_size += st.Write(NULL);
|
||||
}
|
||||
|
||||
const uint64 tag_size =
|
||||
EbmlMasterElementSize(kMkvTag, payload_size) + payload_size;
|
||||
|
||||
if (writer == NULL)
|
||||
return tag_size;
|
||||
|
||||
const int64 start = writer->Position();
|
||||
|
||||
if (!WriteEbmlMasterElement(writer, kMkvTag, payload_size))
|
||||
return 0;
|
||||
|
||||
for (int idx = 0; idx < simple_tags_count_; ++idx) {
|
||||
const SimpleTag& st = simple_tags_[idx];
|
||||
|
||||
if (!st.Write(writer))
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int64 stop = writer->Position();
|
||||
|
||||
if (stop >= start && uint64(stop - start) != tag_size)
|
||||
return 0;
|
||||
|
||||
return tag_size;
|
||||
}
|
||||
|
||||
// Tag::SimpleTag
|
||||
|
||||
void Tag::SimpleTag::Init() {
|
||||
tag_name_ = NULL;
|
||||
tag_string_ = NULL;
|
||||
}
|
||||
|
||||
void Tag::SimpleTag::Clear() {
|
||||
StrCpy(NULL, &tag_name_);
|
||||
StrCpy(NULL, &tag_string_);
|
||||
}
|
||||
|
||||
bool Tag::SimpleTag::set_tag_name(const char* tag_name) {
|
||||
return StrCpy(tag_name, &tag_name_);
|
||||
}
|
||||
|
||||
bool Tag::SimpleTag::set_tag_string(const char* tag_string) {
|
||||
return StrCpy(tag_string, &tag_string_);
|
||||
}
|
||||
|
||||
uint64 Tag::SimpleTag::Write(IMkvWriter* writer) const {
|
||||
uint64 payload_size = EbmlElementSize(kMkvTagName, tag_name_);
|
||||
|
||||
payload_size += EbmlElementSize(kMkvTagString, tag_string_);
|
||||
|
||||
const uint64 simple_tag_size =
|
||||
EbmlMasterElementSize(kMkvSimpleTag, payload_size) + payload_size;
|
||||
|
||||
if (writer == NULL)
|
||||
return simple_tag_size;
|
||||
|
||||
const int64 start = writer->Position();
|
||||
|
||||
if (!WriteEbmlMasterElement(writer, kMkvSimpleTag, payload_size))
|
||||
return 0;
|
||||
|
||||
if (!WriteEbmlElement(writer, kMkvTagName, tag_name_))
|
||||
return 0;
|
||||
|
||||
if (!WriteEbmlElement(writer, kMkvTagString, tag_string_))
|
||||
return 0;
|
||||
|
||||
const int64 stop = writer->Position();
|
||||
|
||||
if (stop >= start && uint64(stop - start) != simple_tag_size)
|
||||
return 0;
|
||||
|
||||
return simple_tag_size;
|
||||
}
|
||||
|
||||
// Tags Class
|
||||
|
||||
Tags::Tags() : tags_size_(0), tags_count_(0), tags_(NULL) {}
|
||||
|
||||
Tags::~Tags() {
|
||||
while (tags_count_ > 0) {
|
||||
Tag& tag = tags_[--tags_count_];
|
||||
tag.Clear();
|
||||
}
|
||||
|
||||
delete[] tags_;
|
||||
tags_ = NULL;
|
||||
}
|
||||
|
||||
int Tags::Count() const { return tags_count_; }
|
||||
|
||||
Tag* Tags::AddTag() {
|
||||
if (!ExpandTagsArray())
|
||||
return NULL;
|
||||
|
||||
Tag& tag = tags_[tags_count_++];
|
||||
|
||||
return &tag;
|
||||
}
|
||||
|
||||
bool Tags::Write(IMkvWriter* writer) const {
|
||||
if (writer == NULL)
|
||||
return false;
|
||||
|
||||
uint64 payload_size = 0;
|
||||
|
||||
for (int idx = 0; idx < tags_count_; ++idx) {
|
||||
const Tag& tag = tags_[idx];
|
||||
payload_size += tag.Write(NULL);
|
||||
}
|
||||
|
||||
if (!WriteEbmlMasterElement(writer, kMkvTags, payload_size))
|
||||
return false;
|
||||
|
||||
const int64 start = writer->Position();
|
||||
|
||||
for (int idx = 0; idx < tags_count_; ++idx) {
|
||||
const Tag& tag = tags_[idx];
|
||||
|
||||
const uint64 tag_size = tag.Write(writer);
|
||||
if (tag_size == 0) // error
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int64 stop = writer->Position();
|
||||
|
||||
if (stop >= start && uint64(stop - start) != payload_size)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Tags::ExpandTagsArray() {
|
||||
if (tags_size_ > tags_count_)
|
||||
return true; // nothing to do yet
|
||||
|
||||
const int size = (tags_size_ == 0) ? 1 : 2 * tags_size_;
|
||||
|
||||
Tag* const tags = new (std::nothrow) Tag[size]; // NOLINT
|
||||
if (tags == NULL)
|
||||
return false;
|
||||
|
||||
for (int idx = 0; idx < tags_count_; ++idx) {
|
||||
const Tag& src = tags_[idx];
|
||||
Tag* const dst = tags + idx;
|
||||
src.ShallowCopy(dst);
|
||||
}
|
||||
|
||||
delete[] tags_;
|
||||
|
||||
tags_ = tags;
|
||||
tags_size_ = size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Cluster class
|
||||
@ -2274,6 +2505,8 @@ Track* Segment::AddTrack(int32 number) {
|
||||
|
||||
Chapter* Segment::AddChapter() { return chapters_.AddChapter(&seed_); }
|
||||
|
||||
Tag* Segment::AddTag() { return tags_.AddTag(); }
|
||||
|
||||
uint64 Segment::AddVideoTrack(int32 width, int32 height, int32 number) {
|
||||
VideoTrack* const track = new (std::nothrow) VideoTrack(&seed_); // NOLINT
|
||||
if (!track)
|
||||
@ -2614,6 +2847,13 @@ bool Segment::WriteSegmentHeader() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tags_.Count() > 0) {
|
||||
if (!seek_head_.AddSeekEntry(kMkvTags, MaxOffset()))
|
||||
return false;
|
||||
if (!tags_.Write(writer_header_))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (chunking_ && (mode_ == kLive || !writer_header_->Seekable())) {
|
||||
if (!chunk_writer_header_)
|
||||
return false;
|
||||
|
112
mkvmuxer.hpp
112
mkvmuxer.hpp
@ -736,6 +736,112 @@ class Chapters {
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Chapters);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Tag element
|
||||
//
|
||||
class Tag {
|
||||
public:
|
||||
bool add_simple_tag(const char* tag_name, const char* tag_string);
|
||||
|
||||
private:
|
||||
// Tags calls Clear and the destructor of Tag
|
||||
friend class Tags;
|
||||
|
||||
// For storage of simple tags
|
||||
class SimpleTag {
|
||||
public:
|
||||
// Establish representation invariant for new SimpleTag object.
|
||||
void Init();
|
||||
|
||||
// Reclaim resources, in anticipation of destruction.
|
||||
void Clear();
|
||||
|
||||
// Copies the title to the |tag_name_| member. Returns false on
|
||||
// error.
|
||||
bool set_tag_name(const char* tag_name);
|
||||
|
||||
// Copies the language to the |tag_string_| member. Returns false
|
||||
// on error.
|
||||
bool set_tag_string(const char* tag_string);
|
||||
|
||||
// If |writer| is non-NULL, serialize the SimpleTag sub-element of
|
||||
// the Atom into the stream. Returns the SimpleTag element size on
|
||||
// success, 0 if error.
|
||||
uint64 Write(IMkvWriter* writer) const;
|
||||
|
||||
private:
|
||||
char* tag_name_;
|
||||
char* tag_string_;
|
||||
};
|
||||
|
||||
Tag();
|
||||
~Tag();
|
||||
|
||||
// Copies this Tag object to a different one. This is used when
|
||||
// expanding a plain array of Tag objects (see Tags).
|
||||
void ShallowCopy(Tag* dst) const;
|
||||
|
||||
// Reclaim resources used by this Tag object, pending its
|
||||
// destruction.
|
||||
void Clear();
|
||||
|
||||
// If there is no storage remaining on the |simple_tags_| array for a
|
||||
// new display object, creates a new, longer array and copies the
|
||||
// existing SimpleTag objects to the new array. Returns false if the
|
||||
// array cannot be expanded.
|
||||
bool ExpandSimpleTagsArray();
|
||||
|
||||
// If |writer| is non-NULL, serialize the Tag sub-element into the
|
||||
// stream. Returns the total size of the element on success, 0 if
|
||||
// error.
|
||||
uint64 Write(IMkvWriter* writer) const;
|
||||
|
||||
// The Atom element can contain multiple SimpleTag sub-elements
|
||||
SimpleTag* simple_tags_;
|
||||
|
||||
// The physical length (total size) of the |simple_tags_| array.
|
||||
int simple_tags_size_;
|
||||
|
||||
// The logical length (number of active elements) on the |simple_tags_|
|
||||
// array.
|
||||
int simple_tags_count_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Tag);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Tags element
|
||||
//
|
||||
class Tags {
|
||||
public:
|
||||
Tags();
|
||||
~Tags();
|
||||
|
||||
Tag* AddTag();
|
||||
|
||||
// Returns the number of tags that have been added.
|
||||
int Count() const;
|
||||
|
||||
// Output the Tags element to the writer. Returns true on success.
|
||||
bool Write(IMkvWriter* writer) const;
|
||||
|
||||
private:
|
||||
// Expands the tags_ array if there is not enough space to contain
|
||||
// another tag object. Returns true on success.
|
||||
bool ExpandTagsArray();
|
||||
|
||||
// Total length of the tags_ array.
|
||||
int tags_size_;
|
||||
|
||||
// Number of active tags on the tags_ array.
|
||||
int tags_count_;
|
||||
|
||||
// Array for storage of tag objects.
|
||||
Tag* tags_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Tags);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Cluster element
|
||||
//
|
||||
@ -1029,6 +1135,11 @@ class Segment {
|
||||
// populate its fields via the Chapter member functions.
|
||||
Chapter* AddChapter();
|
||||
|
||||
// Adds an empty tag to the tags of this segment. Returns
|
||||
// non-NULL on success. After adding the tag, the caller should
|
||||
// populate its fields via the Tag member functions.
|
||||
Tag* AddTag();
|
||||
|
||||
// Adds a cue point to the Cues element. |timestamp| is the time in
|
||||
// nanoseconds of the cue's time. |track| is the Track of the Cue. This
|
||||
// function must be called after AddFrame to calculate the correct
|
||||
@ -1254,6 +1365,7 @@ class Segment {
|
||||
SegmentInfo segment_info_;
|
||||
Tracks tracks_;
|
||||
Chapters chapters_;
|
||||
Tags tags_;
|
||||
|
||||
// Number of chunks written.
|
||||
int chunk_count_;
|
||||
|
287
mkvparser.cpp
287
mkvparser.cpp
@ -607,6 +607,7 @@ Segment::Segment(IMkvReader* pReader, long long elem_start,
|
||||
m_pTracks(NULL),
|
||||
m_pCues(NULL),
|
||||
m_pChapters(NULL),
|
||||
m_pTags(NULL),
|
||||
m_clusters(NULL),
|
||||
m_clusterCount(0),
|
||||
m_clusterPreloadCount(0),
|
||||
@ -631,6 +632,7 @@ Segment::~Segment() {
|
||||
delete m_pInfo;
|
||||
delete m_pCues;
|
||||
delete m_pChapters;
|
||||
delete m_pTags;
|
||||
delete m_pSeekHead;
|
||||
}
|
||||
|
||||
@ -906,6 +908,19 @@ long long Segment::ParseHeaders() {
|
||||
|
||||
const long status = m_pChapters->Parse();
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
} else if (id == 0x0254C367) { // Tags ID
|
||||
if (m_pTags == NULL) {
|
||||
m_pTags = new (std::nothrow)
|
||||
Tags(this, pos, size, element_start, element_size);
|
||||
|
||||
if (m_pTags == NULL)
|
||||
return -1;
|
||||
|
||||
const long status = m_pTags->Parse();
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
@ -3071,6 +3086,7 @@ const Tracks* Segment::GetTracks() const { return m_pTracks; }
|
||||
const SegmentInfo* Segment::GetInfo() const { return m_pInfo; }
|
||||
const Cues* Segment::GetCues() const { return m_pCues; }
|
||||
const Chapters* Segment::GetChapters() const { return m_pChapters; }
|
||||
const Tags* Segment::GetTags() const { return m_pTags; }
|
||||
const SeekHead* Segment::GetSeekHead() const { return m_pSeekHead; }
|
||||
|
||||
long long Segment::GetDuration() const {
|
||||
@ -3536,6 +3552,277 @@ long Chapters::Display::Parse(IMkvReader* pReader, long long pos,
|
||||
return 0;
|
||||
}
|
||||
|
||||
Tags::Tags(Segment* pSegment, long long payload_start, long long payload_size,
|
||||
long long element_start, long long element_size)
|
||||
: m_pSegment(pSegment),
|
||||
m_start(payload_start),
|
||||
m_size(payload_size),
|
||||
m_element_start(element_start),
|
||||
m_element_size(element_size),
|
||||
m_tags(NULL),
|
||||
m_tags_size(0),
|
||||
m_tags_count(0) {}
|
||||
|
||||
Tags::~Tags() {
|
||||
while (m_tags_count > 0) {
|
||||
Tag& t = m_tags[--m_tags_count];
|
||||
t.Clear();
|
||||
}
|
||||
delete[] m_tags;
|
||||
}
|
||||
|
||||
long Tags::Parse() {
|
||||
IMkvReader* const pReader = m_pSegment->m_pReader;
|
||||
|
||||
long long pos = m_start; // payload start
|
||||
const long long stop = pos + m_size; // payload stop
|
||||
|
||||
while (pos < stop) {
|
||||
long long id, size;
|
||||
|
||||
long status = ParseElementHeader(pReader, pos, stop, id, size);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
if (size == 0) // 0 length tag, read another
|
||||
continue;
|
||||
|
||||
if (id == 0x3373) { // Tag ID
|
||||
status = ParseTag(pos, size);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
}
|
||||
|
||||
pos += size;
|
||||
assert(pos <= stop);
|
||||
if (pos > stop)
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(pos == stop);
|
||||
if (pos != stop)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Tags::GetTagCount() const { return m_tags_count; }
|
||||
|
||||
const Tags::Tag* Tags::GetTag(int idx) const {
|
||||
if (idx < 0)
|
||||
return NULL;
|
||||
|
||||
if (idx >= m_tags_count)
|
||||
return NULL;
|
||||
|
||||
return m_tags + idx;
|
||||
}
|
||||
|
||||
bool Tags::ExpandTagsArray() {
|
||||
if (m_tags_size > m_tags_count)
|
||||
return true; // nothing else to do
|
||||
|
||||
const int size = (m_tags_size == 0) ? 1 : 2 * m_tags_size;
|
||||
|
||||
Tag* const tags = new (std::nothrow) Tag[size];
|
||||
|
||||
if (tags == NULL)
|
||||
return false;
|
||||
|
||||
for (int idx = 0; idx < m_tags_count; ++idx) {
|
||||
m_tags[idx].ShallowCopy(tags[idx]);
|
||||
}
|
||||
|
||||
delete[] m_tags;
|
||||
m_tags = tags;
|
||||
|
||||
m_tags_size = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
long Tags::ParseTag(long long pos, long long size) {
|
||||
if (!ExpandTagsArray())
|
||||
return -1;
|
||||
|
||||
Tag& t = m_tags[m_tags_count++];
|
||||
t.Init();
|
||||
|
||||
return t.Parse(m_pSegment->m_pReader, pos, size);
|
||||
}
|
||||
|
||||
Tags::Tag::Tag() {}
|
||||
|
||||
Tags::Tag::~Tag() {}
|
||||
|
||||
int Tags::Tag::GetSimpleTagCount() const { return m_simple_tags_count; }
|
||||
|
||||
const Tags::SimpleTag* Tags::Tag::GetSimpleTag(int index) const {
|
||||
if (index < 0)
|
||||
return NULL;
|
||||
|
||||
if (index >= m_simple_tags_count)
|
||||
return NULL;
|
||||
|
||||
return m_simple_tags + index;
|
||||
}
|
||||
|
||||
void Tags::Tag::Init() {
|
||||
m_simple_tags = NULL;
|
||||
m_simple_tags_size = 0;
|
||||
m_simple_tags_count = 0;
|
||||
}
|
||||
|
||||
void Tags::Tag::ShallowCopy(Tag& rhs) const {
|
||||
rhs.m_simple_tags = m_simple_tags;
|
||||
rhs.m_simple_tags_size = m_simple_tags_size;
|
||||
rhs.m_simple_tags_count = m_simple_tags_count;
|
||||
}
|
||||
|
||||
void Tags::Tag::Clear() {
|
||||
while (m_simple_tags_count > 0) {
|
||||
SimpleTag& d = m_simple_tags[--m_simple_tags_count];
|
||||
d.Clear();
|
||||
}
|
||||
|
||||
delete[] m_simple_tags;
|
||||
m_simple_tags = NULL;
|
||||
|
||||
m_simple_tags_size = 0;
|
||||
}
|
||||
|
||||
long Tags::Tag::Parse(IMkvReader* pReader, long long pos, long long size) {
|
||||
const long long stop = pos + size;
|
||||
|
||||
while (pos < stop) {
|
||||
long long id, size;
|
||||
|
||||
long status = ParseElementHeader(pReader, pos, stop, id, size);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
if (size == 0) // 0 length tag, read another
|
||||
continue;
|
||||
|
||||
if (id == 0x27C8) { // SimpleTag ID
|
||||
status = ParseSimpleTag(pReader, pos, size);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
}
|
||||
|
||||
pos += size;
|
||||
assert(pos <= stop);
|
||||
if (pos > stop)
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(pos == stop);
|
||||
if (pos != stop)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
long Tags::Tag::ParseSimpleTag(IMkvReader* pReader, long long pos,
|
||||
long long size) {
|
||||
if (!ExpandSimpleTagsArray())
|
||||
return -1;
|
||||
|
||||
SimpleTag& st = m_simple_tags[m_simple_tags_count++];
|
||||
st.Init();
|
||||
|
||||
return st.Parse(pReader, pos, size);
|
||||
}
|
||||
|
||||
bool Tags::Tag::ExpandSimpleTagsArray() {
|
||||
if (m_simple_tags_size > m_simple_tags_count)
|
||||
return true; // nothing else to do
|
||||
|
||||
const int size = (m_simple_tags_size == 0) ? 1 : 2 * m_simple_tags_size;
|
||||
|
||||
SimpleTag* const displays = new (std::nothrow) SimpleTag[size];
|
||||
|
||||
if (displays == NULL)
|
||||
return false;
|
||||
|
||||
for (int idx = 0; idx < m_simple_tags_count; ++idx) {
|
||||
m_simple_tags[idx].ShallowCopy(displays[idx]);
|
||||
}
|
||||
|
||||
delete[] m_simple_tags;
|
||||
m_simple_tags = displays;
|
||||
|
||||
m_simple_tags_size = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
Tags::SimpleTag::SimpleTag() {}
|
||||
|
||||
Tags::SimpleTag::~SimpleTag() {}
|
||||
|
||||
const char* Tags::SimpleTag::GetTagName() const { return m_tag_name; }
|
||||
|
||||
const char* Tags::SimpleTag::GetTagString() const { return m_tag_string; }
|
||||
|
||||
void Tags::SimpleTag::Init() {
|
||||
m_tag_name = NULL;
|
||||
m_tag_string = NULL;
|
||||
}
|
||||
|
||||
void Tags::SimpleTag::ShallowCopy(SimpleTag& rhs) const {
|
||||
rhs.m_tag_name = m_tag_name;
|
||||
rhs.m_tag_string = m_tag_string;
|
||||
}
|
||||
|
||||
void Tags::SimpleTag::Clear() {
|
||||
delete[] m_tag_name;
|
||||
m_tag_name = NULL;
|
||||
|
||||
delete[] m_tag_string;
|
||||
m_tag_string = NULL;
|
||||
}
|
||||
|
||||
long Tags::SimpleTag::Parse(IMkvReader* pReader, long long pos,
|
||||
long long size) {
|
||||
const long long stop = pos + size;
|
||||
|
||||
while (pos < stop) {
|
||||
long long id, size;
|
||||
|
||||
long status = ParseElementHeader(pReader, pos, stop, id, size);
|
||||
|
||||
if (status < 0) // error
|
||||
return status;
|
||||
|
||||
if (size == 0) // weird
|
||||
continue;
|
||||
|
||||
if (id == 0x5A3) { // TagName ID
|
||||
status = UnserializeString(pReader, pos, size, m_tag_name);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
} else if (id == 0x487) { // TagString ID
|
||||
status = UnserializeString(pReader, pos, size, m_tag_string);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
pos += size;
|
||||
assert(pos <= stop);
|
||||
if (pos > stop)
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(pos == stop);
|
||||
if (pos != stop)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SegmentInfo::SegmentInfo(Segment* pSegment, long long start, long long size_,
|
||||
long long element_start, long long element_size)
|
||||
: m_pSegment(pSegment),
|
||||
|
@ -591,6 +591,85 @@ class Chapters {
|
||||
int m_editions_count;
|
||||
};
|
||||
|
||||
class Tags {
|
||||
Tags(const Tags&);
|
||||
Tags& operator=(const Tags&);
|
||||
|
||||
public:
|
||||
Segment* const m_pSegment;
|
||||
const long long m_start;
|
||||
const long long m_size;
|
||||
const long long m_element_start;
|
||||
const long long m_element_size;
|
||||
|
||||
Tags(Segment*, long long payload_start, long long payload_size,
|
||||
long long element_start, long long element_size);
|
||||
|
||||
~Tags();
|
||||
|
||||
long Parse();
|
||||
|
||||
class Tag;
|
||||
class SimpleTag;
|
||||
|
||||
class SimpleTag {
|
||||
friend class Tag;
|
||||
SimpleTag();
|
||||
SimpleTag(const SimpleTag&);
|
||||
~SimpleTag();
|
||||
SimpleTag& operator=(const SimpleTag&);
|
||||
|
||||
public:
|
||||
const char* GetTagName() const;
|
||||
const char* GetTagString() const;
|
||||
|
||||
private:
|
||||
void Init();
|
||||
void ShallowCopy(SimpleTag&) const;
|
||||
void Clear();
|
||||
long Parse(IMkvReader*, long long pos, long long size);
|
||||
|
||||
char* m_tag_name;
|
||||
char* m_tag_string;
|
||||
};
|
||||
|
||||
class Tag {
|
||||
friend class Tags;
|
||||
Tag();
|
||||
Tag(const Tag&);
|
||||
~Tag();
|
||||
Tag& operator=(const Tag&);
|
||||
|
||||
public:
|
||||
int GetSimpleTagCount() const;
|
||||
const SimpleTag* GetSimpleTag(int index) const;
|
||||
|
||||
private:
|
||||
void Init();
|
||||
void ShallowCopy(Tag&) const;
|
||||
void Clear();
|
||||
long Parse(IMkvReader*, long long pos, long long size);
|
||||
|
||||
long ParseSimpleTag(IMkvReader*, long long pos, long long size);
|
||||
bool ExpandSimpleTagsArray();
|
||||
|
||||
SimpleTag* m_simple_tags;
|
||||
int m_simple_tags_size;
|
||||
int m_simple_tags_count;
|
||||
};
|
||||
|
||||
int GetTagCount() const;
|
||||
const Tag* GetTag(int index) const;
|
||||
|
||||
private:
|
||||
long ParseTag(long long pos, long long size);
|
||||
bool ExpandTagsArray();
|
||||
|
||||
Tag* m_tags;
|
||||
int m_tags_size;
|
||||
int m_tags_count;
|
||||
};
|
||||
|
||||
class SegmentInfo {
|
||||
SegmentInfo(const SegmentInfo&);
|
||||
SegmentInfo& operator=(const SegmentInfo&);
|
||||
@ -883,6 +962,7 @@ class Segment {
|
||||
const SegmentInfo* GetInfo() const;
|
||||
const Cues* GetCues() const;
|
||||
const Chapters* GetChapters() const;
|
||||
const Tags* GetTags() const;
|
||||
|
||||
long long GetDuration() const;
|
||||
|
||||
@ -908,6 +988,7 @@ class Segment {
|
||||
Tracks* m_pTracks;
|
||||
Cues* m_pCues;
|
||||
Chapters* m_pChapters;
|
||||
Tags* m_pTags;
|
||||
Cluster** m_clusters;
|
||||
long m_clusterCount; // number of entries for which m_index >= 0
|
||||
long m_clusterPreloadCount; // number of entries for which m_index < 0
|
||||
|
15
sample.cpp
15
sample.cpp
@ -336,6 +336,21 @@ int main(int argc, char* argv[]) {
|
||||
} while (cue != NULL);
|
||||
}
|
||||
|
||||
const mkvparser::Tags* const tags = pSegment->GetTags();
|
||||
if (tags && tags->GetTagCount() > 0) {
|
||||
printf("\t\tTags\n");
|
||||
for (int i = 0; i < tags->GetTagCount(); ++i) {
|
||||
const mkvparser::Tags::Tag* const tag = tags->GetTag(i);
|
||||
printf("\t\t\tTag\n");
|
||||
for (int j = 0; j < tag->GetSimpleTagCount(); j++) {
|
||||
const mkvparser::Tags::SimpleTag* const simple_tag =
|
||||
tag->GetSimpleTag(j);
|
||||
printf("\t\t\t\tSimple Tag \"%s\" Value \"%s\"\n",
|
||||
simple_tag->GetTagName(), simple_tag->GetTagString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
@ -51,6 +51,7 @@ void Usage() {
|
||||
printf(" -audio_track_number <int> >0 Changes the audio track number\n");
|
||||
printf(" -video_track_number <int> >0 Changes the video track number\n");
|
||||
printf(" -chunking <string> Chunk output\n");
|
||||
printf(" -copy_tags <int> >0 Copies the tags\n");
|
||||
printf("\n");
|
||||
printf("Video options:\n");
|
||||
printf(" -display_width <int> Display width in pixels\n");
|
||||
@ -159,6 +160,7 @@ int main(int argc, char* argv[]) {
|
||||
int audio_track_number = 0; // 0 tells muxer to decide.
|
||||
int video_track_number = 0; // 0 tells muxer to decide.
|
||||
bool chunking = false;
|
||||
bool copy_tags = false;
|
||||
const char* chunk_name = NULL;
|
||||
|
||||
bool output_cues_block_number = true;
|
||||
@ -212,6 +214,8 @@ int main(int argc, char* argv[]) {
|
||||
} else if (!strcmp("-chunking", argv[i]) && i < argc_check) {
|
||||
chunking = true;
|
||||
chunk_name = argv[++i];
|
||||
} else if (!strcmp("-copy_tags", argv[i]) && i < argc_check) {
|
||||
copy_tags = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||
} else if (!strcmp("-display_width", argv[i]) && i < argc_check) {
|
||||
display_width = strtol(argv[++i], &end, 10);
|
||||
} else if (!strcmp("-display_height", argv[i]) && i < argc_check) {
|
||||
@ -298,6 +302,21 @@ int main(int argc, char* argv[]) {
|
||||
info->set_timecode_scale(timeCodeScale);
|
||||
info->set_writing_app("sample_muxer");
|
||||
|
||||
const mkvparser::Tags* const tags = parser_segment->GetTags();
|
||||
if (copy_tags && tags) {
|
||||
for (int i = 0; i < tags->GetTagCount(); i++) {
|
||||
const mkvparser::Tags::Tag* const tag = tags->GetTag(i);
|
||||
mkvmuxer::Tag* muxer_tag = muxer_segment.AddTag();
|
||||
|
||||
for (int j = 0; j < tag->GetSimpleTagCount(); j++) {
|
||||
const mkvparser::Tags::SimpleTag* const simple_tag =
|
||||
tag->GetSimpleTag(j);
|
||||
muxer_tag->add_simple_tag(simple_tag->GetTagName(),
|
||||
simple_tag->GetTagString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set Tracks element attributes
|
||||
const mkvparser::Tracks* const parser_tracks = parser_segment->GetTracks();
|
||||
unsigned long i = 0;
|
||||
|
@ -133,7 +133,13 @@ enum MkvId {
|
||||
kMkvChapterDisplay = 0x80,
|
||||
kMkvChapString = 0x85,
|
||||
kMkvChapLanguage = 0x437C,
|
||||
kMkvChapCountry = 0x437E
|
||||
kMkvChapCountry = 0x437E,
|
||||
// Tags
|
||||
kMkvTags = 0x1254C367,
|
||||
kMkvTag = 0x7373,
|
||||
kMkvSimpleTag = 0x67C8,
|
||||
kMkvTagName = 0x45A3,
|
||||
kMkvTagString = 0x4487
|
||||
};
|
||||
|
||||
} // end namespace mkvmuxer
|
||||
|
Loading…
x
Reference in New Issue
Block a user