Re: vorbis decoder stuffs
"safe mode" <[email protected]>
| Newsgroups | gmane.comp.audio.zinf.devel |
|---|---|
| Message-ID | <[email protected]> |
Ok, here's the latest and greatest. Commented too. Seeking code works rarely, I kind of know what's going on but i dont know how to fix it. I cant lock around my the writes to the outputbuffer. That and the fact that the seeking code seems to always take effect after my read from the input buffer. Something is not synced up between the accesses to the two threads and i've tried a ton of crap. Multiple locks etc. Nothing seems to work really. I get the seek to work randomnly, and always the slider is at the correct position, then reverts back to the old one, then back to the one i set it at. Something weird is going on. anyway this plugin is now solid except soley for seeking. I can fast-track like a mother and it doesn't crash and i can stop and start and pause and all that works exactly like it should and the time is only slightly off. In my opinion, not crashing when you track select is more important than not crashing when you seek in the file. This is not ready for commit yet obviously though. It wont be until seeking is fixed and i do more cleanups and get rid of unecessary shit. The locks seem like a little too much but it's seriously necessary. At least for some of the methods, perhaps after seeking works i'll go through and test each method to see which ones are succeptible to memmove/malloc issues etc etc. Try these out, tell me what you think. All the other decoders are going to go into similar rewrites since they all violate interfaces. I noticed a bunch of win32 commits but no activity on this mailing list or the irc channel, communication anyone? Still a day or two ...and a slight chance of even a few more days until I have this stupid seeking problem licked and then i'm going to have a number of patches backed up that need to be committed, win32 issues or not. _________________________________________________________________ Add photos to your messages with MSN 8. Get 2 months FREE*. http://join.msn.com/?page=features/featuredemail
vorbislmc.h
(text/x-chdr, 3.1 KB)
/*____________________________________________________________________________
Zinf - Zinf Is Not FreeA*p (The Free MP3 Player)
Portions Copyright (C) 1998-1999 EMusic.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: vorbislmc.h,v 1.4 2003/02/09 19:28:03 rottmann Exp $
____________________________________________________________________________*/
#ifndef INCLUDED_VORBISLMC_H_
#define INCLUDED_VORBISLMC_H_
/* system headers */
#include <stdlib.h>
#include <time.h>
#include <vorbis/vorbisfile.h>
#include <string>
#include <vector>
/* project headers */
#include "config.h"
#include "pmi.h"
#include "pmo.h"
#include "mutex.h"
#include "event.h"
#include "lmc.h"
#include "thread.h"
#include "mutex.h"
#include "queue.h"
#include "semaphore.h"
class VorbisLMC : public LogicalMediaConverter
{
public:
VorbisLMC(FAContext *context);
virtual ~VorbisLMC();
virtual uint32_t CalculateSongLength(const char *url);
virtual Error ChangePosition(int32_t position);
virtual Error CanDecode();
virtual Error ExtractMediaInfo();
virtual void SetPMI(PhysicalMediaInput *pmi) { m_pPmi = pmi; };
virtual void SetPMO(PhysicalMediaOutput *pmo) { m_pPmo = pmo; };
virtual Error Prepare(PullBuffer *pInputBuffer, PullBuffer *&pOutBuffer);
virtual Error InitDecoder();
virtual std::vector<std::string> *GetExtensions(void);
virtual Error SetEQData(float *f, float) { return kError_YouScrewedUp; };
virtual Error SetEQData(bool b) { return kError_YouScrewedUp; };
virtual Error SetDecodeInfo(DecodeInfo &info);
private:
const std::string ConvertToISO(const char *utf8);
static void DecodeWorkerThreadFunc(void *);
void ClrDecode();
void DecodeWork();
PhysicalMediaInput *m_pPmi;
PhysicalMediaOutput *m_pPmo;
Thread *m_decoderThread;
char *m_szUrl;
const char *m_szError;
bool m_bInit;
int m_channels, m_rate;
long m_frameCounter;
// Ogg vorbis related datastructures
ogg_sync_state oy;
ogg_stream_state os;
ogg_page og;
vorbis_dsp_state vd;
vorbis_block vb;
vorbis_info vi;
vorbis_comment vc;
long serialno;
// end of ogg vorbis related datastructures
// input/output buffers
void *pBuffer;
void *pOutBuffer;
void *tbuffer;
int iMaxFrameSize;
int iReadSize;
int left;
Mutex seekLock;
bool seeked;
};
#endif
vorbislmc.cpp
(text/x-c++src, 19.7 KB)
/*____________________________________________________________________________
Zinf - Zinf Is Not FreeA*p (The Free MP3 Player)
Portions Copyright (C) 2000 Monty
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, Write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: vorbislmc.cpp,v 1.16 2003/03/20 22:25:33 kgk Exp $
____________________________________________________________________________*/
/* system headers */
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string>
#include <vector>
#include <math.h>
using namespace std;
#include "config.h"
#include "errors.h"
#include "pmoevent.h"
#include "eventbuffer.h"
#include "event.h"
#include "eventdata.h"
#include "mutex.h"
#include "semaphore.h"
#include "preferences.h"
#include "lmc.h"
#include "facontext.h"
#include "log.h"
#include "debug.h"
#include "vorbislmc.h"
#define DB printf("%s:%d\n", __FILE__, __LINE__);
extern "C"
{
LogicalMediaConverter *Initialize(FAContext *context)
{
return new VorbisLMC(context);
}
}
/*
These are global variables....WHY?!
*/
const int iDecodeBlockSize = 8192;
const int iFramesPerSecond = 10;
const int iBitrateLoopsPerUpdate = iFramesPerSecond * 3;
const int iInitialOutputBufferSize = 65536;
//const char *szFailRead = N_("Cannot read vorbis data from input plugin.");
const char *szFailWrite = N_("Cannot write audio data to output buffer.");
const char *szCannotDecode = N_("Skipped corrupted file.");
VorbisLMC::VorbisLMC(FAContext *context) :
LogicalMediaConverter(context),m_pPmi(NULL),m_pPmo(NULL),
m_decoderThread(NULL),m_szUrl(NULL),m_szError(NULL),pBuffer(NULL),
pOutBuffer(NULL),tbuffer(NULL)
{
m_pContext = context;
m_bInit = false;
m_decodeInfo.sendInfo = true;
iMaxFrameSize = 8192;
iReadSize = 0;
seeked = false;
}
VorbisLMC::~VorbisLMC()
{
if (m_decoderThread)
{
m_pPauseSem->Signal();
m_pSleepSem->Signal();
seekLock.Acquire();
m_pMutex->Acquire();
if(m_bInit) ClrDecode();
m_bExit = true;
m_pMutex->Release();
seekLock.Release();
m_decoderThread->Join();
delete m_decoderThread;
m_decoderThread=NULL;
}
}
Error VorbisLMC::Prepare(PullBuffer *pInputBuffer, PullBuffer *&pOutBuffer)
{
m_pInputBuffer = pInputBuffer;
m_pOutputBuffer = new EventBuffer(iInitialOutputBufferSize, 0,
m_pContext);
if (!m_decoderThread){
m_decoderThread = Thread::CreateThread();
if (!m_decoderThread){
return kError_CreateThreadFailed;
}
m_decoderThread->Create(VorbisLMC::DecodeWorkerThreadFunc, this);
}
pOutBuffer = m_pOutputBuffer;
m_pInputBuffer->SetName("Input");
m_pOutputBuffer->SetName("Output");
return kError_NoErr;
}
vector<string> *VorbisLMC::GetExtensions(void)
{
vector<string> *extList = new vector<string>;
extList->push_back("OGG");
return extList;
}
void VorbisLMC::ClrDecode()
{
m_pMutex->Acquire();
ogg_stream_clear(&os);
vorbis_block_clear(&vb);
vorbis_dsp_clear(&vd);
vorbis_comment_clear(&vc);
vorbis_info_clear(&vi);
ogg_sync_clear(&oy);
m_pMutex->Release();
}
// Only possible use for this method is external to the decoder.
Error VorbisLMC::CanDecode()
{
Error err;
if (!m_bInit){
err = InitDecoder();
if (err != kError_NoErr)
return err;
ClrDecode();
m_bInit = false;
}
return kError_NoErr;
}
Error VorbisLMC::InitDecoder()
{
int result;
int iNewSize,bytes;
int m_iMaxWriteSize;
OutputInfo *info = NULL;
int headers = 0;
Error Err = kError_PluginNotInitialized;
ogg_packet op;
if (!m_pTarget || !m_pPmi || !m_pPmo || !m_pInputBuffer || !m_pOutputBuffer){
return kError_PluginNotInitialized;
}
if (m_bExit)
return kError_Interrupt;
m_pMutex->Acquire();
ogg_sync_init(&oy);
if (iMaxFrameSize > (int)m_pInputBuffer->GetNumBytesInBuffer() &&
m_pInputBuffer->GetNumBytesInBuffer() > 0 &&
m_pInputBuffer->IsEndOfStream())
iReadSize = m_pInputBuffer->GetNumBytesInBuffer();
else
iReadSize = iMaxFrameSize;
// Allocate input buffer space in libvorbis
(char*)pOutBuffer = ogg_sync_buffer(&oy, iReadSize);
// Read in data to different pointer, so we dont lose pointer to libvorbis
// memory
while((Err = m_pInputBuffer->BeginRead(pBuffer,iReadSize)) == kError_NoDataAvail){
m_pPmi->Wake();
if(Sleep()){
m_pMutex->Release();
return kError_Interrupt;
}
}
// Copy data we read in BeginRead to memory in libvorbis
if(Err == kError_NoErr){
memcpy(pOutBuffer,pBuffer,iReadSize);
ogg_sync_wrote(&oy,iReadSize);
m_pInputBuffer->EndRead(iReadSize);
}
// Initialized some vorbis data structures and read in beginning header
if(ogg_sync_pageout(&oy,&og) != 1){
m_pMutex->Release();
return (kError_PluginNotInitialized);
}
serialno = ogg_page_serialno(&og);
ogg_stream_init(&os, serialno);
vorbis_info_init(&vi);
vorbis_comment_init(&vc);
if(ogg_stream_pagein(&os,&og) < 0){
m_pMutex->Release();
return (kError_PluginNotInitialized);
}
if(ogg_stream_packetout(&os,&op) != 1){
m_pMutex->Release();
return (kError_PluginNotInitialized);
}
if(vorbis_synthesis_headerin(&vi,&vc,&op) < 0){
m_pMutex->Release();
return (kError_PluginNotInitialized);
}
// Now read next two identification headers.
headers++;
while(headers < 3) {
while(headers < 3){
if((result = ogg_sync_pageout(&oy,&og)) == 0)
break;
if(result == 1){
ogg_stream_pagein(&os,&og);
while(headers < 3){
if((result = ogg_stream_packetout(&os,&op)) == 0)
break;
if(result < 0){
m_pMutex->Release();
return (kError_PluginNotInitialized);
}
vorbis_synthesis_headerin(&vi,&vc,&op);
headers++;
}
}
}
// read in more data if needed to read next header
if (iMaxFrameSize > (int)m_pInputBuffer->GetNumBytesInBuffer() &&
m_pInputBuffer->GetNumBytesInBuffer() > 0 &&
m_pInputBuffer->IsEndOfStream())
iReadSize = m_pInputBuffer->GetNumBytesInBuffer();
else
iReadSize = iMaxFrameSize;
// Allocate input buffer space in libvorbis
(char*)pOutBuffer = ogg_sync_buffer(&oy,iReadSize);
while((Err = m_pInputBuffer->BeginRead(pBuffer,iReadSize)) == kError_NoDataAvail){
m_pPmi->Wake();
if(Sleep()){
m_pMutex->Release();
return kError_Interrupt;
}
}
if(Err == kError_EndOfStream){
m_pMutex->Release();
return kError_PluginNotInitialized;
}
if(Err==kError_NoErr){
memcpy(pOutBuffer,pBuffer,iReadSize);
ogg_sync_wrote(&oy,iReadSize);
m_pInputBuffer->EndRead(iReadSize);
}
if(iReadSize == 0 && headers < 3 || Err != kError_NoErr){
m_pMutex->Release();
return (kError_PluginNotInitialized);
}
}
// All headers have successfully been read.
m_channels = vi.channels;
m_rate = vi.rate;
vorbis_synthesis_init(&vd,&vi);
vorbis_block_init(&vd,&vb);
// values here probably shouldn't be hardcoded.
info = new OutputInfo;
info->bits_per_sample = 16;
info->number_of_channels = vi.channels;
info->samples_per_second = vi.rate;
m_iMaxWriteSize = info->number_of_channels * (info->bits_per_sample/8) *
4096;
// This determines how fast time is "counted"
info->samples_per_frame = 2048;
info->max_buffer_size = m_iMaxWriteSize;
m_pContext->prefs->GetPrefInt32(kOutputBufferSizePref, &iNewSize);
iNewSize = max(iNewSize, iMinimumOutputBufferSize);
iNewSize *= 1024;
result = m_pOutputBuffer->Resize(iNewSize, iNewSize / 6);
if (IsError((Error)result)){
ReportError(_("Internal buffer sizing error occurred."));
m_pContext->log->Error("Resize output buffer failed.");
m_pMutex->Release();
return (Error)result;
}
((EventBuffer *)m_pOutputBuffer)->AcceptEvent(new PMOInitEvent(info));
m_bInit = true;
m_pMutex->Release();
return kError_NoErr;
}
Error VorbisLMC::ExtractMediaInfo()
{
Error err;
float totalSeconds;
int32_t filesize;
MediaInfoEvent *pMIE;
// If we are here and m_bInit is false then we must not actually be
// decoding the file.
if (!m_bInit){
err = InitDecoder();
if (err != kError_NoErr)
return err;
m_bInit = false;
}
if (m_bExit) {
if(!m_bInit) ClrDecode();
return kError_Interrupt;
}
// If we're streaming we should just return the total time to the
// current position we're at. Seems reasonable.
if(m_pPmi->IsStreaming())
totalSeconds = (double)m_pPmi->Tell(filesize) /
((double)vi.bitrate_nominal/8.0);
else {
// Calculates a rough estimate of the total length of file.
// To get an exact length we'd need to read the last page of the
// file. Not sure it's worth the added cpu time. but it wouldn't be
// too much more cpu time.
err = m_pPmi->GetLength((size_t)filesize);
if(err == kError_NoErr)
totalSeconds = (double)filesize / ((double)vi.bitrate_nominal/8.0);
else {
// something bad happened
if(!m_bInit) ClrDecode();
return (err);
}
}
pMIE = new MediaInfoEvent(m_pPmi->Url().c_str(), totalSeconds);
if (!pMIE) {
// Something got screwed up
if(!m_bInit) ClrDecode();
return kError_OutOfMemory;
}
VorbisInfoEvent *mie = new VorbisInfoEvent(vi.bitrate_nominal,
vi.channels,
vi.rate,
1. / (float)iFramesPerSecond);
if (mie){
pMIE->AddChildEvent((Event *) mie);
} else {
if(!m_bInit) ClrDecode();
return kError_OutOfMemory;
}
if (m_pTarget)
m_pTarget->AcceptEvent(pMIE);
// Since we aren't decoding the file, clear our variables up.
if(!m_bInit){
ClrDecode();
}
return kError_NoErr;
}
// This method is only used external from the decoder, not sure by what
uint32_t VorbisLMC::CalculateSongLength(const char *url)
{
int totalSeconds;
size_t filesize;
Error err;
if (!m_bInit){
err = InitDecoder();
if (err != kError_NoErr)
return err;
m_bInit = false;
}
m_pPmi->GetLength(filesize);
totalSeconds = (int)((float)filesize/((float)vi.bitrate_nominal/8.0));
if(!m_bInit) ClrDecode();
return (totalSeconds);
}
void VorbisLMC::DecodeWorkerThreadFunc(void *pxlmc)
{
if (pxlmc){
VorbisLMC *xlmc = (VorbisLMC *) pxlmc;
xlmc->DecodeWork();
}
}
void VorbisLMC::DecodeWork()
{
Error Err;
int32_t iValue;
int32_t ret;
int eos = 0;
assert(m_pPmi);
assert(m_pPmo);
m_pSleepSem->Wait();
m_pPmi->Wake();
// intermediate buffer
char convbuffer[4096];
// write buffer
char writeBuffer[iMaxFrameSize];
// using void* for ease of use
tbuffer = writeBuffer;
// We have to init the decoder before actually decoding, duh
if (!m_bInit){
Err = InitDecoder();
if (Err == kError_Interrupt)
return;
if (IsError(Err)){
if(m_decodeInfo.sendInfo){
ReportStatus(szCannotDecode);
m_pTarget->AcceptEvent(new Event(INFO_DoneOutputtingDueToError));
}else{
((EventBuffer *)m_pOutputBuffer)->AcceptEvent(new PMOErrorEvent());
}
return;
}
}
// We are an ogg vorbis file, so tell the player some info about it
Err = ExtractMediaInfo();
if (Err == kError_Interrupt)
return;
if (IsError(Err)){
m_pContext->log->Error("ExtractMediaInfo failed: %d\n", Err);
if (m_decodeInfo.sendInfo){
ReportStatus(szCannotDecode);
m_pTarget->AcceptEvent(new Event(INFO_DoneOutputtingDueToError));
} else
((EventBuffer *)m_pOutputBuffer)->AcceptEvent(new PMOErrorEvent());
return;
}
// This is a non-functional feature. Yay. it looks good in theory
m_pContext->prefs->GetPrefInt32(kDecoderThreadPriorityPref, &iValue);
m_decoderThread->SetPriority(iValue);
// start at frame 0 with 8192 bytes to fill in write buffer.
m_frameCounter = 0;
left = iMaxFrameSize;
while(!eos){
while(!eos && !seeked){
// Lock all all ogg vorbis method calls so we dont delete
// or change them via another thread while in execution
// they'll flip out if you do.
m_pMutex->Acquire();
ogg_packet op;
m_pMutex->Release();
if(m_bPause){
m_pPauseSem->Wait();
if(m_bExit)
break;
}
m_pMutex->Acquire();
ret = ogg_sync_pageout(&oy,&og);
m_pMutex->Release();
if(!ret){
// Need more data, breaking to read methods
break;
} else {
m_pMutex->Acquire();
ogg_stream_pagein(&os,&og);
m_pMutex->Release();
// Theoretically this should cause us to break to read methods
while(!seeked){
m_pMutex->Acquire();
ret = ogg_stream_packetout(&os,&op);
m_pMutex->Release();
if(!ret){
// Need more data, try breaking to read methods
break;
} else {
float **pcm;
int samples;
m_pMutex->Acquire();
if((samples = vorbis_synthesis(&vb,&op)) == 0)
vorbis_synthesis_blockin(&vd,&vb);
m_pMutex->Release();
// samples is the error return here, if not 0
// try breaking to read methods.
if(samples)break;
while((samples=vorbis_synthesis_pcmout(&vd,&pcm))>0 &&
!seeked && !m_bExit){
int j;
int clipflag=0;
int bout=(samples<(left/4)?samples:(left/4));
if(m_bPause){
m_pPauseSem->Wait();
if(m_bExit)
break;
}
for(int i=0;i<vi.channels;i++){
ogg_int16_t *ptr=((ogg_int16_t*)convbuffer)+i;
float *mono=pcm[i];
for(j=0;j<bout;j++){
int val= (int)((float)mono[j]*32767.f);
if(val>32767){
val = 32767;
clipflag=1;
}
if(val<-32768){
val = -32768;
clipflag=1;
}
*ptr=val;
ptr+=vi.channels;
}
}
m_pMutex->Acquire();
// Here we fill tbuffer, this should always fill to
// exactly 8192 bytes.
memcpy(((char*)tbuffer+(iMaxFrameSize-left)), convbuffer,bout*2*vi.channels);
left = left - (bout * 2 * vi.channels);
// Theoretically this is obsolete data if we seeked
if(!seeked)
vorbis_synthesis_read(&vd,bout);
m_pMutex->Release();
// We only want to write to the output buffer
// when we have a full tbuffer and haven't seeked
if((left == 0 || iReadSize < iMaxFrameSize)&& !seeked){
while(!seeked && !m_bExit &&
(Err = m_pOutputBuffer->BeginWrite(tbuffer,iMaxFrameSize))==kError_BufferTooSmall){
// Since we're not locked no telling when
// the seek can happen. This is the root
// of the problem with seeking
if(Sleep())
break;
continue;
}
if(m_pOutputBuffer){
if(Err == kError_NoErr){
m_pMutex->Acquire();
/* we increment our counter here since
we could loop any number of times
to reach 8192 bytes so this is only
sure way to know we have done a
"frame"
*/
if(!seeked)
m_frameCounter++;
m_pMutex->Release();
Err = m_pOutputBuffer->EndWrite(iMaxFrameSize);
}
}
// Since we output when left == 0, reset
left = iMaxFrameSize;
}
if(m_bExit || Err == kError_Interrupt || Err == kError_EndOfStream){
return;
}
if(seeked)break;
}
}
}
if(m_bExit || Err == kError_Interrupt || Err == kError_EndOfStream)
return;
m_pMutex->Acquire();
// We have obsolete data here if we seeked
if(!seeked)
if(ogg_page_eos(&og))
eos=1;
m_pMutex->Release();
}
}
if(!eos){
if (iMaxFrameSize > (int)m_pInputBuffer->GetNumBytesInBuffer() &&
m_pInputBuffer->GetNumBytesInBuffer() > 0 &&
m_pInputBuffer->IsEndOfStream())
iReadSize = m_pInputBuffer->GetNumBytesInBuffer();
else
iReadSize = iMaxFrameSize;
// seekLock theoretically allows us to lock just the vorbis
// lmc so we can lock across BeginRead etc methods but this
// doesn't work the way i wanted it to.
seekLock.Acquire();
m_pMutex->Acquire();
// pOutBuffer is a pointer to memory allocated in libvorbis
(char*)pOutBuffer = ogg_sync_buffer(&oy,left);
m_pMutex->Release();
// Since BeginRead allocates it's own buffer and sets the pointer
// we sent to it to it's memory, we have to use a different pointer
// We read "left" since we might be here with partially filled
// tbuffer.
while((Err = m_pInputBuffer->BeginRead(pBuffer,left)) == kError_NoDataAvail){
m_pPmi->Wake();
if(Sleep())
return;
}
if(Err == kError_EndOfStream){
((EventBuffer *)m_pOutputBuffer)->AcceptEvent(new PMOQuitEvent());
eos = 1;
}
// Since we now have two pointers to the same amount of memory
// we have to copy the data from BeginRead to the ogg pointer
// If we seeked we've theoretically resynced given new position
seeked = false;
if(Err == kError_NoErr){
((EventBuffer *)m_pOutputBuffer)->AcceptEvent(
new PMOTimeInfoEvent(m_frameCounter));
m_pMutex->Acquire();
memcpy(pOutBuffer,pBuffer,left);
ogg_sync_wrote(&oy,left);
m_pMutex->Release();
m_pInputBuffer->EndRead(left);
}
seekLock.Release();
if(m_bExit || Err == kError_Interrupt || Err == kError_EndOfStream)
return;
if(!iReadSize)
eos=1;
}
}
}
// This is the annoying bastard method that doesn't wanna work.
Error VorbisLMC::ChangePosition(int32_t position)
{
int32_t dummy;
uint32_t ISeekTo;
size_t length;
Error Err;
m_bPause = true;
m_pPmi->GetLength(length);
ISeekTo = (position * 2048);
m_pMutex->Acquire();
m_frameCounter = position*2;
seeked = true;
left = iMaxFrameSize;
m_pMutex->Release();
m_pPmi->Seek(dummy,ISeekTo, SEEK_FROM_START);
m_bPause = false;
return kError_NoErr;
}
// Not sure if this is used anywhere
Error VorbisLMC::SetDecodeInfo(DecodeInfo &info)
{
m_decodeInfo = info;
return kError_NoErr;
}
// Not sure if this is used anywhere.
const string VorbisLMC::ConvertToISO(const char *utf8)
{
unsigned char *in, *buf;
unsigned char *out, *end;
string ret;
in = (unsigned char *)utf8;
buf = out = new unsigned char[strlen(utf8) + 1];
end = in + strlen(utf8);
for(;*in != 0x00 && in <= end; in++, out++)
{
if (*in < 0x80)
{ /* lower 7-bits unchanged */
*out = *in;
}
else
if (*in > 0xC3)
{ /* discard anything above 0xFF */
*out = '?';
}
else
if (*in & 0xC0)
{ /* parse upper 7-bits */
if (in >= end)
*out = 0;
else
{
*out = (((*in) & 0x1F) << 6) | (0x3F & (*(++in)));
}
}
else
{
*out = '?'; /* this should never happen */
}
}
*out = 0x00; /* append null */
ret = string((char *)buf);
delete[] buf;
return ret;
}