* Copyright (c) 2002-2007 Jean-Marc Valin
* Copyright (c) 2008 CSIRO
* Copyright (c) 2007-2012 Xiph.Org Foundation
- * Copyright (C) 2012-2013 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 2012 Andre Noll <maan@tuebingen.mpg.de>
*
* Licensed under the GPL v2. For licencing details see COPYING.
*/
#include "para.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "filter.h"
#include "error.h"
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;
};
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)
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,
+};