diff --git a/taglib/mp4/mp4properties.cpp b/taglib/mp4/mp4properties.cpp index 605f6cb4..88ed26ca 100644 --- a/taglib/mp4/mp4properties.cpp +++ b/taglib/mp4/mp4properties.cpp @@ -184,6 +184,17 @@ MP4::Properties::read(File *file, Atoms *atoms) unit = data.toUInt(20U); length = data.toUInt(24U); } + if(length == 0) { + // No length found in the media header (mdhd), try the movie header (mvhd) + if(MP4::Atom *mvhd = moov->find("mvhd")) { + file->seek(mvhd->offset); + data = file->readBlock(mvhd->length); + if(data.size() >= 24 + 4) { + unit = data.toUInt(20U); + length = data.toUInt(24U); + } + } + } if(unit > 0 && length > 0) d->length = static_cast(length * 1000.0 / unit + 0.5); diff --git a/tests/test_mp4.cpp b/tests/test_mp4.cpp index d9fd7e7e..5d8909da 100644 --- a/tests/test_mp4.cpp +++ b/tests/test_mp4.cpp @@ -47,6 +47,7 @@ class TestMP4 : public CppUnit::TestFixture CPPUNIT_TEST(testPropertiesAACWithoutBitrate); CPPUNIT_TEST(testPropertiesALAC); CPPUNIT_TEST(testPropertiesALACWithoutBitrate); + CPPUNIT_TEST(testPropertiesAACWithoutLength); CPPUNIT_TEST(testPropertiesM4V); CPPUNIT_TEST(testFreeForm); CPPUNIT_TEST(testCheckValid); @@ -144,6 +145,28 @@ public: CPPUNIT_ASSERT_EQUAL(MP4::Properties::ALAC, f.audioProperties()->codec()); } + void testPropertiesAACWithoutLength() + { + ByteVector m4aData = PlainFile(TEST_FILE_PATH_C("no-tags.m4a")).readAll(); + CPPUNIT_ASSERT_EQUAL(2898U, m4aData.size()); + CPPUNIT_ASSERT_EQUAL(ByteVector("mdhd"), m4aData.mid(1749, 4)); + // Set the length to zero + for (int offset = 1769; offset < 1773; ++offset) { + m4aData[offset] = 0; + } + ByteVectorStream m4aStream(m4aData); + MP4::File f(&m4aStream); + CPPUNIT_ASSERT(f.audioProperties()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds()); + CPPUNIT_ASSERT_EQUAL(3707, f.audioProperties()->lengthInMilliseconds()); + CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->bitrate()); + CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); + CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); + CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample()); + CPPUNIT_ASSERT_EQUAL(false, f.audioProperties()->isEncrypted()); + CPPUNIT_ASSERT_EQUAL(MP4::Properties::AAC, f.audioProperties()->codec()); + } + void testPropertiesM4V() { MP4::File f(TEST_FILE_PATH_C("blank_video.m4v"));