mirror of
https://github.com/taglib/taglib.git
synced 2025-05-27 21:20:26 -04:00
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:
parent
15d139e271
commit
56343767ce
2
NEWS
2
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)
|
||||
===========================
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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}
|
||||
|
@ -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
BIN
tests/data/no_length.wv
Normal file
Binary file not shown.
28
tests/test_wavpack.cpp
Normal file
28
tests/test_wavpack.cpp
Normal 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);
|
Loading…
Reference in New Issue
Block a user