From d1bd220c26053a09aaf07cd2f142aac93556f028 Mon Sep 17 00:00:00 2001 From: Ryan Francesconi <2917795+ryanfrancesconi@users.noreply.github.com> Date: Sat, 31 Oct 2026 23:06:07 -0700 Subject: [PATCH] Matroska: Read SamplingFrequency and Channels defaults when absent (#1358) An Audio element without SamplingFrequency or Channels now reads their defaults (RFC 9559: 8000 Hz, one channel) instead of 0, and the track is no longer skipped when BitDepth is absent too. A track without an Audio element is still skipped. --- taglib/matroska/ebml/ebmlmktracks.cpp | 4 ++++ tests/test_matroska.cpp | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/taglib/matroska/ebml/ebmlmktracks.cpp b/taglib/matroska/ebml/ebmlmktracks.cpp index 5852d3bf..c7f1b0f6 100644 --- a/taglib/matroska/ebml/ebmlmktracks.cpp +++ b/taglib/matroska/ebml/ebmlmktracks.cpp @@ -67,6 +67,10 @@ void EBML::MkTracks::parse(Matroska::Properties *properties) const if(const Id trackEntryChildId = trackEntryChild->getId(); trackEntryChildId == Id::MkCodecID) codecId = element_cast(trackEntryChild)->getValue(); else if(trackEntryChildId == Id::MkAudio) { + // Their defaults (RFC 9559, 5.1.4.1.29), which a muxer may leave out + // when the value equals them (RFC 8794, 11.1.19). + samplingFrequency = 8000.0; + channels = 1; const auto audio = element_cast(trackEntryChild); for(const auto &audioChild : *audio) { if(const Id audioChildId = audioChild->getId(); audioChildId == Id::MkSamplingFrequency) diff --git a/tests/test_matroska.cpp b/tests/test_matroska.cpp index 3c12ab15..9717881e 100644 --- a/tests/test_matroska.cpp +++ b/tests/test_matroska.cpp @@ -219,6 +219,7 @@ class TestMatroska : public CppUnit::TestFixture CPPUNIT_TEST(testPropertiesMka); CPPUNIT_TEST(testPropertiesMkv); CPPUNIT_TEST(testPropertiesWebm); + CPPUNIT_TEST(testPropertiesAudioDefaults); CPPUNIT_TEST(testSimpleTagsAndAttachments); CPPUNIT_TEST(testAddRemoveTagsAttachments); CPPUNIT_TEST(testTagsWebm); @@ -291,6 +292,27 @@ public: CPPUNIT_ASSERT(!noProps.audioProperties()); } + void testPropertiesAudioDefaults() + { + // no-tags.mka's Audio element holds SamplingFrequency (44100) and Channels (2). + // Replaced by Void elements of the same size, they are absent, and their + // defaults apply. + ScopedFileCopy copy("no-tags", ".mka"); + { + FileStream stream(copy.fileName().c_str()); + const ByteVector audio("\xe1\x89\xb5\x84\x47\x2c\x44\x00\x9f\x81\x02", 11); + const offset_t offset = stream.readBlock(stream.length()).find(audio); + CPPUNIT_ASSERT(offset > 0); + stream.seek(offset + 2); + stream.writeBlock(ByteVector("\xec\x84\x00\x00\x00\x00\xec\x81\x00", 9)); + } + Matroska::File f(copy.fileName().c_str()); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(8000, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(String("A_MPEG/L3"), f.audioProperties()->codecName()); + } + void testSimpleTagsAndAttachments() { ScopedFileCopy copy("no-tags", ".mka");