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
This commit is contained in:
Lukáš Lalinský 2010-11-27 20:58:57 +00:00
parent 15d139e271
commit 56343767ce
8 changed files with 99 additions and 7 deletions

2
NEWS
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

BIN
tests/data/no_length.wv Normal file

Binary file not shown.

28
tests/test_wavpack.cpp Normal file
View File

@ -0,0 +1,28 @@
#include <cppunit/extensions/HelperMacros.h>
#include <string>
#include <stdio.h>
#include <tag.h>
#include <tbytevectorlist.h>
#include <wavpackfile.h>
#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);