forked from len0rd/rockbox
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
This commit is contained in:
parent
01e8fce287
commit
88e32c2fc6
3 changed files with 104 additions and 65 deletions
|
|
@ -137,6 +137,11 @@ typedef struct WMADecodeContext
|
||||||
fixed64 lsp_pow_m_table1[(1 << LSP_POW_BITS)];
|
fixed64 lsp_pow_m_table1[(1 << LSP_POW_BITS)];
|
||||||
fixed64 lsp_pow_m_table2[(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
|
#ifdef TRACE
|
||||||
|
|
||||||
int frame_count;
|
int frame_count;
|
||||||
|
|
@ -145,7 +150,9 @@ typedef struct WMADecodeContext
|
||||||
WMADecodeContext;
|
WMADecodeContext;
|
||||||
|
|
||||||
int wma_decode_init(WMADecodeContext* s, asf_waveformatex_t *wfx);
|
int wma_decode_init(WMADecodeContext* s, asf_waveformatex_t *wfx);
|
||||||
int wma_decode_superframe(WMADecodeContext* s,
|
int wma_decode_superframe_init(WMADecodeContext* s,
|
||||||
void *data, int *data_size,
|
uint8_t *buf, int buf_size);
|
||||||
uint8_t *buf, int buf_size);
|
int wma_decode_superframe_frame(WMADecodeContext* s,
|
||||||
|
int16_t *samples,
|
||||||
|
uint8_t *buf, int buf_size);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -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],
|
init_coef_vlc(&s->coef_vlc[1], &s->run_table[1], &s->level_table[1],
|
||||||
&coef_vlcs[coef_vlc_table * 2 + 1], 1);
|
&coef_vlcs[coef_vlc_table * 2 + 1], 1);
|
||||||
|
|
||||||
|
s->last_superframe_len = 0;
|
||||||
|
s->last_bitoffset = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1666,42 +1669,67 @@ static int wma_decode_frame(WMADecodeContext *s, int16_t *samples)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wma_decode_superframe(WMADecodeContext* s,
|
/* Initialise the superframe decoding */
|
||||||
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;
|
|
||||||
|
|
||||||
|
int wma_decode_superframe_init(WMADecodeContext* s,
|
||||||
|
uint8_t *buf, /*input*/
|
||||||
|
int buf_size)
|
||||||
|
{
|
||||||
if (buf_size==0)
|
if (buf_size==0)
|
||||||
{
|
{
|
||||||
s->last_superframe_len = 0;
|
s->last_superframe_len = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
samples = data;
|
s->current_frame = 0;
|
||||||
|
|
||||||
init_get_bits(&s->gb, buf, buf_size*8);
|
init_get_bits(&s->gb, buf, buf_size*8);
|
||||||
|
|
||||||
if (s->use_bit_reservoir)
|
if (s->use_bit_reservoir)
|
||||||
{
|
{
|
||||||
/* read super frame header */
|
/* read super frame header */
|
||||||
get_bits(&s->gb, 4); /* super frame index */
|
get_bits(&s->gb, 4); /* super frame index */
|
||||||
nb_frames = get_bits(&s->gb, 4) - 1;
|
s->nb_frames = get_bits(&s->gb, 4);
|
||||||
|
|
||||||
bit_offset = get_bits(&s->gb, s->byte_offset_bits + 3);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
if (s->last_superframe_len > 0)
|
||||||
{
|
{
|
||||||
/* add bit_offset bits to last frame */
|
/* add s->bit_offset bits to last frame */
|
||||||
if ((s->last_superframe_len + ((bit_offset + 7) >> 3)) >
|
if ((s->last_superframe_len + ((s->bit_offset + 7) >> 3)) >
|
||||||
MAX_CODED_SUPERFRAME_SIZE)
|
MAX_CODED_SUPERFRAME_SIZE)
|
||||||
{
|
{
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
q = s->last_superframe + s->last_superframe_len;
|
q = s->last_superframe + s->last_superframe_len;
|
||||||
len = bit_offset;
|
len = s->bit_offset;
|
||||||
while (len > 0)
|
while (len > 0)
|
||||||
{
|
{
|
||||||
*q++ = (get_bits)(&s->gb, 8);
|
*q++ = (get_bits)(&s->gb, 8);
|
||||||
|
|
@ -1712,39 +1740,46 @@ int wma_decode_superframe(WMADecodeContext* s,
|
||||||
*q++ = (get_bits)(&s->gb, len) << (8 - len);
|
*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);
|
init_get_bits(&s->gb, s->last_superframe, MAX_CODED_SUPERFRAME_SIZE*8);
|
||||||
/* skip unused bits */
|
/* skip unused bits */
|
||||||
if (s->last_bitoffset > 0)
|
if (s->last_bitoffset > 0)
|
||||||
skip_bits(&s->gb, s->last_bitoffset);
|
skip_bits(&s->gb, s->last_bitoffset);
|
||||||
|
|
||||||
/* this frame is stored in the last superframe and in the
|
/* this frame is stored in the last superframe and in the
|
||||||
current one */
|
current one */
|
||||||
if (wma_decode_frame(s, samples) < 0)
|
if (wma_decode_frame(s, samples) < 0)
|
||||||
{
|
{
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
samples += s->nb_channels * s->frame_len;
|
done = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read each frame starting from bit_offset */
|
/* read each frame starting from s->bit_offset */
|
||||||
pos = bit_offset + 4 + 4 + s->byte_offset_bits + 3;
|
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);
|
init_get_bits(&s->gb, buf + (pos >> 3), (MAX_CODED_SUPERFRAME_SIZE - (pos >> 3))*8);
|
||||||
len = pos & 7;
|
len = pos & 7;
|
||||||
if (len > 0)
|
if (len > 0)
|
||||||
skip_bits(&s->gb, len);
|
skip_bits(&s->gb, len);
|
||||||
|
|
||||||
s->reset_block_lengths = 1;
|
s->reset_block_lengths = 1;
|
||||||
for(i=0;i<nb_frames;++i)
|
}
|
||||||
{
|
|
||||||
if (wma_decode_frame(s, samples) < 0)
|
|
||||||
{
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
samples += s->nb_channels * s->frame_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* If we haven't decoded a frame yet, do it now */
|
||||||
|
if (!done)
|
||||||
|
{
|
||||||
|
if (wma_decode_frame(s, samples) < 0)
|
||||||
|
{
|
||||||
|
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 */
|
/* 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;
|
s->last_bitoffset = pos & 7;
|
||||||
pos >>= 3;
|
pos >>= 3;
|
||||||
len = buf_size - pos;
|
len = buf_size - pos;
|
||||||
|
|
@ -1755,21 +1790,11 @@ int wma_decode_superframe(WMADecodeContext* s,
|
||||||
s->last_superframe_len = len;
|
s->last_superframe_len = len;
|
||||||
memcpy(s->last_superframe, buf + pos, len);
|
memcpy(s->last_superframe, buf + pos, len);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return s->frame_len;
|
||||||
/* 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;
|
|
||||||
fail:
|
fail:
|
||||||
/* when error, we reset the bit reservoir */
|
/* when error, we reset the bit reservoir */
|
||||||
s->last_superframe_len = 0;
|
s->last_superframe_len = 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,16 +23,15 @@
|
||||||
|
|
||||||
CODEC_HEADER
|
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) */
|
/* NOTE: WMADecodeContext is 142688 bytes (on x86) */
|
||||||
static WMADecodeContext wmadec;
|
static WMADecodeContext wmadec;
|
||||||
|
|
||||||
/* TODO: Check the size of this */
|
|
||||||
#define OUTBUF_SIZE 256*1024
|
|
||||||
|
|
||||||
enum asf_error_e {
|
enum asf_error_e {
|
||||||
ASF_ERROR_INTERNAL = -1, /* incorrect input to API calls */
|
ASF_ERROR_INTERNAL = -1, /* incorrect input to API calls */
|
||||||
ASF_ERROR_OUTOFMEM = -2, /* some malloc inside program failed */
|
ASF_ERROR_OUTOFMEM = -2, /* some malloc inside program failed */
|
||||||
|
|
@ -286,8 +285,8 @@ enum codec_status codec_main(void)
|
||||||
unsigned char* inbuffer;
|
unsigned char* inbuffer;
|
||||||
size_t resume_offset;
|
size_t resume_offset;
|
||||||
size_t n;
|
size_t n;
|
||||||
int wmares, res, padding, outbufsize;
|
int i;
|
||||||
uint8_t* outbuf;
|
int wmares, res, padding;
|
||||||
|
|
||||||
/* Generic codec initialisation */
|
/* Generic codec initialisation */
|
||||||
ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
|
ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
|
||||||
|
|
@ -313,8 +312,6 @@ enum codec_status codec_main(void)
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
outbuf = codec_malloc(OUTBUF_SIZE);
|
|
||||||
|
|
||||||
/* Copy the format metadata we've stored in the id3 TOC field. This
|
/* Copy the format metadata we've stored in the id3 TOC field. This
|
||||||
saves us from parsing it again here. */
|
saves us from parsing it again here. */
|
||||||
memcpy(&wfx, ci->id3->toc, sizeof(wfx));
|
memcpy(&wfx, ci->id3->toc, sizeof(wfx));
|
||||||
|
|
@ -355,21 +352,31 @@ enum codec_status codec_main(void)
|
||||||
if (res > 0) {
|
if (res > 0) {
|
||||||
inbuffer = ci->request_buffer(&n, res - padding);
|
inbuffer = ci->request_buffer(&n, res - padding);
|
||||||
|
|
||||||
wmares = wma_decode_superframe(&wmadec,
|
wma_decode_superframe_init(&wmadec,
|
||||||
outbuf,&outbufsize,
|
inbuffer,res - padding);
|
||||||
inbuffer,res - padding);
|
|
||||||
|
|
||||||
ci->advance_buffer(res);
|
for (i=0; i < wmadec.nb_frames; i++)
|
||||||
|
{
|
||||||
|
wmares = wma_decode_superframe_frame(&wmadec,
|
||||||
|
decoded,
|
||||||
|
inbuffer,res - padding);
|
||||||
|
|
||||||
if (wmares > 0) {
|
ci->yield ();
|
||||||
ci->pcmbuf_insert(outbuf, NULL, outbufsize / (wfx.channels * 2));
|
|
||||||
samplesdone += (outbufsize / (wfx.channels * 2));
|
if (wmares < 0)
|
||||||
DEBUGF("Decoded %d samples\n",(outbufsize / (wfx.channels * 2)));
|
{
|
||||||
elapsedtime = (samplesdone*10)/(wfx.rate/100);
|
LOGF("WMA decode error %d\n",wmares);
|
||||||
ci->set_elapsed(elapsedtime);
|
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;
|
retval = CODEC_OK;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue