1
0
Fork 0
forked from len0rd/rockbox

Add support for AC3 audio in RM container.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@22155 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Mohamed Tarek 2009-08-04 13:54:06 +00:00
parent 7996e77334
commit 26cee86a0c
8 changed files with 231 additions and 8 deletions

View file

@ -11,6 +11,7 @@ alac.c
#endif
cook.c
raac.c
dnet.c
mpc.c
wma.c
sid.c

View file

@ -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

190
apps/codecs/dnet.c Normal file
View file

@ -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;
}

View file

@ -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);
@ -551,6 +552,15 @@ 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);

View file

@ -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 */

View file

@ -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
};

View file

@ -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 -

View file

@ -160,18 +160,26 @@ static inline int real_read_audio_stream_info(int fd, RMContext *rmctx)
skipped += 1;
}
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;
switch(fourcc) {
case FOURCC('c','o','o','k'):
rmctx->codec_type = CODEC_COOK;
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 */
@ -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;