Skip to content

Commit b9122af

Browse files
committed
Preserve track UID in simple tags
Some encoders write track specific DURATION tags, which should not be removed.
1 parent 1d3a375 commit b9122af

8 files changed

Lines changed: 78 additions & 22 deletions

File tree

examples/matroskareader.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ int main(int argc, char *argv[])
4444
PRINT_PRETTY("Target Type Value",
4545
targetTypeValue == 0 ? "None" : TagLib::Utils::formatString("%i", targetTypeValue).toCString(false)
4646
);
47+
if(auto trackUid = t.trackUid()) {
48+
PRINT_PRETTY("Track UID",
49+
TagLib::Utils::formatString("%llu",trackUid).toCString(false)
50+
);
51+
}
4752
const TagLib::String &language = t.language();
4853
PRINT_PRETTY("Language", !language.isEmpty() ? language.toCString(false) : "Not set");
4954

taglib/matroska/ebml/ebmlelement.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ std::unique_ptr<EBML::Element> EBML::Element::factory(File &file)
8282
RETURN_ELEMENT_FOR_CASE(Id::MkAttachedFileMediaType);
8383
RETURN_ELEMENT_FOR_CASE(Id::MkCodecID);
8484
RETURN_ELEMENT_FOR_CASE(Id::MkTagTargetTypeValue);
85+
RETURN_ELEMENT_FOR_CASE(Id::MkTagTrackUID);
8586
RETURN_ELEMENT_FOR_CASE(Id::MkTagsLanguageDefault);
8687
RETURN_ELEMENT_FOR_CASE(Id::MkAttachedFileUID);
8788
RETURN_ELEMENT_FOR_CASE(Id::MkSeekPosition);

taglib/matroska/ebml/ebmlelement.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ namespace TagLib::EBML {
4040
MkTag = 0x7373,
4141
MkTagTargets = 0x63C0,
4242
MkTagTargetTypeValue = 0x68CA,
43+
MkTagTrackUID = 0x63C5,
4344
MkSimpleTag = 0x67C8,
4445
MkTagName = 0x45A3,
4546
MkTagLanguage = 0x447A,
@@ -168,6 +169,7 @@ namespace TagLib::EBML {
168169
template <> struct GetElementTypeById<Element::Id::MkAttachedFileMediaType> { using type = Latin1StringElement; };
169170
template <> struct GetElementTypeById<Element::Id::MkCodecID> { using type = Latin1StringElement; };
170171
template <> struct GetElementTypeById<Element::Id::MkTagTargetTypeValue> { using type = UIntElement; };
172+
template <> struct GetElementTypeById<Element::Id::MkTagTrackUID> { using type = UIntElement; };
171173
template <> struct GetElementTypeById<Element::Id::MkAttachedFileUID> { using type = UIntElement; };
172174
template <> struct GetElementTypeById<Element::Id::MkSeekPosition> { using type = UIntElement; };
173175
template <> struct GetElementTypeById<Element::Id::MkTimestampScale> { using type = UIntElement; };

taglib/matroska/ebml/ebmlmktags.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ std::unique_ptr<Matroska::Tag> EBML::MkTags::parse()
5454

5555
// Parse the <Targets> element
5656
Matroska::SimpleTag::TargetTypeValue targetTypeValue = Matroska::SimpleTag::TargetTypeValue::None;
57+
unsigned long long trackUid = 0;
5758
if(targets) {
5859
for(const auto &targetsChild : *targets) {
5960
Id id = targetsChild->getId();
@@ -63,6 +64,9 @@ std::unique_ptr<Matroska::Tag> EBML::MkTags::parse()
6364
element_cast<Id::MkTagTargetTypeValue>(targetsChild)->getValue()
6465
);
6566
}
67+
else if(id == Id::MkTagTrackUID) {
68+
trackUid = element_cast<Id::MkTagTrackUID>(targetsChild)->getValue();
69+
}
6670
}
6771
}
6872

@@ -92,9 +96,11 @@ std::unique_ptr<Matroska::Tag> EBML::MkTags::parse()
9296

9397
mTag->addSimpleTag(tagValueString
9498
? Matroska::SimpleTag(tagName, *tagValueString,
95-
targetTypeValue, language, defaultLanguageFlag)
99+
targetTypeValue, language, defaultLanguageFlag,
100+
trackUid)
96101
: Matroska::SimpleTag(tagName, *tagValueBinary,
97-
targetTypeValue, language, defaultLanguageFlag));
102+
targetTypeValue, language, defaultLanguageFlag,
103+
trackUid));
98104
}
99105
}
100106
return mTag;

taglib/matroska/matroskasimpletag.cpp

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,19 @@ class Matroska::SimpleTag::SimpleTagPrivate
3030
{
3131
public:
3232
explicit SimpleTagPrivate(const String &name, const String& value,
33-
TargetTypeValue targetTypeValue, const String &language, bool defaultLanguage) :
34-
value(value), name(name), language(language),
33+
TargetTypeValue targetTypeValue, const String &language, bool defaultLanguage,
34+
unsigned long long trackUid) :
35+
value(value), name(name), language(language), trackUid(trackUid),
3536
targetTypeValue(targetTypeValue), defaultLanguageFlag(defaultLanguage) {}
3637
explicit SimpleTagPrivate(const String &name, const ByteVector& value,
37-
TargetTypeValue targetTypeValue, const String &language, bool defaultLanguage) :
38-
value(value), name(name), language(language),
38+
TargetTypeValue targetTypeValue, const String &language, bool defaultLanguage,
39+
unsigned long long trackUid) :
40+
value(value), name(name), language(language), trackUid(trackUid),
3941
targetTypeValue(targetTypeValue), defaultLanguageFlag(defaultLanguage) {}
4042
const std::variant<String, ByteVector> value;
4143
const String name;
4244
const String language;
45+
const unsigned long long trackUid;
4346
const TargetTypeValue targetTypeValue;
4447
const bool defaultLanguageFlag;
4548
};
@@ -49,16 +52,20 @@ class Matroska::SimpleTag::SimpleTagPrivate
4952
////////////////////////////////////////////////////////////////////////////////
5053

5154
Matroska::SimpleTag::SimpleTag(const String &name, const String &value,
52-
TargetTypeValue targetTypeValue, const String &language, bool defaultLanguage) :
55+
TargetTypeValue targetTypeValue,
56+
const String &language, bool defaultLanguage,
57+
unsigned long long trackUid) :
5358
d(std::make_unique<SimpleTagPrivate>(name, value, targetTypeValue,
54-
language, defaultLanguage))
59+
language, defaultLanguage, trackUid))
5560
{
5661
}
5762

5863
Matroska::SimpleTag::SimpleTag(const String &name, const ByteVector &value,
59-
TargetTypeValue targetTypeValue, const String &language, bool defaultLanguage) :
64+
TargetTypeValue targetTypeValue,
65+
const String &language, bool defaultLanguage,
66+
unsigned long long trackUid) :
6067
d(std::make_unique<SimpleTagPrivate>(name, value, targetTypeValue,
61-
language, defaultLanguage))
68+
language, defaultLanguage, trackUid))
6269
{
6370
}
6471

@@ -106,6 +113,11 @@ bool Matroska::SimpleTag::defaultLanguageFlag() const
106113
return d->defaultLanguageFlag;
107114
}
108115

116+
unsigned long long Matroska::SimpleTag::trackUid() const
117+
{
118+
return d->trackUid;
119+
}
120+
109121
Matroska::SimpleTag::ValueType Matroska::SimpleTag::type() const
110122
{
111123
return std::holds_alternative<ByteVector>(d->value) ? BinaryType : StringType;

taglib/matroska/matroskasimpletag.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,16 @@ namespace TagLib {
5555
*/
5656
SimpleTag(const String &name, const String &value,
5757
TargetTypeValue targetTypeValue = None,
58-
const String &language = String(), bool defaultLanguage = true);
58+
const String &language = String(), bool defaultLanguage = true,
59+
unsigned long long trackUid = 0);
5960

6061
/*!
6162
* Construct a binary simple tag.
6263
*/
6364
SimpleTag(const String &name, const ByteVector &value,
6465
TargetTypeValue targetTypeValue = None,
65-
const String &language = String(), bool defaultLanguage = true);
66+
const String &language = String(), bool defaultLanguage = true,
67+
unsigned long long trackUid = 0);
6668

6769
/*!
6870
* Construct a simple tag as a copy of \a other.
@@ -114,6 +116,12 @@ namespace TagLib {
114116
*/
115117
bool defaultLanguageFlag() const;
116118

119+
/*!
120+
* Returns the UID that identifies the track that the tags belong to,
121+
* zero if not defined, the tag applies to all tracks
122+
*/
123+
unsigned long long trackUid() const;
124+
117125
/*!
118126
* Returns the type of the value.
119127
*/

taglib/matroska/matroskatag.cpp

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,13 @@ void Matroska::Tag::addSimpleTag(const SimpleTag &tag)
9292
}
9393

9494
void Matroska::Tag::removeSimpleTag(const String &name,
95-
SimpleTag::TargetTypeValue targetTypeValue)
95+
SimpleTag::TargetTypeValue targetTypeValue,
96+
unsigned long long trackUid)
9697
{
9798
auto it = std::find_if(d->tags.begin(), d->tags.end(),
98-
[&name, targetTypeValue](const SimpleTag &t) {
99-
return t.name() == name && t.targetTypeValue() == targetTypeValue;
99+
[&name, targetTypeValue, trackUid](const SimpleTag &t) {
100+
return t.name() == name && t.targetTypeValue() == targetTypeValue &&
101+
t.trackUid() == trackUid;
100102
}
101103
);
102104
if(it != d->tags.end()) {
@@ -221,11 +223,13 @@ ByteVector Matroska::Tag::renderInternal()
221223
// Build target-based list
222224
for(const auto &tag : std::as_const(d->tags)) {
223225
auto targetTypeValue = tag.targetTypeValue();
226+
auto trackUid = tag.trackUid();
224227
auto it = std::find_if(targetList.begin(),
225228
targetList.end(),
226229
[&](const auto &list) {
227230
const auto &simpleTag = list.front();
228-
return simpleTag.targetTypeValue() == targetTypeValue;
231+
return simpleTag.targetTypeValue() == targetTypeValue &&
232+
simpleTag.trackUid() == trackUid;
229233
}
230234
);
231235
if(it == targetList.end()) {
@@ -239,6 +243,7 @@ ByteVector Matroska::Tag::renderInternal()
239243
for(const auto &list : targetList) {
240244
const auto &frontTag = list.front();
241245
auto targetTypeValue = frontTag.targetTypeValue();
246+
auto trackUid = frontTag.trackUid();
242247
auto tag = EBML::make_unique_element<EBML::Element::Id::MkTag>();
243248

244249
// Build <Tag Targets> element
@@ -248,6 +253,11 @@ ByteVector Matroska::Tag::renderInternal()
248253
element->setValue(static_cast<unsigned int>(targetTypeValue));
249254
targets->appendElement(std::move(element));
250255
}
256+
if(trackUid != 0) {
257+
auto element = EBML::make_unique_element<EBML::Element::Id::MkTagTrackUID>();
258+
element->setValue(trackUid);
259+
targets->appendElement(std::move(element));
260+
}
251261
tag->appendElement(std::move(targets));
252262

253263
// Build <Simple Tag> element
@@ -401,7 +411,8 @@ String Matroska::Tag::TagPrivate::getTag(const String &key) const
401411
return t.name() == name
402412
&& t.type() == SimpleTag::StringType
403413
&& (t.targetTypeValue() == targetTypeValue ||
404-
(t.targetTypeValue() == SimpleTag::TargetTypeValue::None && !strict));
414+
(t.targetTypeValue() == SimpleTag::TargetTypeValue::None && !strict))
415+
&& t.trackUid() == 0;
405416
}
406417
);
407418
return it != tags.end() ? it->toString() : String();
@@ -411,7 +422,7 @@ PropertyMap Matroska::Tag::properties() const
411422
{
412423
PropertyMap properties;
413424
for(const auto &simpleTag : std::as_const(d->tags)) {
414-
if(simpleTag.type() == SimpleTag::StringType) {
425+
if(simpleTag.type() == SimpleTag::StringType && simpleTag.trackUid() == 0) {
415426
String key = translateTag(simpleTag.name(), simpleTag.targetTypeValue());
416427
if(!key.isEmpty())
417428
properties[key].append(simpleTag.toString());
@@ -428,6 +439,7 @@ PropertyMap Matroska::Tag::setProperties(const PropertyMap &propertyMap)
428439
for(auto it = d->tags.begin(); it != d->tags.end();) {
429440
String key;
430441
if(it->type() == SimpleTag::StringType &&
442+
it->trackUid() == 0 &&
431443
!(key = translateTag(it->name(), it->targetTypeValue())).isEmpty()) {
432444
it = d->tags.erase(it);
433445
setNeedsRender(true);
@@ -468,6 +480,7 @@ StringList Matroska::Tag::complexPropertyKeys() const
468480
StringList keys;
469481
for(const SimpleTag &t : std::as_const(d->tags)) {
470482
if(t.type() != SimpleTag::StringType ||
483+
t.trackUid() != 0 ||
471484
translateTag(t.name(), t.targetTypeValue()).isEmpty()) {
472485
keys.append(t.name());
473486
}
@@ -482,6 +495,7 @@ List<VariantMap> Matroska::Tag::complexProperties(const String& key) const
482495
for(const SimpleTag &t : std::as_const(d->tags)) {
483496
if(t.name() == key &&
484497
(t.type() != SimpleTag::StringType ||
498+
t.trackUid() != 0 ||
485499
translateTag(t.name(), t.targetTypeValue()).isEmpty())) {
486500
VariantMap property;
487501
if(t.type() != SimpleTag::StringType) {
@@ -491,7 +505,12 @@ List<VariantMap> Matroska::Tag::complexProperties(const String& key) const
491505
property.insert("value", t.toString());
492506
}
493507
property.insert("name", t.name());
494-
property.insert("targetTypeValue", t.targetTypeValue());
508+
if(t.targetTypeValue() != SimpleTag::TargetTypeValue::None) {
509+
property.insert("targetTypeValue", t.targetTypeValue());
510+
}
511+
if(t.trackUid()) {
512+
property.insert("trackUid", t.trackUid());
513+
}
495514
property.insert("language", t.language());
496515
property.insert("defaultLanguage", t.defaultLanguageFlag());
497516
props.append(property);
@@ -511,6 +530,7 @@ bool Matroska::Tag::setComplexProperties(const String& key, const List<VariantMa
511530
[&key](const SimpleTag &t) {
512531
return t.name() == key &&
513532
(t.type() != SimpleTag::StringType ||
533+
t.trackUid() != 0 ||
514534
translateTag(t.name(), t.targetTypeValue()).isEmpty());
515535
}
516536
);
@@ -535,11 +555,12 @@ bool Matroska::Tag::setComplexProperties(const String& key, const List<VariantMa
535555
}
536556
auto language = property.value("language").value<String>();
537557
bool defaultLanguage = property.value("defaultLanguage", true).value<bool>();
558+
auto trackUid = property.value("trackUid", 0ULL).value<unsigned long long>();
538559
d->tags.append(property.contains("data")
539560
? SimpleTag(key, property.value("data").value<ByteVector>(),
540-
targetTypeValue, language, defaultLanguage)
561+
targetTypeValue, language, defaultLanguage, trackUid)
541562
: SimpleTag(key, property.value("value").value<String>(),
542-
targetTypeValue, language, defaultLanguage));
563+
targetTypeValue, language, defaultLanguage, trackUid));
543564
setNeedsRender(true);
544565
result = true;
545566
}

taglib/matroska/matroskatag.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ namespace TagLib {
8989
bool setComplexProperties(const String& key, const List<VariantMap>& value) override;
9090

9191
void addSimpleTag(const SimpleTag &tag);
92-
void removeSimpleTag(const String &name, SimpleTag::TargetTypeValue targetTypeValue);
92+
void removeSimpleTag(const String &name, SimpleTag::TargetTypeValue targetTypeValue,
93+
unsigned long long trackUid = 0);
9394
void clearSimpleTags();
9495
const SimpleTagsList &simpleTagsList() const;
9596

0 commit comments

Comments
 (0)