summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMohamed Tarek <mt@rockbox.org>2009-08-04 13:54:06 +0000
committerMohamed Tarek <mt@rockbox.org>2009-08-04 13:54:06 +0000
commit26cee86a0ca354ac15d46fb92db0cc9a776dd4b2 (patch)
tree2b06da998cff4e4cdfcd7545b6d616116ec947e5
parent7996e773340698a6d8c7bcdc465b8a9245f65601 (diff)
downloadrockbox-26cee86a0ca354ac15d46fb92db0cc9a776dd4b2.tar.gz
rockbox-26cee86a0ca354ac15d46fb92db0cc9a776dd4b2.zip
Add support for AC3 audio in RM container.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@22155 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/codecs/SOURCES1
-rw-r--r--apps/codecs/codecs.make1
-rw-r--r--apps/codecs/dnet.c190
-rw-r--r--apps/codecs/librm/rm.c14
-rw-r--r--apps/codecs/librm/rm.h7
-rw-r--r--apps/metadata.c3
-rw-r--r--apps/metadata.h1
-rw-r--r--apps/metadata/rm.c22
8 files changed, 231 insertions, 8 deletions
diff --git a/apps/codecs/SOURCES b/apps/codecs/SOURCES
index dc6819d272..92e4d2d254 100644
--- a/apps/codecs/SOURCES
+++ b/apps/codecs/SOURCES
@@ -11,6 +11,7 @@ alac.c
#endif
cook.c
raac.c
+dnet.c
mpc.c
wma.c
sid.c
diff --git a/apps/codecs/codecs.make b/apps/codecs/codecs.make
index b327bd7c69..41f5bdccd1 100644
--- a/apps/codecs/codecs.make
+++ b/apps/codecs/codecs.make
@@ -77,6 +77,7 @@ $(CODECDIR)/wavpack_enc.codec: $(CODECDIR)/libwavpack.a
$(CODECDIR)/asap.codec : $(CODECDIR)/libasap.a
$(CODECDIR)/cook.codec : $(CODECDIR)/libcook.a $(CODECDIR)/librm.a
$(CODECDIR)/raac.codec : $(CODECDIR)/libfaad.a $(CODECDIR)/librm.a
+$(CODECDIR)/dnet.codec : $(CODECDIR)/liba52.a $(CODECDIR)/librm.a
$(CODECS): $(CODECLIB) # this must be last in codec dependency list
diff --git a/apps/codecs/dnet.c b/apps/codecs/dnet.c
new file mode 100644
index 0000000000..12352ed903
--- /dev/null
+++ b/apps/codecs/dnet.c
@@ -0,0 +1,190 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id:$
+ *
+ * Copyright (C) 2009 Mohamed Tarek
+ *
+ * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "codeclib.h"
+#include <codecs/librm/rm.h>
+#include <inttypes.h> /* Needed by a52.h */
+#include <codecs/liba52/config-a52.h>
+#include <codecs/liba52/a52.h>
+
+CODEC_HEADER
+
+#define BUFFER_SIZE 4096
+
+#define A52_SAMPLESPERFRAME (6*256)
+
+static a52_state_t *state;
+unsigned long samplesdone;
+unsigned long frequency;
+RMContext rmctx;
+RMPacket pkt;
+
+static void init_rm(RMContext *rmctx)
+{
+ memcpy(rmctx, (void*)(( (intptr_t)ci->id3->id3v2buf + 3 ) &~ 3), sizeof(RMContext));
+}
+
+/* used outside liba52 */
+static uint8_t buf[3840] IBSS_ATTR;
+
+static inline void output_audio(sample_t *samples)
+{
+ ci->yield();
+ ci->pcmbuf_insert(&samples[0], &samples[256], 256);
+}
+
+static void a52_decode_data(uint8_t *start, uint8_t *end)
+{
+ static uint8_t *bufptr = buf;
+ static uint8_t *bufpos = buf + 7;
+ /*
+ * sample_rate and flags are static because this routine could
+ * exit between the a52_syncinfo() and the ao_setup(), and we want
+ * to have the same values when we get back !
+ */
+ static int sample_rate;
+ static int flags;
+ int bit_rate;
+ int len;
+
+ while (1) {
+ len = end - start;
+ if (!len)
+ break;
+ if (len > bufpos - bufptr)
+ len = bufpos - bufptr;
+ memcpy(bufptr, start, len);
+ bufptr += len;
+ start += len;
+ if (bufptr == bufpos) {
+ if (bufpos == buf + 7) {
+ int length;
+
+ length = a52_syncinfo(buf, &flags, &sample_rate, &bit_rate);
+ if (!length) {
+ //DEBUGF("skip\n");
+ for (bufptr = buf; bufptr < buf + 6; bufptr++)
+ bufptr[0] = bufptr[1];
+ continue;
+ }
+ bufpos = buf + length;
+ } else {
+ /* Unity gain is 1 << 26, and we want to end up on 28 bits
+ of precision instead of the default 30.
+ */
+ level_t level = 1 << 24;
+ sample_t bias = 0;
+ int i;
+
+ /* This is the configuration for the downmixing: */
+ flags = A52_STEREO | A52_ADJUST_LEVEL;
+
+ if (a52_frame(state, buf, &flags, &level, bias))
+ goto error;
+ a52_dynrng(state, NULL, NULL);
+ frequency = sample_rate;
+
+ /* An A52 frame consists of 6 blocks of 256 samples
+ So we decode and output them one block at a time */
+ for (i = 0; i < 6; i++) {
+ if (a52_block(state))
+ goto error;
+ output_audio(a52_samples(state));
+ samplesdone += 256;
+ }
+ ci->set_elapsed(samplesdone/(frequency/1000));
+ bufptr = buf;
+ bufpos = buf + 7;
+ continue;
+ error:
+ //logf("Error decoding A52 stream\n");
+ bufptr = buf;
+ bufpos = buf + 7;
+ }
+ }
+ }
+}
+
+
+/* this is the codec entry point */
+enum codec_status codec_main(void)
+{
+ size_t n;
+ uint8_t *filebuf;
+ int retval, consumed, packet_offset;
+
+ /* Generic codec initialisation */
+ ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
+ ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
+
+next_track:
+ if (codec_init()) {
+ retval = CODEC_ERROR;
+ goto exit;
+ }
+
+ while (!ci->taginfo_ready)
+ ci->yield();
+
+ ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
+ codec_set_replaygain(ci->id3);
+
+ /* Intializations */
+ state = a52_init(0);
+ ci->memset(&rmctx,0,sizeof(RMContext));
+ ci->memset(&pkt,0,sizeof(RMPacket));
+ init_rm(&rmctx);
+
+ /* Seek to the first packet */
+ ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE );
+
+ /* The main decoding loop */
+ while(pkt.timestamp < rmctx.duration) {
+ ci->yield();
+ if (ci->stop_codec || ci->new_track)
+ break;
+
+ if (ci->seek_time) {
+ packet_offset = ci->seek_time / (((rmctx.block_align + PACKET_HEADER_SIZE)*8*1000)/rmctx.bit_rate);
+ ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + packet_offset*(rmctx.block_align + PACKET_HEADER_SIZE));
+ samplesdone = A52_SAMPLESPERFRAME * packet_offset;
+ ci->seek_complete();
+ }
+
+ filebuf = ci->request_buffer(&n, rmctx.block_align + PACKET_HEADER_SIZE);
+ consumed = rm_get_packet(&filebuf, &rmctx, &pkt);
+ if(consumed < 0) {
+ DEBUGF("rm_get_packet failed\n");
+ return CODEC_ERROR;
+ }
+ a52_decode_data(filebuf, filebuf + rmctx.block_align);
+ ci->advance_buffer(pkt.length);
+ }
+
+ retval = CODEC_OK;
+
+ if (ci->request_next_track())
+ goto next_track;
+
+exit:
+ a52_free(state);
+ return retval;
+}
diff --git a/apps/codecs/librm/rm.c b/apps/codecs/librm/rm.c
index c802a0c5a9..b205e7f88d 100644
--- a/apps/codecs/librm/rm.c
+++ b/apps/codecs/librm/rm.c
@@ -27,6 +27,8 @@
#include "codeclib.h"
#endif
+#define SWAP(a, b) do{uint8_t SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0)
+
void advance_buffer(uint8_t **buf, int val)
{
*buf += val;
@@ -464,7 +466,6 @@ void rm_get_packet_fd(int fd,RMContext *rmctx, RMPacket *pkt)
" stream = %d\n"
" timestmp= %d\n",pkt->version,pkt->length,pkt->stream_number,pkt->timestamp);
- //getchar();
if(pkt->version == 0)
{
read_uint8(fd,&packet_group);
@@ -550,7 +551,16 @@ int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt)
}
rmctx->audio_pkt_cnt = --rmctx->sub_packet_cnt;
}
- }
+ }
+
+ else if (rmctx->codec_type == CODEC_AC3) {
+ /* The byte order of the data is reversed from standard AC3 */
+ for(x = 0; x < pkt->length - PACKET_HEADER_SIZE; x+=2) {
+ SWAP((*src)[0], (*src)[1]);
+ *src += 2;
+ }
+ *src -= x;
+ }
rmctx->audio_pkt_cnt++;
}while(++(rmctx->sub_packet_cnt) < h);
diff --git a/apps/codecs/librm/rm.h b/apps/codecs/librm/rm.h
index 12e9b18fa3..86fe5e7f1a 100644
--- a/apps/codecs/librm/rm.h
+++ b/apps/codecs/librm/rm.h
@@ -28,7 +28,12 @@
#define DATA_HEADER_SIZE 18
#define PACKET_HEADER_SIZE 12
-enum codecs{CODEC_COOK, CODEC_AAC};
+enum codecs {
+ CODEC_COOK,
+ CODEC_AAC,
+ CODEC_AC3
+};
+
typedef struct rm_packet
{
uint8_t *frames[100]; /* Pointers to ordered audio frames in buffer */
diff --git a/apps/metadata.c b/apps/metadata.c
index f227776c0a..63547646ca 100644
--- a/apps/metadata.c
+++ b/apps/metadata.c
@@ -121,6 +121,9 @@ const struct afmt_entry audio_formats[AFMT_NUM_CODECS] =
/* AAC in RM/RA */
[AFMT_RM_AAC] =
AFMT_ENTRY("RAAC", "raac", NULL, "rm\0ra\0rmvb\0" ),
+ /* AC3 in RM/RA */
+ [AFMT_RM_AC3] =
+ AFMT_ENTRY("AC3", "dnet", NULL, "rm\0ra\0rmvb\0" ),
#endif
};
diff --git a/apps/metadata.h b/apps/metadata.h
index cefc6c3945..c43d2c2260 100644
--- a/apps/metadata.h
+++ b/apps/metadata.h
@@ -63,6 +63,7 @@ enum
AFMT_SAP, /* Amiga 8Bit SAP Format */
AFMT_RM_COOK, /* Cook in RM/RA */
AFMT_RM_AAC, /* AAC in RM/RA */
+ AFMT_RM_AC3, /* AC3 in RM/RA */
#endif
/* add new formats at any index above this line to have a sensible order -
diff --git a/apps/metadata/rm.c b/apps/metadata/rm.c
index 4be0de647f..c74acef5dd 100644
--- a/apps/metadata/rm.c
+++ b/apps/metadata/rm.c
@@ -160,24 +160,32 @@ static inline int real_read_audio_stream_info(int fd, RMContext *rmctx)
skipped += 1;
}
- read_uint32be(fd, &rmctx->extradata_size);
- skipped += 4;
- read(fd, rmctx->codec_extradata, rmctx->extradata_size);
- skipped += rmctx->extradata_size;
switch(fourcc) {
case FOURCC('c','o','o','k'):
rmctx->codec_type = CODEC_COOK;
+ read_uint32be(fd, &rmctx->extradata_size);
+ skipped += 4;
+ read(fd, rmctx->codec_extradata, rmctx->extradata_size);
+ skipped += rmctx->extradata_size;
break;
case FOURCC('r','a','a','c'):
case FOURCC('r','a','c','p'):
rmctx->codec_type = CODEC_AAC;
+ read_uint32be(fd, &rmctx->extradata_size);
+ skipped += 4;
+ read(fd, rmctx->codec_extradata, rmctx->extradata_size);
+ skipped += rmctx->extradata_size;
+ break;
+
+ case FOURCC('d','n','e','t'):
+ rmctx->codec_type = CODEC_AC3;
break;
default: /* Not a supported codec */
return -1;
}
-
+
DEBUGF(" flavor = %d\n",flavor);
DEBUGF(" coded_frame_size = %ld\n",coded_framesize);
DEBUGF(" sub_packet_h = %d\n",rmctx->sub_packet_h);
@@ -407,6 +415,10 @@ bool get_rm_metadata(int fd, struct mp3entry* id3)
case CODEC_AAC:
id3->codectype = AFMT_RM_AAC;
break;
+
+ case CODEC_AC3:
+ id3->codectype = AFMT_RM_AC3;
+ break;
}
id3->bitrate = rmctx->bit_rate / 1000;