diff --git a/taglib/matroska/ebml/ebmlelement.cpp b/taglib/matroska/ebml/ebmlelement.cpp index 7c947e85..348303ac 100644 --- a/taglib/matroska/ebml/ebmlelement.cpp +++ b/taglib/matroska/ebml/ebmlelement.cpp @@ -91,6 +91,7 @@ std::unique_ptr EBML::Element::factory(File &file) RETURN_ELEMENT_FOR_CASE(Id::MkAttachedFileData); RETURN_ELEMENT_FOR_CASE(Id::MkSeekID); RETURN_ELEMENT_FOR_CASE(Id::MkDuration); + RETURN_ELEMENT_FOR_CASE(Id::MkTitle); RETURN_ELEMENT_FOR_CASE(Id::MkSamplingFrequency); RETURN_ELEMENT_FOR_CASE(Id::MkSeekHead); RETURN_ELEMENT_FOR_CASE(Id::VoidElement); diff --git a/taglib/matroska/ebml/ebmlelement.h b/taglib/matroska/ebml/ebmlelement.h index 84639c8f..3b8c9267 100644 --- a/taglib/matroska/ebml/ebmlelement.h +++ b/taglib/matroska/ebml/ebmlelement.h @@ -75,6 +75,7 @@ namespace TagLib::EBML { MkInfo = 0x1549A966, MkTimestampScale = 0x2AD7B1, MkDuration = 0x4489, + MkTitle = 0x7BA9, MkTracks = 0x1654AE6B, MkTrackEntry = 0xAE, MkCodecID = 0x86, @@ -186,6 +187,7 @@ namespace TagLib::EBML { template <> struct GetElementTypeById { using type = BinaryElement; }; template <> struct GetElementTypeById { using type = BinaryElement; }; template <> struct GetElementTypeById { using type = FloatElement; }; + template <> struct GetElementTypeById { using type = UTF8StringElement; }; template <> struct GetElementTypeById { using type = FloatElement; }; template <> struct GetElementTypeById { using type = MkSeekHead; }; template <> struct GetElementTypeById { using type = VoidElement; }; diff --git a/taglib/matroska/ebml/ebmlmkinfo.cpp b/taglib/matroska/ebml/ebmlmkinfo.cpp index c6c48f3c..d9228b40 100644 --- a/taglib/matroska/ebml/ebmlmkinfo.cpp +++ b/taglib/matroska/ebml/ebmlmkinfo.cpp @@ -38,6 +38,7 @@ void EBML::MkInfo::parse(Matroska::Properties *properties) unsigned long long timestampScale = 1000000; double duration = 0.0; + String title; for(const auto &element : elements) { Id id = element->getId(); if (id == Id::MkTimestampScale) { @@ -46,8 +47,12 @@ void EBML::MkInfo::parse(Matroska::Properties *properties) else if (id == Id::MkDuration) { duration = element_cast(element)->getValueAsDouble(); } + else if (id == Id::MkTitle) { + title = element_cast(element)->getValue(); + } } properties->setLengthInMilliseconds( static_cast(duration * static_cast(timestampScale) / 1000000.0)); + properties->setTitle(title); } diff --git a/taglib/matroska/matroskafile.cpp b/taglib/matroska/matroskafile.cpp index 29e4d9db..5f3634d8 100644 --- a/taglib/matroska/matroskafile.cpp +++ b/taglib/matroska/matroskafile.cpp @@ -108,8 +108,12 @@ Tag *Matroska::File::tag() const Matroska::Tag *Matroska::File::tag(bool create) const { - if(!d->tag && create) + if(!d->tag && create) { d->tag = std::make_unique(); + if(d->properties) { + d->tag->setSegmentTitle(d->properties->title()); + } + } return d->tag.get(); } @@ -305,6 +309,9 @@ void Matroska::File::read(bool readProperties, Properties::ReadStyle readStyle) d->properties = std::make_unique(this); segment->parseInfo(d->properties.get()); segment->parseTracks(d->properties.get()); + if(d->tag) { + d->tag->setSegmentTitle(d->properties->title()); + } } if(readStyle == AudioProperties::Accurate && diff --git a/taglib/matroska/matroskaproperties.cpp b/taglib/matroska/matroskaproperties.cpp index 9bb9d0fc..aa14dcd8 100644 --- a/taglib/matroska/matroskaproperties.cpp +++ b/taglib/matroska/matroskaproperties.cpp @@ -40,6 +40,7 @@ public: File *file; String codecName; + String title; int length { 0 }; int bitrate { -1 }; int sampleRate { 0 }; @@ -92,6 +93,11 @@ String Matroska::Properties::codecName() const return d->codecName; } +String Matroska::Properties::title() const +{ + return d->title; +} + //////////////////////////////////////////////////////////////////////////////// // private members //////////////////////////////////////////////////////////////////////////////// @@ -125,3 +131,8 @@ void Matroska::Properties::setCodecName(const String &codecName) { d->codecName = codecName; } + +void Matroska::Properties::setTitle(const String& title) +{ + d->title = title; +} diff --git a/taglib/matroska/matroskaproperties.h b/taglib/matroska/matroskaproperties.h index 805d3dbe..11d61c95 100644 --- a/taglib/matroska/matroskaproperties.h +++ b/taglib/matroska/matroskaproperties.h @@ -86,6 +86,13 @@ namespace TagLib::Matroska { */ String codecName() const; + /*! + * Returns the general name of the segment. + * Some applications store the title of the file here, but players should + * prioritize the tag title over the segment title. + */ + String title() const; + private: class PropertiesPrivate; friend class EBML::MkInfo; @@ -97,6 +104,7 @@ namespace TagLib::Matroska { void setChannels(int channels); void setBitsPerSample(int bitsPerSample); void setCodecName(const String &codecName); + void setTitle(const String &title); TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE std::unique_ptr d; diff --git a/taglib/matroska/matroskatag.cpp b/taglib/matroska/matroskatag.cpp index b4e7b215..7c896934 100644 --- a/taglib/matroska/matroskatag.cpp +++ b/taglib/matroska/matroskatag.cpp @@ -74,6 +74,7 @@ public: SimpleTagsList tags; ByteVector data; + String segmentTitle; }; Matroska::Tag::Tag() : @@ -115,6 +116,11 @@ const Matroska::SimpleTagsList &Matroska::Tag::simpleTagsList() const return d->tags; } +void Matroska::Tag::setSegmentTitle(const String& title) +{ + d->segmentTitle = title; +} + void Matroska::Tag::setTitle(const String &s) { d->setTag("TITLE", s); @@ -152,7 +158,11 @@ void Matroska::Tag::setTrack(unsigned int i) String Matroska::Tag::title() const { - return d->getTag("TITLE"); + String s = d->getTag("TITLE"); + if(s.isEmpty()) { + return d->segmentTitle; + } + return s; } String Matroska::Tag::artist() const diff --git a/taglib/matroska/matroskatag.h b/taglib/matroska/matroskatag.h index e9106b82..2ceaa453 100644 --- a/taglib/matroska/matroskatag.h +++ b/taglib/matroska/matroskatag.h @@ -98,6 +98,8 @@ namespace TagLib { friend class EBML::MkTags; class TagPrivate; + void setSegmentTitle(const String &title); + // private Element implementation ByteVector renderInternal() override;