diff --git a/libavcodec/gsm.h b/libavcodec/gsm.h index e56f4cd0b4..53d65c4dc7 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 f76bbef3e7..9a3b94ef1d 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 7ca9677923..077056a9be 100644 --- a/libavcodec/gsmdec.c +++ b/libavcodec/gsmdec.c @@ -55,7 +55,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; @@ -87,12 +96,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 4324ea28a9..d90c69b98f 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 fd89ed63ee..b57194b8d1 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 0f559530ec..0c60813a4a 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 90e83ae7ac..4c4ddb46f5 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 3bfd1fd407..b2a1a627a5 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 */