This is essentially a MS GSM decoder extension that supports more
sampling rates and lower bitrates.
---
Because of lower bitrates it can have varying block sizes too - from
65, 62, 59 down to 41. And thus we need to disable setting fixed block size in
that case.
Most of the details were figured during VideoLAN meeting on Sunday.
---
libavcodec/gsm.h | 18 ++++++++++++++++--
libavcodec/gsm_parser.c | 3 ++-
libavcodec/gsmdec.c | 19 +++++++++++++++----
libavcodec/gsmdec_data.c | 26 ++++++++++++++++++++++++++
libavcodec/gsmdec_data.h | 2 ++
libavcodec/gsmdec_template.c | 21 +++++++++++++++------
libavcodec/msgsmdec.c | 6 +++---
libavcodec/msgsmdec.h | 2 +-
libavformat/riff.c | 1 +
9 files changed, 81 insertions(+), 17 deletions(-)
diff --git a/libavcodec/gsm.h b/libavcodec/gsm.h
index c7c3e22..238cb73 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 1d381fc..c0befc7 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 d67f0b4..866e892 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 8b75bb6..8ef3160 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* 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 7a81da9..32d4858 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* ff_gsm_apcm_bits[][4];
+
#endif /* AVCODEC_GSMDEC_DATA_H */
diff --git a/libavcodec/gsmdec_template.c b/libavcodec/gsmdec_template.c
index b5222af..0b54dc5 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 52b0f5d..be5062a 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 76c87f1..adbda9a 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 */
diff --git a/libavformat/riff.c b/libavformat/riff.c
index 8216261..4181554 100644
--- a/libavformat/riff.c
+++ b/libavformat/riff.c
@@ -337,6 +337,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 },
--
1.7.9.5
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel