[Ffmpeg-devel] Fixed point arithmetic RealAudio G2 (cook) decoder
Benjamin Larsson
banan
Mon Mar 12 23:12:56 CET 2007
Ian Braithwaite wrote:
> Hi,
>
>
> Benjamin Larsson wrote:
>> Ian Braithwaite wrote:
>>> Patch 3.
>>> Replace custom modified discrete cosine transform with ffmpeg's own.
>>> This does alter the decoded output, although not to my ears.
>>> The new output is closer to that produced by Real's "official" decoder,
>>> and the decoder runs slightly faster.
>>>
>>> cook.c | 98
>>> +++++++++++++++++++----------------------------------------------
>>> 1 file changed, 30 insertions(+), 68 deletions(-)
>> Applied with suggested modifications.
>
> Thanks - sorry I didn't get a new patch sent myself, too slow!
>
> I was looking at combining the window and overlap loops,
> as well as getting rid of the data swapping.
> Patch attached - please see what you think.
>
>
> Regards,
> Ian
>
>
> ------------------------------------------------------------------------
>
> diff -u svn/cook.c mlt2/cook.c
> --- svn/cook.c 2007-03-12 13:53:07.000000000 +0100
> +++ mlt2/cook.c 2007-03-12 14:33:11.000000000 +0100
> @@ -685,33 +685,6 @@
>
>
> /**
> - * The modulated lapped transform, this takes transform coefficients
> - * and transforms them into timedomain samples. This is done through
> - * an FFT-based algorithm with pre- and postrotation steps.
> - * A window and reorder step is also included.
> - *
> - * @param q pointer to the COOKContext
> - * @param inbuffer pointer to the mltcoefficients
> - * @param outbuffer pointer to the timedomain buffer
> - * @param mlt_tmp pointer to temporary storage space
> - */
> -
> -static void cook_imlt(COOKContext *q, float* inbuffer, float* outbuffer)
> -{
> - int i;
> -
> - q->mdct_ctx.fft.imdct_calc(&q->mdct_ctx, outbuffer, inbuffer, q->mdct_tmp);
> -
> - for(i = 0; i < q->samples_per_channel; i++){
> - float tmp = outbuffer[i];
> -
> - outbuffer[i] = q->mlt_window[i] * outbuffer[q->samples_per_channel + i];
> - outbuffer[q->samples_per_channel + i] = q->mlt_window[q->samples_per_channel - 1 - i] * -tmp;
> - }
> -}
> -
> -
> -/**
> * the actual requantization of the timedomain samples
> *
> * @param q pointer to the COOKContext
> @@ -743,36 +716,49 @@
>
>
> /**
> - * mlt overlapping and buffer management
> + * The modulated lapped transform, this takes transform coefficients
> + * and transforms them into timedomain samples.
> + * Apply transform window, overlap buffers, apply gain profile
> + * and buffer management.
> *
> * @param q pointer to the COOKContext
> + * @param inbuffer pointer to the mltcoefficients
> * @param gains_ptr current and previous gains
> * @param previous_buffer pointer to the previous buffer to be used for overlapping
> */
>
> -static void gain_compensate(COOKContext *q, cook_gains *gains_ptr,
> - float* previous_buffer)
> +static void imlt_gain(COOKContext *q, float *inbuffer,
> + cook_gains *gains_ptr, float* previous_buffer)
> {
> const float fc = q->pow2tab[gains_ptr->previous[0] + 63];
> - float *buffer = q->mono_mdct_output;
> + float *buffer0 = q->mono_mdct_output;
> + float *buffer1 = q->mono_mdct_output + q->samples_per_channel;
> int i;
>
> - /* Overlap with the previous block. */
> - for(i=0 ; i<q->samples_per_channel ; i++) {
> - buffer[i] *= fc;
> - buffer[i] += previous_buffer[i];
> + /* Inverse modified discrete cosine transform */
> + ff_imdct_calc(&q->mdct_ctx, q->mono_mdct_output, inbuffer, q->mdct_tmp);
q->mdct_ctx.fft.imdct_calc
> +
> + /* The weird thing here, is that the two halves of the time domain
> + * buffer are swapped. Also, the newest data, that we save away for
> + * next frame, has the wrong sign. Hence the subtraction below.
> + * Almost sounds like a complex conjugate/reverse data/FFT effect.
> + */
If you look at my original code you'll see that it almost matches a mdct
so that is probably the cause.
> +
> + /* Apply window and overlap */
> + for(i = 0; i < q->samples_per_channel; i++){
> + buffer1[i] = buffer1[i] * fc * q->mlt_window[i] -
> + previous_buffer[i] * q->mlt_window[q->samples_per_channel - 1 - i];
> }
buffer1[i] *=
To me all this saves a negation and it simplifies some code, but is it
any faster ?
>
> /* Apply gain profile */
> for (i = 0; i < 8; i++) {
> if (gains_ptr->now[i] || gains_ptr->now[i + 1])
> - interpolate(q, &buffer[q->gain_size_factor * i],
> + interpolate(q, &buffer1[q->gain_size_factor * i],
> gains_ptr->now[i], gains_ptr->now[i + 1]);
> }
>
> /* Save away the current to be previous block. */
> - memcpy(previous_buffer, buffer+q->samples_per_channel,
> - sizeof(float)*q->samples_per_channel);
> + memcpy(previous_buffer, buffer0, sizeof(float)*q->samples_per_channel);
> }
>
>
> @@ -904,14 +890,14 @@
> {
> int j;
>
> - cook_imlt(q, decode_buffer, q->mono_mdct_output);
> - gain_compensate(q, gains, previous_buffer);
> + imlt_gain(q, decode_buffer, gains, previous_buffer);
>
> /* Clip and convert floats to 16 bits.
> */
> for (j = 0; j < q->samples_per_channel; j++) {
for (j =q->samples_per_channel ... etc
Is that faster or is gcc smart enough to get it right ?
> out[chan + q->nb_channels * j] =
> - av_clip(lrintf(q->mono_mdct_output[j]), -32768, 32767);
> + av_clip(lrintf(q->mono_mdct_output[q->samples_per_channel + j]),
> + -32768, 32767);
> }
> }
>
>
MvH
Benjamin Larsson
More information about the ffmpeg-devel
mailing list