X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=opusdec_filter.c;h=6a93f41f6b25f9e9d36b58726708861a52ed6b89;hp=9a767d72bdf415f55acb946545ac96e1576da5d5;hb=9cc91f2d8d746e77947eeb2fd7af711a43c3a56a;hpb=d50aa36f089978eaba9bf6eb43a20f620b8d03a4 diff --git a/opusdec_filter.c b/opusdec_filter.c index 9a767d72..6a93f41f 100644 --- a/opusdec_filter.c +++ b/opusdec_filter.c @@ -2,7 +2,7 @@ * Copyright (c) 2002-2007 Jean-Marc Valin * Copyright (c) 2008 CSIRO * Copyright (c) 2007-2012 Xiph.Org Foundation - * Copyright (C) 2012-2013 Andre Noll + * Copyright (C) 2012 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -72,6 +72,7 @@ struct opusdec_context { int channels; int preskip; bool have_opus_stream; + bool have_more; ogg_int32_t opus_serialno; }; @@ -204,72 +205,84 @@ static int decode_packet(struct opusdec_context *ctx, ogg_packet *op, return 1; } -static void opusdec_pre_select(struct sched *s, struct task *t) -{ - struct filter_node *fn = container_of(t, struct filter_node, task); - struct btr_node *btrn = fn->btrn; - int ns; +#define OPUSDEC_MAX_OUTPUT_SIZE (1024 * 1024) - ns = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL); - if (ns != 0) - return sched_min_delay(s); - sched_request_timeout_ms(100, s); -} - -static int opusdec_post_select(__a_unused struct sched *s, struct task *t) +static int opusdec_post_select(__a_unused struct sched *s, void *context) { - struct filter_node *fn = container_of(t, struct filter_node, task); + struct filter_node *fn = context; struct opusdec_context *ctx = fn->private_data; struct btr_node *btrn = fn->btrn; int ret; - char *btr_buf, *data; - size_t nbytes; ogg_packet op; ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL); - if (ret <= 0) - goto out; - btr_merge(btrn, fn->min_iqs); - nbytes = btr_next_buffer(btrn, &btr_buf); - nbytes = PARA_MIN(nbytes, (size_t)32768); - ret = 0; - if (nbytes == 0) - goto out; - data = ogg_sync_buffer(&ctx->oy, nbytes); - memcpy(data, btr_buf, nbytes); - btr_consume(btrn, nbytes); - ogg_sync_wrote(&ctx->oy, nbytes); - for (;;) { /* loop over all ogg pages we got */ - ret = 0; - if (ogg_sync_pageout(&ctx->oy, &ctx->ogg_page) != 1) + if (ret < 0) { + if (ret != -E_BTR_EOF) /* fatal error */ + goto out; + if (!ctx->have_more) /* EOF */ goto out; - if (!ctx->stream_init) { - ogg_stream_init(&ctx->os, ogg_page_serialno(&ctx->ogg_page)); + } else if (ret == 0 && !ctx->have_more) /* nothing to do */ + goto out; + if (btr_get_output_queue_size(btrn) > OPUSDEC_MAX_OUTPUT_SIZE) + return 0; + for (;;) { + int serial; + if (ctx->stream_init) { + ret = ogg_stream_packetout(&ctx->os, &op); + if (ret == 1) + break; + } + while (ogg_sync_pageout(&ctx->oy, &ctx->ogg_page) != 1) { + char *btr_buf, *data; + size_t nbytes = btr_next_buffer(btrn, &btr_buf); + nbytes = PARA_MIN(nbytes, (size_t)24 * 1024); + //PARA_CRIT_LOG("nbytes: %d\n", nbytes); + ctx->have_more = false; + if (nbytes == 0) + return 0; + data = ogg_sync_buffer(&ctx->oy, nbytes); + memcpy(data, btr_buf, nbytes); + btr_consume(btrn, nbytes); + ogg_sync_wrote(&ctx->oy, nbytes); + } + ctx->have_more = true; + serial = ogg_page_serialno(&ctx->ogg_page); + if (ctx->stream_init) { + if (serial != ctx->os.serialno) + ogg_stream_reset_serialno(&ctx->os, serial); + } else { + ogg_stream_init(&ctx->os, serial); ctx->stream_init = true; } - if (ogg_page_serialno(&ctx->ogg_page) != ctx->os.serialno) - ogg_stream_reset_serialno(&ctx->os, - ogg_page_serialno(&ctx->ogg_page)); /* Add page to the bitstream */ ogg_stream_pagein(&ctx->os, &ctx->ogg_page); - for (;;) { /* loop over all opus packets */ - ret = ogg_stream_packetout(&ctx->os, &op); - if (ret != 1) - break; - ret = decode_packet(ctx, &op, btrn); - if (ret < 0) - goto out; - ctx->packet_count++; - if (ctx->eos) - ctx->have_opus_stream = false; - } } + ret = decode_packet(ctx, &op, btrn); + if (ret < 0) + goto out; + ctx->packet_count++; + if (ctx->eos) + ctx->have_opus_stream = false; out: if (ret < 0) btr_remove_node(&fn->btrn); return ret; } +static void opusdec_pre_select(struct sched *s, void *context) +{ + struct filter_node *fn = context; + struct opusdec_context *ctx = fn->private_data; + int ret = btr_node_status(fn->btrn, fn->min_iqs, BTR_NT_INTERNAL); + + if (ret != 0) + return sched_min_delay(s); + if (!ctx->have_more) + return; + if (btr_get_output_queue_size(fn->btrn) <= OPUSDEC_MAX_OUTPUT_SIZE) + return sched_min_delay(s); +} + /** * The init function of the opusdec filter. * @@ -281,7 +294,6 @@ void opusdec_filter_init(struct filter *f) { f->open = opusdec_open; f->close = opusdec_close; - f->pre_select = generic_filter_pre_select; f->pre_select = opusdec_pre_select; f->post_select = opusdec_post_select; f->execute = opusdec_execute;