First draft of the aac audio format handler
authorAndre <maan@p133.(none)>
Fri, 12 May 2006 18:38:45 +0000 (20:38 +0200)
committerAndre <maan@p133.(none)>
Fri, 12 May 2006 18:38:45 +0000 (20:38 +0200)
Not working yet. aacdec still works.

Makefile.in
aac.h [new file with mode: 0644]
aac_afh.c [new file with mode: 0644]
aac_common.c [new file with mode: 0644]
aacdec.c
afs.c
afs.h
configure.ac
error.h

index ee0cca6..e221494 100644 (file)
@@ -142,6 +142,12 @@ grab_client.cmdline.h grab_client.cmdline.c: grab_client.ggo
 aacdec.o: aacdec.c
        $(CC) -c $(CPPFLAGS) $(DEBUG_CPPFLAGS) @faad_cppflags@ $<
 
+aac_common.o: aac_common.c
+       $(CC) -c $(CPPFLAGS) $(DEBUG_CPPFLAGS) @faad_cppflags@ $<
+
+aac_afh.o: aac_afh.c
+       $(CC) -c $(CPPFLAGS) $(DEBUG_CPPFLAGS) @faad_cppflags@ $<
+
 para_recv: @recv_objs@
        $(CC) @recv_objs@ -o $@ @recv_ldflags@
 
diff --git a/aac.h b/aac.h
new file mode 100644 (file)
index 0000000..8ae7502
--- /dev/null
+++ b/aac.h
@@ -0,0 +1,5 @@
+#include <neaacdec.h>
+
+/* exported symbols from aac_common.c */
+NeAACDecHandle aac_open(void);
+int aac_find_esds(unsigned char *buf, unsigned buflen, int *skip);
diff --git a/aac_afh.c b/aac_afh.c
new file mode 100644 (file)
index 0000000..436005e
--- /dev/null
+++ b/aac_afh.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2006 Andre Noll <maan@systemlinux.org>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ */
+/** \file aac_afh.c para_server's aac audio format handler */
+
+
+#include "server.cmdline.h"
+#include "server.h"
+#include "afs.h"
+#include "error.h"
+#include "string.h"
+#include "aac.h"
+
+/* must be big enough to hold header */
+#define DEFAULT_INBUF_SIZE 65536
+
+static FILE *infile;
+static int inbuf_size;
+static unsigned char *inbuf;
+static ssize_t *chunk_table;
+struct audio_format *af;
+
+unsigned num_chunks, chunk_num;
+
+NeAACDecHandle handle;
+static void aac_close_audio_file(void)
+{
+}
+
+/*
+ * Init m4a file and write some tech data to given pointers.
+ */
+static int aac_get_file_info(FILE *file, char *info_str, long unsigned *frames,
+       int *seconds)
+{
+       int ret, skip, decoder_len;
+       unsigned inbuf_len;
+       unsigned long rate = 0;
+       unsigned char channels = 0;
+
+       free(inbuf);
+       inbuf_size = DEFAULT_INBUF_SIZE;
+       inbuf = para_malloc(inbuf_size);
+       infile = file;
+
+       PARA_INFO_LOG("file: %p\n", file);
+       ret = read(fileno(infile), inbuf, inbuf_size);
+       PARA_INFO_LOG("read %d bytes\n", ret);
+       if (ret <= 0)
+               return -E_AAC_READ;
+       PARA_INFO_LOG("checking aac %d bytes\n", ret);
+       inbuf_len = ret;
+       ret = aac_find_esds(inbuf, inbuf_len, &skip);
+       if (ret < 0)
+               return ret;
+       decoder_len = ret;
+       handle = aac_open();
+       ret = NeAACDecInit(handle, inbuf + skip,
+               inbuf_len - skip, &rate, &channels);
+       PARA_INFO_LOG("rate: %lu, channels: %d\n", rate, channels);
+       
+       return 1;
+}
+
+/*
+ * Simple stream reposition routine
+ */
+static int aac_reposition_stream(long unsigned request)
+{
+       return -E_AAC_REPOS;
+}
+
+static int get_chunk_size(long unsigned chunk_num)
+{
+       int ret;
+       if (chunk_num >= num_chunks)
+               return -1;
+       ret = chunk_table[chunk_num + 1] - chunk_table[chunk_num];
+       if (!ret)
+               return ret;
+#if 0
+       PARA_DEBUG_LOG("chunk %d: %lli-%lli (%lli bytes)\n",
+               chunk_num,
+               chunk_table[chunk_num],
+               chunk_table[chunk_num + 1] - 1,
+               ret);
+#endif
+       return ret;
+}
+
+char *aac_read_chunk(long unsigned current_chunk, ssize_t *len)
+{
+       return (char *)inbuf;
+}
+
+void aac_afh_init(void *p)
+{
+       af = p;
+       af->reposition_stream = aac_reposition_stream;
+       af->get_file_info = aac_get_file_info,
+       af->read_chunk = aac_read_chunk;
+       af->close_audio_file = aac_close_audio_file;
+       af->get_header_info = NULL;
+       af->chunk_tv.tv_sec = 0;
+       af->chunk_tv.tv_usec = 250 * 1000;
+       tv_scale(3, &af->chunk_tv, &af->eof_tv);
+}
diff --git a/aac_common.c b/aac_common.c
new file mode 100644 (file)
index 0000000..16109b9
--- /dev/null
@@ -0,0 +1,95 @@
+#include "para.h"
+#include "aac.h"
+#include "error.h"
+
+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 int aac_read_decoder_length(unsigned char *buf, int *description_len)
+{
+       uint8_t b;
+       uint8_t numBytes = 0;
+       uint32_t length = 0;
+
+       do {
+               b = buf[numBytes];
+               numBytes++;
+               length = (length << 7) | (b & 0x7F);
+       } while
+               ((b & 0x80) && numBytes < 4);
+       *description_len = numBytes;
+       return length;
+}
+
+int aac_find_esds(unsigned char *buf, unsigned buflen, int *skip)
+{
+       int i;
+
+       for (i = 0; i + 4 < buflen; i++) {
+               unsigned char *p = buf + i;
+               int decoder_length, 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@%d, 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++;
+               decoder_length = aac_read_decoder_length(p, &description_len);
+               PARA_INFO_LOG("decoder length: %d\n", decoder_length);
+               i += description_len;
+               *skip = i;
+               return decoder_length;
+       }
+       return -E_ESDS;
+}
+
+unsigned aac_read_int32(unsigned char *buf)
+{
+       uint8_t *d = (uint8_t*)buf;
+       return (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3];
+}
+
+
+int find_stco(unsigned char *buf, unsigned buflen, int *skip)
+{
+       int i, ret;
+
+       for (i = 0; i + 16 < buflen; i++) {
+               unsigned char *p = buf + i;
+
+               if (p[0] != 's' || p[1] != 't' || p[2] != 'c' || p[3] != 'o')
+                       continue;
+               PARA_INFO_LOG("found stco@%d\n", i);
+               i += 8;
+               ret = aac_read_int32(buf + i);
+               i += 4;
+               PARA_INFO_LOG("num entries: %d\n", ret);
+               *skip = i;
+               return ret;
+       }
+       return -E_STCO;
+}
+
index 0eab773..7ea7856 100644 (file)
--- a/aacdec.c
+++ b/aacdec.c
 #include "list.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
@@ -44,9 +42,7 @@
  */
 struct private_mp4dec_data {
        NeAACDecHandle decoder;
-       NeAACDecConfigurationPtr config;
        NeAACDecFrameInfo frame_info;
-       mp4AudioSpecificConfig mp4ASC;
 
        int initialized;
        int decoder_length;
@@ -57,61 +53,10 @@ struct private_mp4dec_data {
 
        unsigned noffsets;
        unsigned *offset;
+       unsigned offset0;
        int offset_pos;
 };
 
-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);
@@ -173,7 +118,9 @@ static ssize_t mp4dec(char *inbuffer, size_t len, struct filter_node *fn)
        padd->inbuf_len = len;
 
        if (!padd->initialized) {
-               padd->decoder_length = find_esds(padd);
+               int skip;
+               padd->decoder_length = aac_find_esds(padd->inbuf, padd->inbuf_len,
+                       &skip);
                if (padd->decoder_length < 0) {
                        ret = NeAACDecInit(padd->decoder, padd->inbuf,
                                padd->inbuf_len, &rate, &channels);
@@ -183,6 +130,7 @@ static ssize_t mp4dec(char *inbuffer, size_t len, struct filter_node *fn)
                        }
                        padd->consumed = ret;
                } else {
+                       padd->consumed += skip;
                        p = padd->inbuf + padd->consumed;
                        ret = E_AACDEC_INIT;
                        if (NeAACDecInit2(padd->decoder, p,
@@ -260,13 +208,7 @@ static void mp4dec_open(struct filter_node *fn)
 
        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->decoder = aac_open();
 }
 
 static void mp4dec_close(struct filter_node *fn)
diff --git a/afs.c b/afs.c
index 6cc58bb..29bae16 100644 (file)
--- a/afs.c
+++ b/afs.c
  * the current audio format, audio file selector and of the activated senders.
  */
 
+#include "server.h"
 #include <sys/time.h> /* gettimeofday */
 #include "server.cmdline.h"
 #include "db.h"
-#include "server.h"
 #include "afs.h"
 #include "send.h"
 #include "error.h"
@@ -51,6 +51,9 @@ static FILE *audio_file = NULL;
 #ifdef HAVE_OGGVORBIS
        void ogg_init(void *);
 #endif
+#ifdef HAVE_FAAD
+       void aac_afh_init(void *);
+#endif
 
 /**
  * the list of supported  audio formats
@@ -67,6 +70,12 @@ struct audio_format afl[] = {
                .name = "ogg",
                .init = ogg_init,
        },
+#endif
+#ifdef HAVE_FAAD
+       {
+               .name = "aac",
+               .init = aac_afh_init,
+       },
 #endif
        {
                .name = NULL,
diff --git a/afs.h b/afs.h
index f1dc9b9..cc96dbb 100644 (file)
--- a/afs.h
+++ b/afs.h
 #define OV_AUDIO_FORMAT_ARRAY
 #endif
 
-#define SUPPORTED_AUDIO_FORMATS "mp3" OV_AUDIO_FORMAT
-#define SUPPORTED_AUDIO_FORMATS_ARRAY "mp3" OV_AUDIO_FORMAT_ARRAY, NULL
+#ifdef HAVE_FAAD
+#define AAC_AUDIO_FORMAT " aac"
+#define AAC_AUDIO_FORMAT_ARRAY , "aac"
+#else
+#define AAC_AUDIO_FORMAT ""
+#define AAC_AUDIO_FORMAT_ARRAY
+#endif
 
+#define SUPPORTED_AUDIO_FORMATS "mp3" OV_AUDIO_FORMAT AAC_AUDIO_FORMAT
+#define SUPPORTED_AUDIO_FORMATS_ARRAY "mp3" OV_AUDIO_FORMAT_ARRAY \
+       AAC_AUDIO_FORMAT_ARRAY, NULL
 
 /* status flags */
 #define AFS_NOMORE 1
index 91cd284..8972090 100644 (file)
@@ -233,8 +233,10 @@ AC_CHECK_HEADER(neaacdec.h, [], have_faad=no)
 AC_CHECK_LIB([faad], [NeAACDecOpen], [], have_faad=no)
 if test "$have_faad" = "yes"; then
        AC_DEFINE(HAVE_FAAD, 1, define to 1 if you want to build the aacdec filter)
-       filter_errlist_objs="$filter_errlist_objs aacdec"
-       audiod_errlist_objs="$audiod_errlist_objs aacdec"
+       filter_errlist_objs="$filter_errlist_objs aacdec aac_common"
+       audiod_errlist_objs="$audiod_errlist_objs aacdec aac_common"
+       server_errlist_objs="$server_errlist_objs aac_afh aac_common"
+       server_ldflags="$server_ldflags $faad_libs -lfaad"
        filter_ldflags="$filter_ldflags $faad_libs -lfaad"
        audiod_ldflags="$audiod_ldflags $faad_libs -lfaad"
        AC_SUBST(faad_cppflags)
diff --git a/error.h b/error.h
index 614390f..eda6962 100644 (file)
--- a/error.h
+++ b/error.h
@@ -48,8 +48,10 @@ enum para_subsystem {
        SS_DB,
        SS_OGG,
        SS_MP3,
+       SS_AAC_AFH,
        SS_MP3DEC,
        SS_AACDEC,
+       SS_AAC_COMMON,
        SS_SERVER,
        SS_AFS,
        SS_MYSQL_SELECTOR,
@@ -188,6 +190,15 @@ extern const char **para_errlist[];
        PARA_ERROR(HEADER_BITRATE, "invalid header bitrate"), \
 
 
+#define AAC_AFH_ERRORS \
+       PARA_ERROR(AAC_REPOS, "aac repositioning error"), \
+       PARA_ERROR(AAC_READ, "aac read error"), \
+
+
+#define AAC_COMMON_ERRORS \
+       PARA_ERROR(AAC_OPEN, "NeAACDecOpen() failed"), \
+       PARA_ERROR(AAC_BUF, "invalid buffer"), \
+
 #define OGG_ERRORS \
        PARA_ERROR(OGG_READ, "ogg read error"), \
        PARA_ERROR(SYNC_PAGEOUT, "ogg sync page-out error (no ogg file?)"), \
@@ -448,6 +459,8 @@ SS_ENUM(AACDEC);
 SS_ENUM(FILTER);
 SS_ENUM(MP3);
 SS_ENUM(OGG);
+SS_ENUM(AAC_AFH);
+SS_ENUM(AAC_COMMON);
 SS_ENUM(SERVER);
 SS_ENUM(AFS);
 SS_ENUM(COMMAND);