cog/Libraries/DecMPA/Files/src/MPAInfo.cpp

201 lines
4.5 KiB
C++

/* DecMPA - simple MPEG Audio decoding library.
Copyright (C) 2002 Hauke Duden
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For more information look at the file License.txt in this package.
email: hazard_hd@users.sourceforge.net
*/
#include "MPAInfo.h"
CMPAInfo::CMPAInfo()
{
m_nEncodedDataSize=-1;
m_nEncodedDataOffset=0;
m_nDuration=-1;
m_bXingVBR=false;
m_XingHeader.toc=m_aXingTOC;
}
CMPAInfo::~CMPAInfo()
{
}
bool CMPAInfo::InitInfo(CMPAFrameFinder* pFrameFinder,IFileAccess* pFileAccess)
{
m_nEncodedDataSize=-1;
m_nEncodedDataOffset=0;
m_nDuration=-1;
m_bXingVBR=false;
while(!pFrameFinder->ReadNextFrame())
{
if(pFrameFinder->IsStreamInvalid())
return false;
if(!pFrameFinder->ReadInput(pFileAccess))
return false;
}
m_nEncodedDataOffset=pFrameFinder->GetFirstFramePosition();
m_nEncodedDataSize=pFileAccess->GetLength();
if(m_nEncodedDataSize!=-1)
{
//ignore any leading non-MPEG-Audio data
m_nEncodedDataSize-=m_nEncodedDataOffset;
}
Init(pFrameFinder);
return true;
}
void CMPAInfo::Init(CMPAFrameFinder* pFrameFinder)
{
double nAvgFrameSize;
int nFrameSize;
long nFrameCount=-1;
nAvgFrameSize=pFrameFinder->GetAvgFrameSize();
nFrameSize=pFrameFinder->GetFrameSize();
if(nAvgFrameSize>0)
{
if(ReadXingHeader(pFrameFinder->GetFrameData(),nFrameSize))
{
m_bXingVBR=true;
nFrameCount=m_XingHeader.frames;
}
else
{
if(m_nEncodedDataSize>=0)
nFrameCount=(long)(m_nEncodedDataSize/nAvgFrameSize);
}
}
if(nFrameCount!=-1)
{
MpegAudioHeader* pHeader=pFrameFinder->GetFrameHeader();
int nDecodedSamplesPerFrame;
int nFrequency;
double nDecodedSamples;
nDecodedSamplesPerFrame=pHeader->getpcmperframe();
nFrequency=pHeader->getFrequencyHz();
nDecodedSamples=((double)nFrameCount)*nDecodedSamplesPerFrame;
if(nFrequency!=0)
m_nDuration=(long)((nDecodedSamples*1000)/nFrequency);
}
}
bool CMPAInfo::ReadXingHeader(void* pFrameData,int nFrameSize)
{
if(nFrameSize<152) //cannot have xing header
return false;
if(::GetXingHeader(&m_XingHeader,(unsigned char*)pFrameData)==0)
return false;
//we use floats so that we won't loose precision
//with the un-compensation stuff below
for(int i=0;i<100;i++)
m_aTOC[i]=((float)m_XingHeader.toc[i])/256.0f;
m_aTOC[100]=1.0f;
if(m_aTOC[0]!=0)
{
//the Xing table of contents compensates for some
//leading non-MP3 data (maybe an ID3 tag or something)
//Since that data may never have been passed to the library
//(or if it has been passed, it should have been skipped)
//we undo this compensation
float FullSizeValue;
FullSizeValue=1.0f-m_aTOC[0];
for(int i=100;i>=0;i--)
m_aTOC[i]=(m_aTOC[i]-m_aTOC[0])/FullSizeValue;
}
return true;
}
long CMPAInfo::GetFilePositionFromTime(long Millis)
{
long nPos=-1;
double nTimeFraction;
if(m_nDuration>0 && m_nEncodedDataSize>=0)
{
nTimeFraction=((double)Millis)/m_nDuration;
if(m_bXingVBR)
{
nPos=GetEncodedDataPositionFromTOC((float)nTimeFraction);
if(nPos>=m_nEncodedDataSize)
nPos=m_nEncodedDataSize;
}
else
nPos=(long)(nTimeFraction*m_nEncodedDataSize);
}
if(nPos==-1)
{
//ok, we couldn't find the correct position because
//we don't know enough about the stream
//however, ONE position we know: the beginning
if(Millis==0)
nPos=0;
}
nPos+=m_nEncodedDataOffset;
return nPos;
}
long CMPAInfo::GetEncodedDataPositionFromTOC(float TimeFract)
{
// interpolate in TOC to get file seek point in bytes
int nTOCIndex;
float LowerPosFract;
float UpperPosFract;
float PosFract;
float Percent=TimeFract*100.0f;
if(Percent<0.0f)
Percent=0.0f;
if(Percent>100.0f)
Percent=100.0f;
nTOCIndex=(int)Percent;
if(nTOCIndex>99)
nTOCIndex=99;
LowerPosFract=m_aTOC[nTOCIndex];
UpperPosFract=m_aTOC[nTOCIndex+1];
PosFract=LowerPosFract + ((UpperPosFract-LowerPosFract)*(Percent-nTOCIndex));
return (long)(PosFract*m_nEncodedDataSize);
}