* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*/
-
/*
* based in parts on libfaad, Copyright (C) 2003-2005 M. Bakker,
* Ahead Software AG
*/
-/** \file aacdec.c paraslash's mp3 decoder */
+/** \file aacdec.c paraslash's aac (m4a) decoder */
#include "para.h"
#include "list.h"
+#include "sched.h"
#include "filter.h"
#include "error.h"
-#include <mad.h>
#include "string.h"
-
-#include <neaacdec.h>
+#include "aac.h"
/** the output buffer size */
-#define MAX_CHANNELS 6
-#define AAC_OUTBUF_SIZE (FAAD_MIN_STREAMSIZE * MAX_CHANNELS)
+#define AAC_OUTBUF_SIZE (32 * 1024)
+
+#define MAX_ERRORS 20
/**
* data specific to the aacdec filter
*
* \sa filter, filter_node
*/
-struct private_mp4dec_data {
- NeAACDecHandle decoder;
- NeAACDecConfigurationPtr config;
+struct private_aacdec_data {
+ NeAACDecHandle handle;
NeAACDecFrameInfo frame_info;
- mp4AudioSpecificConfig mp4ASC;
int initialized;
int decoder_length;
- unsigned char *inbuf;
- int inbuf_len;
- int consumed;
- long unsigned consumed_total;
-
- unsigned noffsets;
- unsigned *offset;
- int offset_pos;
+ unsigned error_count;
+ size_t consumed_total;
+ size_t entry;
};
-static int read_mp4_descr_length(struct private_mp4dec_data *padd)
-{
- uint8_t b;
- uint8_t numBytes = 0;
- uint32_t length = 0;
-
- do {
- b = padd->inbuf[padd->consumed + numBytes];
- numBytes++;
- length = (length << 7) | (b & 0x7F);
- } while
- ((b & 0x80) && numBytes < 4);
- padd->consumed += numBytes;
- return length;
-}
-
-static int find_esds(struct private_mp4dec_data *padd)
-{
- for (; padd->consumed < padd->inbuf_len; padd->consumed++) {
- unsigned char *p = padd->inbuf + padd->consumed;
- int decoder_length;
-
- if (p[0] != 'e' || p[1] != 's' || p[2] != 'd' || p[3] != 's')
- continue;
- padd->consumed += 8;
- p = padd->inbuf + padd->consumed;
- PARA_INFO_LOG("found esds: %d, next: %x\n", padd->consumed, *p);
- if (*p == 3)
- padd->consumed += 8;
- else
- padd->consumed += 6;
- p = padd->inbuf + padd->consumed;
- PARA_INFO_LOG("next: %x\n", *p);
- if (*p != 4)
- continue;
- padd->consumed += 18;
- p = padd->inbuf + padd->consumed;
- PARA_INFO_LOG("next: %x\n", *p);
- if (*p != 5)
- continue;
- padd->consumed++;
- decoder_length = read_mp4_descr_length(padd);
- PARA_INFO_LOG("decoder length: %d\n", decoder_length);
- p = padd->inbuf + padd->consumed;
- PARA_INFO_LOG("decoder data0: %x\n", *p & 0xff);
- p++;
- PARA_INFO_LOG("decoder data1: %x\n", *p & 0xff);
- return decoder_length;
- }
- return -E_ESDS;
-}
-
-static int read_int32(struct private_mp4dec_data *padd, unsigned *result)
-{
- uint8_t *d = (uint8_t*)(padd->inbuf + padd->consumed);
- if (padd->consumed + 4 > padd->inbuf_len)
- return -1;
- padd->consumed += 4;
- *result = (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3];
- return 1;
-}
-
-static int fill_offset_table(struct private_mp4dec_data *padd)
+static ssize_t aacdec(char *input_buffer, size_t len, struct filter_node *fn)
{
+ struct private_aacdec_data *padd = fn->private_data;
+ struct filter_chain *fc = fn->fc;
int i, ret;
-
- for (i = padd->offset_pos; i < padd->noffsets; i++) {
- ret = read_int32(padd, &padd->offset[i]);
- if (ret < 0)
- return -1;
- PARA_DEBUG_LOG("offset #%d: %d\n", i, padd->offset[i]);
- padd->offset_pos++;
- }
- return 1;
-}
-
-static int find_stco(struct private_mp4dec_data *padd)
-{
- int ret;
-
- for (; padd->consumed < padd->inbuf_len; padd->consumed++) {
- unsigned char *p = padd->inbuf + padd->consumed;
-
- if (p[0] != 's' || p[1] != 't' || p[2] != 'c' || p[3] != 'o')
- continue;
- PARA_INFO_LOG("found stco: %d\n", padd->consumed);
- padd->consumed += 8;
- ret = read_int32(padd, &padd->noffsets);
- padd->offset = para_malloc(padd->noffsets * sizeof(int));
- PARA_INFO_LOG("num entries: %d\n", padd->noffsets);
- return 1;
- }
- return -E_STCO;
-}
-
-static ssize_t mp4dec(char *inbuffer, size_t len, struct filter_node *fn)
-{
- struct private_mp4dec_data *padd = fn->private_data;
- struct filter_chain_info *fci = fn->fci;
- unsigned long rate = 0;
- unsigned char channels = 0;
- int i, ret, nbytes;
unsigned char *p, *outbuffer;
+ unsigned char *inbuf = (unsigned char*)input_buffer;
+ size_t skip, consumed = 0;
- if (fn->loaded > fn->bufsize * 4 / 5)
+ if (fn->loaded > fn->bufsize * 3 / 5)
return 0;
- if (len < 1000 && !*fci->eof)
+ if (len < 2048 && !*fc->input_eof)
return 0;
- padd->consumed = 0;
- padd->inbuf = (unsigned char*)inbuffer;
- padd->inbuf_len = len;
if (!padd->initialized) {
- padd->decoder_length = find_esds(padd);
+ unsigned long rate = 0;
+ unsigned char channels = 0;
+ padd->decoder_length = aac_find_esds(inbuf, len, &skip);
+ PARA_INFO_LOG("decoder len: %d\n", padd->decoder_length);
if (padd->decoder_length < 0) {
- ret = NeAACDecInit(padd->decoder, padd->inbuf,
- padd->inbuf_len, &rate, &channels);
+ ret = NeAACDecInit(padd->handle, inbuf,
+ len, &rate, &channels);
+ PARA_INFO_LOG("decoder init: %d\n", ret);
if (ret < 0) {
- ret = E_AACDEC_INIT;
+ ret = -E_AACDEC_INIT;
goto out;
}
- padd->consumed = ret;
+ consumed = ret;
} else {
- p = padd->inbuf + padd->consumed;
- ret = E_AACDEC_INIT;
- if (NeAACDecInit2(padd->decoder, p,
+ consumed += skip;
+ p = inbuf + consumed;
+ ret = -E_AACDEC_INIT;
+ if (NeAACDecInit2(padd->handle, p,
padd->decoder_length, &rate,
&channels) < 0)
goto out;
}
- fci->samplerate = rate;
- fci->channels = channels;
- PARA_INFO_LOG("rate: %u, channels: %d\n", fci->samplerate,
- fci->channels);
+ fc->samplerate = rate;
+ fc->channels = channels;
+ PARA_INFO_LOG("rate: %u, channels: %d\n",
+ fc->samplerate, fc->channels);
padd->initialized = 1;
}
if (padd->decoder_length > 0) {
- padd->consumed = 0;
- if (!padd->offset_pos) {
- ret = len;
- if (find_stco(padd) < 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);
}
- if (padd->offset_pos < padd->noffsets) {
- fill_offset_table(padd);
- ret = padd->consumed;
- goto out;
- }
-// PARA_INFO_LOG("consumed total: %lu, first_chunk: %d\n",
-// padd->consumed_total, padd->offset[0]);
ret = len;
- if (padd->consumed_total + len < padd->offset[0])
+ if (padd->consumed_total + len < padd->entry)
goto out;
- if (padd->consumed_total < padd->offset[0])
- padd->consumed = padd->offset[0] - padd->consumed_total;
+ if (padd->consumed_total < padd->entry)
+ consumed = padd->entry - padd->consumed_total;
}
- for (; padd->consumed < padd->inbuf_len; padd->consumed++)
- if ((padd->inbuf[padd->consumed] & 0xfe) == 0x20)
+ for (; consumed < len; consumed++)
+ if ((inbuf[consumed] & 0xfe) == 0x20)
break;
- if (padd->consumed >= padd->inbuf_len)
+ if (consumed >= len)
goto success;
- p = padd->inbuf + padd->consumed;
-// PARA_NOTICE_LOG("p[0]: %lx\n", (long unsigned) *p);
- outbuffer = NeAACDecDecode(padd->decoder, &padd->frame_info, p,
- len - padd->consumed);
- ret = -E_AAC_DECODE;
- if (padd->frame_info.error != 0) {
- PARA_ERROR_LOG("frame_error: %d, consumed: %lu + %d + %lu\n",
+ p = inbuf + consumed;
+ outbuffer = NeAACDecDecode(padd->handle, &padd->frame_info, p,
+ len - consumed);
+ if (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,
- padd->consumed, padd->frame_info.bytesconsumed);
+ consumed, padd->frame_info.bytesconsumed);
PARA_ERROR_LOG("%s\n", NeAACDecGetErrorMessage(
padd->frame_info.error));
- padd->consumed++; /* catch 21 */
+ consumed++; /* catch 21 */
goto success;
}
- padd->consumed += padd->frame_info.bytesconsumed;
- ret = padd->consumed;
+ padd->error_count = 0;
+ consumed += padd->frame_info.bytesconsumed;
+ ret = consumed;
if (!padd->frame_info.samples)
goto out;
- nbytes = padd->frame_info.samples;
+ ret = -E_AAC_OVERRUN;
+ if (padd->frame_info.samples * 2 + fn->loaded > fn->bufsize)
+ goto out;
for (i = 0; i < padd->frame_info.samples; i++) {
short *s = (short *)outbuffer;
fn->buf[fn->loaded++] = s[i] & 0xff;
fn->buf[fn->loaded++] = (s[i] >> 8) & 0xff;
}
success:
- ret = padd->consumed;
+ ret = consumed;
out:
if (ret > 0)
padd->consumed_total += ret;
return ret;
}
-static void mp4dec_open(struct filter_node *fn)
+static void aacdec_open(struct filter_node *fn)
{
- fn->private_data = para_calloc(sizeof(struct private_mp4dec_data));
- struct private_mp4dec_data *padd = fn->private_data;
+ fn->private_data = para_calloc(sizeof(struct private_aacdec_data));
+ struct private_aacdec_data *padd = fn->private_data;
fn->bufsize = AAC_OUTBUF_SIZE;
fn->buf = para_calloc(fn->bufsize);
-
- padd->decoder = NeAACDecOpen();
- padd->config = NeAACDecGetCurrentConfiguration(padd->decoder);
- padd->config->defObjectType = LC;
- padd->config->outputFormat = FAAD_FMT_16BIT;
- padd->config->downMatrix = 0;
- NeAACDecSetConfiguration(padd->decoder, padd->config);
+ padd->handle = aac_open();
}
-static void mp4dec_close(struct filter_node *fn)
+static void aacdec_close(struct filter_node *fn)
{
- struct private_mp4dec_data *padd = fn->private_data;
+ struct private_aacdec_data *padd = fn->private_data;
- NeAACDecClose(padd->decoder);
+ NeAACDecClose(padd->handle);
free(fn->buf);
fn->buf = NULL;
free(padd);
}
/**
- * the init function of the mp3dec filter
+ * the init function of the aacdec filter
*
* \sa filter::init
*/
void aacdec_init(struct filter *f)
{
- f->open = mp4dec_open;
- f->convert = mp4dec;
- f->close = mp4dec_close;
+ f->open = aacdec_open;
+ f->convert = aacdec;
+ f->close = aacdec_close;
}