From d868c56eb7c65b2c5a287998b08201986e361c5f Mon Sep 17 00:00:00 2001 Message-Id: From: Mark Wooding Date: Mon, 7 Jun 2010 22:15:04 +0100 Subject: [PATCH] Hands-off reading for FLAC. Organization: Straylight/Edgeware From: Richard Kettlewell --- lib/hreader.h | 20 ++++++++++++++ server/decode.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/lib/hreader.h b/lib/hreader.h index 46f8bd9..9e9a91c 100644 --- a/lib/hreader.h +++ b/lib/hreader.h @@ -69,6 +69,26 @@ int hreader_pread(struct hreader *h, void *buffer, size_t n, off_t offset); */ off_t hreader_seek(struct hreader *h, off_t offset, int whence); +/** @brief Return file size + * @param h Reader to find size of + * @return Size in bytes + */ +static inline off_t hreader_size(const struct hreader *h) { + return h->size; +} + +/** @brief Test for end of file + * @param h Reader to test + * @return 1 at eof, 0 otherwise + * + * This tells you whether the next read will return 0 bytes, rather than + * whether the last read reached end of file. So it is slightly different to + * feof(). + */ +static inline int hreader_eof(const struct hreader *h) { + return h->read_offset == h->size; +} + #endif /* HREADER_H */ /* diff --git a/server/decode.c b/server/decode.c index 19f7f3a..303fef0 100644 --- a/server/decode.c +++ b/server/decode.c @@ -397,18 +397,80 @@ static FLAC__StreamDecoderWriteStatus flac_write return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } +static FLAC__StreamDecoderReadStatus flac_read(const FLAC__StreamDecoder attribute((unused)) *decoder, + FLAC__byte buffer[], + size_t *bytes, + void *client_data) { + struct hreader *flacinput = client_data; + int n = hreader_read(flacinput, buffer, *bytes); + if(n == 0) { + *bytes = 0; + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + } + if(n < 0) { + *bytes = 0; + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + } + *bytes = n; + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; +} + +static FLAC__StreamDecoderSeekStatus flac_seek(const FLAC__StreamDecoder attribute((unused)) *decoder, + FLAC__uint64 absolute_byte_offset, + void *client_data) { + struct hreader *flacinput = client_data; + if(hreader_seek(flacinput, absolute_byte_offset, SEEK_SET) < 0) + return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; + else + return FLAC__STREAM_DECODER_SEEK_STATUS_OK; +} + +static FLAC__StreamDecoderTellStatus flac_tell(const FLAC__StreamDecoder attribute((unused)) *decoder, + FLAC__uint64 *absolute_byte_offset, + void *client_data) { + struct hreader *flacinput = client_data; + off_t offset = hreader_seek(flacinput, 0, SEEK_CUR); + if(offset < 0) + return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; + *absolute_byte_offset = offset; + return FLAC__STREAM_DECODER_TELL_STATUS_OK; +} + +static FLAC__StreamDecoderLengthStatus flac_length(const FLAC__StreamDecoder attribute((unused)) *decoder, + FLAC__uint64 *stream_length, + void *client_data) { + struct hreader *flacinput = client_data; + *stream_length = hreader_size(flacinput); + return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; +} + +static FLAC__bool flac_eof(const FLAC__StreamDecoder attribute((unused)) *decoder, + void *client_data) { + struct hreader *flacinput = client_data; + return hreader_eof(flacinput); +} /** @brief FLAC file decoder */ static void decode_flac(void) { FLAC__StreamDecoder *sd = FLAC__stream_decoder_new(); FLAC__StreamDecoderInitStatus is; + struct hreader flacinput[1]; if (!sd) disorder_fatal(0, "FLAC__stream_decoder_new failed"); - - if((is = FLAC__stream_decoder_init_file(sd, path, flac_write, flac_metadata, - flac_error, 0))) - disorder_fatal(0, "FLAC__stream_decoder_init_file %s: %s", + if(hreader_init(path, flacinput)) + disorder_fatal(errno, "error opening %s", path); + + if((is = FLAC__stream_decoder_init_stream(sd, + flac_read, + flac_seek, + flac_tell, + flac_length, + flac_eof, + flac_write, flac_metadata, + flac_error, + flacinput))) + disorder_fatal(0, "FLAC__stream_decoder_init_stream %s: %s", path, FLAC__StreamDecoderInitStatusString[is]); FLAC__stream_decoder_process_until_end_of_stream(sd); -- [mdw]