mirror of
https://github.com/taglib/taglib.git
synced 2025-05-27 21:20:26 -04:00
Ignore fake MPEG frame headers when seeking them.
This commit is contained in:
parent
d2e0e55223
commit
6bb92c34fa
@ -346,55 +346,52 @@ void MPEG::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory)
|
||||
|
||||
long MPEG::File::nextFrameOffset(long position)
|
||||
{
|
||||
bool foundLastSyncPattern = false;
|
||||
|
||||
ByteVector buffer;
|
||||
char frameSyncBytes[2] = {};
|
||||
|
||||
while(true) {
|
||||
seek(position);
|
||||
buffer = readBlock(bufferSize());
|
||||
|
||||
if(buffer.size() <= 0)
|
||||
const ByteVector buffer = readBlock(bufferSize());
|
||||
if(buffer.size() == 0)
|
||||
return -1;
|
||||
|
||||
if(foundLastSyncPattern && secondSynchByte(buffer[0]))
|
||||
return position - 1;
|
||||
|
||||
for(unsigned int i = 0; i < buffer.size() - 1; i++) {
|
||||
if(firstSyncByte(buffer[i]) && secondSynchByte(buffer[i + 1]))
|
||||
return position + i;
|
||||
for(unsigned int i = 0; i < buffer.size(); ++i) {
|
||||
frameSyncBytes[0] = frameSyncBytes[1];
|
||||
frameSyncBytes[1] = buffer[i];
|
||||
if(firstSyncByte(frameSyncBytes[0]) && secondSynchByte(frameSyncBytes[1])) {
|
||||
Header header(this, position + i - 1, true);
|
||||
if(header.isValid())
|
||||
return position + i - 1;
|
||||
}
|
||||
}
|
||||
|
||||
foundLastSyncPattern = firstSyncByte(buffer[buffer.size() - 1]);
|
||||
position += buffer.size();
|
||||
position += bufferSize();
|
||||
}
|
||||
}
|
||||
|
||||
long MPEG::File::previousFrameOffset(long position)
|
||||
{
|
||||
bool foundFirstSyncPattern = false;
|
||||
ByteVector buffer;
|
||||
char frameSyncBytes[2] = {};
|
||||
|
||||
while (position > 0) {
|
||||
long size = std::min<long>(position, bufferSize());
|
||||
while(position > 0) {
|
||||
const long size = std::min<long>(position, bufferSize());
|
||||
position -= size;
|
||||
|
||||
seek(position);
|
||||
buffer = readBlock(size);
|
||||
const ByteVector buffer = readBlock(bufferSize());
|
||||
if(buffer.size() == 0)
|
||||
return -1;
|
||||
|
||||
if(buffer.size() <= 0)
|
||||
break;
|
||||
|
||||
if(foundFirstSyncPattern && firstSyncByte(buffer[buffer.size() - 1]))
|
||||
return position + buffer.size() - 1;
|
||||
|
||||
for(int i = buffer.size() - 2; i >= 0; i--) {
|
||||
if(firstSyncByte(buffer[i]) && secondSynchByte(buffer[i + 1]))
|
||||
return position + i;
|
||||
for(int i = buffer.size() - 1; i >= 0; i--) {
|
||||
frameSyncBytes[1] = frameSyncBytes[0];
|
||||
frameSyncBytes[0] = buffer[i];
|
||||
if(firstSyncByte(frameSyncBytes[0]) && secondSynchByte(frameSyncBytes[1])) {
|
||||
Header header(this, position + i, true);
|
||||
if(header.isValid())
|
||||
return position + i + header.frameLength();
|
||||
}
|
||||
}
|
||||
|
||||
foundFirstSyncPattern = secondSynchByte(buffer[0]);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -157,23 +157,13 @@ void MPEG::Properties::read(File *file)
|
||||
{
|
||||
// Only the first valid frame is required if we have a VBR header.
|
||||
|
||||
long firstFrameOffset = file->firstFrameOffset();
|
||||
const long firstFrameOffset = file->firstFrameOffset();
|
||||
if(firstFrameOffset < 0) {
|
||||
debug("MPEG::Properties::read() -- Could not find an MPEG frame in the stream.");
|
||||
return;
|
||||
}
|
||||
|
||||
Header firstHeader(file, firstFrameOffset);
|
||||
|
||||
while(!firstHeader.isValid()) {
|
||||
firstFrameOffset = file->nextFrameOffset(firstFrameOffset + 1);
|
||||
if(firstFrameOffset < 0) {
|
||||
debug("MPEG::Properties::read() -- Could not find a valid first MPEG frame in the stream.");
|
||||
return;
|
||||
}
|
||||
|
||||
firstHeader = Header(file, firstFrameOffset);
|
||||
}
|
||||
const Header firstHeader(file, firstFrameOffset, false);
|
||||
|
||||
// Check for a VBR header that will help us in gathering information about a
|
||||
// VBR stream.
|
||||
@ -207,24 +197,13 @@ void MPEG::Properties::read(File *file)
|
||||
|
||||
// Look for the last MPEG audio frame to calculate the stream length.
|
||||
|
||||
long lastFrameOffset = file->lastFrameOffset();
|
||||
const long lastFrameOffset = file->lastFrameOffset();
|
||||
if(lastFrameOffset < 0) {
|
||||
debug("MPEG::Properties::read() -- Could not find an MPEG frame in the stream.");
|
||||
return;
|
||||
}
|
||||
|
||||
Header lastHeader(file, lastFrameOffset, false);
|
||||
|
||||
while(!lastHeader.isValid()) {
|
||||
lastFrameOffset = file->previousFrameOffset(lastFrameOffset);
|
||||
if(lastFrameOffset < 0) {
|
||||
debug("MPEG::Properties::read() -- Could not find a valid last MPEG frame in the stream.");
|
||||
return;
|
||||
}
|
||||
|
||||
lastHeader = Header(file, lastFrameOffset, false);
|
||||
}
|
||||
|
||||
const Header lastHeader(file, lastFrameOffset, false);
|
||||
const long streamLength = lastFrameOffset - firstFrameOffset + lastHeader.frameLength();
|
||||
if(streamLength > 0)
|
||||
d->length = static_cast<int>(streamLength * 8.0 / d->bitrate + 0.5);
|
||||
|
BIN
tests/data/garbage.mp3
Normal file
BIN
tests/data/garbage.mp3
Normal file
Binary file not shown.
@ -64,6 +64,7 @@ class TestMPEG : public CppUnit::TestFixture
|
||||
CPPUNIT_TEST(testEmptyID3v2);
|
||||
CPPUNIT_TEST(testEmptyID3v1);
|
||||
CPPUNIT_TEST(testEmptyAPE);
|
||||
CPPUNIT_TEST(testIgnoreGarbage);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
@ -119,13 +120,8 @@ public:
|
||||
CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate());
|
||||
CPPUNIT_ASSERT(!f.audioProperties()->xingHeader());
|
||||
|
||||
long last = f.lastFrameOffset();
|
||||
MPEG::Header lastHeader(&f, last, false);
|
||||
|
||||
while(!lastHeader.isValid()) {
|
||||
last = f.previousFrameOffset(last);
|
||||
lastHeader = MPEG::Header(&f, last, false);
|
||||
}
|
||||
const long last = f.lastFrameOffset();
|
||||
const MPEG::Header lastHeader(&f, last, false);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(28213L, last);
|
||||
CPPUNIT_ASSERT_EQUAL(209, lastHeader.frameLength());
|
||||
@ -163,7 +159,7 @@ public:
|
||||
CPPUNIT_ASSERT(f.audioProperties());
|
||||
CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->length());
|
||||
CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->lengthInSeconds());
|
||||
CPPUNIT_ASSERT_EQUAL(176, f.audioProperties()->lengthInMilliseconds());
|
||||
CPPUNIT_ASSERT_EQUAL(183, f.audioProperties()->lengthInMilliseconds());
|
||||
CPPUNIT_ASSERT_EQUAL(320, f.audioProperties()->bitrate());
|
||||
CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels());
|
||||
CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate());
|
||||
@ -421,6 +417,27 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void testIgnoreGarbage()
|
||||
{
|
||||
const ScopedFileCopy copy("garbage", ".mp3");
|
||||
{
|
||||
MPEG::File f(copy.fileName().c_str());
|
||||
CPPUNIT_ASSERT(f.isValid());
|
||||
CPPUNIT_ASSERT(f.hasID3v2Tag());
|
||||
CPPUNIT_ASSERT_EQUAL(2255L, f.firstFrameOffset());
|
||||
CPPUNIT_ASSERT_EQUAL(6015L, f.lastFrameOffset());
|
||||
CPPUNIT_ASSERT_EQUAL(String("Title A"), f.ID3v2Tag()->title());
|
||||
f.ID3v2Tag()->setTitle("Title B");
|
||||
f.save();
|
||||
}
|
||||
{
|
||||
MPEG::File f(copy.fileName().c_str());
|
||||
CPPUNIT_ASSERT(f.isValid());
|
||||
CPPUNIT_ASSERT(f.hasID3v2Tag());
|
||||
CPPUNIT_ASSERT_EQUAL(String("Title B"), f.ID3v2Tag()->title());
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestMPEG);
|
||||
|
Loading…
Reference in New Issue
Block a user