diff --git a/examples/matroskareader.cpp b/examples/matroskareader.cpp index 4f7f86cc..c688f2e0 100644 --- a/examples/matroskareader.cpp +++ b/examples/matroskareader.cpp @@ -76,5 +76,15 @@ int main(int argc, char *argv[]) else printf("File has no attachments\n"); + if(auto properties = dynamic_cast(file.audioProperties())) { + printf("Properties:\n"); + PRINT_PRETTY("Doc Type", properties->docType().toCString(false)); + PRINT_PRETTY("Doc Type Version", TagLib::String::number(properties->docTypeVersion()).toCString(false)); + PRINT_PRETTY("Codec Name", properties->codecName().toCString(true)); + PRINT_PRETTY("Bitrate", TagLib::String::number(properties->bitrate()).toCString(false)); + PRINT_PRETTY("Sample Rate", TagLib::String::number(properties->sampleRate()).toCString(false)); + PRINT_PRETTY("Channels", TagLib::String::number(properties->channels()).toCString(false)); + PRINT_PRETTY("Length [ms]", TagLib::String::number(properties->lengthInMilliseconds()).toCString(false)); + } return 0; } diff --git a/taglib/matroska/ebml/ebmlelement.cpp b/taglib/matroska/ebml/ebmlelement.cpp index 8d2e3a41..8ecea7fb 100644 --- a/taglib/matroska/ebml/ebmlelement.cpp +++ b/taglib/matroska/ebml/ebmlelement.cpp @@ -62,6 +62,8 @@ std::unique_ptr EBML::Element::factory(File &file) auto id = static_cast(uintId); switch(id) { RETURN_ELEMENT_FOR_CASE(Id::EBMLHeader); + RETURN_ELEMENT_FOR_CASE(Id::DocType); + RETURN_ELEMENT_FOR_CASE(Id::DocTypeVersion); RETURN_ELEMENT_FOR_CASE(Id::MkSegment); RETURN_ELEMENT_FOR_CASE(Id::MkInfo); RETURN_ELEMENT_FOR_CASE(Id::MkTracks); diff --git a/taglib/matroska/ebml/ebmlelement.h b/taglib/matroska/ebml/ebmlelement.h index ac043150..7487889c 100644 --- a/taglib/matroska/ebml/ebmlelement.h +++ b/taglib/matroska/ebml/ebmlelement.h @@ -34,6 +34,8 @@ namespace TagLib::EBML { enum class Id : unsigned int { EBMLHeader = 0x1A45DFA3, + DocType = 0x4282, + DocTypeVersion = 0x4287, VoidElement = 0xEC, MkSegment = 0x18538067, MkTags = 0x1254C367, @@ -143,7 +145,9 @@ namespace TagLib::EBML { template struct GetElementTypeById; - template <> struct GetElementTypeById { using type = Element; }; + template <> struct GetElementTypeById { using type = MasterElement; }; + template <> struct GetElementTypeById { using type = Latin1StringElement; }; + template <> struct GetElementTypeById { using type = UIntElement; }; template <> struct GetElementTypeById { using type = MkSegment; }; template <> struct GetElementTypeById { using type = MkInfo; }; template <> struct GetElementTypeById { using type = MkTracks; }; diff --git a/taglib/matroska/matroskafile.cpp b/taglib/matroska/matroskafile.cpp index 5f3634d8..e0accda1 100644 --- a/taglib/matroska/matroskafile.cpp +++ b/taglib/matroska/matroskafile.cpp @@ -27,6 +27,8 @@ #include "matroskasegment.h" #include "ebmlutils.h" #include "ebmlelement.h" +#include "ebmlstringelement.h" +#include "ebmluintelement.h" #include "ebmlmksegment.h" #include "tlist.h" #include "tdebug.h" @@ -96,7 +98,7 @@ Matroska::File::File(IOStream *stream, bool readProperties, Matroska::File::~File() = default; -AudioProperties *Matroska::File::audioProperties() const +Matroska::Properties *Matroska::File::audioProperties() const { return d->properties.get(); } @@ -271,13 +273,19 @@ void Matroska::File::read(bool readProperties, Properties::ReadStyle readStyle) offset_t fileLength = length(); // Find the EBML Header - std::unique_ptr head(EBML::Element::factory(*this)); + auto head = EBML::element_cast( + EBML::Element::factory(*this)); if(!head || head->getId() != EBML::Element::Id::EBMLHeader) { debug("Failed to find EBML head"); setValid(false); return; } - head->skipData(*this); + if(readProperties) { + head->read(*this); + } + else { + head->skipData(*this); + } // Find the Matroska segment in the file std::unique_ptr segment( @@ -307,6 +315,19 @@ void Matroska::File::read(bool readProperties, Properties::ReadStyle readStyle) if(readProperties) { d->properties = std::make_unique(this); + + for(const auto &element : *head) { + auto id = element->getId(); + if (id == EBML::Element::Id::DocType) { + d->properties->setDocType( + EBML::element_cast(element)->getValue()); + } + else if (id == EBML::Element::Id::DocTypeVersion) { + d->properties->setDocTypeVersion(static_cast( + EBML::element_cast(element)->getValue())); + } + } + segment->parseInfo(d->properties.get()); segment->parseTracks(d->properties.get()); if(d->tag) { diff --git a/taglib/matroska/matroskafile.h b/taglib/matroska/matroskafile.h index 66c1c07f..af57e5a6 100644 --- a/taglib/matroska/matroskafile.h +++ b/taglib/matroska/matroskafile.h @@ -134,7 +134,7 @@ namespace TagLib::Matroska { * Returns the Matroska::Properties for this file. If no audio properties * were read then this will return a null pointer. */ - AudioProperties *audioProperties() const override; + Properties *audioProperties() const override; /*! * Save the file. diff --git a/taglib/matroska/matroskaproperties.cpp b/taglib/matroska/matroskaproperties.cpp index aa14dcd8..c1c2a3c5 100644 --- a/taglib/matroska/matroskaproperties.cpp +++ b/taglib/matroska/matroskaproperties.cpp @@ -41,6 +41,8 @@ public: File *file; String codecName; String title; + String docType; + int docTypeVersion { 0 }; int length { 0 }; int bitrate { -1 }; int sampleRate { 0 }; @@ -88,6 +90,16 @@ int Matroska::Properties::bitsPerSample() const return d->bitsPerSample; } +String Matroska::Properties::docType() const +{ + return d->docType; +} + +int Matroska::Properties::docTypeVersion() const +{ + return d->docTypeVersion; +} + String Matroska::Properties::codecName() const { return d->codecName; @@ -107,11 +119,6 @@ void Matroska::Properties::setLengthInMilliseconds(int length) d->length = length; } -void Matroska::Properties::setBitrate(int bitrate) -{ - d->bitrate = bitrate; -} - void Matroska::Properties::setSampleRate(int sampleRate) { d->sampleRate = sampleRate; @@ -127,6 +134,16 @@ void Matroska::Properties::setBitsPerSample(int bitsPerSample) d->bitsPerSample = bitsPerSample; } +void Matroska::Properties::setDocType(const String &docType) +{ + d->docType = docType; +} + +void Matroska::Properties::setDocTypeVersion(int docTypeVersion) +{ + d->docTypeVersion = docTypeVersion; +} + void Matroska::Properties::setCodecName(const String &codecName) { d->codecName = codecName; diff --git a/taglib/matroska/matroskaproperties.h b/taglib/matroska/matroskaproperties.h index 11d61c95..0481ffc4 100644 --- a/taglib/matroska/matroskaproperties.h +++ b/taglib/matroska/matroskaproperties.h @@ -80,6 +80,16 @@ namespace TagLib::Matroska { */ int bitsPerSample() const; + /*! + * Returns the EBML doc type, "matroska" or "webm". + */ + String docType() const; + + /*! + * Returns the EBML doc type version, typical values are 2 or 4. + */ + int docTypeVersion() const; + /*! * Returns the concrete codec name, for example "A_MPEG/L3" * used in the file if available, otherwise an empty string. @@ -97,12 +107,14 @@ namespace TagLib::Matroska { class PropertiesPrivate; friend class EBML::MkInfo; friend class EBML::MkTracks; + friend class File; void setLengthInMilliseconds(int length); - void setBitrate(int bitrate); void setSampleRate(int sampleRate); void setChannels(int channels); void setBitsPerSample(int bitsPerSample); + void setDocType(const String &docType); + void setDocTypeVersion(int docTypeVersion); void setCodecName(const String &codecName); void setTitle(const String &title);