From 5b9bdbe0a5fe533818259ad75d4785033057f598 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Sat, 2 Jan 2010 23:03:54 +0100 Subject: [PATCH] Add buffer tree support for the aacdec filter. --- aacdec_filter.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++ error.h | 1 + 2 files changed, 183 insertions(+) diff --git a/aacdec_filter.c b/aacdec_filter.c index ae3a90e6..0b520da4 100644 --- a/aacdec_filter.c +++ b/aacdec_filter.c @@ -52,8 +52,28 @@ struct private_aacdec_data { size_t consumed_total; /** return value of aac_find_entry_point */ size_t entry; + /** The number of channels of the current stream. */ + unsigned int channels; + /** Current sample rate in Hz. */ + unsigned int samplerate; }; +#define AACDEC_MAX_PENDING (640 * 1024) + +static void aacdec_pre_select(struct sched *s, struct task *t) +{ + struct filter_node *fn = container_of(t, struct filter_node, task); + size_t iqs = btr_get_input_queue_size(fn->btrn); + + t->error = 0; + if (iqs == 0) + return; + if (btr_bytes_pending(fn->btrn) > AACDEC_MAX_PENDING) + return; /* FIXME, should use reasonable bound on timeout */ + s->timeout.tv_sec = 0; + s->timeout.tv_usec = 1; +} + static ssize_t aacdec(char *input_buffer, size_t len, struct filter_node *fn) { struct private_aacdec_data *padd = fn->private_data; @@ -162,6 +182,26 @@ out: return ret; } +static int aacdec_execute(struct btr_node *btrn, const char *cmd, char **result) +{ + struct filter_node *fn = btr_context(btrn); + struct private_aacdec_data *padd = fn->private_data; + + if (!strcmp(cmd, "samplerate")) { + if (padd->samplerate == 0) + return -ERRNO_TO_PARA_ERROR(ENAVAIL); + *result = make_message("%u", padd->samplerate); + return 1; + } + if (!strcmp(cmd, "channels")) { + if (padd->channels == 0) + return -ERRNO_TO_PARA_ERROR(ENAVAIL); + *result = make_message("%u", padd->channels); + return 1; + } + return -ERRNO_TO_PARA_ERROR(ENOTSUP); +} + static void aacdec_open(struct filter_node *fn) { struct private_aacdec_data *padd = para_calloc(sizeof(*padd)); @@ -183,6 +223,144 @@ static void aacdec_close(struct filter_node *fn) fn->private_data = NULL; } +static void aacdec_post_select(__a_unused struct sched *s, struct task *t) +{ + struct filter_node *fn = container_of(t, struct filter_node, task); + struct btr_node *btrn = fn->btrn; + struct private_aacdec_data *padd = fn->private_data; + int i, ret; + unsigned char *p, *inbuf, *outbuffer; + char *btr_buf; + size_t len, skip, consumed = 0, loaded, iqs; + +next_buffer: + t->error = 0; + iqs = btr_get_input_queue_size(btrn); + if (iqs < 2048) { + if (!btr_no_parent(btrn)) /* wait for more data */ + return; + } + if (btr_bytes_pending(btrn) > AACDEC_MAX_PENDING) + return; + /* avoid "buffer too small" errors from the decoder */ + for (;;) { + len = btr_next_buffer(btrn, (char **)&inbuf); + if (len >= 2048) + break; + if (btr_merge(btrn) < 2) /* only one buffer left */ + break; + } + //PARA_CRIT_LOG("next buffer: %zu\n", len); + if (len == 0) { + if (btr_no_parent(btrn)) { + ret = -E_AACDEC_EOF; + goto err; + } + return; + } + if (!padd->initialized) { + unsigned long rate = 0; + unsigned char channels = 0; + ret = aac_find_esds(inbuf, len, &skip, &padd->decoder_length); + if (ret < 0) { + PARA_INFO_LOG("%s\n", para_strerror(-ret)); + ret = NeAACDecInit(padd->handle, inbuf, + len, &rate, &channels); + PARA_INFO_LOG("decoder init: %d\n", ret); + if (ret < 0) { + ret = -E_AACDEC_INIT; + goto out; + } + consumed = ret; + } else { + PARA_INFO_LOG("decoder len: %lu\n", + padd->decoder_length); + consumed += skip; + p = inbuf + consumed; + ret = -E_AACDEC_INIT; + if (NeAACDecInit2(padd->handle, p, + padd->decoder_length, &rate, + &channels) < 0) + goto out; + } + padd->samplerate = rate; + padd->channels = channels; + PARA_INFO_LOG("rate: %u, channels: %d\n", + padd->samplerate, padd->channels); + padd->initialized = 1; + } + if (padd->decoder_length > 0) { + consumed = 0; + if (!padd->entry) { + ret = aac_find_entry_point(inbuf + consumed, + len - consumed, &skip); + if (ret < 0) { + ret = len; + goto out; + } + consumed += skip; + padd->entry = ret; + PARA_INFO_LOG("entry: %zu\n", padd->entry); + } + ret = len; + if (padd->consumed_total + len < padd->entry) + goto out; + if (padd->consumed_total < padd->entry) + consumed = padd->entry - padd->consumed_total; + } + for (; consumed < len; consumed++) + if ((inbuf[consumed] & 0xfe) == 0x20) + break; + if (consumed >= len) + goto success; + p = inbuf + consumed; + //PARA_CRIT_LOG("consumed: %zu (%zu + %zu), have: %zu\n", padd->consumed_total + consumed, + // padd->consumed_total, consumed, len - consumed); + outbuffer = NeAACDecDecode(padd->handle, &padd->frame_info, p, + len - consumed); + if (padd->frame_info.error) { + int err = padd->frame_info.error; + ret = -E_AAC_DECODE; + if (padd->error_count++ > MAX_ERRORS) + goto err; + PARA_ERROR_LOG("frame_error: %d (%s), consumed: %zu + %zd + %lu\n", + err, NeAACDecGetErrorMessage(padd->frame_info.error), + padd->consumed_total, consumed, + padd->frame_info.bytesconsumed); + PARA_ERROR_LOG("%s\n", NeAACDecGetErrorMessage( + padd->frame_info.error)); + consumed++; /* catch 21 */ + goto success; + } + padd->error_count = 0; + //PARA_CRIT_LOG("decoder ate %lu\n", padd->frame_info.bytesconsumed); + consumed += padd->frame_info.bytesconsumed; + ret = consumed; + if (!padd->frame_info.samples) + goto out; + btr_buf = para_malloc(2 * padd->frame_info.samples); + loaded = 0; + for (i = 0; i < padd->frame_info.samples; i++) { + short sh = ((short *)outbuffer)[i]; + write_int16_host_endian(btr_buf + loaded, sh); + loaded += 2; + } + btr_add_output(btr_buf, loaded, btrn); +success: + ret = consumed; +out: + if (ret >= 0) { + padd->consumed_total += ret; + btr_consume(btrn, ret); + goto next_buffer; + } +err: + assert(ret < 0); + aacdec_close(fn); + t->error = ret; + btr_del_node(btrn); +} + /** * the init function of the aacdec filter * @@ -195,4 +373,8 @@ void aacdec_filter_init(struct filter *f) f->open = aacdec_open; f->convert = aacdec; f->close = aacdec_close; + f->pre_select = aacdec_pre_select; + f->post_select = aacdec_post_select; + f->post_select = aacdec_post_select; + f->execute = aacdec_execute; } diff --git a/error.h b/error.h index 3817da13..0a491690 100644 --- a/error.h +++ b/error.h @@ -427,6 +427,7 @@ extern const char **para_errlist[]; PARA_ERROR(AACDEC_INIT, "failed to init aac decoder"), \ PARA_ERROR(AAC_DECODE, "aac decode error"), \ PARA_ERROR(AAC_OVERRUN, "aac output buffer overrun"), \ + PARA_ERROR(AACDEC_EOF, "aacdec: end of file"), \ #define CHUNK_QUEUE_ERRORS \ -- 2.39.5