MSN Audio support
authorKostya Shishkov <kostya.shishkov@gmail.com>
Sat, 7 Sep 2013 19:06:22 +0000 (21:06 +0200)
committerAnton Khirnov <anton@khirnov.net>
Tue, 26 Nov 2013 07:31:10 +0000 (08:31 +0100)
This is essentially a MS GSM decoder extension that supports more
sampling rates and lower bitrates.

Signed-off-by: Anton Khirnov <anton@khirnov.net>
libavcodec/gsm.h
libavcodec/gsm_parser.c
libavcodec/gsmdec.c
libavcodec/gsmdec_data.c
libavcodec/gsmdec_data.h
libavcodec/gsmdec_template.c
libavcodec/msgsmdec.c
libavcodec/msgsmdec.h
libavformat/riff.c

index c7c3e22..238cb73 100644 (file)
 #define AVCODEC_GSM_H
 
 /* bytes per block */
-#define GSM_BLOCK_SIZE    33
-#define GSM_MS_BLOCK_SIZE 65
+#define GSM_BLOCK_SIZE     33
+#define GSM_MS_BLOCK_SIZE  65
+#define MSN_MIN_BLOCK_SIZE 41
 
 /* samples per block */
 #define GSM_FRAME_SIZE 160
 
+enum GSMModes {
+    GSM_13000 = 0,
+    MSN_12400,
+    MSN_11800,
+    MSN_11200,
+    MSN_10600,
+    MSN_10000,
+    MSN_9400,
+    MSN_8800,
+    MSN_8200,
+    NUM_GSM_MODES
+};
+
 #endif /* AVCODEC_GSM_H */
index 1d381fc..c0befc7 100644 (file)
@@ -50,7 +50,8 @@ static int gsm_parse(AVCodecParserContext *s1, AVCodecContext *avctx,
             s->duration   = GSM_FRAME_SIZE;
             break;
         case AV_CODEC_ID_GSM_MS:
-            s->block_size = GSM_MS_BLOCK_SIZE;
+            s->block_size = avctx->block_align ? avctx->block_align
+                                               : GSM_MS_BLOCK_SIZE;
             s->duration   = GSM_FRAME_SIZE * 2;
             break;
         default:
index 642f3b7..b763ce8 100644 (file)
@@ -36,7 +36,8 @@ static av_cold int gsm_init(AVCodecContext *avctx)
 {
     avctx->channels       = 1;
     avctx->channel_layout = AV_CH_LAYOUT_MONO;
-    avctx->sample_rate    = 8000;
+    if (!avctx->sample_rate)
+        avctx->sample_rate = 8000;
     avctx->sample_fmt     = AV_SAMPLE_FMT_S16;
 
     switch (avctx->codec_id) {
@@ -46,7 +47,16 @@ static av_cold int gsm_init(AVCodecContext *avctx)
         break;
     case AV_CODEC_ID_GSM_MS:
         avctx->frame_size  = 2 * GSM_FRAME_SIZE;
-        avctx->block_align = GSM_MS_BLOCK_SIZE;
+        if (!avctx->block_align)
+            avctx->block_align = GSM_MS_BLOCK_SIZE;
+        else
+            if (avctx->block_align < MSN_MIN_BLOCK_SIZE ||
+                avctx->block_align > GSM_MS_BLOCK_SIZE  ||
+                (avctx->block_align - MSN_MIN_BLOCK_SIZE) % 3) {
+                av_log(avctx, AV_LOG_ERROR, "Invalid block alignment %d\n",
+                       avctx->block_align);
+                return AVERROR_INVALIDDATA;
+            }
     }
 
     return 0;
@@ -80,12 +90,13 @@ static int gsm_decode_frame(AVCodecContext *avctx, void *data,
         init_get_bits(&gb, buf, buf_size * 8);
         if (get_bits(&gb, 4) != 0xd)
             av_log(avctx, AV_LOG_WARNING, "Missing GSM magic!\n");
-        res = gsm_decode_block(avctx, samples, &gb);
+        res = gsm_decode_block(avctx, samples, &gb, GSM_13000);
         if (res < 0)
             return res;
         break;
     case AV_CODEC_ID_GSM_MS:
-        res = ff_msgsm_decode_block(avctx, samples, buf);
+        res = ff_msgsm_decode_block(avctx, samples, buf,
+                                    (GSM_MS_BLOCK_SIZE - avctx->block_align) / 3);
         if (res < 0)
             return res;
     }
index 8b75bb6..c9b3183 100644 (file)
@@ -92,3 +92,29 @@ const int16_t ff_gsm_dequant_tab[64][8] = {
     {-26879, -19199, -11520,  -3840,   3840,  11520,  19199,  26879},
     {-28671, -20479, -12288,  -4096,   4096,  12288,  20479,  28671}
 };
+
+static const int apcm_bits[11][13] = {
+    { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+    { 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 },
+    { 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1 },
+    { 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1 },
+    { 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1 },
+    { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+    { 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+    { 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+    { 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+    { 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+    { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }
+};
+
+const int* const ff_gsm_apcm_bits[][4] = {
+    { apcm_bits[10], apcm_bits[10], apcm_bits[10], apcm_bits[10] }, // 13000
+    { apcm_bits[10], apcm_bits[10], apcm_bits[10], apcm_bits[ 6] }, // 12400
+    { apcm_bits[10], apcm_bits[10], apcm_bits[ 7], apcm_bits[ 5] }, // 11800
+    { apcm_bits[10], apcm_bits[ 8], apcm_bits[ 5], apcm_bits[ 5] }, // 11200
+    { apcm_bits[ 9], apcm_bits[ 5], apcm_bits[ 5], apcm_bits[ 5] }, // 10600
+    { apcm_bits[ 5], apcm_bits[ 5], apcm_bits[ 5], apcm_bits[ 1] }, // 10000
+    { apcm_bits[ 5], apcm_bits[ 5], apcm_bits[ 2], apcm_bits[ 0] }, //  9400
+    { apcm_bits[ 5], apcm_bits[ 3], apcm_bits[ 0], apcm_bits[ 0] }, //  8800
+    { apcm_bits[ 4], apcm_bits[ 0], apcm_bits[ 0], apcm_bits[ 0] }, //  8200
+};
index 7a81da9..f5581d5 100644 (file)
@@ -40,4 +40,6 @@ typedef struct GSMContext {
 extern const uint16_t ff_gsm_long_term_gain_tab[4];
 extern const int16_t ff_gsm_dequant_tab[64][8];
 
+extern const int* const ff_gsm_apcm_bits[][4];
+
 #endif /* AVCODEC_GSMDEC_DATA_H */
index b5222af..0b54dc5 100644 (file)
 #include "gsm.h"
 #include "gsmdec_data.h"
 
-static void apcm_dequant_add(GetBitContext *gb, int16_t *dst)
+static const int requant_tab[4][8] = {
+    { 0 },
+    { 0, 7 },
+    { 0, 2, 5, 7 },
+    { 0, 1, 2, 3, 4, 5, 6, 7 }
+};
+
+static void apcm_dequant_add(GetBitContext *gb, int16_t *dst, const int *frame_bits)
 {
-    int i;
+    int i, val;
     int maxidx = get_bits(gb, 6);
     const int16_t *tab = ff_gsm_dequant_tab[maxidx];
-    for (i = 0; i < 13; i++)
-        dst[3*i] += tab[get_bits(gb, 3)];
+    for (i = 0; i < 13; i++) {
+        val = get_bits(gb, frame_bits[i]);
+        dst[3*i] += tab[requant_tab[frame_bits[i]][val]];
+    }
 }
 
 static inline int gsm_mult(int a, int b)
@@ -118,7 +127,7 @@ static int postprocess(int16_t *data, int msr)
 }
 
 static int gsm_decode_block(AVCodecContext *avctx, int16_t *samples,
-                            GetBitContext *gb)
+                            GetBitContext *gb, int mode)
 {
     GSMContext *ctx = avctx->priv_data;
     int i;
@@ -139,7 +148,7 @@ static int gsm_decode_block(AVCodecContext *avctx, int16_t *samples,
         int offset   = get_bits(gb, 2);
         lag = av_clip(lag, 40, 120);
         long_term_synth(ref_dst, lag, gain_idx);
-        apcm_dequant_add(gb, ref_dst + offset);
+        apcm_dequant_add(gb, ref_dst + offset, ff_gsm_apcm_bits[mode][i]);
         ref_dst += 40;
     }
     memcpy(ctx->ref_buf, ctx->ref_buf + 160, 120 * sizeof(*ctx->ref_buf));
index 52b0f5d..be5062a 100644 (file)
 #include "gsmdec_template.c"
 
 int ff_msgsm_decode_block(AVCodecContext *avctx, int16_t *samples,
-                          const uint8_t *buf)
+                          const uint8_t *buf, int mode)
 {
     int res;
     GetBitContext gb;
     init_get_bits(&gb, buf, GSM_MS_BLOCK_SIZE * 8);
-    res = gsm_decode_block(avctx, samples, &gb);
+    res = gsm_decode_block(avctx, samples, &gb, mode);
     if (res < 0)
         return res;
-    return gsm_decode_block(avctx, samples + GSM_FRAME_SIZE, &gb);
+    return gsm_decode_block(avctx, samples + GSM_FRAME_SIZE, &gb, mode);
 }
index 76c87f1..adbda9a 100644 (file)
@@ -25,6 +25,6 @@
 #include "avcodec.h"
 
 int ff_msgsm_decode_block(AVCodecContext *avctx, int16_t *samples,
-                          const uint8_t *buf);
+                          const uint8_t *buf, int mode);
 
 #endif /* AVCODEC_MSGSMDEC_H */
index 2668d19..536ba43 100644 (file)
@@ -338,6 +338,7 @@ const AVCodecTag ff_codec_wav_tags[] = {
     { AV_CODEC_ID_ADPCM_YAMAHA,    0x0020 },
     { AV_CODEC_ID_TRUESPEECH,      0x0022 },
     { AV_CODEC_ID_GSM_MS,          0x0031 },
+    { AV_CODEC_ID_GSM_MS,          0x0032 },
     { AV_CODEC_ID_ADPCM_G726,      0x0045 },
     { AV_CODEC_ID_MP2,             0x0050 },
     { AV_CODEC_ID_MP3,             0x0055 },