Sign in to follow this  

ogg, vorbis & theora

This topic is 3722 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've been attempting to create a library that plays ogg files. I'm trying to add audio/video play in my game. Unfortunately they don't seem to be well documented. I've been taking a look at the source code of VLC which implements the above but the code is terribly documented. Does anyone have an idea where I can find documentation/tutorials on doing the above using ogg? I've already checked out Nehe's implementation using AVI and the ogg, vorbis and theora websites plus the OpenAL article in gamedev. THANKS.

Share this post


Link to post
Share on other sites
I've no idea about theora, but Ogg audio is pretty straightforward to get going with DirectSound. Here's some relevant code from my engine:

bool PMusic::OpenOgg(EResource::SP pResource)
{
// Setup callbacks
ov_callbacks theCallbacks;
theCallbacks.read_func = Ogg_Read;
theCallbacks.seek_func = Ogg_Seek;
theCallbacks.close_func = Ogg_Close;
theCallbacks.tell_func = Ogg_Tell;

// Open OGG file
m_pResource = pResource;
m_nReadOffset = 0;
if(ov_open_callbacks(this, &m_theFile, NULL, 0, theCallbacks) < 0)
{
m_pResource = 0;
m_nReadOffset = 0;
return false;
}

// Get file info and create buffer
vorbis_info* pInfo = ov_info(&m_theFile, -1);
if(!InitStreaming((int)pInfo->rate, 16, pInfo->channels))
{
memset(&m_theFile, 0, sizeof(m_theFile));
ov_clear(&m_theFile);
m_pResource = 0;
m_nReadOffset = 0;
return false;
}

return true;
}

// Fill the buffer passed in with the next chunk of data from the ogg file
void PMusic::FillBuffer(BYTE* pBuffer, size_t nLen)
{
size_t nRemain = nLen;

// Any data in the buffer already?
if(m_nBufferLen != 0)
{
size_t nCopyLen = min(nRemain, m_nBufferLen);
memcpy(pBuffer, m_byBuffer + (ms_nMaxBufferLen-m_nBufferLen), nCopyLen);
nRemain -= nCopyLen;
pBuffer += nCopyLen;
m_nBufferLen -= nCopyLen;
}

// Read from the file into out buffer
m_mutex.Enter();
bool bEOF = false;
while(!bEOF)
{
// Read a chunk
Assert(m_nBufferLen == 0, "");
long lRet = ov_read(&m_theFile, (char*)m_byBuffer, ms_nMaxBufferLen, 0, 2, 1, NULL);
if(lRet == 0)
{
// If we're looping, go back to the start and carry on
if(m_bLooping)
ov_raw_seek(&m_theFile, 0);
else
bEOF = true;
}

// We read data ok
else if(lRet > 0)
{
if((size_t)lRet > nRemain)
{
m_nBufferLen = (size_t)lRet - nRemain;
memcpy(pBuffer, m_byBuffer, nRemain);
nRemain = 0;
break;
}
else
{
memcpy(pBuffer, m_byBuffer, lRet);
nRemain -= (size_t)lRet;
pBuffer = pBuffer + lRet;
}
}

else if(lRet == OV_HOLE)
{
// OV_HOLE can happen after we rewind the stream.
// Just re-loop to ov_read again
continue;
}

// Error
else
{
Assert(false, "ov_read returns error code %d", lRet);
break;
}
}
m_mutex.Exit();

// Fill the remainder of the buffer with silence
if(nRemain) memset(pBuffer, 0, nRemain);
return;
}

// The following are static functions, the callbacks called by the Ogg library:

size_t PMusic::Ogg_Read(void* ptr, size_t size, size_t nmemb, void* datasource)
{
PMusic* pThis = (PMusic*)datasource;
size_t nSize = size*nmemb;
if(pThis->m_nReadOffset + nSize > pThis->m_pResource->GetLength())
nSize = pThis->m_pResource->GetLength() - pThis->m_nReadOffset;
memcpy(ptr, pThis->m_pResource->GetData()+pThis->m_nReadOffset, nSize);
pThis->m_nReadOffset += nSize;
return nSize;
}

int PMusic::Ogg_Seek(void* datasource, ogg_int64_t offset, int whence)
{
PMusic* pThis = (PMusic*)datasource;

switch(whence)
{
case SEEK_SET: pThis->m_nReadOffset = (size_t)offset; break;
case SEEK_CUR: pThis->m_nReadOffset += (size_t)offset; break;
case SEEK_END: pThis->m_nReadOffset = (size_t)(pThis->m_pResource->GetLength() - offset); break;
}

if(pThis->m_nReadOffset > pThis->m_pResource->GetLength())
{
pThis->m_nReadOffset = 0;
return -1;
}
return 0;
}

int PMusic::Ogg_Close(void* datasource)
{
PMusic* pThis = (PMusic*)datasource;
pThis->m_nReadOffset = 0;
return 0;
}

long PMusic::Ogg_Tell(void* datasource)
{
PMusic* pThis = (PMusic*)datasource;
return (long)pThis->m_nReadOffset;
}



And the header:

class PMusic : public EMusic, public PSoundBuffer
{
public:
PMusic();
virtual ~PMusic();

typedef ESP<PMusic> SP;

//========================================================================
// EMusic:
virtual void Play(bool bLoop);
virtual void Pause();
virtual void Stop();
virtual bool IsPlaying() const;
virtual void SetVolume(u8 nVolume);

//========================================================================
// PMusic:
bool OpenOgg(EResource::SP pResource);

protected:
//========================================================================
// PSoundBuffer:
virtual void FillBuffer(BYTE* pBuffer, size_t nLen);

private:
// Ogg vorbis callbacks
static size_t Ogg_Read(void* ptr, size_t size, size_t nmemb, void *datasource);
static int Ogg_Seek(void* datasource, ogg_int64_t offset, int whence);
static int Ogg_Close(void* datasource);
static long Ogg_Tell(void* datasource);


PMutex m_mutex;
EResource::SP m_pResource;
size_t m_nReadOffset;
OggVorbis_File m_theFile;
bool m_bLooping;

// Pre-decompressed vorbis buffer
static const size_t ms_nMaxBufferLen = 4096;
BYTE m_byBuffer[ms_nMaxBufferLen];
size_t m_nBufferLen;
};



I'm not sure how helpful that code really is, but it's difficult to cut out jus tthe ogg code...

Share this post


Link to post
Share on other sites
Thanks for the code.
What I don't understand in the documentation/code I have is the timing stuff. granulepos (a variable in ogg_packet) seems to be used to do some timing stuff. I think this is important to sync the video and audio, but I can't understand how it actually works.

Share this post


Link to post
Share on other sites

This topic is 3722 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this