Audio-FLAC-Decoder
view release on metacpan or search on metacpan
union {
double seconds;
FLAC__int64 samples;
} value;
} SkipUntilSpecification;
/* Allow multiple instances of the decoder object. Stuff each filehandle into (void*)stream */
typedef struct {
int abort_flag;
int bytes_streamed;
int is_streaming;
FLAC__uint64 stream_length;
void *buffer;
PerlIO *stream;
decoder_t *decoder;
FLAC__bool has_replaygain;
/* (24/8) for max bytes per sample */
FLAC__byte sample_buffer[SAMPLES_PER_WRITE * FLAC__MAX_SUPPORTED_CHANNELS * (24/8)];
FLAC__int32 reservoir[FLAC__MAX_BLOCK_SIZE * 2 * FLAC__MAX_SUPPORTED_CHANNELS];
FLAC__uint64 decode_position_last;
warn("FLAC decoder error_callback: %s\n", status);
}
static FLAC__StreamDecoderSeekStatus seek_callback(
const decoder_t *decoder,
FLAC__uint64 absolute_byte_offset, void *client_data) {
flac_datasource *datasource = (flac_datasource *)client_data;
/* can't seek on a socket */
if (datasource->is_streaming) {
return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
}
if (PerlIO_seek(datasource->stream, absolute_byte_offset, SEEK_SET) >= 0) {
return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
}
return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
}
static FLAC__StreamDecoderTellStatus tell_callback(
const decoder_t *decoder,
FLAC__uint64 *absolute_byte_offset, void *client_data) {
flac_datasource *datasource = (flac_datasource *)client_data;
FLAC__uint64 pos = -1;
/* can't tell on a socket */
if (datasource->is_streaming) {
return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
}
pos = PerlIO_tell(datasource->stream);
if (pos < 0) {
return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
}
*absolute_byte_offset = pos;
return FLAC__STREAM_DECODER_TELL_STATUS_OK;
}
static FLAC__StreamDecoderLengthStatus length_callback(
const decoder_t *decoder,
FLAC__uint64 *stream_length, void *client_data) {
flac_datasource *datasource = (flac_datasource *)client_data;
/* can't find the total length of a socket */
if (datasource->is_streaming) {
return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
}
*stream_length = datasource->stream_length;
return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
}
static FLAC__bool eof_callback(
const decoder_t *decoder, void *client_data) {
flac_datasource *datasource = (flac_datasource *)client_data;
FLAC__uint64 pos = 0;
if (datasource->is_streaming) {
return false;
}
pos = PerlIO_tell(datasource->stream);
if (pos >= 0 && pos >= datasource->stream_length) {
/* printf("stream length: %d pos: %d\n", datasource->stream_length, pos); */
return true;
}
FLACdecoder_finish(datasource->decoder);
FLACdecoder_delete(datasource->decoder);
safefree(datasource);
warn("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;
}
if (!datasource->is_streaming) {
pos = PerlIO_tell(datasource->stream);
if (PerlIO_seek(datasource->stream, 0, SEEK_END) != -1) {
datasource->stream_length = PerlIO_tell(datasource->stream);
if (PerlIO_seek(datasource->stream, pos, SEEK_SET) == -1) {
FLACdecoder_finish(datasource->decoder);
long pos;
int whence;
CODE:
{
HV *self = (HV *) SvRV(obj);
flac_datasource *datasource = (flac_datasource *) SvIV(*(my_hv_fetch(self, "DATASOURCE")));
/* can't seek on a socket. */
if (datasource->is_streaming) {
XSRETURN_UNDEF;
}
if (!FLAC__stream_decoder_reset(datasource->decoder)) {
XSRETURN_UNDEF;
}
RETVAL = PerlIO_seek(datasource->stream, pos, whence);
}
( run in 0.242 second using v1.01-cache-2.11-cpan-a5abf4f5562 )