1
0
forked from 0ad/0ad

Fix playing of sound files in archives (by disabling proper streaming).

This was SVN commit r8370.
This commit is contained in:
Ykkrosh 2010-10-15 23:06:14 +00:00
parent ee8d49200a
commit 094ccc6a98
3 changed files with 105 additions and 9 deletions

View File

@ -115,24 +115,92 @@ private:
off_t offset;
};
//-----------------------------------------------------------------------------
class VorbisBufferAdapter
{
public:
VorbisBufferAdapter(const shared_ptr<u8>& buffer, size_t size)
: buffer(buffer)
, size(size)
, offset(0)
{
}
static size_t Read(void* bufferToFill, size_t itemSize, size_t numItems, void* context)
{
VorbisBufferAdapter* adapter = (VorbisBufferAdapter*)context;
const off_t sizeRequested = numItems*itemSize;
const off_t sizeRemaining = adapter->size - adapter->offset;
const size_t sizeToRead = (size_t)std::min(sizeRequested, sizeRemaining);
memcpy(bufferToFill, adapter->buffer.get() + adapter->offset, sizeToRead);
adapter->offset += sizeToRead;
return sizeToRead;
}
static int Seek(void* context, ogg_int64_t offset, int whence)
{
VorbisBufferAdapter* adapter = (VorbisBufferAdapter*)context;
off_t origin = 0;
switch(whence)
{
case SEEK_SET:
origin = 0;
break;
case SEEK_CUR:
origin = adapter->offset;
break;
case SEEK_END:
origin = adapter->size+1;
break;
NODEFAULT;
}
adapter->offset = Clamp(off_t(origin+offset), off_t(0), adapter->size);
return 0;
}
static int Close(void* context)
{
VorbisBufferAdapter* adapter = (VorbisBufferAdapter*)context;
adapter->buffer.reset();
return 0; // return value is ignored
}
static long Tell(void* context)
{
VorbisBufferAdapter* adapter = (VorbisBufferAdapter*)context;
return adapter->offset;
}
private:
shared_ptr<u8> buffer;
off_t size;
off_t offset;
};
//-----------------------------------------------------------------------------
template <typename Adapter>
class OggStreamImpl : public OggStream
{
public:
OggStreamImpl(const PFile& openedFile)
: adapter(openedFile)
OggStreamImpl(const Adapter& adapter)
: adapter(adapter)
{
}
LibError Open()
{
ov_callbacks callbacks;
callbacks.read_func = VorbisFileAdapter::Read;
callbacks.close_func = VorbisFileAdapter::Close;
callbacks.seek_func = VorbisFileAdapter::Seek;
callbacks.tell_func = VorbisFileAdapter::Tell;
callbacks.read_func = Adapter::Read;
callbacks.close_func = Adapter::Close;
callbacks.seek_func = Adapter::Seek;
callbacks.tell_func = Adapter::Tell;
const int ret = ov_open_callbacks(&adapter, &vf, 0, 0, callbacks);
if(ret != 0)
WARN_RETURN(LibErrorFromVorbis(ret));
@ -181,7 +249,7 @@ public:
}
private:
VorbisFileAdapter adapter;
Adapter adapter;
OggVorbis_File vf;
vorbis_info* info;
};
@ -194,7 +262,19 @@ LibError OpenOggStream(const fs::wpath& pathname, OggStreamPtr& stream)
PFile file(new File);
RETURN_ERR(file->Open(pathname, L'r'));
shared_ptr<OggStreamImpl> tmp(new OggStreamImpl(file));
shared_ptr<OggStreamImpl<VorbisFileAdapter> > tmp(new OggStreamImpl<VorbisFileAdapter>(VorbisFileAdapter(file)));
RETURN_ERR(tmp->Open());
stream = tmp;
return INFO::OK;
}
LibError OpenOggNonstream(const PIVFS& vfs, const VfsPath& pathname, OggStreamPtr& stream)
{
shared_ptr<u8> contents;
size_t size;
RETURN_ERR(vfs->LoadFile(pathname, contents, size));
shared_ptr<OggStreamImpl<VorbisBufferAdapter> > tmp(new OggStreamImpl<VorbisBufferAdapter>(VorbisBufferAdapter(contents, size)));
RETURN_ERR(tmp->Open());
stream = tmp;
return INFO::OK;

View File

@ -2,6 +2,7 @@
#define INCLUDED_OGG
#include "lib/external_libraries/openal.h"
#include "lib/file/vfs/vfs.h"
class OggStream
{
@ -20,4 +21,10 @@ typedef shared_ptr<OggStream> OggStreamPtr;
extern LibError OpenOggStream(const fs::wpath& pathname, OggStreamPtr& stream);
/**
* A non-streaming OggStream (reading the whole file in advance)
* that can cope with archived/compressed files.
*/
extern LibError OpenOggNonstream(const PIVFS& vfs, const VfsPath& pathname, OggStreamPtr& stream);
#endif // INCLUDED_OGG

View File

@ -924,6 +924,8 @@ static void SndData_dtor(SndData* sd)
static LibError SndData_reload(SndData* sd, const PIVFS& vfs, const VfsPath& pathname, Handle hsd)
{
#if 0 // HACK: streaming disabled because it breaks archives
// (OGG streaming requires a real POSIX pathname - see OpenOggStream)
fs::wpath real_pathname;
RETURN_ERR(vfs->GetRealPath(pathname, real_pathname));
@ -934,10 +936,17 @@ static LibError SndData_reload(SndData* sd, const PIVFS& vfs, const VfsPath& pat
// effort - OGG should be better in all cases.
RETURN_ERR(OpenOggStream(real_pathname, sd->ogg));
const size_t size = fs::file_size(real_pathname);
#else
RETURN_ERR(OpenOggNonstream(vfs, pathname, sd->ogg));
FileInfo fileInfo;
RETURN_ERR(vfs->GetFileInfo(pathname, &fileInfo));
const size_t size = fileInfo.Size();
#endif
sd->al_freq = sd->ogg->SamplingRate();
sd->al_fmt = sd->ogg->Format();
const size_t size = fs::file_size(real_pathname);
// HACK - it would be nicer for callers to confirm they won't
// open the same (streamed) file multiple times,
// but that's not possible with the current JSI_Sound.