diff options
author | Mohamed Tarek <mt@rockbox.org> | 2009-07-25 15:47:13 +0000 |
---|---|---|
committer | Mohamed Tarek <mt@rockbox.org> | 2009-07-25 15:47:13 +0000 |
commit | b8cccb5ae18f35ea7d210c513bafe10b19fafbd7 (patch) | |
tree | 901a2d75ad40134a005c3bbb68949f551fc9c50e /apps/codecs/raac.c | |
parent | 8f572ca525bf3812799e627a4a716300e412c244 (diff) |
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
Diffstat (limited to 'apps/codecs/raac.c')
-rw-r--r-- | apps/codecs/raac.c | 176 |
1 files changed, 176 insertions, 0 deletions
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; +} + |