From b8cccb5ae18f35ea7d210c513bafe10b19fafbd7 Mon Sep 17 00:00:00 2001 From: Mohamed Tarek Date: Sat, 25 Jul 2009 15:47:13 +0000 Subject: Adding support for playback of aac audio in rm container, with seeking. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@22031 a1c6a512-1295-4272-9138-f99709370657 --- apps/codecs/SOURCES | 1 + apps/codecs/codecs.make | 1 + apps/codecs/librm/rm.c | 29 ++++++-- apps/codecs/raac.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++ apps/metadata.c | 3 + apps/metadata.h | 1 + apps/metadata/rm.c | 19 ++++-- 7 files changed, 217 insertions(+), 13 deletions(-) create mode 100644 apps/codecs/raac.c (limited to 'apps') diff --git a/apps/codecs/SOURCES b/apps/codecs/SOURCES index 44a8498fa9..dc6819d272 100644 --- a/apps/codecs/SOURCES +++ b/apps/codecs/SOURCES @@ -10,6 +10,7 @@ wavpack.c alac.c #endif cook.c +raac.c mpc.c wma.c sid.c diff --git a/apps/codecs/codecs.make b/apps/codecs/codecs.make index fbe3b1c978..b327bd7c69 100644 --- a/apps/codecs/codecs.make +++ b/apps/codecs/codecs.make @@ -76,6 +76,7 @@ $(CODECDIR)/wma.codec : $(CODECDIR)/libwma.a $(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 $(CODECS): $(CODECLIB) # this must be last in codec dependency list diff --git a/apps/codecs/librm/rm.c b/apps/codecs/librm/rm.c index c9c40986ba..a48fb51cc6 100644 --- a/apps/codecs/librm/rm.c +++ b/apps/codecs/librm/rm.c @@ -529,13 +529,28 @@ int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt) advance_buffer(src,12); consumed += 12; - for(x = 0 ; x < w/sps; x++) - { - place = sps*(h*x+((h+1)/2)*(y&1)+(y>>1)); - pkt->frames[place/sps] = *src; - advance_buffer(src,sps); - consumed += sps; - } + if (rmctx->codec_type == cook) { + for(x = 0 ; x < w/sps; x++) + { + place = sps*(h*x+((h+1)/2)*(y&1)+(y>>1)); + pkt->frames[place/sps] = *src; + advance_buffer(src,sps); + consumed += sps; + } + } + else if (rmctx->codec_type == aac) { + rmctx->sub_packet_cnt = (get_uint16be(*src) & 0xf0) >> 4; + advance_buffer(src, 2); + consumed += 2; + if (rmctx->sub_packet_cnt) { + for(x = 0; x < rmctx->sub_packet_cnt; x++) { + rmctx->sub_packet_lengths[x] = get_uint16be(*src); + advance_buffer(src, 2); + consumed += 2; + } + rmctx->audio_pkt_cnt = --rmctx->sub_packet_cnt; + } + } rmctx->audio_pkt_cnt++; }while(++(rmctx->sub_packet_cnt) < h); diff --git a/apps/codecs/raac.c b/apps/codecs/raac.c new file mode 100644 index 0000000000..cfc5b4a460 --- /dev/null +++ b/apps/codecs/raac.c @@ -0,0 +1,176 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: aac.c 19743 2009-01-10 21:10:56Z zagor $ + * + * 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 "librm/rm.h" +#include "libfaad/common.h" +#include "libfaad/structs.h" +#include "libfaad/decoder.h" +#include "libfaad/output.h" + +CODEC_HEADER +#define DATA_HEADER_SIZE 18 +static void init_rm(RMContext *rmctx) +{ + memcpy(rmctx, (void*)(( (intptr_t)ci->id3->id3v2buf + 3 ) &~ 3), sizeof(RMContext)); +} + +RMContext rmctx; +RMPacket pkt; +/* this is the codec entry point */ +enum codec_status codec_main(void) +{ + static NeAACDecFrameInfo frame_info; + NeAACDecHandle decoder; + size_t n; + int32_t *output; + unsigned int i; + unsigned char* buffer; + int err, consumed, pkt_offset, skipped = 0; + uint32_t s = 0; /* sample rate */ + unsigned char c = 0; /* channels */ + /* Generic codec initialisation */ + ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); + ci->configure(DSP_SET_SAMPLE_DEPTH, 16); + +next_track: + err = CODEC_OK; + + if (codec_init()) { + DEBUGF("FAAD: Codec init error\n"); + return CODEC_ERROR; + } + + while (!*ci->taginfo_ready && !ci->stop_codec) + ci->sleep(1); + + ci->memset(&rmctx,0,sizeof(RMContext)); + ci->memset(&pkt,0,sizeof(RMPacket)); + init_rm(&rmctx); + ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); + codec_set_replaygain(ci->id3); + + /* initialise the sound converter */ + decoder = NeAACDecOpen(); + + if (!decoder) { + DEBUGF("FAAD: Decode open error\n"); + err = CODEC_ERROR; + goto done; + } + NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder); + conf->outputFormat = FAAD_FMT_16BIT; + NeAACDecSetConfiguration(decoder, conf); + + decoder->config.defObjectType = rmctx.codec_extradata[0]; + decoder->config.defSampleRate = rmctx.sample_rate; + err = NeAACDecInit(decoder, NULL, 0, &s, &c); + + if (err) { + DEBUGF("FAAD: DecInit: %d, %d\n", err, decoder->object_type); + err = CODEC_ERROR; + goto done; + } + ci->id3->frequency = s; + ci->set_elapsed(0); + ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE); + + /* The main decoding loop */ +seek_start: + while (1) { + ci->yield(); + if (ci->stop_codec || ci->new_track) { + break; + } + + if (ci->seek_time) { + + /* Do not allow seeking beyond the file's length */ + if ((unsigned) ci->seek_time > ci->id3->length) { + ci->seek_complete(); + goto done; + } + + ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE); + + /* Seek to the start of the track */ + if (ci->seek_time == 1) { + ci->set_elapsed(0); + ci->seek_complete(); + goto seek_start; + } + + skipped = 0; + while(1) { + buffer = ci->request_buffer(&n,rmctx.audio_framesize + 1000); + pkt_offset = skipped - pkt.length; + consumed = rm_get_packet(&buffer, &rmctx, &pkt); + if(consumed < 0) { + DEBUGF("rm_get_packet failed\n"); + return CODEC_ERROR; + } + skipped += pkt.length; + if(pkt.timestamp > (unsigned)ci->seek_time) break; + ci->advance_buffer(pkt.length); + } + ci->seek_buffer(pkt_offset + rmctx.data_offset + DATA_HEADER_SIZE); + buffer = ci->request_buffer(&n,rmctx.audio_framesize + 1000); + ci->seek_complete(); + } + + /* Request the required number of bytes from the input buffer */ + buffer=ci->request_buffer(&n,rmctx.audio_framesize + 1000); + consumed = rm_get_packet(&buffer, &rmctx, &pkt); + if(consumed < 0) { + DEBUGF("rm_get_packet failed\n"); + return CODEC_ERROR; + } + + if (pkt.timestamp >= ci->id3->length) + goto done; + /* Decode one block - returned samples will be host-endian */ + for(i = 0; i < rmctx.sub_packet_cnt; i++) { + output = (int32_t *)NeAACDecDecode(decoder, &frame_info, buffer, rmctx.sub_packet_lengths[i]); + buffer += rmctx.sub_packet_lengths[i]; + if (frame_info.error > 0) { + DEBUGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error)); + err = CODEC_ERROR; + goto exit; + } + output = (int32_t *) output_to_PCM(decoder, decoder->time_out, output, + rmctx.nb_channels, decoder->frameLength, decoder->config.outputFormat); + ci->pcmbuf_insert(output, NULL, frame_info.samples/rmctx.nb_channels); + ci->set_elapsed(pkt.timestamp); + } + + ci->advance_buffer(pkt.length); + } + + err = CODEC_OK; + +done: + if (ci->request_next_track()) + goto next_track; + +exit: + return err; +} + diff --git a/apps/metadata.c b/apps/metadata.c index a0409a83ac..80f2c126e2 100644 --- a/apps/metadata.c +++ b/apps/metadata.c @@ -118,6 +118,9 @@ const struct afmt_entry audio_formats[AFMT_NUM_CODECS] = /* Cook in RM/RA */ [AFMT_COOK] = AFMT_ENTRY("Cook", "cook", NULL, "rm\0ra\0" ), + /* AAC in RM/RA */ + [AFMT_RAAC] = + AFMT_ENTRY("RAAC", "raac", NULL, NULL ), #endif }; diff --git a/apps/metadata.h b/apps/metadata.h index f3b50c947d..0125b29e5e 100644 --- a/apps/metadata.h +++ b/apps/metadata.h @@ -62,6 +62,7 @@ enum AFMT_MOD, /* Amiga MOD File Format */ AFMT_SAP, /* Amiga 8Bit SAP Format */ AFMT_COOK, /* Cook in RM/RA */ + AFMT_RAAC, /* AAC 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 bfaa803be7..95889c35c3 100644 --- a/apps/metadata/rm.c +++ b/apps/metadata/rm.c @@ -169,6 +169,11 @@ static inline int real_read_audio_stream_info(int fd, RMContext *rmctx) rmctx->codec_type = cook; break; + case FOURCC('r','a','a','c'): + case FOURCC('r','a','c','p'): + rmctx->codec_type = aac; + break; + default: /* Not a supported codec */ return -1; } @@ -183,7 +188,10 @@ static inline int real_read_audio_stream_info(int fd, RMContext *rmctx) DEBUGF(" fourcc = %s\n",fourcc2str(fourcc)); DEBUGF(" codec_extra_data_length = %ld\n",rmctx->extradata_size); DEBUGF(" codec_extradata :\n"); - print_cook_extradata(rmctx); + if(rmctx->codec_type == cook) { + DEBUGF(" cook_extradata :\n"); + print_cook_extradata(rmctx); + } } @@ -391,12 +399,11 @@ bool get_rm_metadata(int fd, struct mp3entry* id3) id3->artist = id3->id3v1buf[1]; id3->comment = id3->id3v1buf[3]; - /*switch(rmctx->codec_type) + switch(rmctx->codec_type) { - case cook: - id3->codectype = AFMT_COOK; - break; - }*/ + case aac: + id3->codectype = AFMT_RAAC; + } id3->bitrate = rmctx->bit_rate / 1000; id3->frequency = rmctx->sample_rate; -- cgit v1.2.3