Ignore fake MPEG frame headers when seeking them.

This commit is contained in:
Tsuda Kageyu
2017-01-20 22:38:25 +09:00
parent d2e0e55223
commit 6bb92c34fa
4 changed files with 56 additions and 63 deletions

View File

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

View File

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