X-Git-Url: http://git.tdb.fi/?p=libs%2Fal.git;a=blobdiff_plain;f=source%2Fvorbis%2Foggdecoder.cpp;fp=source%2Fvorbis%2Foggdecoder.cpp;h=374cf0b5ba06966174270a96c1d193a511843bcb;hp=0000000000000000000000000000000000000000;hb=8e12e7c9f65632342a8f370ea2de6b029cb564ec;hpb=1e7141871d33e3e184456ba063fcf3448a8cc12a diff --git a/source/vorbis/oggdecoder.cpp b/source/vorbis/oggdecoder.cpp new file mode 100644 index 0000000..374cf0b --- /dev/null +++ b/source/vorbis/oggdecoder.cpp @@ -0,0 +1,130 @@ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" +#include +#pragma GCC diagnostic pop +#include +#include "oggdecoder.h" + +using namespace std; + +namespace { + +size_t read(void *ptr, size_t size, size_t nmemb, void *src) +{ + Msp::IO::Base *in = reinterpret_cast(src); + unsigned len = in->read(reinterpret_cast(ptr), size*nmemb); + return len/size; +} + +int seek(void *src, ogg_int64_t offset, int whence) +{ + Msp::IO::SeekType type; + if(whence==SEEK_SET) + type = Msp::IO::S_BEG; + else if(whence==SEEK_CUR) + type = Msp::IO::S_CUR; + else if(whence==SEEK_END) + type = Msp::IO::S_END; + else + return -1; + + Msp::IO::Seekable *in = reinterpret_cast(src); + return in->seek(offset, type); +} + +long tell(void *src) +{ + return reinterpret_cast(src)->tell(); +} + +ov_callbacks io_callbacks = +{ + &read, + &seek, + 0, + &tell +}; + +} // namespace + + +namespace Msp { +namespace AL { + +ogg_error::ogg_error(const std::string &func, int code): + runtime_error(format("%s: %s", func, get_message(code))) +{ } + +string ogg_error::get_message(int code) +{ + switch(code) + { + case OV_FALSE: return "No data available"; + case OV_HOLE: return "Missing or corrupt data"; + case OV_EREAD: return "Read error"; + case OV_EFAULT: return "Internal inconsistency"; + case OV_EIMPL: return "Not implemented"; + case OV_EINVAL: return "Invalid argument"; + case OV_ENOTVORBIS: return "Not Vorbis data"; + case OV_EBADHEADER: return "Corrupt Vorbis header"; + case OV_EVERSION: return "Unsupported version"; + case OV_EBADLINK: return "Bad link"; + case OV_ENOSEEK: return "Stream is not seekable"; + default: return format("Unknown error (%d)", code); + } +} + + +struct OggDecoder::Private +{ + OggVorbis_File ovfile; +}; + +OggDecoder::OggDecoder(IO::Seekable &io): + priv(new Private) +{ + int ret = ov_open_callbacks(&io, &priv->ovfile, 0, 0, io_callbacks); + if(ret<0) + throw ogg_error("ov_open_callbacks", ret); + + vorbis_info *info = ov_info(&priv->ovfile, -1); + freq = info->rate; + format = create_format(2, info->channels); + + size = ov_pcm_total(&priv->ovfile, 0)*get_unit_size(format); +} + +OggDecoder::~OggDecoder() +{ + if(priv->ovfile.datasource) + ov_clear(&priv->ovfile); + delete priv; +} + +bool OggDecoder::detect(const std::string &sig) +{ + static const char ogg_sig[] = { 'O', 'g', 'g', 'S' }; + if(sig.size()ovfile, pos); +} + +unsigned OggDecoder::read(char *buf, unsigned len) +{ + int section = 0; + int res = ov_read(&priv->ovfile, buf, len, 0, 2, 1, §ion); + if(res<0) + throw ogg_error("ov_read", res); + else if(res==0) + eof_flag = true; + return res; +} + +} // namespace AL +} // namespace Msp