From 88e32c2fc66544dfe55c2e307461ee01d590fef3 Mon Sep 17 00:00:00 2001 From: Dave Chapman Date: Mon, 9 Jul 2007 17:24:00 +0000 Subject: Reorganise the wma_decode_superframe() function - split into a separate init and decode functions. Each call to the decode function now decodes a single frame (2048 samples) instead of an entire superframe (which typically contained about 7 or 8 frames and can in theory contain up to 16 frames). This allows us to replace the 256KB output buffer with a 8KB buffer, and also perform more yields in the main decoding loop. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13833 a1c6a512-1295-4272-9138-f99709370657 --- apps/codecs/libwma/wmadec.h | 13 ++++-- apps/codecs/libwma/wmadeci.c | 105 ++++++++++++++++++++++++++----------------- apps/codecs/wma.c | 51 ++++++++++++--------- 3 files changed, 104 insertions(+), 65 deletions(-) (limited to 'apps/codecs') diff --git a/apps/codecs/libwma/wmadec.h b/apps/codecs/libwma/wmadec.h index e23d7c20b0..fd2d63c9d4 100644 --- a/apps/codecs/libwma/wmadec.h +++ b/apps/codecs/libwma/wmadec.h @@ -137,6 +137,11 @@ typedef struct WMADecodeContext fixed64 lsp_pow_m_table1[(1 << LSP_POW_BITS)]; fixed64 lsp_pow_m_table2[(1 << LSP_POW_BITS)]; + /* State of current superframe decoding */ + int bit_offset; + int nb_frames; + int current_frame; + #ifdef TRACE int frame_count; @@ -145,7 +150,9 @@ typedef struct WMADecodeContext WMADecodeContext; int wma_decode_init(WMADecodeContext* s, asf_waveformatex_t *wfx); -int wma_decode_superframe(WMADecodeContext* s, - void *data, int *data_size, - uint8_t *buf, int buf_size); +int wma_decode_superframe_init(WMADecodeContext* s, + uint8_t *buf, int buf_size); +int wma_decode_superframe_frame(WMADecodeContext* s, + int16_t *samples, + uint8_t *buf, int buf_size); #endif diff --git a/apps/codecs/libwma/wmadeci.c b/apps/codecs/libwma/wmadeci.c index c266316cf9..1a7081fd29 100644 --- a/apps/codecs/libwma/wmadeci.c +++ b/apps/codecs/libwma/wmadeci.c @@ -935,6 +935,9 @@ int wma_decode_init(WMADecodeContext* s, asf_waveformatex_t *wfx) init_coef_vlc(&s->coef_vlc[1], &s->run_table[1], &s->level_table[1], &coef_vlcs[coef_vlc_table * 2 + 1], 1); + s->last_superframe_len = 0; + s->last_bitoffset = 0; + return 0; } @@ -1666,42 +1669,67 @@ static int wma_decode_frame(WMADecodeContext *s, int16_t *samples) return 0; } -int wma_decode_superframe(WMADecodeContext* s, - void *data, /*output*/ - int *data_size, - uint8_t *buf, /*input*/ - int buf_size) -{ - //WMADecodeContext *s = avctx->priv_data; - int nb_frames, bit_offset, i, pos, len; - uint8_t *q; - int16_t *samples; +/* Initialise the superframe decoding */ +int wma_decode_superframe_init(WMADecodeContext* s, + uint8_t *buf, /*input*/ + int buf_size) +{ if (buf_size==0) { s->last_superframe_len = 0; return 0; } - samples = data; + s->current_frame = 0; + init_get_bits(&s->gb, buf, buf_size*8); + if (s->use_bit_reservoir) { /* read super frame header */ get_bits(&s->gb, 4); /* super frame index */ - nb_frames = get_bits(&s->gb, 4) - 1; + s->nb_frames = get_bits(&s->gb, 4); + + if (s->last_superframe_len == 0) + s->nb_frames --; + else if (s->nb_frames == 0) + s->nb_frames++; + + s->bit_offset = get_bits(&s->gb, s->byte_offset_bits + 3); + } else { + s->nb_frames = 1; + } - bit_offset = get_bits(&s->gb, s->byte_offset_bits + 3); + return 1; +} + + +/* Decode a single frame in the current superframe - return -1 if + there was a decoding error, or the number of samples decoded. +*/ + +int wma_decode_superframe_frame(WMADecodeContext* s, + int16_t* samples, /*output*/ + uint8_t *buf, /*input*/ + int buf_size) +{ + int pos, len; + uint8_t *q; + int done = 0; + + if ((s->use_bit_reservoir) && (s->current_frame == 0)) + { if (s->last_superframe_len > 0) { - /* add bit_offset bits to last frame */ - if ((s->last_superframe_len + ((bit_offset + 7) >> 3)) > + /* add s->bit_offset bits to last frame */ + if ((s->last_superframe_len + ((s->bit_offset + 7) >> 3)) > MAX_CODED_SUPERFRAME_SIZE) { goto fail; } q = s->last_superframe + s->last_superframe_len; - len = bit_offset; + len = s->bit_offset; while (len > 0) { *q++ = (get_bits)(&s->gb, 8); @@ -1712,39 +1740,46 @@ int wma_decode_superframe(WMADecodeContext* s, *q++ = (get_bits)(&s->gb, len) << (8 - len); } - /* XXX: bit_offset bits into last frame */ + /* XXX: s->bit_offset bits into last frame */ init_get_bits(&s->gb, s->last_superframe, MAX_CODED_SUPERFRAME_SIZE*8); /* skip unused bits */ if (s->last_bitoffset > 0) skip_bits(&s->gb, s->last_bitoffset); + /* this frame is stored in the last superframe and in the current one */ if (wma_decode_frame(s, samples) < 0) { goto fail; } - samples += s->nb_channels * s->frame_len; + done = 1; } - /* read each frame starting from bit_offset */ - pos = bit_offset + 4 + 4 + s->byte_offset_bits + 3; + /* read each frame starting from s->bit_offset */ + pos = s->bit_offset + 4 + 4 + s->byte_offset_bits + 3; init_get_bits(&s->gb, buf + (pos >> 3), (MAX_CODED_SUPERFRAME_SIZE - (pos >> 3))*8); len = pos & 7; if (len > 0) skip_bits(&s->gb, len); s->reset_block_lengths = 1; - for(i=0;inb_channels * s->frame_len; + goto fail; } + } + + s->current_frame++; + if ((s->use_bit_reservoir) && (s->current_frame == s->nb_frames)) + { /* we copy the end of the frame in the last frame buffer */ - pos = get_bits_count(&s->gb) + ((bit_offset + 4 + 4 + s->byte_offset_bits + 3) & ~7); + pos = get_bits_count(&s->gb) + ((s->bit_offset + 4 + 4 + s->byte_offset_bits + 3) & ~7); s->last_bitoffset = pos & 7; pos >>= 3; len = buf_size - pos; @@ -1755,21 +1790,11 @@ int wma_decode_superframe(WMADecodeContext* s, s->last_superframe_len = len; memcpy(s->last_superframe, buf + pos, len); } - else - { - /* single frame decode */ - if (wma_decode_frame(s, samples) < 0) - { - goto fail; - } - samples += s->nb_channels * s->frame_len; - } - *data_size = (int8_t *)samples - (int8_t *)data; - return s->block_align; + + return s->frame_len; + fail: /* when error, we reset the bit reservoir */ s->last_superframe_len = 0; return -1; } - - diff --git a/apps/codecs/wma.c b/apps/codecs/wma.c index a8e386a177..ab4a808f92 100644 --- a/apps/codecs/wma.c +++ b/apps/codecs/wma.c @@ -23,16 +23,15 @@ CODEC_HEADER -#define MAX_BLOCKSIZE 2048 +/* The output buffer containing the decoded samples (channels 0 and 1) + BLOCK_MAX_SIZE is 2048 (samples) and MAX_CHANNELS is 2. + */ -/* The output buffers containing the decoded samples (channels 0 and 1) */ +static uint16_t decoded[BLOCK_MAX_SIZE * MAX_CHANNELS]; /* NOTE: WMADecodeContext is 142688 bytes (on x86) */ static WMADecodeContext wmadec; -/* TODO: Check the size of this */ -#define OUTBUF_SIZE 256*1024 - enum asf_error_e { ASF_ERROR_INTERNAL = -1, /* incorrect input to API calls */ ASF_ERROR_OUTOFMEM = -2, /* some malloc inside program failed */ @@ -286,8 +285,8 @@ enum codec_status codec_main(void) unsigned char* inbuffer; size_t resume_offset; size_t n; - int wmares, res, padding, outbufsize; - uint8_t* outbuf; + int i; + int wmares, res, padding; /* Generic codec initialisation */ ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512); @@ -313,8 +312,6 @@ enum codec_status codec_main(void) goto exit; } - outbuf = codec_malloc(OUTBUF_SIZE); - /* Copy the format metadata we've stored in the id3 TOC field. This saves us from parsing it again here. */ memcpy(&wfx, ci->id3->toc, sizeof(wfx)); @@ -355,21 +352,31 @@ enum codec_status codec_main(void) if (res > 0) { inbuffer = ci->request_buffer(&n, res - padding); - wmares = wma_decode_superframe(&wmadec, - outbuf,&outbufsize, - inbuffer,res - padding); - - ci->advance_buffer(res); - - if (wmares > 0) { - ci->pcmbuf_insert(outbuf, NULL, outbufsize / (wfx.channels * 2)); - samplesdone += (outbufsize / (wfx.channels * 2)); - DEBUGF("Decoded %d samples\n",(outbufsize / (wfx.channels * 2))); - elapsedtime = (samplesdone*10)/(wfx.rate/100); - ci->set_elapsed(elapsedtime); + wma_decode_superframe_init(&wmadec, + inbuffer,res - padding); + + for (i=0; i < wmadec.nb_frames; i++) + { + wmares = wma_decode_superframe_frame(&wmadec, + decoded, + inbuffer,res - padding); + + ci->yield (); + + if (wmares < 0) + { + LOGF("WMA decode error %d\n",wmares); + goto done; + } else if (wmares > 0) { + ci->pcmbuf_insert(decoded, NULL, wmares); + samplesdone += wmares; + elapsedtime = (samplesdone*10)/(wfx.rate/100); + ci->set_elapsed(elapsedtime); + } + ci->yield (); } - ci->yield (); + ci->advance_buffer(res); } } retval = CODEC_OK; -- cgit v1.2.3