X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=opusdec_filter.c;h=10ed394d295072d909441fe211fbcdc695ff62d0;hp=90e65bc369571fbf9e8cde134efc07a17b76e124;hb=85ec8f30f6bef37a9a3bc2b84314654648f2f81c;hpb=0169fe33dbf961fe363f4c65b7424b1e126e639d diff --git a/opusdec_filter.c b/opusdec_filter.c index 90e65bc3..10ed394d 100644 --- a/opusdec_filter.c +++ b/opusdec_filter.c @@ -2,9 +2,9 @@ * 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. + * Licensed under the GPL v2, see file COPYING. */ /** \file opusdec_filter.c The ogg/opus decoder. */ @@ -50,7 +50,6 @@ #include "para.h" #include "list.h" #include "sched.h" -#include "ggo.h" #include "buffer_tree.h" #include "filter.h" #include "error.h" @@ -70,8 +69,9 @@ struct opusdec_context { ogg_page ogg_page; bool eos; int channels; - int preskip; + uint16_t preskip; bool have_opus_stream; + bool have_more; ogg_int32_t opus_serialno; }; @@ -141,9 +141,10 @@ static int opusdec_init(ogg_packet *op, struct opusdec_context *ctx) static void opusdec_add_output(short *pcm, int frames_available, struct btr_node *btrn, struct opusdec_context *ctx) { - int tmp_skip, num_frames, bytes; + int num_frames, bytes; + uint16_t tmp_skip; - tmp_skip = PARA_MIN(ctx->preskip, frames_available); + tmp_skip = PARA_MIN((int)ctx->preskip, frames_available); ctx->preskip -= tmp_skip; num_frames = frames_available - tmp_skip; if (num_frames <= 0) @@ -204,72 +205,88 @@ static int decode_packet(struct opusdec_context *ctx, ogg_packet *op, return 1; } -static int opusdec_post_select(__a_unused struct sched *s, struct task *t) +#define OPUSDEC_MAX_OUTPUT_SIZE (1024 * 1024) + +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; } -/** - * The init function of the opusdec filter. - * - * \param f Pointer to the filter struct to initialize. - * - * \sa filter::init. - */ -void opusdec_filter_init(struct filter *f) +static void opusdec_pre_select(struct sched *s, void *context) { - f->open = opusdec_open; - f->close = opusdec_close; - f->pre_select = generic_filter_pre_select; - f->post_select = opusdec_post_select; - f->execute = opusdec_execute; + 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); } + +const struct filter lsg_filter_cmd_com_opusdec_user_data = { + .open = opusdec_open, + .close = opusdec_close, + .pre_select = opusdec_pre_select, + .post_select = opusdec_post_select, + .execute = opusdec_execute, +};