Ogg-Vorbis-Decoder
view release on metacpan or search on metacpan
/* http://www.xiph.org/ogg/vorbis/doc/vorbisfile/ov_callbacks.html */
ov_callbacks vorbis_callbacks = {
ovcb_read,
ovcb_seek,
ovcb_close,
ovcb_tell
};
/* Allow multiple instances of the decoder object. Stuff each filehandle into (void*)stream */
typedef struct {
int is_streaming;
int bytes_streamed;
int last_bitstream;
PerlIO *stream;
} ocvb_datasource;
/* useful items from XMMS */
static size_t ovcb_read(void *ptr, size_t size, size_t nmemb, void *vdatasource) {
size_t read_bytes = 0;
datasource->bytes_streamed += read_bytes;
return read_bytes;
}
static int ovcb_seek(void *vdatasource, ogg_int64_t offset, int whence) {
ocvb_datasource *datasource = vdatasource;
if (datasource->is_streaming) {
return -1;
}
/* For some reason PerlIO_seek fails miserably here. < 5.8.1 works */
/* return PerlIO_seek(datasource->stream, offset, whence); */
return fseek(PerlIO_findFILE(datasource->stream), offset, whence);
}
static int ovcb_close(void *vdatasource) {
ocvb_datasource *datasource = vdatasource;
return PerlIO_close(datasource->stream);
}
static long ovcb_tell(void *vdatasource) {
ocvb_datasource *datasource = vdatasource;
if (datasource->is_streaming) {
return datasource->bytes_streamed;
}
return PerlIO_tell(datasource->stream);
}
/* Loads the commments from the stream and fills the object's hash */
void __read_comments(HV *self, OggVorbis_File *vf) {
int i;
/* check and see if a pathname was passed in, otherwise it might be a
* IO::Socket subclass, or even a *FH Glob */
if (SvOK(path) && (SvTYPE(SvRV(path)) != SVt_PVGV)) {
if ((datasource->stream = PerlIO_open((char*)SvPV_nolen(path), "r")) == NULL) {
safefree(vf);
printf("failed on open: [%d] - [%s]\n", errno, strerror(errno));
XSRETURN_UNDEF;
}
datasource->is_streaming = 0;
} else if (SvOK(path)) {
/* Did we get a Glob, or a IO::Socket subclass?
*
* XXX This should really be a class method so the caller
* can tell us if it's streaming or not. But how to do this on
* a per object basis without changing open()s arugments. That
* may be the easiest/only way. XXX
*
*/
if (sv_isobject(path) && sv_derived_from(path, "IO::Socket")) {
datasource->is_streaming = 1;
} else {
datasource->is_streaming = 0;
}
/* dereference and get the SV* that contains the Magic & FH,
* then pull the fd from the PerlIO object */
datasource->stream = IoIFP(GvIOp(SvRV(path)));
} else {
XSRETURN_UNDEF;
}
HV *self = (HV *) SvRV(obj);
OggVorbis_File *vf = (OggVorbis_File *) SvIV(*(my_hv_fetch(self, "VFILE")));
if (!vf) XSRETURN_UNDEF;
if (ix) {
/* empty */
}
/* See http://www.xiph.org/ogg/vorbis/doc/vorbisfile/ov_read.html for
* a description of the bitstream parameter. This allows streaming
* without a hack like icy-metaint */
cur_bitstream = (int) SvIV(*(my_hv_fetch(self, "BSTREAM")));
old_bitstream = cur_bitstream;
/* When we get a new bitstream, re-read the comment fields */
read_comments = (int)SvIV(*(my_hv_fetch(self, "READCOMMENTS")));
/* The nbytes argument to ov_read is only a limit, not a request. So
* read until we hit the requested number of bytes */
while (nbytes > 0) {
( run in 0.268 second using v1.01-cache-2.11-cpan-4d50c553e7e )