Include doc type and version in properties

This commit is contained in:
Urs Fleisch
2025-09-03 16:53:03 +02:00
parent b9122afaca
commit 81815e1091
7 changed files with 77 additions and 11 deletions

View File

@ -76,5 +76,15 @@ int main(int argc, char *argv[])
else
printf("File has no attachments\n");
if(auto properties = dynamic_cast<const TagLib::Matroska::Properties *>(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;
}

View File

@ -62,6 +62,8 @@ std::unique_ptr<EBML::Element> EBML::Element::factory(File &file)
auto id = static_cast<Id>(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);

View File

@ -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 <Element::Id ID>
struct GetElementTypeById;
template <> struct GetElementTypeById<Element::Id::EBMLHeader> { using type = Element; };
template <> struct GetElementTypeById<Element::Id::EBMLHeader> { using type = MasterElement; };
template <> struct GetElementTypeById<Element::Id::DocType> { using type = Latin1StringElement; };
template <> struct GetElementTypeById<Element::Id::DocTypeVersion> { using type = UIntElement; };
template <> struct GetElementTypeById<Element::Id::MkSegment> { using type = MkSegment; };
template <> struct GetElementTypeById<Element::Id::MkInfo> { using type = MkInfo; };
template <> struct GetElementTypeById<Element::Id::MkTracks> { using type = MkTracks; };

View File

@ -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<EBML::Element> head(EBML::Element::factory(*this));
auto head = EBML::element_cast<EBML::Element::Id::EBMLHeader>(
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<EBML::MkSegment> segment(
@ -307,6 +315,19 @@ void Matroska::File::read(bool readProperties, Properties::ReadStyle readStyle)
if(readProperties) {
d->properties = std::make_unique<Properties>(this);
for(const auto &element : *head) {
auto id = element->getId();
if (id == EBML::Element::Id::DocType) {
d->properties->setDocType(
EBML::element_cast<EBML::Element::Id::DocType>(element)->getValue());
}
else if (id == EBML::Element::Id::DocTypeVersion) {
d->properties->setDocTypeVersion(static_cast<int>(
EBML::element_cast<EBML::Element::Id::DocTypeVersion>(element)->getValue()));
}
}
segment->parseInfo(d->properties.get());
segment->parseTracks(d->properties.get());
if(d->tag) {

View File

@ -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.

View File

@ -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;

View File

@ -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);