]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/ra288.c
Fix lossless jpeg encoder to comply to spec and store full redundant
[ffmpeg] / libavcodec / ra288.c
index 43686d80bf97835e90543a2dde435a985c5c5c7d..353ae529a657da557cf40f393b56b9ba2a88ea68 100644 (file)
 #include "ra288.h"
 
 typedef struct {
-    float history[8];
-    float output[40];
-    float pr1[36];
-    float pr2[10];
-    int   phase, phasep;
-
-    float st1a[111], st1b[37], st1[37];
-    float st2a[38], st2b[11], st2[11];
-    float sb[41];
-    float lhist[10];
-} Real288_internal;
-
-/* Decode and produce output */
-static void decode(Real288_internal *glob, int amp_coef, int cb_coef)
-{
-    unsigned int x, y;
-    float f;
-    double sum, sumsum;
-    float *p1, *p2;
-    float buffer[5];
+    float sp_lpc[36];      ///< LPC coefficients for speech data (spec: A)
+    float gain_lpc[10];    ///< LPC coefficients for gain (spec: GB)
 
-    for (x=36; x--; glob->sb[x+5] = glob->sb[x]);
+    float sp_hist[111];    ///< Speech data history (spec: SB)
 
-    for (x=5; x--;) {
-        p1 = glob->sb+x;
-        p2 = glob->pr1;
-        for (sum=0, y=36; y--; sum -= (*(++p1))*(*(p2++)));
+    /** Speech part of the gain autocorrelation (spec: REXP) */
+    float sp_rec[37];
 
-        glob->sb[x] = sum;
-    }
+    float gain_hist[38];   ///< Log-gain history (spec: SBLG)
+
+    /** Recursive part of the gain autocorrelation (spec: REXPLG) */
+    float gain_rec[11];
+
+    float sp_block[41];    ///< Speech data of four blocks (spec: STTMP)
+    float gain_block[10];  ///< Gain data of four blocks (spec: GSTATE)
+} RA288Context;
+
+static av_cold int ra288_decode_init(AVCodecContext *avctx)
+{
+    avctx->sample_fmt = SAMPLE_FMT_S16;
+    return 0;
+}
+
+static inline float scalar_product_float(const float * v1, const float * v2,
+                                         int size)
+{
+    float res = 0.;
 
-    f = amptable[amp_coef];
+    while (size--)
+        res += *v1++ * *v2++;
 
-    /* convert log and do rms */
-    for (sum=32, x=10; x--; sum -= glob->pr2[x] * glob->lhist[x]);
+    return res;
+}
+
+static void colmult(float *tgt, const float *m1, const float *m2, int n)
+{
+    while (n--)
+        *tgt++ = *m1++ * *m2++;
+}
 
-    if (sum < 0)
-        sum = 0;
-    else if (sum > 60)
-        sum = 60;
+static void decode(RA288Context *ractx, float gain, int cb_coef)
+{
+    int i, j;
+    double sumsum;
+    float sum, buffer[5];
+    float *block = ractx->sp_block + 36; // Current block
 
-    sumsum = exp(sum * 0.1151292546497) * f;    /* pow(10.0,sum/20)*f */
+    memmove(ractx->sp_block, ractx->sp_block + 5, 36*sizeof(*ractx->sp_block));
 
-    for (sum=0, x=5; x--;) {
-        buffer[x] = codetable[cb_coef][x] * sumsum;
-        sum += buffer[x] * buffer[x];
+    for (i=0; i < 5; i++) {
+        block[i] = 0.;
+        for (j=0; j < 36; j++)
+            block[i] -= block[i-1-j]*ractx->sp_lpc[j];
     }
 
-    if ((sum /= 5) < 1)
-        sum = 1;
+    /* block 46 of G.728 spec */
+    sum = 32.;
+    for (i=0; i < 10; i++)
+        sum -= ractx->gain_block[9-i] * ractx->gain_lpc[i];
 
-    /* shift and store */
-    for (x=10; --x; glob->lhist[x] = glob->lhist[x-1]);
+    /* block 47 of G.728 spec */
+    sum = av_clipf(sum, 0, 60);
 
-    *glob->lhist = glob->history[glob->phase] = 10 * log10(sum) - 32;
+    /* block 48 of G.728 spec */
+    sumsum = exp(sum * 0.1151292546497) * gain; /* pow(10.0,sum/20)*gain */
 
-    for (x=1; x < 5; x++)
-        for (y=x; y--; buffer[x] -= glob->pr1[x-y-1] * buffer[y]);
+    for (i=0; i < 5; i++)
+        buffer[i] = codetable[cb_coef][i] * sumsum;
 
-    /* output */
-    for (x=0; x < 5; x++) {
-        f = glob->sb[4-x] + buffer[x];
+    sum = scalar_product_float(buffer, buffer, 5) / 5;
 
-        if (f > 4095)
-            f = 4095;
-        else if (f < -4095)
-            f = -4095;
+    sum = FFMAX(sum, 1);
 
-        glob->output[glob->phasep+x] = glob->sb[4-x] = f;
-    }
-}
+    /* shift and store */
+    memmove(ractx->gain_block, ractx->gain_block + 1,
+            9 * sizeof(*ractx->gain_block));
 
-/* column multiply */
-static void colmult(float *tgt, float *m1, const float *m2, int n)
-{
-    while (n--)
-        *(tgt++) = (*(m1++)) * (*(m2++));
+    ractx->gain_block[9] = 10 * log10(sum) - 32;
+
+    for (i=1; i < 5; i++)
+        for (j=i-1; j >= 0; j--)
+            buffer[i] -= ractx->sp_lpc[i-j-1] * buffer[j];
+
+    /* output */
+    for (i=0; i < 5; i++)
+        block[i] = av_clipf(block[i] + buffer[i], -4095, 4095);
 }
 
-static int pred(float *in, float *tgt, int n)
+/**
+ * Converts autocorrelation coefficients to LPC coefficients using the
+ * Levinson-Durbin algorithm. See blocks 37 and 50 of the G.728 specification.
+ *
+ * @return 0 if success, -1 if fail
+ */
+static int eval_lpc_coeffs(const float *in, float *tgt, int n)
 {
-    int x, y;
-    float *p1, *p2;
+    int i, j;
     double f0, f1, f2;
-    float temp;
 
     if (in[n] == 0)
-        return 0;
+        return -1;
 
     if ((f0 = *in) <= 0)
-        return 0;
+        return -1;
+
+    in--; // To avoid a -1 subtraction in the inner loop
 
-    for (x=1 ; ; x++) {
-        if (n < x)
-            return 1;
-
-        p1 = in + x;
-        p2 = tgt;
-        f1 = *(p1--);
-        for (y=x; --y; f1 += (*(p1--))*(*(p2++)));
-
-        p1 = tgt + x - 1;
-        p2 = tgt;
-        *(p1--) = f2 = -f1/f0;
-        for (y=x >> 1; y--;) {
-            temp = *p2 + *p1 * f2;
-            *(p1--) += *p2 * f2;
-            *(p2++) = temp;
+    for (i=1; i <= n; i++) {
+        f1 = in[i+1];
+
+        for (j=0; j < i - 1; j++)
+            f1 += in[i-j]*tgt[j];
+
+        tgt[i-1] = f2 = -f1/f0;
+        for (j=0; j < i >> 1; j++) {
+            float temp = tgt[j] + tgt[i-j-2]*f2;
+            tgt[i-j-2] += tgt[j]*f2;
+            tgt[j] = temp;
         }
         if ((f0 += f1*f2) < 0)
-            return 0;
+            return -1;
     }
+
+    return 0;
 }
 
-/* product sum (lsf) */
-static void prodsum(float *tgt, float *src, int len, int n)
+static void convolve(float *tgt, const float *src, int len, int n)
 {
-    unsigned int x;
-    float *p1, *p2;
-    double sum;
-
-    while (n >= 0) {
-        p1 = (p2 = src) - n;
-        for (sum=0, x=len; x--; sum += (*p1++) * (*p2++));
-        tgt[n--] = sum;
-    }
+    for (; n >= 0; n--)
+        tgt[n] = scalar_product_float(src, src - n, len);
+
 }
 
-static void co(int n, int i, int j, float *in, float *out, float *st1,
-               float *st2, const float *table)
+/**
+ * Hybrid window filtering. See blocks 36 and 49 of the G.728 specification.
+ *
+ * @param order   the order of the filter
+ * @param n       the length of the input
+ * @param non_rec the number of non-recursive samples
+ * @param out     the filter output
+ * @param in      pointer to the input of the filter
+ * @param hist    pointer to the input history of the filter. It is updated by
+ *                this function.
+ * @param out     pointer to the non-recursive part of the output
+ * @param out2    pointer to the recursive part of the output
+ * @param window  pointer to the windowing function table
+ */
+static void do_hybrid_window(int order, int n, int non_rec, const float *in,
+                             float *out, float *hist, float *out2,
+                             const float *window)
 {
-    int a, b, c;
-    unsigned int x;
-    float *fp;
-    float buffer1[37];
-    float buffer2[37];
-    float work[111];
-
-    /* rotate and multiply */
-    c = (b = (a = n + i) + j) - i;
-    fp = st1 + i;
-    for (x=0; x < b; x++) {
-        if (x == c)
-            fp=in;
-        work[x] = *(table++) * (*(st1++) = *(fp++));
-    }
+    int i;
+    float buffer1[order + 1];
+    float buffer2[order + 1];
+    float work[order + n + non_rec];
+
+    /* update history */
+    memmove(hist                  , hist + n, (order + non_rec)*sizeof(*hist));
+    memcpy (hist + order + non_rec, in      , n                *sizeof(*hist));
 
-    prodsum(buffer1, work + n, i, n);
-    prodsum(buffer2, work + a, j, n);
+    colmult(work, window, hist, order + n + non_rec);
 
-    for (x=0;x<=n;x++) {
-        *st2 = *st2 * (0.5625) + buffer1[x];
-        out[x] = *(st2++) + buffer2[x];
+    convolve(buffer1, work + order    , n      , order);
+    convolve(buffer2, work + order + n, non_rec, order);
+
+    for (i=0; i <= order; i++) {
+        out2[i] = out2[i] * 0.5625 + buffer1[i];
+        out [i] = out2[i]          + buffer2[i];
     }
-    *out *= 1.00390625; /* to prevent clipping */
+
+    /* Multiply by the white noise correcting factor (WNCF) */
+    *out *= 257./256.;
 }
 
-static void update(Real288_internal *glob)
+/**
+ * Backward synthesis filter. Find the LPC coefficients from past speech data.
+ */
+static void backward_filter(RA288Context *ractx)
 {
-    int x,y;
-    float buffer1[40], temp1[37];
-    float buffer2[8], temp2[11];
+    float temp1[37]; // RTMP in the spec
+    float temp2[11]; // GPTPMP in the spec
 
-    for (x=0, y=glob->phasep+5; x < 40; buffer1[x++] = glob->output[(y++)%40]);
+    do_hybrid_window(36, 40, 35, ractx->sp_block+1, temp1, ractx->sp_hist,
+                     ractx->sp_rec, syn_window);
 
-    co(36, 40, 35, buffer1, temp1, glob->st1a, glob->st1b, table1);
+    if (!eval_lpc_coeffs(temp1, ractx->sp_lpc, 36))
+        colmult(ractx->sp_lpc, ractx->sp_lpc, syn_bw_tab, 36);
 
-    if (pred(temp1, glob->st1, 36))
-        colmult(glob->pr1, glob->st1, table1a, 36);
+    do_hybrid_window(10, 8, 20, ractx->gain_block+2, temp2, ractx->gain_hist,
+                     ractx->gain_rec, gain_window);
 
-    for (x=0, y=glob->phase + 1; x < 8; buffer2[x++] = glob->history[(y++) % 8]);
-
-    co(10, 8, 20, buffer2, temp2, glob->st2a, glob->st2b, table2);
-
-    if (pred(temp2, glob->st2, 10))
-        colmult(glob->pr2, glob->st2, table2a, 10);
+    if (!eval_lpc_coeffs(temp2, ractx->gain_lpc, 10))
+        colmult(ractx->gain_lpc, ractx->gain_lpc, gain_bw_tab, 10);
 }
 
-/* Decode a block (celp) */
 static int ra288_decode_frame(AVCodecContext * avctx, void *data,
                               int *data_size, const uint8_t * buf,
                               int buf_size)
 {
     int16_t *out = data;
-    int x, y;
-    Real288_internal *glob = avctx->priv_data;
+    int i, j;
+    RA288Context *ractx = avctx->priv_data;
     GetBitContext gb;
 
     if (buf_size < avctx->block_align) {
@@ -220,18 +236,22 @@ static int ra288_decode_frame(AVCodecContext * avctx, void *data,
         return 0;
     }
 
+    if (*data_size < 32*5*2)
+        return -1;
+
     init_get_bits(&gb, buf, avctx->block_align * 8);
 
-    for (x=0; x < 32; x++) {
-        int amp_coef = get_bits(&gb, 3);
-        int cb_coef = get_bits(&gb, 6 + (x&1));
-        glob->phasep = (glob->phase = x & 7) * 5;
-        decode(glob, amp_coef, cb_coef);
+    for (i=0; i < 32; i++) {
+        float gain = amptable[get_bits(&gb, 3)];
+        int cb_coef = get_bits(&gb, 6 + (i&1));
 
-        for (y=0; y<5; *(out++) = 8 * glob->output[glob->phasep+(y++)]);
+        decode(ractx, gain, cb_coef);
 
-        if (glob->phase == 3)
-            update(glob);
+        for (j=0; j < 5; j++)
+            *(out++) = 8 * ractx->sp_block[36 + j];
+
+        if ((i & 7) == 3)
+            backward_filter(ractx);
     }
 
     *data_size = (char *)out - (char *)data;
@@ -243,8 +263,8 @@ AVCodec ra_288_decoder =
     "real_288",
     CODEC_TYPE_AUDIO,
     CODEC_ID_RA_288,
-    sizeof(Real288_internal),
-    NULL,
+    sizeof(RA288Context),
+    ra288_decode_init,
     NULL,
     NULL,
     ra288_decode_frame,