From 56343767ce35175d2f2e96d0ae9e284283859be4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Luk=C3=A1=C5=A1=20Lalinsk=C3=BD?= Date: Sat, 27 Nov 2010 20:58:57 +0000 Subject: [PATCH] Fix reading of WavPack streams without a length information in the header When the WavPack's total_samples header fiels contains -1, try to find the final block and get the number of samples from there as block_index + block_samples. BUG:258016 git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@1201476 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- NEWS | 2 + taglib/wavpack/wavpackfile.cpp | 3 +- taglib/wavpack/wavpackproperties.cpp | 55 +++++++++++++++++++++++++-- taglib/wavpack/wavpackproperties.h | 10 +++++ tests/CMakeLists.txt | 2 + tests/Makefile.am | 6 ++- tests/data/no_length.wv | Bin 0 -> 532 bytes tests/test_wavpack.cpp | 28 ++++++++++++++ 8 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 tests/data/no_length.wv create mode 100644 tests/test_wavpack.cpp diff --git a/NEWS b/NEWS index 6ded56fa..b8fd7c10 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,8 @@ TagLib 1.7 * Exposed FLAC MD5 signature of the uncompressed audio stream via FLAC::Properties::signature(). (BUG:160172) * Added function ByteVector::toHex() for hex-encoding of byte vectors. + * WavPack reader now tries to get the audio length by finding the final + block, if the header doesn't have the information. (BUG:258016) TagLib 1.6.3 (Apr 17, 2010) =========================== diff --git a/taglib/wavpack/wavpackfile.cpp b/taglib/wavpack/wavpackfile.cpp index 3a2f25ca..9983dfed 100644 --- a/taglib/wavpack/wavpackfile.cpp +++ b/taglib/wavpack/wavpackfile.cpp @@ -230,8 +230,7 @@ void WavPack::File::read(bool readProperties, Properties::ReadStyle /* propertie if(readProperties) { seek(0); - d->properties = new Properties(readBlock(WavPack::HeaderSize), - length() - d->APESize); + d->properties = new Properties(this, length() - d->APESize); } } diff --git a/taglib/wavpack/wavpackproperties.cpp b/taglib/wavpack/wavpackproperties.cpp index 697f223a..05436f92 100644 --- a/taglib/wavpack/wavpackproperties.cpp +++ b/taglib/wavpack/wavpackproperties.cpp @@ -48,7 +48,8 @@ public: sampleRate(0), channels(0), version(0), - bitsPerSample(0) {} + bitsPerSample(0), + file(0) {} ByteVector data; long streamLength; @@ -59,6 +60,7 @@ public: int channels; int version; int bitsPerSample; + File *file; }; //////////////////////////////////////////////////////////////////////////////// @@ -71,6 +73,14 @@ WavPack::Properties::Properties(const ByteVector &data, long streamLength, ReadS read(); } +WavPack::Properties::Properties(File *file, long streamLength, ReadStyle style) : AudioProperties(style) +{ + ByteVector data = file->readBlock(32); + d = new PropertiesPrivate(data, streamLength, style); + d->file = file; + read(); +} + WavPack::Properties::~Properties() { delete d; @@ -122,12 +132,19 @@ static const unsigned int sample_rates[] = { 6000, 8000, 9600, 11025, 12000, #define SRATE_LSB 23 #define SRATE_MASK (0xfL << SRATE_LSB) +#define MIN_STREAM_VERS 0x402 +#define MAX_STREAM_VERS 0x410 + +#define FINAL_BLOCK 0x1000 + void WavPack::Properties::read() { if(!d->data.startsWith("wvpk")) return; d->version = d->data.mid(8, 2).toShort(false); + if(d->version < MIN_STREAM_VERS || d->version > MAX_STREAM_VERS) + return; unsigned int flags = d->data.mid(24, 4).toUInt(false); d->bitsPerSample = ((flags & BYTES_STORED) + 1) * 8 - @@ -136,11 +153,43 @@ void WavPack::Properties::read() d->channels = (flags & MONO_FLAG) ? 1 : 2; unsigned int samples = d->data.mid(12, 4).toUInt(false); - if (samples == ~0u) { - samples = 0; + if(samples == ~0u) { + if(d->file && d->style != Fast) { + samples = seekFinalIndex(); + } + else { + samples = 0; + } } d->length = d->sampleRate > 0 ? (samples + (d->sampleRate / 2)) / d->sampleRate : 0; d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0; } +unsigned int WavPack::Properties::seekFinalIndex() +{ + ByteVector blockID("wvpk", 4); + + long offset = d->streamLength; + while(offset > 0) { + offset = d->file->rfind(blockID, offset); + if(offset == -1) + return 0; + d->file->seek(offset); + ByteVector data = d->file->readBlock(32); + if(data.size() != 32) + return 0; + int version = data.mid(8, 2).toShort(false); + if(version < MIN_STREAM_VERS || version > MAX_STREAM_VERS) + continue; + unsigned int flags = data.mid(24, 4).toUInt(false); + if(!(flags & FINAL_BLOCK)) + return 0; + unsigned int blockIndex = data.mid(16, 4).toUInt(false); + unsigned int blockSamples = data.mid(20, 4).toUInt(false); + return blockIndex + blockSamples; + } + + return 0; +} + diff --git a/taglib/wavpack/wavpackproperties.h b/taglib/wavpack/wavpackproperties.h index a77e4de4..7bd28e3f 100644 --- a/taglib/wavpack/wavpackproperties.h +++ b/taglib/wavpack/wavpackproperties.h @@ -54,9 +54,18 @@ namespace TagLib { /*! * Create an instance of WavPack::Properties with the data read from the * ByteVector \a data. + * + * \deprecated This constructor will be dropped in favor of the one below + * in a future version. */ Properties(const ByteVector &data, long streamLength, ReadStyle style = Average); + /*! + * Create an instance of WavPack::Properties. + */ + // BIC: merge with the above constructor + Properties(File *file, long streamLength, ReadStyle style = Average); + /*! * Destroys this WavPack::Properties instance. */ @@ -84,6 +93,7 @@ namespace TagLib { Properties &operator=(const Properties &); void read(); + unsigned int seekFinalIndex(); class PropertiesPrivate; PropertiesPrivate *d; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f5b80c69..a93e4c55 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -18,6 +18,7 @@ INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg/vorbis ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg/flac ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/flac + ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/wavpack ) SET(test_runner_SRCS @@ -42,6 +43,7 @@ SET(test_runner_SRCS test_ape.cpp test_apetag.cpp test_wav.cpp + test_wavpack.cpp ) IF(WITH_MP4) SET(test_runner_SRCS ${test_runner_SRCS} diff --git a/tests/Makefile.am b/tests/Makefile.am index 94131821..c7585acb 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -12,7 +12,8 @@ INCLUDES = \ -I$(top_srcdir)/taglib/flac \ -I$(top_srcdir)/taglib/riff \ -I$(top_srcdir)/taglib/riff/aiff \ - -I$(top_srcdir)/taglib/mpeg/id3v2/frames + -I$(top_srcdir)/taglib/mpeg/id3v2/frames \ + -I$(top_srcdir)/taglib/wavpack test_runner_SOURCES = \ main.cpp \ @@ -32,7 +33,8 @@ test_runner_SOURCES = \ test_aiff.cpp \ test_ogg.cpp \ test_oggflac.cpp \ - test_flac.cpp + test_flac.cpp \ + test_wavpack.cpp if build_tests TESTS = test_runner diff --git a/tests/data/no_length.wv b/tests/data/no_length.wv new file mode 100644 index 0000000000000000000000000000000000000000..c06d1071d5ac76d9be9d6eff977a5f8cd4c82863 GIT binary patch literal 532 zcmXRfE6C1ZU|?WpVPNYZf+_+IT^wo!(7vHOB4iv zDi|4<7+lscFbHg9VqjqqU`R$tHroccd6NuFXB>(^Kh$sizX9DDd z>~pAN0^5abA2t(k=>@rfT)k;bjAZNWh#+6@s&(Y+J;TDpu*(J#H}CIsO5qHv`jVgM K;oRm(yj}nfOJeE( literal 0 HcmV?d00001 diff --git a/tests/test_wavpack.cpp b/tests/test_wavpack.cpp new file mode 100644 index 00000000..7129a604 --- /dev/null +++ b/tests/test_wavpack.cpp @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include +#include +#include "utils.h" + +using namespace std; +using namespace TagLib; + +class TestWavPack : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(TestWavPack); + CPPUNIT_TEST(testLengthScan); + CPPUNIT_TEST_SUITE_END(); + +public: + + void testLengthScan() + { + WavPack::File f("data/no_length.wv"); + CPPUNIT_ASSERT_EQUAL(4, f.audioProperties()->length()); + } + +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TestWavPack); -- 2.40.0