X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=aacdec_filter.c;h=d48b18e03d729c5617455aa39eb5de91f0ea27ef;hp=59c49893f59acc58a6df8c5d8b7386b8008c3dca;hb=80b5eac6e7363199f62fc39e583a28ce898a0b2b;hpb=ad6c68022eea0b0962855a2120cf242446bf10b9 diff --git a/aacdec_filter.c b/aacdec_filter.c index 59c49893..d48b18e0 100644 --- a/aacdec_filter.c +++ b/aacdec_filter.c @@ -11,20 +11,19 @@ /** \file aacdec_filter.c paraslash's aac (m4a) decoder. */ #include +#include #include "para.h" #include "list.h" #include "sched.h" #include "ggo.h" +#include "buffer_tree.h" #include "filter.h" #include "error.h" #include "string.h" #include "aac.h" -/** the output buffer size */ -#define AAC_OUTBUF_SIZE (32 * 1024) - -/** give up decoding after that many errors */ +/** Give up decoding after that many errors. */ #define MAX_ERRORS 20 /** @@ -50,25 +49,71 @@ 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; }; -static ssize_t aacdec(char *input_buffer, size_t len, struct filter_node *fn) +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 -E_BTR_NAVAIL; + *result = make_message("%u", padd->samplerate); + return 1; + } + if (!strcmp(cmd, "channels")) { + if (padd->channels == 0) + return -E_BTR_NAVAIL; + *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)); + + fn->private_data = padd; + fn->min_iqs = 2048; + padd->handle = aac_open(); +} + +static void aacdec_close(struct filter_node *fn) +{ + struct private_aacdec_data *padd = fn->private_data; + + NeAACDecClose(padd->handle); + free(padd); + 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; - struct filter_chain *fc = fn->fc; int i, ret; - unsigned char *p, *outbuffer; - unsigned char *inbuf = (unsigned char*)input_buffer; - size_t skip, consumed = 0; + unsigned char *p, *inbuf, *outbuffer; + char *btr_buf; + size_t len, skip, consumed, loaded, iqs; - if (fn->loaded > fn->bufsize * 3 / 5) - return 0; - ret = *fc->input_error; +next_buffer: + t->error = 0; + ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL); if (ret < 0) - return ret; - if (len < 2048) - return 0; - + goto err; + if (ret == 0) + return; + btr_merge(btrn, fn->min_iqs); + len = btr_next_buffer(btrn, (char **)&inbuf); + consumed = 0; + iqs = btr_get_input_queue_size(btrn); if (!padd->initialized) { unsigned long rate = 0; unsigned char channels = 0; @@ -94,10 +139,10 @@ static ssize_t aacdec(char *input_buffer, size_t len, struct filter_node *fn) &channels) < 0) goto out; } - fc->samplerate = rate; - fc->channels = channels; + padd->samplerate = rate; + padd->channels = channels; PARA_INFO_LOG("rate: %u, channels: %d\n", - fc->samplerate, fc->channels); + padd->samplerate, padd->channels); padd->initialized = 1; } if (padd->decoder_length > 0) { @@ -125,72 +170,64 @@ static ssize_t aacdec(char *input_buffer, size_t len, struct filter_node *fn) 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 out; - PARA_ERROR_LOG("frame_error: %d, consumed: %zu + %zd + %lu\n", - padd->frame_info.error, padd->consumed_total, - consumed, padd->frame_info.bytesconsumed); + 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; - ret = -E_AAC_OVERRUN; - if (padd->frame_info.samples * 2 + fn->loaded > fn->bufsize) - goto out; + btr_buf = para_malloc(2 * padd->frame_info.samples); + loaded = 0; for (i = 0; i < padd->frame_info.samples; i++) { - short *s = (short *)outbuffer; - write_int16_host_endian(fn->buf + fn->loaded, s[i]); - fn->loaded += 2; + 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) + if (ret >= 0) { padd->consumed_total += ret; - return ret; -} - -static void aacdec_open(struct filter_node *fn) -{ - struct private_aacdec_data *padd = para_calloc(sizeof(*padd)); - - fn->private_data = padd; - fn->bufsize = AAC_OUTBUF_SIZE; - fn->buf = para_calloc(fn->bufsize); - padd->handle = aac_open(); -} - -static void aacdec_close(struct filter_node *fn) -{ - struct private_aacdec_data *padd = fn->private_data; - - NeAACDecClose(padd->handle); - free(fn->buf); - fn->buf = NULL; - free(padd); - fn->private_data = NULL; + btr_consume(btrn, ret); + goto next_buffer; + } +err: + assert(ret < 0); + t->error = ret; + btr_remove_node(btrn); } /** - * the init function of the aacdec filter + * The init function of the aacdec filter. * - * \param f pointer to the filter struct to initialize + * \param f Pointer to the filter struct to initialize. * * \sa filter::init */ void aacdec_filter_init(struct filter *f) { f->open = aacdec_open; - f->convert = aacdec; f->close = aacdec_close; + f->pre_select = generic_filter_pre_select; + f->post_select = aacdec_post_select; + f->execute = aacdec_execute; }