diff options
author | Dave Chapman <dave@dchapman.com> | 2005-06-11 10:08:17 +0000 |
---|---|---|
committer | Dave Chapman <dave@dchapman.com> | 2005-06-11 10:08:17 +0000 |
commit | 55ed7d7214684d53c38eb4fe293249e5d3e0ac91 (patch) | |
tree | 26432321890d0e8d616b7257807e31a2b8cc7cdd /apps | |
parent | c82518ce060d3da4800bcc08fffe910b37711f38 (diff) |
First codeca52 (A52 aka AC3 playback) - it is already faster than realtime, with zero optimisations
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6668 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r-- | apps/playback.c | 7 | ||||
-rw-r--r-- | apps/plugins/SOURCES | 1 | ||||
-rw-r--r-- | apps/plugins/codeca52.c | 213 | ||||
-rw-r--r-- | apps/tree.c | 1 |
4 files changed, 221 insertions, 1 deletions
diff --git a/apps/playback.c b/apps/playback.c index 2276a4588b..faea55aec1 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -66,6 +66,7 @@ static volatile bool paused; #define CODEC_MPA_L3 "/.rockbox/codecs/codecmpa.rock"; #define CODEC_FLAC "/.rockbox/codecs/codecflac.rock"; #define CODEC_WAV "/.rockbox/codecs/codecwav.rock"; +#define CODEC_A52 "/.rockbox/codecs/codeca52.rock"; #define AUDIO_DEFAULT_WATERMARK (1024*256) #define AUDIO_DEFAULT_FILECHUNK (1024*32) @@ -413,7 +414,7 @@ int probe_file_format(const char *filename) return AFMT_APE; else if (!strcasecmp("wma", suffix)) return AFMT_WMA; - else if (!strcasecmp("a52", suffix)) + else if ((!strcasecmp("a52", suffix)) || (!strcasecmp("ac3", suffix))) return AFMT_A52; else if (!strcasecmp("rm", suffix)) return AFMT_REAL; @@ -515,6 +516,10 @@ bool loadcodec(const char *trackname, bool start_play) logf("Codec: FLAC"); codec_path = CODEC_FLAC; break; + case AFMT_A52: + logf("Codec: A52"); + codec_path = CODEC_A52; + break; default: logf("Codec: Unsupported"); snprintf(msgbuf, sizeof(msgbuf)-1, "No codec for: %s", trackname); diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index ae7f831819..35a7d39cbf 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES @@ -76,6 +76,7 @@ codecvorbis.c codecmpa.c codecflac.c codecwav.c +codeca52.c #endif wv2wav.c mpc2wav.c diff --git a/apps/plugins/codeca52.c b/apps/plugins/codeca52.c new file mode 100644 index 0000000000..5cb27defc8 --- /dev/null +++ b/apps/plugins/codeca52.c @@ -0,0 +1,213 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 Dave Chapman + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "plugin.h" + +#include <inttypes.h> /* Needed by a52.h */ +#include <codecs/liba52/config-a52.h> +#include <codecs/liba52/a52.h> + +#include "playback.h" +#include "lib/codeclib.h" + +#define BUFFER_SIZE 4096 + +struct plugin_api* rb; +struct codec_api* ci; + +static float gain = 1; +static a52_state_t * state; +unsigned long samplesdone; +unsigned long frequency; + +/* A post-processing buffer used outside liba52 */ +static uint8_t buf[3840] IDATA_ATTR; + +static inline int16_t convert (int32_t i) +{ + i >>= 15; + return (i > 32767) ? 32767 : ((i < -32768) ? -32768 : i); +} + +void output_audio(sample_t* samples,int flags) { + int i; + static int16_t int16_samples[256*2]; + + flags &= A52_CHANNEL_MASK | A52_LFE; + + if (flags==A52_STEREO) { + for (i = 0; i < 256; i++) { + int16_samples[2*i] = convert (samples[i]); + int16_samples[2*i+1] = convert (samples[i+256]); + } + } else { + DEBUGF("ERROR: unsupported format: %d\n",flags); + } + + rb->yield(); + while(!ci->audiobuffer_insert((unsigned char*)int16_samples,256*2*2)) + rb->yield(); +} + + +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 { + // The following two defaults are taken from audio_out_oss.c: + level_t level; + sample_t bias; + int i; + + /* This is the configuration for the downmixing: */ + flags=A52_STEREO|A52_ADJUST_LEVEL|A52_LFE; + level=(1 << 26); + bias=0; + + level = (level_t) (level * gain); + + if (a52_frame (state, buf, &flags, &level, bias)) { + goto error; + } + +// file_info->frames_decoded++; + +// /* We assume this never changes */ +// file_info->samplerate=sample_rate; + 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),flags); + 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; + } + } + } +} + +#ifndef SIMULATOR +extern char iramcopy[]; +extern char iramstart[]; +extern char iramend[]; +#endif + +/* this is the plugin entry point */ +enum plugin_status plugin_start(struct plugin_api* api, void* parm) +{ + size_t n; + unsigned char* filebuf; + + /* Generic plugin initialisation */ + TEST_PLUGIN_API(api); + + rb = api; + ci = (struct codec_api*)parm; + +#ifndef SIMULATOR + rb->memcpy(iramstart, iramcopy, iramend-iramstart); +#endif + + ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*2)); + ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*16)); + + next_track: + + if (codec_init(api, ci)) { + return PLUGIN_ERROR; + } + + /* Intialise the A52 decoder and check for success */ + state = a52_init (0); // Parameter is "accel" + + /* The main decoding loop */ + + samplesdone=0; + while (1) { + if (ci->stop_codec || ci->reload_codec) { + break; + } + + filebuf=ci->request_buffer(&n,BUFFER_SIZE); + + if (n==0) { /* End of Stream */ + break; + } + + a52_decode_data(filebuf,filebuf+n); + + ci->advance_buffer(n); + } + + if (ci->request_next_track()) + goto next_track; + +//NOT NEEDED??: a52_free (state); + + return PLUGIN_OK; +} diff --git a/apps/tree.c b/apps/tree.c index 176add2909..b52e897bc3 100644 --- a/apps/tree.c +++ b/apps/tree.c @@ -77,6 +77,7 @@ const struct filetype filetypes[] = { { ".wma", TREE_ATTR_MPA, File, VOICE_EXT_MPA }, { ".wav", TREE_ATTR_MPA, File, VOICE_EXT_MPA }, { ".flac", TREE_ATTR_MPA, File, VOICE_EXT_MPA }, + { ".ac3", TREE_ATTR_MPA, File, VOICE_EXT_MPA }, #endif { ".m3u", TREE_ATTR_M3U, Playlist, LANG_PLAYLIST }, { ".cfg", TREE_ATTR_CFG, Config, VOICE_EXT_CFG }, |