summaryrefslogtreecommitdiff
path: root/libavcodec
diff options
context:
space:
mode:
authorKostya Shishkov <kostya.shishkov@gmail.com>2013-09-07 21:06:22 +0200
committerAnton Khirnov <anton@khirnov.net>2013-11-26 08:31:10 +0100
commita16577d9857206089fd8bce6a342b31dbd7fb9b0 (patch)
tree45a4d07e2dddcd076bd0bf04ed2b4c65ed8e5d44 /libavcodec
parent56d061ce9da954560892e3551513d5ecc0439846 (diff)
downloadffmpeg-a16577d9857206089fd8bce6a342b31dbd7fb9b0.tar.gz
MSN Audio support
This is essentially a MS GSM decoder extension that supports more sampling rates and lower bitrates. Signed-off-by: Anton Khirnov <anton@khirnov.net>
Diffstat (limited to 'libavcodec')
-rw-r--r--libavcodec/gsm.h18
-rw-r--r--libavcodec/gsm_parser.c3
-rw-r--r--libavcodec/gsmdec.c19
-rw-r--r--libavcodec/gsmdec_data.c26
-rw-r--r--libavcodec/gsmdec_data.h2
-rw-r--r--libavcodec/gsmdec_template.c21
-rw-r--r--libavcodec/msgsmdec.c6
-rw-r--r--libavcodec/msgsmdec.h2
8 files changed, 80 insertions, 17 deletions
diff --git a/libavcodec/gsm.h b/libavcodec/gsm.h
index c7c3e22bde..238cb7359d 100644
--- a/libavcodec/gsm.h
+++ b/libavcodec/gsm.h
@@ -22,10 +22,24 @@
#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 */
diff --git a/libavcodec/gsm_parser.c b/libavcodec/gsm_parser.c
index 1d381fc109..c0befc7796 100644
--- a/libavcodec/gsm_parser.c
+++ b/libavcodec/gsm_parser.c
@@ -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:
diff --git a/libavcodec/gsmdec.c b/libavcodec/gsmdec.c
index 642f3b711f..b763ce8a58 100644
--- a/libavcodec/gsmdec.c
+++ b/libavcodec/gsmdec.c
@@ -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;
}
diff --git a/libavcodec/gsmdec_data.c b/libavcodec/gsmdec_data.c
index 8b75bb6a67..c9b3183a55 100644
--- a/libavcodec/gsmdec_data.c
+++ b/libavcodec/gsmdec_data.c
@@ -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
+};
diff --git a/libavcodec/gsmdec_data.h b/libavcodec/gsmdec_data.h
index 7a81da9a3b..f5581d53ba 100644
--- a/libavcodec/gsmdec_data.h
+++ b/libavcodec/gsmdec_data.h
@@ -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 */
diff --git a/libavcodec/gsmdec_template.c b/libavcodec/gsmdec_template.c
index b5222af4da..0b54dc54ce 100644
--- a/libavcodec/gsmdec_template.c
+++ b/libavcodec/gsmdec_template.c
@@ -28,13 +28,22 @@
#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));
diff --git a/libavcodec/msgsmdec.c b/libavcodec/msgsmdec.c
index 52b0f5db0a..be5062ad91 100644
--- a/libavcodec/msgsmdec.c
+++ b/libavcodec/msgsmdec.c
@@ -26,13 +26,13 @@
#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);
}
diff --git a/libavcodec/msgsmdec.h b/libavcodec/msgsmdec.h
index 76c87f1bd9..adbda9a9d0 100644
--- a/libavcodec/msgsmdec.h
+++ b/libavcodec/msgsmdec.h
@@ -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 */