]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/imc.c
alacdec: fix packed sample output with 5.1
[ffmpeg] / libavcodec / imc.c
index d53693c848f7b426e9f6fd6c8a2b299a7356e437..2650bf7821f9094eff545fcb1e56fd7c90bfe403 100644 (file)
@@ -4,20 +4,20 @@
  * Copyright (c) 2006 Benjamin Larsson
  * Copyright (c) 2006 Konstantin Shishkov
  *
- * This file is part of Libav.
+ * This file is part of FFmpeg.
  *
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
@@ -79,7 +79,7 @@ typedef struct IMCChannel {
 typedef struct {
     AVFrame frame;
 
-    IMCChannel chctx[1];
+    IMCChannel chctx[2];
 
     /** MDCT tables */
     //@{
@@ -98,6 +98,9 @@ typedef struct {
     FFTContext fft;
     DECLARE_ALIGNED(32, FFTComplex, samples)[COEFFS / 2];
     float *out_samples;
+
+    int8_t cyclTab[32], cyclTab2[32];
+    float  weights1[31], weights2[31];
 } IMCContext;
 
 static VLC huffman_vlc[4][4];
@@ -111,13 +114,70 @@ static const int vlc_offsets[17] = {
 
 static VLC_TYPE vlc_tables[VLC_TABLES_SIZE][2];
 
+static inline double freq2bark(double freq)
+{
+    return 3.5 * atan((freq / 7500.0) * (freq / 7500.0)) + 13.0 * atan(freq * 0.00076);
+}
+
+static av_cold void iac_generate_tabs(IMCContext *q, int sampling_rate)
+{
+    double freqmin[32], freqmid[32], freqmax[32];
+    double scale = sampling_rate / (256.0 * 2.0 * 2.0);
+    double nyquist_freq = sampling_rate * 0.5;
+    double freq, bark, prev_bark = 0, tf, tb;
+    int i, j;
+
+    for (i = 0; i < 32; i++) {
+        freq = (band_tab[i] + band_tab[i + 1] - 1) * scale;
+        bark = freq2bark(freq);
+
+        if (i > 0) {
+            tb = bark - prev_bark;
+            q->weights1[i - 1] = pow(10.0, -1.0 * tb);
+            q->weights2[i - 1] = pow(10.0, -2.7 * tb);
+        }
+        prev_bark = bark;
+
+        freqmid[i] = freq;
+
+        tf = freq;
+        while (tf < nyquist_freq) {
+            tf += 0.5;
+            tb =  freq2bark(tf);
+            if (tb > bark + 0.5)
+                break;
+        }
+        freqmax[i] = tf;
+
+        tf = freq;
+        while (tf > 0.0) {
+            tf -= 0.5;
+            tb =  freq2bark(tf);
+            if (tb <= bark - 0.5)
+                break;
+        }
+        freqmin[i] = tf;
+    }
+
+    for (i = 0; i < 32; i++) {
+        freq = freqmax[i];
+        for (j = 31; j > 0 && freq <= freqmid[j]; j--);
+        q->cyclTab[i] = j + 1;
+
+        freq = freqmin[i];
+        for (j = 0; j < 32 && freq >= freqmid[j]; j++);
+        q->cyclTab2[i] = j - 1;
+    }
+}
+
 static av_cold int imc_decode_init(AVCodecContext *avctx)
 {
     int i, j, ret;
     IMCContext *q = avctx->priv_data;
     double r1, r2;
 
-    if (avctx->channels != 1) {
+    if ((avctx->codec_id == CODEC_ID_IMC && avctx->channels != 1)
+        || (avctx->codec_id == CODEC_ID_IAC && avctx->channels > 2)) {
         av_log_ask_for_sample(avctx, "Number of channels is not supported\n");
         return AVERROR_PATCHWELCOME;
     }
@@ -169,6 +229,18 @@ static av_cold int imc_decode_init(AVCodecContext *avctx)
     }
     q->one_div_log2 = 1 / log(2);
 
+    if (avctx->codec_id == CODEC_ID_IAC) {
+    }
+
+    if (avctx->codec_id == CODEC_ID_IAC) {
+        iac_generate_tabs(q, avctx->sample_rate);
+    } else {
+        memcpy(q->cyclTab,  cyclTab,  sizeof(cyclTab));
+        memcpy(q->cyclTab2, cyclTab2, sizeof(cyclTab2));
+        memcpy(q->weights1, imc_weights1, sizeof(imc_weights1));
+        memcpy(q->weights2, imc_weights2, sizeof(imc_weights2));
+    }
+
     if ((ret = ff_fft_init(&q->fft, 7, 1))) {
         av_log(avctx, AV_LOG_INFO, "FFT init failed\n");
         return ret;
@@ -210,13 +282,13 @@ static void imc_calculate_coeffs(IMCContext *q, float *flcoeffs1,
     }
 
     for (i = 0; i < BANDS; i++) {
-        for (cnt2 = i; cnt2 < cyclTab[i]; cnt2++)
+        for (cnt2 = i; cnt2 < q->cyclTab[i]; cnt2++)
             flcoeffs5[cnt2] = flcoeffs5[cnt2] + workT3[i];
         workT2[cnt2 - 1] = workT2[cnt2 - 1] + workT3[i];
     }
 
     for (i = 1; i < BANDS; i++) {
-        accum = (workT2[i - 1] + accum) * imc_weights1[i - 1];
+        accum = (workT2[i - 1] + accum) * q->weights1[i - 1];
         flcoeffs5[i] += accum;
     }
 
@@ -224,7 +296,7 @@ static void imc_calculate_coeffs(IMCContext *q, float *flcoeffs1,
         workT2[i] = 0.0;
 
     for (i = 0; i < BANDS; i++) {
-        for (cnt2 = i - 1; cnt2 > cyclTab2[i]; cnt2--)
+        for (cnt2 = i - 1; cnt2 > q->cyclTab2[i]; cnt2--)
             flcoeffs5[cnt2] += workT3[i];
         workT2[cnt2+1] += workT3[i];
     }
@@ -232,7 +304,7 @@ static void imc_calculate_coeffs(IMCContext *q, float *flcoeffs1,
     accum = 0.0;
 
     for (i = BANDS-2; i >= 0; i--) {
-        accum = (workT2[i+1] + accum) * imc_weights2[i];
+        accum = (workT2[i+1] + accum) * q->weights2[i];
         flcoeffs5[i] += accum;
         // there is missing code here, but it seems to never be triggered
     }
@@ -589,10 +661,12 @@ static void imc_adjust_bit_allocation(IMCContext *q, IMCChannel *chctx,
     }
 }
 
-static void imc_imdct256(IMCContext *q, IMCChannel *chctx)
+static void imc_imdct256(IMCContext *q, IMCChannel *chctx, int channels)
 {
     int i;
     float re, im;
+    float *dst1 = q->out_samples;
+    float *dst2 = q->out_samples + (COEFFS - 1) * channels;
 
     /* prerotation */
     for (i = 0; i < COEFFS / 2; i++) {
@@ -610,10 +684,12 @@ static void imc_imdct256(IMCContext *q, IMCChannel *chctx)
     for (i = 0; i < COEFFS / 2; i++) {
         re = ( q->samples[i].re * q->post_cos[i]) + (-q->samples[i].im * q->post_sin[i]);
         im = (-q->samples[i].im * q->post_cos[i]) - ( q->samples[i].re * q->post_sin[i]);
-        q->out_samples[i * 2]              =  (q->mdct_sine_window[COEFFS - 1 - i * 2] * chctx->last_fft_im[i])
-                                            + (q->mdct_sine_window[i * 2] * re);
-        q->out_samples[COEFFS - 1 - i * 2] =  (q->mdct_sine_window[i * 2] * chctx->last_fft_im[i])
-                                            - (q->mdct_sine_window[COEFFS - 1 - i * 2] * re);
+        *dst1 =  (q->mdct_sine_window[COEFFS - 1 - i * 2] * chctx->last_fft_im[i])
+               + (q->mdct_sine_window[i * 2] * re);
+        *dst2 =  (q->mdct_sine_window[i * 2] * chctx->last_fft_im[i])
+               - (q->mdct_sine_window[COEFFS - 1 - i * 2] * re);
+        dst1 += channels * 2;
+        dst2 -= channels * 2;
         chctx->last_fft_im[i] = im;
     }
 }
@@ -697,16 +773,17 @@ static int imc_decode_block(AVCodecContext *avctx, IMCContext *q, int ch)
 
     /* Check the frame header */
     imc_hdr = get_bits(&q->gb, 9);
-    if (imc_hdr != IMC_FRAME_ID) {
-        av_log(avctx, AV_LOG_ERROR, "imc frame header check failed!\n");
-        av_log(avctx, AV_LOG_ERROR, "got %x instead of 0x21.\n", imc_hdr);
+    if (imc_hdr & 0x18) {
+        av_log(avctx, AV_LOG_ERROR, "frame header check failed!\n");
+        av_log(avctx, AV_LOG_ERROR, "got %X.\n", imc_hdr);
         return AVERROR_INVALIDDATA;
     }
     stream_format_code = get_bits(&q->gb, 3);
 
     if (stream_format_code & 1) {
-        av_log(avctx, AV_LOG_ERROR, "Stream code format %X is not supported\n", stream_format_code);
-        return AVERROR_INVALIDDATA;
+        av_log_ask_for_sample(avctx, "Stream format %X is not supported\n",
+                              stream_format_code);
+        return AVERROR_PATCHWELCOME;
     }
 
 //    av_log(avctx, AV_LOG_DEBUG, "stream_format_code = %d\n", stream_format_code);
@@ -769,6 +846,11 @@ static int imc_decode_block(AVCodecContext *avctx, IMCContext *q, int ch)
             }
         }
     }
+    if (avctx->codec_id == CODEC_ID_IAC) {
+        bitscount += !!chctx->bandWidthT[BANDS - 1];
+        if (!(stream_format_code & 0x2))
+            bitscount += 16;
+    }
 
     if ((ret = bit_allocation(q, chctx, stream_format_code,
                               512 - bitscount - get_bits_count(&q->gb),
@@ -840,7 +922,7 @@ static int imc_decode_block(AVCodecContext *avctx, IMCContext *q, int ch)
 
     memset(chctx->skipFlags, 0, sizeof(chctx->skipFlags));
 
-    imc_imdct256(q, chctx);
+    imc_imdct256(q, chctx, avctx->channels);
 
     return 0;
 }
@@ -856,8 +938,8 @@ static int imc_decode_frame(AVCodecContext *avctx, void *data,
 
     LOCAL_ALIGNED_16(uint16_t, buf16, [IMC_BLOCK_SIZE / 2]);
 
-    if (buf_size < IMC_BLOCK_SIZE) {
-        av_log(avctx, AV_LOG_ERROR, "imc frame too small!\n");
+    if (buf_size < IMC_BLOCK_SIZE * avctx->channels) {
+        av_log(avctx, AV_LOG_ERROR, "frame too small!\n");
         return AVERROR_INVALIDDATA;
     }
 
@@ -881,6 +963,18 @@ static int imc_decode_frame(AVCodecContext *avctx, void *data,
             return ret;
     }
 
+    if (avctx->channels == 2) {
+        float *src = (float*)q->frame.data[0], t1, t2;
+
+        for (i = 0; i < COEFFS; i++) {
+            t1     = src[0];
+            t2     = src[1];
+            src[0] = t1 + t2;
+            src[1] = t1 - t2;
+            src   += 2;
+        }
+    }
+
     *got_frame_ptr   = 1;
     *(AVFrame *)data = q->frame;
 
@@ -897,7 +991,7 @@ static av_cold int imc_decode_close(AVCodecContext * avctx)
     return 0;
 }
 
-
+#if CONFIG_IMC_DECODER
 AVCodec ff_imc_decoder = {
     .name           = "imc",
     .type           = AVMEDIA_TYPE_AUDIO,
@@ -909,3 +1003,17 @@ AVCodec ff_imc_decoder = {
     .capabilities   = CODEC_CAP_DR1,
     .long_name      = NULL_IF_CONFIG_SMALL("IMC (Intel Music Coder)"),
 };
+#endif
+#if CONFIG_IAC_DECODER
+AVCodec ff_iac_decoder = {
+    .name           = "iac",
+    .type           = AVMEDIA_TYPE_AUDIO,
+    .id             = CODEC_ID_IAC,
+    .priv_data_size = sizeof(IMCContext),
+    .init           = imc_decode_init,
+    .close          = imc_decode_close,
+    .decode         = imc_decode_frame,
+    .capabilities   = CODEC_CAP_DR1,
+    .long_name      = NULL_IF_CONFIG_SMALL("IAC (Indeo Audio Coder)"),
+};
+#endif