From f40bfc9267b13b54e6379dfe7539447662879d24 Mon Sep 17 00:00:00 2001 From: Sean Bartell Date: Sat, 25 Jun 2011 21:32:25 -0400 Subject: Add codecs to librbcodec. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id7f4717d51ed02d67cb9f9cb3c0ada4a81843f97 Reviewed-on: http://gerrit.rockbox.org/137 Reviewed-by: Nils Wallménius Tested-by: Nils Wallménius --- lib/rbcodec/codecs/libpcm/swf_adpcm.c | 236 ++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 lib/rbcodec/codecs/libpcm/swf_adpcm.c (limited to 'lib/rbcodec/codecs/libpcm/swf_adpcm.c') diff --git a/lib/rbcodec/codecs/libpcm/swf_adpcm.c b/lib/rbcodec/codecs/libpcm/swf_adpcm.c new file mode 100644 index 0000000000..c440fd1303 --- /dev/null +++ b/lib/rbcodec/codecs/libpcm/swf_adpcm.c @@ -0,0 +1,236 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2010 Yoshihisa Uchida + * + * 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 "ima_adpcm_common.h" +#include "support_formats.h" + +/* + * Adobe SWF ADPCM + * + * References + * [1] Adobe, SWF File Format Specification Version 10, 2008 + * [2] Jack Jansen, adpcm.c in adpcm.zip + * [3] ffmpeg source code, libavcodec/adpcm.c + */ + +/* step index table when bitspersample is 3. + * (when bitspersample is 2, 4, 5, step index table uses the table + * which is defined ima_adpcm_common.c.) + */ +static const int index_table[4] ICONST_ATTR = { + -1, -1, 2, 4, +}; + +static int validity_bits = 8; +static bool first_block = true; +static int blockbits = 0; +static int lastbytebits = 0; +static bool after_seek = false; + +static struct pcm_format *fmt; + +#define GET_SAMPLE_COUNT(s) ((((s) << 3) / fmt->channels - 22) / fmt->bitspersample + 1) + +static bool set_format(struct pcm_format *format) +{ + fmt = format; + + if (fmt->bitspersample < 2 || fmt->bitspersample > 5) + { + DEBUGF("CODEC_ERROR: swf adpcm must be 2, 3, 4 or 5 bitspersample: %d\n", + fmt->bitspersample); + return false; + } + + if (fmt->samplesperblock == 0) + fmt->samplesperblock = (((fmt->blockalign << 3) - 2) / fmt->channels - 22) + / fmt->bitspersample + 1; + + blockbits = ((fmt->samplesperblock - 1) * fmt->bitspersample + 22) * fmt->channels; + + /* + * chunksize = about 93 [ms] data (frequency:44.1kHz, 4096 [sample/block]) + * chunksize changes depending upon the position of block. + */ + fmt->chunksize = (blockbits + 9) >> 3; + + /* initialize for ima adpcm common functions */ + if (fmt->bitspersample == 3) + init_ima_adpcm_decoder(fmt->bitspersample, index_table); + else + init_ima_adpcm_decoder(fmt->bitspersample, NULL); + + return true; +} + +static struct pcm_pos *get_seek_pos(uint32_t seek_val, int seek_mode, + uint8_t *(*read_buffer)(size_t *realsize)) +{ + static struct pcm_pos newpos; + uint32_t chunkbits = blockbits; + uint32_t seekblocks = (seek_mode == PCM_SEEK_TIME)? + ((uint64_t)seek_val * ci->id3->frequency) + / (1000LL * fmt->samplesperblock) : + ((seek_val << 3) - 2) / blockbits; + uint32_t seekbits = seekblocks * blockbits + 2; + + (void)read_buffer; + + newpos.pos = seekbits >> 3; + newpos.samples = seekblocks * fmt->samplesperblock; + + if (newpos.pos == 0) + { + first_block = true; + lastbytebits = 0; + } + else + { + first_block = false; + lastbytebits = seekbits & 0x07; + if (lastbytebits != 0) + chunkbits -= (8 - lastbytebits); + } + + /* calculates next read bytes */ + fmt->chunksize = (chunkbits >> 3) + (((chunkbits & 0x07) > 0)?1:0) + + ((lastbytebits > 0)?1:0); + + after_seek = true; + return &newpos; +} + +static uint8_t get_data(const uint8_t **buf, int bit) +{ + uint8_t res = 0; + uint8_t mask = (1 << bit) - 1; + + if (validity_bits >= bit) + { + validity_bits -= bit; + return (**buf >> validity_bits) & mask; + } + + if (validity_bits > 0) + res = **buf << (bit - validity_bits); + + validity_bits += 8 - bit; + res = (res | (*(++(*buf)) >> validity_bits)) & mask; + return res; +} + +static int decode(const uint8_t *inbuf, size_t inbufsize, + int32_t *outbuf, int *outbufcount) +{ + int ch; + int adpcm_code_size; + int count = ((size_t)fmt->chunksize == inbufsize) ? fmt->samplesperblock : + GET_SAMPLE_COUNT(inbufsize); + int32_t init_pcmdata[2]; + int8_t init_index[2]; + static uint8_t lastbyte = 0; + + validity_bits = 8; + *outbufcount = count; + + /* read block header */ + ch = fmt->channels - 1; + if (first_block) + { + adpcm_code_size = get_data(&inbuf, 2) + 2; + if (fmt->bitspersample != adpcm_code_size) + { + DEBUGF("CODEC_ERROR: swf adpcm different adpcm code size=%d != %d\n", + adpcm_code_size, fmt->bitspersample); + return CODEC_ERROR; + } + init_pcmdata[0] = (get_data(&inbuf, 8) << 8) | get_data(&inbuf, 8); + + lastbytebits = 0; + first_block = false; + } + else + { + if (after_seek && lastbytebits > 0) + { + lastbyte = *inbuf++; + after_seek = false; + } + if (lastbytebits > 0) + init_pcmdata[0] = ((lastbyte << (8 + lastbytebits)) | + (get_data(&inbuf, 8) << lastbytebits) | + get_data(&inbuf, lastbytebits)) & 65535; + else + init_pcmdata[0] = (get_data(&inbuf, 8) << 8) | get_data(&inbuf, 8); + } + after_seek = false; + + init_index[0] = get_data(&inbuf, 6); + if (init_pcmdata[0] > 32767) + init_pcmdata[0] -= 65536; + + if (ch > 0) + { + init_pcmdata[1] = (get_data(&inbuf, 8) << 8) | get_data(&inbuf, 8); + init_index[1] = get_data(&inbuf, 6); + if (init_pcmdata[1] > 32767) + init_pcmdata[1] -= 65536; + } + + *outbuf++ = init_pcmdata[0] << IMA_ADPCM_INC_DEPTH; + if (ch > 0) + *outbuf++ = init_pcmdata[1] << IMA_ADPCM_INC_DEPTH; + + set_decode_parameters(fmt->channels, init_pcmdata, init_index); + + /* read block data */ + while (--count > 0) + { + *outbuf++ = create_pcmdata(0, get_data(&inbuf, fmt->bitspersample)) + << IMA_ADPCM_INC_DEPTH; + if (ch > 0) + *outbuf++ = create_pcmdata(ch, get_data(&inbuf, fmt->bitspersample)) + << IMA_ADPCM_INC_DEPTH; + } + + lastbyte = *inbuf; + lastbytebits = (8 - validity_bits) & 0x07; + + /* calculates next read bytes */ + fmt->chunksize = (blockbits - validity_bits + 7) >> 3; + + return CODEC_OK; +} + +static const struct pcm_codec codec = { + set_format, + get_seek_pos, + decode, + }; + +const struct pcm_codec *get_swf_adpcm_codec(void) +{ + first_block = true; + lastbytebits = 0; + after_seek = false; + + return &codec; +} -- cgit v1.2.3