📄 xinglmc.cpp
字号:
if( h_mode != 3 ) buf+=(17+4);
else buf+=(9+4);
}
if( buf[0] != 'X' ) return 0; // fail
if( buf[1] != 'i' ) return 0; // header not found
if( buf[2] != 'n' ) return 0;
if( buf[3] != 'g' ) return 0;
buf+=4;
X->h_id = h_id;
X->samprate = sr_table[h_sr_index];
if( h_id == 0 ) X->samprate >>= 1;
head_flags = X->flags = ExtractI4(buf); buf+=4; // get flags
if( head_flags & FRAMES_FLAG ) {X->frames = ExtractI4(buf); buf+=4;}
if( head_flags & BYTES_FLAG ) {X->bytes = ExtractI4(buf); buf+=4;}
if( head_flags & TOC_FLAG ) {
if( X->toc != NULL ) {
for(i=0;i<100;i++) X->toc[i] = buf[i];
}
buf+=100;
}
X->vbr_scale = -1;
if( head_flags & VBR_SCALE_FLAG ) {X->vbr_scale = ExtractI4(buf); buf+=4;}
return 1; // success
}
int XingLMC::SeekPoint(unsigned char TOC[100], int file_bytes, float percent)
{
// interpolate in TOC to get file seek point in bytes
int a, seekpoint;
float fa, fb, fx;
if( percent < 0.0f ) percent = 0.0f;
if( percent > 100.0f ) percent = 100.0f;
a = (int)percent;
if( a > 99 ) a = 99;
fa = TOC[a];
if( a < 99 ) {
fb = TOC[a+1];
}
else {
fb = 256.0f;
}
fx = fa + (fb-fa)*(percent-a);
seekpoint = (int)((1.0f/256.0f)*fx*file_bytes);
return seekpoint;
}
Error XingLMC::InitDecoder()
{
Error Err;
if (!m_pTarget || !m_pPmi || !m_pPmo || !m_pInputBuffer || !m_pOutputBuffer)
{
return kError_NullValueInvalid;
}
if (m_frameBytes < 0)
{
Err = GetHeadInfo();
if (Err != kError_NoErr)
return Err;
}
// select decoder
m_audioMethods = audio_table[0][0]; // not integer, non 8 bit mode
if (m_audioMethods.decode_init(&m_sMpegHead,
m_frameBytes,
0 /* reduction code */ ,
0 /* transform code (ignored) */ ,
0 /* convert code */ ,
24000 /* freq limit */ ))
{
DEC_INFO decinfo;
int32 iNewSize;
Error result;
m_audioMethods.decode_info(&decinfo);
#if __BYTE_ORDER != __LITTLE_ENDIAN
cvt_to_wave_init(decinfo.bits);
#endif
OutputInfo *info;
info = new OutputInfo;
info->bits_per_sample = decinfo.bits;
info->number_of_channels = decinfo.channels;
info->samples_per_second = decinfo.samprate;
if (m_sMpegHead.id)
{
m_iMaxWriteSize = (info->number_of_channels *
(decinfo.bits / 8) * 1152);
info->samples_per_frame = 1152;
}
else
{
m_iMaxWriteSize = (info->number_of_channels *
(decinfo.bits / 8) * 576);
info->samples_per_frame = 576;
}
info->max_buffer_size = m_iMaxWriteSize;
m_pContext->prefs->GetOutputBufferSize(&iNewSize);
iNewSize *= 1024;
iNewSize -= iNewSize % m_iMaxWriteSize;
result = m_pOutputBuffer->Resize(iNewSize, 0);
if (IsError(result))
{
ReportError("Internal buffer sizing error occurred.");
m_pContext->log->Error("Resize output buffer failed.");
return result;
}
((EventBuffer *)m_pOutputBuffer)->AcceptEvent(new PMOInitEvent(info));
}
else
{
m_pContext->log->Log(LogDecode, "Audio decode init failed.\n");
return (Error) lmcError_AudioDecodeInitFailed;
}
return (Error) kError_NoErr;
}
#if MP3_PROF
extern "C"
{
etext();
monstartup();
_mcleanup();
}
#endif
void XingLMC::DecodeWorkerThreadFunc(void *pxlmc)
{
if (pxlmc)
{
XingLMC *xlmc = (XingLMC *) pxlmc;
#if MP3_PROF
monstartup(0x08040000, etext);
#endif
xlmc->DecodeWork();
#if MP3_PROF
_mcleanup();
#endif
}
}
void XingLMC::DecodeWork()
{
void *pBuffer, *pOutBuffer;
Error Err;
int32 iLoop = 0, iValue;
IN_OUT x = {0, 0};
assert(m_pPmi);
assert(m_pPmo);
m_pSleepSem->Wait();
m_pPmi->Wake();
Err = CanDecode();
if (Err == kError_Interrupt)
return;
if (Err != kError_NoErr)
{
m_pContext->log->Error("CanDecode returned false.\n");
ReportError(szCannotDecode);
return;
}
Err = ExtractMediaInfo();
if (Err == kError_Interrupt)
return;
if (IsError(Err))
{
m_pContext->log->Error("ExtractMediaInfo failed: %d\n", Err);
ReportError(szCannotDecode);
return;
}
Err = InitDecoder();
if (Err == kError_Interrupt)
return;
if (IsError(Err))
{
m_pContext->log->Error("Initializing the decoder failed: %d\n", Err);
ReportError("Initializing the decoder failed.");
return;
}
m_pContext->prefs->GetDecoderThreadPriority(&iValue);
m_decoderThread->SetPriority(iValue);
for (m_frameCounter = 0; !m_bExit;)
{
((EventBuffer *)m_pOutputBuffer)->AcceptEvent(
new PMOTimeInfoEvent(m_frameCounter));
// TODO: This loop needs to be terminated after 64k worth of data..
for(; !m_bExit; )
{
if (m_bPause)
{
m_pPauseSem->Wait();
if (m_bExit)
break;
}
x.in_bytes = 0;
Err = m_pOutputBuffer->BeginWrite(pOutBuffer, m_iMaxWriteSize);
if (Err == kError_Interrupt)
{
break;
}
if (Err == kError_BufferTooSmall)
{
if (Sleep())
break;
continue;
}
if (Err != kError_NoErr)
{
ReportError(szFailWrite);
m_pContext->log->Error("LMC: Cannot write to eventbuffer: %s (%d)\n",
m_szError, Err);
return;
}
Err = BeginRead(pBuffer, iMaxFrameSize);
if (Err == kError_Interrupt)
{
m_pOutputBuffer->EndWrite(0);
break;
}
if (Err == kError_EndOfStream)
{
m_pOutputBuffer->EndWrite(0);
((EventBuffer *)m_pOutputBuffer)->AcceptEvent(new PMOQuitEvent());
return;
}
if (Err == kError_NoDataAvail)
{
m_pOutputBuffer->EndWrite(0);
if (Sleep())
break;
continue;
}
if (Err != kError_NoErr)
{
ReportError(szFailRead);
m_pContext->log->Error("LMC: Cannot read from pullbuffer: %s\n", m_szError);
return;
}
x = m_audioMethods.decode((unsigned char *)pBuffer,
(short *)pOutBuffer);
if (x.in_bytes == 0)
{
EndRead(x.in_bytes);
m_pOutputBuffer->EndWrite(x.in_bytes);
m_pContext->log->Log(LogDecode, "Audio decode failed. "
"Resetting the decoder.\n");
Err = AdvanceBufferToNextFrame();
if (Err == kError_Interrupt)
break;
if (Err == kError_EndOfStream)
{
((EventBuffer *)m_pOutputBuffer)->AcceptEvent(new PMOQuitEvent());
return;
}
if (Err != kError_NoErr)
{
m_pContext->log->Error("LMC: Cannot advance to next frame: %d\n", Err);
ReportError("Cannot advance to next frame. Possible media corruption?");
return;
}
m_audioMethods.decode_init(&m_sMpegHead, m_frameBytes, 0, 0, 0, 24000);
}
else
{
break;
}
}
if (m_bExit || Err == kError_Interrupt)
{
return;
}
EndRead(x.in_bytes);
m_pPmi->Wake();
if (m_pOutputBuffer)
{
#if __BYTE_ORDER != __LITTLE_ENDIAN
x.out_bytes = cvt_to_wave(pOutBuffer, x.out_bytes);
#endif
#define _VISUAL_ENABLE_
#ifdef _VISUAL_ENABLE_
// if (m_pTarget)
// {
// SendVisBufEvent *e = new SendVisBufEvent(x.out_bytes,
// pOutBuffer,x.out_bytes);
// m_pTarget->AcceptEvent(e);
// m_pTarget->AcceptEvent(new SendVisBufEvent(x.out_bytes,
// pOutBuffer,x.out_bytes));
// }
#endif //_VISUAL_ENABLE_
#undef _VISUAL_ENABLE_
Err = m_pOutputBuffer->EndWrite(x.out_bytes);
if (Err == kError_Interrupt)
break;
if (IsError(Err))
{
m_pContext->log->Error("lmc: EndWrite returned %d\n", Err);
ReportError(szFailWrite);
return;
}
}
if (iLoop == iMaxDecodeRetries)
{
m_pContext->log->Error("LMC: Maximum number of retries reached"
" while trying to decode.\n");
ReportError("Cannot decode this MP3. Is the MP3 corrupted?");
return;
}
m_frameCounter++;
}
return;
}
// This function encapsulates all the buffering event management
Error XingLMC::BeginRead(void *&pBuffer, unsigned int iBytesNeeded,
bool bBufferUp)
{
int32 iInPercent, iOutPercent;
unsigned int iBufferUpBytes;
if (m_fpFile)
{
int iRead;
pBuffer = new char[iBytesNeeded];
m_pLocalReadBuffer = (char*)pBuffer;
iRead = fread(pBuffer, sizeof(char), iBytesNeeded, m_fpFile);
if (iRead != (int)iBytesNeeded)
return kError_EndOfStream;
return kError_NoErr;
}
if (m_pPmi && m_pInputBuffer && (!m_pPmi->IsStreaming() || m_iBitRate <= 0))
{
return BlockingBeginRead(pBuffer, iBytesNeeded);
}
iInPercent = m_pInputBuffer->GetBufferPercentage();
iOutPercent = m_pOutputBuffer->GetBufferPercentage();
// If the input buffer is getting too full, discard some bytes.
// This could be caused by a soundcard with slow playback or
// a host that is sending data too quicky. Clock-drift-a-moo!
if (iOutPercent > 90 && iInPercent > 90 && m_pPmi->UseBufferReduction())
{
m_pInputBuffer->DiscardBytes();
}
iBufferUpBytes = (m_iBitRate * m_iBufferUpInterval * 1000) / 8192;
if (iBufferUpBytes > (unsigned)m_iBufferSize)
iBufferUpBytes = m_iBufferSize / 2;
if (bBufferUp && iOutPercent < 1 &&
m_pInputBuffer->GetNumBytesInBuffer() < iBufferUpBytes / 2)
{
assert(m_iBufferSize > 0);
assert(m_iBufferUpInterval > 0);
assert(m_iBitRate > 0);
ReportStatus("Buffering up...");
m_pTarget->AcceptEvent(new StreamBufferEvent(true, iInPercent,
iOutPercent));
for(; !m_bExit;)
{
usleep(1000000);
iInPercent = m_pInputBuffer->GetBufferPercentage();
iOutPercent = m_pOutputBuffer->GetBufferPercentage();
m_pTarget->AcceptEvent(new StreamBufferEvent(true, iInPercent,
iOutPercent));
if (m_pInputBuffer->GetNumBytesInBuffer() >= iBufferUpBytes)
{
break;
}
if (m_pInputBuffer->GetBufferPercentage() > 90)
{
break;
}
}
m_pTarget->AcceptEvent(new StreamBufferEvent(false, iInPercent,
iOutPercent));
ReportStatus("Playing stream...");
}
return BlockingBeginRead(pBuffer, iBytesNeeded);
}
Error XingLMC::BlockingBeginRead(void *&pBuffer, unsigned int iBytesNeeded)
{
Error eRet;
for(;;)
{
eRet = m_pInputBuffer->BeginRead(pBuffer, iBytesNeeded);
if (eRet == kError_NoDataAvail)
{
m_pPmi->Wake();
if (Sleep())
return kError_Interrupt;
continue;
}
break;
}
return eRet;
}
Error XingLMC::EndRead(size_t iBytesUsed)
{
if (m_fpFile)
{
delete m_pLocalReadBuffer;
m_pLocalReadBuffer = NULL;
return kError_NoErr;
}
return m_pInputBuffer->EndRead(iBytesUsed);
}
#define _EQUALIZER_ENABLE_
#ifdef _EQUALIZER_ENABLE_
extern "C" {
float equalizer[32] = {
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
};
int enableEQ = false;
}
Error XingLMC::SetEQData(float *arrayEQ) {
Error error = kError_NoErr;
for(int i=0; i<32; i++)
equalizer[i] = arrayEQ[i];
return error;
}
Error XingLMC::SetEQData(bool enable) {
Error error = kError_NoErr;
enableEQ = enable;
return error;
}
#endif //_EQUALIZER_ENABLE_
#undef _EQUALIZER_ENABLE_
Error XingLMC::ChangePosition(int32 position)
{
int32 dummy;
uint32 lSeekTo;
m_frameCounter = position;
if (m_pXingHeader)
lSeekTo = XingLMC::SeekPoint(m_pXingHeader->toc, m_lFileSize,
(float)position * 100/
(float)m_pXingHeader->frames);
else
lSeekTo = position * m_frameBytes;
m_pPmi->Seek(dummy, lSeekTo, SEEK_FROM_START);
return kError_NoErr;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -