[FFmpeg-devel] [PATCH] GSM 6.10 audio decoder
Ronald S. Bultje
rsbultje
Mon Jul 5 15:47:02 CEST 2010
Hi,
On Sat, Jul 3, 2010 at 7:03 PM, Reimar D?ffinger
<Reimar.Doeffinger at gmx.de> wrote:
> I fear I may have gone a bit too far when removing clipping protections,
Looks fine to me, I think...
> As for the purpose: I want to throw out MPlayer's "native" variant
> of this, which is basically libgsm just with a bit more of those horrible
> old-style function declarations.
Great!
> +#define GSM_BLOCK_SIZE 33
> +#define GSM_MS_BLOCK_SIZE 65
> +#define GSM_FRAME_SIZE 160
Missing doxy. E.g. are they in bits, bytes, what are they, etc. (see
other speech codecs as example).
> +static int16_t dequant_tab[64][8] = {
[cut]
gsmdata.h, missing const.
> +static void apcm_dequant_add(GetBitContext *gb, int16_t *dst)
> +{
> + int i;
> + int maxidx = get_bits(gb, 6);
> + int16_t *tab = dequant_tab[maxidx];
const.
> +static int gsm_mult(int a, int b)
> +{
> + return (a * b + (1 << 14)) >> 15;
> +}
Should probably be inline, just in case some compiler is silly.
> +static inline int decode_log_area(int coded, int factor, int offset)
> +{
> + coded <<= 10;
> + coded -= offset;
> + return gsm_mult(coded, factor) << 1;
> +}
E.g. here that will save several instructions.
> +static int get_rrp(int filtered)
> +{
> + int abs = filtered;
> + if (abs < 0) abs = -abs;
> + if (abs < 11059) abs <<= 1;
> + else if (abs < 20070) abs += 11059;
> + else abs = (abs >> 2) + 26112;
> + return filtered < 0 ? -abs : abs;
> +}
FFABS() as already pointed out, vertical align would help a lot also.
What's "rrp"? Note also that you're doing "filtered<0" twice here, you
could do both of that at once (if gcc doesn't already, check
disassembly), as in:
if (filtered < 0) {
abs = -filtered;
sign = -1;
} else {
abs = filtered;
sign = 1;
}
if (abs < 11059) abs <<= 1;
else if (abs < 20070) abs += 11059;
else abs = (abs >> 2) + 26112
return sign * abs;
> +
> +static int filter_value(int in, int rrp[8], int v[9])
> +{
> + int i;
> + for (i = 7; i >= 0; i--) {
> + in -= gsm_mult(rrp[i], v[i]);
> + v[i + 1] = v[i] + gsm_mult(rrp[i], in);
> + }
> + v[0] = in;
> + return in;
> +}
Is this similar to the inner loop of ff_celp_lp_synthesis_filter()?
Can we generalize that to decrease binary size without significantly
hurting performance?
> +static void short_term_synth(GSMContext *ctx, int16_t *dst, const int16_t *src)
> +{
> + int i;
> + int rrp[8];
> + int *lar = ctx->lar[ctx->lar_idx];
> + int *lar_prev = ctx->lar[ctx->lar_idx ^ 1];
> + for (i = 0; i < 8; i++)
> + rrp[i] = get_rrp((lar_prev[i] >> 2) + (lar_prev[i] >> 1) + (lar[i] >> 2));
> + for (i = 0; i < 13; i++)
> + dst[i] = filter_value(src[i], rrp, ctx->v);
[cut]
Note how ff_celp_lp_synthesis_filter() does this loop in the actual
function itself. You might want to follow a similar design, this is
what other audio codecs do also (e.g. ra144.c).
> +static int gsm_decode_block(AVCodecContext *avctx, int16_t *samples,
> + GetBitContext *gb)
[..]
> + for (i = 0; i < 4; i++) {
> + int lag = get_bits(gb, 7);
> + int gain_idx = get_bits(gb, 2);
> + int offset = get_bits(gb, 2);
> + lag = av_clip(lag, 40, 120);
lag = av_clip(get_bits(), .., ..);
> + memcpy(ctx->ref_buf, ctx->ref_buf + 160, 120 * sizeof(*ctx->ref_buf));
> + short_term_synth(ctx, samples, ctx->ref_buf + 120);
> + ctx->msr = postprocess(samples, ctx->msr);
memcpy() is slow, can you change postprocess to take ref_buf as input
and output into samples? That's what all other voice codecs do.
> + switch(avctx->codec_id) {
> + case CODEC_ID_GSM:
> + if (get_bits(&gb, 4) != 0xd)
> + av_log(avctx, AV_LOG_WARNING, "Missing GSM magic!\n");
> + res = gsm_decode_block(avctx, samples, &gb);
> + if (res < 0)
> + return res;
> + *data_size = 2*GSM_FRAME_SIZE;
> + break;
> + case CODEC_ID_GSM_MS:
> + res = gsm_decode_block(avctx, samples, &gb);
> + if (res < 0)
> + return res;
> + res = gsm_decode_block(avctx, samples + GSM_FRAME_SIZE, &gb);
> + if (res < 0)
> + return res;
This can probably be written smaller.
> + *data_size = 2*2*GSM_FRAME_SIZE;
> + }
> + *data_size = frame_bytes;
Isn't that a little pointless?
> +AVCodec gsm_decoder = {
> + "gsm",
> + AVMEDIA_TYPE_AUDIO,
> + CODEC_ID_GSM,
> + sizeof(GSMContext),
> + gsm_init,
> + NULL,
> + NULL,
> + gsm_decode_frame,
> + .long_name = NULL_IF_CONFIG_SMALL("GSM"),
> +};
> +
> +AVCodec gsm_ms_decoder = {
> + "gsm_ms",
> + AVMEDIA_TYPE_AUDIO,
> + CODEC_ID_GSM_MS,
> + sizeof(GSMContext),
> + gsm_init,
> + NULL,
> + NULL,
> + gsm_decode_frame,
> + .long_name = NULL_IF_CONFIG_SMALL("GSM Microsoft variant"),
> +};
You could use a macro here to decrease source code size.
Ronald
More information about the ffmpeg-devel
mailing list