X-Git-Url: http://git.tuebingen.mpg.de/?a=blobdiff_plain;f=aacdec_filter.c;h=c9f81512bf5398c76e51865f8bb4acdd5fa4a5f5;hb=c22fa00c45822fe62a8a921e54f19c012680fc2b;hp=59c49893f59acc58a6df8c5d8b7386b8008c3dca;hpb=ef81b9f4f0fa6a26043c68d429c0deeb7c949351;p=paraslash.git diff --git a/aacdec_filter.c b/aacdec_filter.c index 59c49893..c9f81512 100644 --- a/aacdec_filter.c +++ b/aacdec_filter.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2009 Andre Noll + * Copyright (C) 2006 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -11,20 +11,19 @@ /** \file aacdec_filter.c paraslash's aac (m4a) decoder. */ #include +#include #include "para.h" +#include "portable_io.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,32 +49,181 @@ 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 sample_rate; }; -static ssize_t aacdec(char *input_buffer, size_t len, struct filter_node *fn) +/* + * Get a new libfaad decoder handle. + * + * \return The handle returned by NeAACDecOpen(). + */ +static NeAACDecHandle aac_open(void) +{ + NeAACDecHandle h = NeAACDecOpen(); + NeAACDecConfigurationPtr c = NeAACDecGetCurrentConfiguration(h); + + c->defObjectType = LC; + c->outputFormat = FAAD_FMT_16BIT; + c->downMatrix = 0; + NeAACDecSetConfiguration(h, c); + return h; +} + +static unsigned long aac_read_decoder_length(char *buf, int *description_len) +{ + uint8_t b; + uint8_t numBytes = 0; + unsigned long length = 0; + + do { + b = buf[numBytes]; + numBytes++; + length = (length << 7) | (b & 0x7F); + } while + ((b & 0x80) && numBytes < 4); + *description_len = numBytes; + return length; +} + +/* + * Search for the position and the length of the decoder configuration. + * + * \param buf Buffer to seach. + * \param buflen Length of \a buf. + * \param skip Upon succesful return, this contains the offset in \a buf where + * the decoder config starts. + * \param decoder_length Result pointer that is filled in with the length of + * the decoder configuration on success. + * + * \return Standard. + */ +static int aac_find_esds(char *buf, size_t buflen, size_t *skip, + unsigned long *decoder_length) +{ + size_t i; + + for (i = 0; i + 4 < buflen; i++) { + char *p = buf + i; + int description_len; + + if (p[0] != 'e' || p[1] != 's' || p[2] != 'd' || p[3] != 's') + continue; + i += 8; + p = buf + i; + PARA_INFO_LOG("found esds@%zu, next: %x\n", i, *p); + if (*p == 3) + i += 8; + else + i += 6; + p = buf + i; + PARA_INFO_LOG("next: %x\n", *p); + if (*p != 4) + continue; + i += 18; + p = buf + i; + PARA_INFO_LOG("next: %x\n", *p); + if (*p != 5) + continue; + i++; + p = buf + i; + *decoder_length = aac_read_decoder_length(p, &description_len); + PARA_INFO_LOG("decoder length: %lu\n", *decoder_length); + i += description_len; + *skip = i; + return 1; + } + return -E_ESDS; +} + +/* + * Search for the first entry in the stco table. + * + * \param buf Buffer to seach. + * \param buflen Length of \a buf. + * \param skip Upon succesful return, this contains the number + * of bytes to skip from the input buffer. + * + * \return The position of the first entry in the table on success, + * -E_STCO on errors. + */ +static ssize_t aac_find_entry_point(char *buf, size_t buflen, size_t *skip) +{ + ssize_t ret; + size_t i; + + for (i = 0; i + 20 < buflen; i++) { + char *p = buf + i; + + if (p[0] != 's' || p[1] != 't' || p[2] != 'c' || p[3] != 'o') + continue; + PARA_INFO_LOG("found stco@%zu\n", i); + i += 12; + ret = read_u32_be(buf + i); /* first offset */ + i += 4; + PARA_INFO_LOG("entry point: %zd\n", ret); + *skip = i; + return ret; + } + PARA_WARNING_LOG("stco not found, buflen: %zu\n", buflen); + return -E_STCO; +} + +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; + + return decoder_execute(cmd, padd->sample_rate, padd->channels, result); +} + +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 int aacdec_post_select(__a_unused struct sched *s, void *context) +{ + struct filter_node *fn = context; + 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; + char *p, *inbuf, *outbuffer; + char *btr_buf; + size_t len, skip, consumed, loaded; - if (fn->loaded > fn->bufsize * 3 / 5) - return 0; - ret = *fc->input_error; +next_buffer: + ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL); if (ret < 0) - return ret; - if (len < 2048) + goto err; + if (ret == 0) return 0; - + btr_merge(btrn, fn->min_iqs); + len = btr_next_buffer(btrn, &inbuf); + len = PARA_MIN(len, (size_t)8192); + consumed = 0; 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, + ret = NeAACDecInit(padd->handle, (unsigned char *)inbuf, len, &rate, &channels); PARA_INFO_LOG("decoder init: %d\n", ret); if (ret < 0) { @@ -89,15 +237,15 @@ static ssize_t aacdec(char *input_buffer, size_t len, struct filter_node *fn) consumed += skip; p = inbuf + consumed; ret = -E_AACDEC_INIT; - if (NeAACDecInit2(padd->handle, p, + if (NeAACDecInit2(padd->handle, (unsigned char *)p, padd->decoder_length, &rate, - &channels) < 0) + &channels) != 0) goto out; } - fc->samplerate = rate; - fc->channels = channels; - PARA_INFO_LOG("rate: %u, channels: %d\n", - fc->samplerate, fc->channels); + padd->sample_rate = rate; + padd->channels = channels; + PARA_INFO_LOG("rate: %u, channels: %u\n", + padd->sample_rate, padd->channels); padd->initialized = 1; } if (padd->decoder_length > 0) { @@ -119,78 +267,71 @@ static ssize_t aacdec(char *input_buffer, size_t len, struct filter_node *fn) 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; - outbuffer = NeAACDecDecode(padd->handle, &padd->frame_info, p, - len - 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, + (unsigned char *)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); - PARA_ERROR_LOG("%s\n", NeAACDecGetErrorMessage( - padd->frame_info.error)); - consumed++; /* catch 21 */ + goto err; + /* Suppress non-fatal bitstream error message at BOF/EOF */ + if (len < fn->min_iqs || padd->consumed_total == 0) { + consumed = len; + goto success; + } + PARA_ERROR_LOG("%s\n", NeAACDecGetErrorMessage(err)); + PARA_ERROR_LOG("consumed: %zu + %zu + %lu\n", + padd->consumed_total, consumed, + padd->frame_info.bytesconsumed); + if (consumed < len) + 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; + btr_consume(btrn, ret); + goto next_buffer; + } +err: + assert(ret < 0); + btr_remove_node(&fn->btrn); 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; -} - /** - * 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; }