diff options
author | Sean Bartell <wingedtachikoma@gmail.com> | 2011-06-25 21:32:25 -0400 |
---|---|---|
committer | Nils Wallménius <nils@rockbox.org> | 2012-04-25 22:13:20 +0200 |
commit | f40bfc9267b13b54e6379dfe7539447662879d24 (patch) | |
tree | 9b20069d5e62809ff434061ad730096836f916f2 /lib/rbcodec/codecs/raac.c | |
parent | a0009907de7a0107d49040d8a180f140e2eff299 (diff) |
Add codecs to librbcodec.
Change-Id: Id7f4717d51ed02d67cb9f9cb3c0ada4a81843f97
Reviewed-on: http://gerrit.rockbox.org/137
Reviewed-by: Nils Wallménius <nils@rockbox.org>
Tested-by: Nils Wallménius <nils@rockbox.org>
Diffstat (limited to 'lib/rbcodec/codecs/raac.c')
-rw-r--r-- | lib/rbcodec/codecs/raac.c | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/raac.c b/lib/rbcodec/codecs/raac.c new file mode 100644 index 0000000000..0ef7e715bc --- /dev/null +++ b/lib/rbcodec/codecs/raac.c @@ -0,0 +1,212 @@ +/*************************************************************************** + * __________ __ ___. + * 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 "librm/rm.h" +#include "libfaad/common.h" +#include "libfaad/structs.h" +#include "libfaad/decoder.h" +/* rockbox: not used +#include "libfaad/output.h" +*/ + +CODEC_HEADER + +static void init_rm(RMContext *rmctx) +{ + memcpy(rmctx, (void*)(( (intptr_t)ci->id3->id3v2buf + 3 ) &~ 3), sizeof(RMContext)); +} + +static RMContext rmctx; +static RMPacket pkt; + +/* this is the codec entry point */ +enum codec_status codec_main(enum codec_entry_call_reason reason) +{ + if (reason == CODEC_LOAD) { + /* Generic codec initialisation */ + ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); + ci->configure(DSP_SET_SAMPLE_DEPTH, 29); + } + + return CODEC_OK; +} + +/* this is called for each file to process */ +enum codec_status codec_run(void) +{ + static NeAACDecFrameInfo frame_info; + NeAACDecHandle decoder; + size_t n; + unsigned int i; + unsigned char* buffer; + int err, consumed, pkt_offset, skipped = 0; + uint32_t s = 0; /* sample rate */ + unsigned char c = 0; /* channels */ + int playback_on = -1; + size_t resume_offset; + intptr_t param; + enum codec_command_action action = CODEC_ACTION_NULL; + + if (codec_init()) { + DEBUGF("FAAD: Codec init error\n"); + return CODEC_ERROR; + } + + resume_offset = ci->id3->offset; + + ci->memset(&rmctx,0,sizeof(RMContext)); + ci->memset(&pkt,0,sizeof(RMPacket)); + + ci->seek_buffer(0); + + 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"); + return CODEC_ERROR; + } + + NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder); + conf->outputFormat = FAAD_FMT_16BIT; /* irrelevant, we don't convert */ + 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); + return CODEC_ERROR; + } + + /* check for a mid-track resume and force a seek time accordingly */ + if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) { + resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE; + /* put number of subpackets to skip in resume_offset */ + resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE); + param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate); + action = CODEC_ACTION_SEEK_TIME; + } + ci->set_elapsed(0); + ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE); + + /* The main decoding loop */ + while (1) { + if (action == CODEC_ACTION_NULL) + action = ci->get_command(¶m); + + if (action == CODEC_ACTION_HALT) + break; + + if (action == CODEC_ACTION_SEEK_TIME) { + /* Do not allow seeking beyond the file's length */ + if ((unsigned) param > ci->id3->length) { + ci->set_elapsed(ci->id3->length); + ci->seek_complete(); + break; + } + + ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE); + + /* Seek to the start of the track */ + if (param == 0) { + ci->set_elapsed(0); + ci->seek_complete(); + action = CODEC_ACTION_NULL; + continue; + } + + 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 && playback_on != 0) { + if(playback_on == -1) { + /* Error only if packet-parsing failed and playback hadn't started */ + DEBUGF("rm_get_packet failed\n"); + ci->seek_complete(); + return CODEC_ERROR; + } + else { + ci->seek_complete(); + return CODEC_OK; + } + } + skipped += pkt.length; + + if(pkt.timestamp > (unsigned)param) + 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); + NeAACDecPostSeekReset(decoder, decoder->frame); + ci->set_elapsed(pkt.timestamp); + ci->seek_complete(); + } + + action = CODEC_ACTION_NULL; + + /* 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 && playback_on != 0) { + if(playback_on == -1) { + /* Error only if packet-parsing failed and playback hadn't started */ + DEBUGF("rm_get_packet failed\n"); + return CODEC_ERROR; + } + else + break; + } + + playback_on = 1; + if (pkt.timestamp >= ci->id3->length) + break; + + /* Decode one block - returned samples will be host-endian */ + for(i = 0; i < rmctx.sub_packet_cnt; i++) { + 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)); + return CODEC_ERROR; + } + ci->pcmbuf_insert(decoder->time_out[0], + decoder->time_out[1], + decoder->frameLength); + ci->set_elapsed(pkt.timestamp); + } + + ci->advance_buffer(pkt.length); + } + + return CODEC_OK; +} |