X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=oggdec_filter.c;h=6a97d6c6191420a99af25327d517fcf6bc58ece1;hp=0653f7dadd0d7223e27ea9e339d113420aaa7a5f;hb=bb6721e17e741b7ea52fbf88661d2b177bed72c3;hpb=ebe54cf6ee1b9c5daf7837cb618c299a5b5187e0;ds=sidebyside diff --git a/oggdec_filter.c b/oggdec_filter.c index 0653f7da..6a97d6c6 100644 --- a/oggdec_filter.c +++ b/oggdec_filter.c @@ -1,13 +1,15 @@ /* - * Copyright (C) 2005-2008 Andre Noll + * Copyright (C) 2005-2009 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ /** \file oggdec_filter.c Paraslash's ogg vorbis decoder. */ -#include "para.h" +#include +#include +#include "para.h" #include "oggdec_filter.cmdline.h" #include "list.h" #include "sched.h" @@ -16,8 +18,6 @@ #include "error.h" #include "string.h" -#include - /** Determine byte sex. */ #ifdef WORDS_BIGENDIAN #define ENDIAN 1 @@ -35,6 +35,8 @@ struct private_oggdec_data { size_t inbuf_len; /** The number of bytes consumed from the input buffer. */ size_t converted; + /** When to start producing output. */ + struct timeval stream_start; }; static size_t cb_read(void *buf, size_t size, size_t nmemb, void *datasource) @@ -124,22 +126,30 @@ static ssize_t ogg_convert(char *inbuffer, size_t len, struct filter_node *fn) pod->converted = 0; if (!pod->vf) { - int ib = 1024 * conf->initial_buffer_arg; /* initial buffer */ - if (len fc->input_error) { - PARA_DEBUG_LOG("initial input buffer %zd/%d, " - "waiting for more data\n", len, ib); + if (*fn->fc->input_error < 0) + return *fn->fc->input_error; + if (!len) return 0; - } pod->vf = para_malloc(sizeof(struct OggVorbis_File)); PARA_NOTICE_LOG("input buffer: %zd, opening ov callbacks\n", len); ret = ov_open_callbacks(fn, pod->vf, NULL, /* no initial buffer */ 0, /* no initial bytes */ ovc); /* the ov_open_callbacks */ + if (ret == OV_ENOTVORBIS) { + /* this might be due to the input buffer being too small */ + int ib = 1024 * conf->initial_buffer_arg; /* initial buffer */ + if (len < ib) { + PARA_INFO_LOG("initial input buffer %zd/%d, " + "waiting for more data\n", len, ib); + free(pod->vf); + pod->vf = NULL; + return 0; + } + return -E_OGGDEC_NOTVORBIS; + } if (ret == OV_EREAD) return -E_OGGDEC_READ; - if (ret == OV_ENOTVORBIS) - return -E_OGGDEC_NOTVORBIS; if (ret == OV_EVERSION) return -E_OGGDEC_VERSION; if (ret == OV_EBADHEADER) @@ -150,13 +160,27 @@ static ssize_t ogg_convert(char *inbuffer, size_t len, struct filter_node *fn) fn->fc->samplerate = ov_info(pod->vf, 0)->rate; PARA_NOTICE_LOG("%d channels, %d Hz\n", fn->fc->channels, fn->fc->samplerate); + /* wait a bit to avoid buffer underruns */ + tv_add(now, &(struct timeval){0, 500 * 1000}, &pod->stream_start); + return pod->converted; + } + if (tv_diff(now, &pod->stream_start, NULL) < 0) { + PARA_DEBUG_LOG("initial delay..\n"); + return 0; } while (fn->loaded < fn->bufsize) { int length = fn->bufsize - fn->loaded; long read_ret = ov_read(pod->vf, fn->buf + fn->loaded, length, ENDIAN, 2 /* 16 bit */, 1 /* signed */, NULL); - if (read_ret == OV_HOLE || !read_ret) + if (read_ret == 0) + return pod->converted; + if (read_ret == OV_HOLE) { + if (!fn->loaded) { + PARA_INFO_LOG("hole, delaying playback\n"); + tv_add(now, &(struct timeval){0, 500 * 1000}, &pod->stream_start); + } return pod->converted; + } if (read_ret < 0) return -E_OGGDEC_BADLINK; fn->loaded += read_ret;