diff options
author | Kostya Shishkov <kostya.shishkov@gmail.com> | 2013-09-07 21:06:22 +0200 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2013-11-26 08:31:10 +0100 |
commit | a16577d9857206089fd8bce6a342b31dbd7fb9b0 (patch) | |
tree | 45a4d07e2dddcd076bd0bf04ed2b4c65ed8e5d44 | |
parent | 56d061ce9da954560892e3551513d5ecc0439846 (diff) | |
download | ffmpeg-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>
-rw-r--r-- | libavcodec/gsm.h | 18 | ||||
-rw-r--r-- | libavcodec/gsm_parser.c | 3 | ||||
-rw-r--r-- | libavcodec/gsmdec.c | 19 | ||||
-rw-r--r-- | libavcodec/gsmdec_data.c | 26 | ||||
-rw-r--r-- | libavcodec/gsmdec_data.h | 2 | ||||
-rw-r--r-- | libavcodec/gsmdec_template.c | 21 | ||||
-rw-r--r-- | libavcodec/msgsmdec.c | 6 | ||||
-rw-r--r-- | libavcodec/msgsmdec.h | 2 | ||||
-rw-r--r-- | libavformat/riff.c | 1 |
9 files changed, 81 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 */ diff --git a/libavformat/riff.c b/libavformat/riff.c index 2668d19840..536ba43dd0 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -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 }, |