diff options
author | Kostya Shishkov <kostya.shishkov@gmail.com> | 2013-03-12 19:33:29 +0100 |
---|---|---|
committer | Kostya Shishkov <kostya.shishkov@gmail.com> | 2013-03-15 09:50:42 +0100 |
commit | c42e2625130204733916e6ffb1a86ccdffe5fe71 (patch) | |
tree | 6be87ba04588f08b56939901831be1e8b941ae00 /libavcodec/apedec.c | |
parent | 9652d4fcfc9c07a726b35efc4ac644d9751b36d7 (diff) | |
download | ffmpeg-c42e2625130204733916e6ffb1a86ccdffe5fe71.tar.gz |
add support for Monkey's Audio versions from 3.93
Diffstat (limited to 'libavcodec/apedec.c')
-rw-r--r-- | libavcodec/apedec.c | 91 |
1 files changed, 89 insertions, 2 deletions
diff --git a/libavcodec/apedec.c b/libavcodec/apedec.c index d4a3dcf3eb..3597742500 100644 --- a/libavcodec/apedec.c +++ b/libavcodec/apedec.c @@ -176,6 +176,8 @@ static void entropy_decode_stereo_3900(APEContext *ctx, int blockstodecode); static void entropy_decode_mono_3990(APEContext *ctx, int blockstodecode); static void entropy_decode_stereo_3990(APEContext *ctx, int blockstodecode); +static void predictor_decode_mono_3930(APEContext *ctx, int count); +static void predictor_decode_stereo_3930(APEContext *ctx, int count); static void predictor_decode_mono_3950(APEContext *ctx, int count); static void predictor_decode_stereo_3950(APEContext *ctx, int count); @@ -255,8 +257,13 @@ static av_cold int ape_decode_init(AVCodecContext *avctx) s->entropy_decode_stereo = entropy_decode_stereo_3990; } - s->predictor_decode_mono = predictor_decode_mono_3950; - s->predictor_decode_stereo = predictor_decode_stereo_3950; + if (s->fileversion < 3950) { + s->predictor_decode_mono = predictor_decode_mono_3930; + s->predictor_decode_stereo = predictor_decode_stereo_3930; + } else { + s->predictor_decode_mono = predictor_decode_mono_3950; + s->predictor_decode_stereo = predictor_decode_stereo_3950; + } ff_dsputil_init(&s->dsp, avctx); avctx->channel_layout = (avctx->channels==2) ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO; @@ -603,6 +610,86 @@ static inline int APESIGN(int32_t x) { return (x < 0) - (x > 0); } +static av_always_inline int predictor_update_3930(APEPredictor *p, + const int decoded, const int filter, + const int delayA) +{ + int32_t predictionA, sign; + int32_t d0, d1, d2, d3; + + p->buf[delayA] = p->lastA[filter]; + d0 = p->buf[delayA ]; + d1 = p->buf[delayA ] - p->buf[delayA - 1]; + d2 = p->buf[delayA - 1] - p->buf[delayA - 2]; + d3 = p->buf[delayA - 2] - p->buf[delayA - 3]; + + predictionA = d0 * p->coeffsA[filter][0] + + d1 * p->coeffsA[filter][1] + + d2 * p->coeffsA[filter][2] + + d3 * p->coeffsA[filter][3]; + + p->lastA[filter] = decoded + (predictionA >> 9); + p->filterA[filter] = p->lastA[filter] + ((p->filterA[filter] * 31) >> 5); + + sign = APESIGN(decoded); + p->coeffsA[filter][0] += ((d0 < 0) * 2 - 1) * sign; + p->coeffsA[filter][1] += ((d1 < 0) * 2 - 1) * sign; + p->coeffsA[filter][2] += ((d2 < 0) * 2 - 1) * sign; + p->coeffsA[filter][3] += ((d3 < 0) * 2 - 1) * sign; + + return p->filterA[filter]; +} + +static void predictor_decode_stereo_3930(APEContext *ctx, int count) +{ + APEPredictor *p = &ctx->predictor; + int32_t *decoded0 = ctx->decoded[0]; + int32_t *decoded1 = ctx->decoded[1]; + + ape_apply_filters(ctx, ctx->decoded[0], ctx->decoded[1], count); + + while (count--) { + /* Predictor Y */ + int Y = *decoded1, X = *decoded0; + *decoded0 = predictor_update_3930(p, Y, 0, YDELAYA); + decoded0++; + *decoded1 = predictor_update_3930(p, X, 1, XDELAYA); + decoded1++; + + /* Combined */ + p->buf++; + + /* Have we filled the history buffer? */ + if (p->buf == p->historybuffer + HISTORY_SIZE) { + memmove(p->historybuffer, p->buf, + PREDICTOR_SIZE * sizeof(*p->historybuffer)); + p->buf = p->historybuffer; + } + } +} + +static void predictor_decode_mono_3930(APEContext *ctx, int count) +{ + APEPredictor *p = &ctx->predictor; + int32_t *decoded0 = ctx->decoded[0]; + + ape_apply_filters(ctx, ctx->decoded[0], NULL, count); + + while (count--) { + *decoded0 = predictor_update_3930(p, *decoded0, 0, YDELAYA); + decoded0++; + + p->buf++; + + /* Have we filled the history buffer? */ + if (p->buf == p->historybuffer + HISTORY_SIZE) { + memmove(p->historybuffer, p->buf, + PREDICTOR_SIZE * sizeof(*p->historybuffer)); + p->buf = p->historybuffer; + } + } +} + static av_always_inline int predictor_update_filter(APEPredictor *p, const int decoded, const int filter, const int delayA, const int delayB, |