From: Richard Kettlewell Date: Mon, 7 Jun 2010 20:19:04 +0000 (+0100) Subject: Hands-off reading for OGGs. X-Git-Tag: branchpoint-5.1~77^2~6 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/commitdiff_plain/21237d054e4b9d6091decded21898b22dfb4f92c Hands-off reading for OGGs. --- diff --git a/lib/hreader.c b/lib/hreader.c index 9bcc808..177aa93 100644 --- a/lib/hreader.c +++ b/lib/hreader.c @@ -22,14 +22,21 @@ #include "mem.h" #include #include +#include +#include static int hreader_fill(struct hreader *h, off_t offset); -void hreader_init(const char *path, struct hreader *h) { +int hreader_init(const char *path, struct hreader *h) { + struct stat sb; + if(stat(path, &sb) < 0) + return -1; memset(h, 0, sizeof *h); h->path = xstrdup(path); + h->size = sb.st_size; h->bufsize = 65536; h->buffer = xmalloc_noptr(h->bufsize); + return 0; } int hreader_read(struct hreader *h, void *buffer, size_t n) { @@ -78,6 +85,18 @@ static int hreader_fill(struct hreader *h, off_t offset) { return n; } +off_t hreader_seek(struct hreader *h, off_t offset, int whence) { + switch(whence) { + case SEEK_SET: break; + case SEEK_CUR: offset += h->read_offset; break; + case SEEK_END: offset += h->size; break; + default: einval: errno = EINVAL; return -1; + } + if(offset < 0) goto einval; + h->read_offset = offset; + return offset; +} + /* Local Variables: c-basic-offset:2 diff --git a/lib/hreader.h b/lib/hreader.h index 8ef3a40..46f8bd9 100644 --- a/lib/hreader.h +++ b/lib/hreader.h @@ -29,6 +29,7 @@ */ struct hreader { const char *path; /* file to read */ + off_t size; /* file size */ off_t read_offset; /* for next hreader_read() */ off_t buf_offset; /* offset of start of buffer */ char *buffer; /* input buffer */ @@ -39,8 +40,9 @@ struct hreader { /** @brief Initialize a hands-off reader * @param path File to read * @param h Reader to initialize + * @return 0 on success, -1 on error */ -void hreader_init(const char *path, struct hreader *h); +int hreader_init(const char *path, struct hreader *h); /** @brief Read some bytes * @param h Reader to read from @@ -59,6 +61,14 @@ int hreader_read(struct hreader *h, void *buffer, size_t n); */ int hreader_pread(struct hreader *h, void *buffer, size_t n, off_t offset); +/** @brief Seek within a file + * @param h Reader to seek + * @param offset Offset + * @param whence SEEK_* + * @return Result offset + */ +off_t hreader_seek(struct hreader *h, off_t offset, int whence); + #endif /* HREADER_H */ /* diff --git a/lib/wav.c b/lib/wav.c index 8b2d640..6558c69 100644 --- a/lib/wav.c +++ b/lib/wav.c @@ -129,7 +129,7 @@ int wav_init(struct wavfile *f, const char *path) { memset(f, 0, sizeof *f); f->data = -1; - hreader_init(path, f->input); + if(hreader_init(path, f->input)) goto error_errno; /* Read the file header * * offset size meaning diff --git a/server/decode.c b/server/decode.c index 1724876..81aa351 100644 --- a/server/decode.c +++ b/server/decode.c @@ -269,7 +269,8 @@ static enum mad_flow mp3_error(void attribute((unused)) *data, static void decode_mp3(void) { struct mad_decoder mad[1]; - hreader_init(path, input); + if(hreader_init(path, input)) + disorder_fatal(errno, "opening %s", path); mad_decoder_init(mad, 0/*data*/, mp3_input, 0/*header*/, 0/*filter*/, mp3_output, mp3_error, 0/*message*/); if(mad_decoder_run(mad, MAD_DECODER_MODE_SYNC)) @@ -277,21 +278,52 @@ static void decode_mp3(void) { mad_decoder_finish(mad); } +static size_t ogg_read_func(void *ptr, size_t size, size_t nmemb, void *datasource) { + struct hreader *h = datasource; + + int n = hreader_read(h, ptr, size * nmemb); + if(n < 0) n = 0; + return n / size; +} + +static int ogg_seek_func(void *datasource, ogg_int64_t offset, int whence) { + struct hreader *h = datasource; + + return hreader_seek(h, offset, whence) < 0 ? -1 : 0; +} + +static int ogg_close_func(void attribute((unused)) *datasource) { + return 0; +} + +static long ogg_tell_func(void *datasource) { + struct hreader *h = datasource; + + return hreader_seek(h, 0, SEEK_CUR); +} + +static const ov_callbacks ogg_callbacks = { + ogg_read_func, + ogg_seek_func, + ogg_close_func, + ogg_tell_func, +}; + /** @brief OGG decoder */ static void decode_ogg(void) { - FILE *fp; + struct hreader ogginput[1]; OggVorbis_File vf[1]; int err; long n; int bitstream; vorbis_info *vi; - if(!(fp = fopen(path, "rb"))) - disorder_fatal(errno, "cannot open %s", path); + hreader_init(path, ogginput); /* There doesn't seem to be any standard function for mapping the error codes * to strings l-( */ - if((err = ov_open(fp, vf, 0/*initial*/, 0/*ibytes*/))) - disorder_fatal(0, "ov_fopen %s: %d", path, err); + if((err = ov_open_callbacks(ogginput, vf, 0/*initial*/, 0/*ibytes*/, + ogg_callbacks))) + disorder_fatal(0, "ov_open_callbacks %s: %d", path, err); if(!(vi = ov_info(vf, 0/*link*/))) disorder_fatal(0, "ov_info %s: failed", path); while((n = ov_read(vf, input_buffer, sizeof input_buffer, 1/*bigendianp*/,