X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=oggdec_filter.c;h=7155a54f6c9a172dc72905ca6eb9ed07588ebd8c;hp=8d1abb99b4f9cf47e329fa74c3186b7e47030de8;hb=4d5a9b90c3e9cbdff019776d05792beb57fbfa31;hpb=6bdac07456cb5872f824028912d1049883a9c21f diff --git a/oggdec_filter.c b/oggdec_filter.c index 8d1abb99..7155a54f 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,39 +126,60 @@ 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 || ret == OV_EBADHEADER) { + /* 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 ret == OV_ENOTVORBIS? + -E_OGGDEC_NOTVORBIS : -E_OGGDEC_BADHEADER; + } 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) - return -E_OGGDEC_BADHEADER; if (ret < 0) return -E_OGGDEC_FAULT; fn->fc->channels = ov_info(pod->vf, 0)->channels; 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;