From: Andre Noll Date: Sat, 19 Sep 2009 08:38:25 +0000 (+0200) Subject: oggdec filter improvements. X-Git-Tag: v0.3.5~1^2~1 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=d38eb22bbb5e89d70872a6ed07766f937af3ee47;hp=80dba626e7eddcaa9059e37afef95ad01967d833 oggdec filter improvements. Try to open the ogg vorbis callbacks as soon as possible rather than waiting until the input buffer reaches the given initial buffer size. If that fails, try again later when more data is available but fail if the input buffer size is larger than the initial buffer size and we can still not open the ov callbacks. Also, if a hole was detected, likely because we started streaming in the middle of the file, add an additional delay to avoid buffer underruns. --- diff --git a/oggdec_filter.c b/oggdec_filter.c index b158a5e1..bdfafedf 100644 --- a/oggdec_filter.c +++ b/oggdec_filter.c @@ -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,24 +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 (*fn->fc->input_error < 0) return *fn->fc->input_error; - if (len < ib) { - PARA_DEBUG_LOG("initial input buffer %zd/%d, " - "waiting for more data\n", len, ib); + 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) @@ -152,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;