Fix playing of sound files in archives (by disabling proper streaming).
This was SVN commit r8370.
This commit is contained in:
parent
ee8d49200a
commit
094ccc6a98
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user