aboutsummaryrefslogtreecommitdiffstats
path: root/libavcodec/apedec.c
diff options
context:
space:
mode:
authorKostya Shishkov <kostya.shishkov@gmail.com>2013-03-12 19:33:29 +0100
committerKostya Shishkov <kostya.shishkov@gmail.com>2013-03-15 09:50:42 +0100
commitc42e2625130204733916e6ffb1a86ccdffe5fe71 (patch)
tree6be87ba04588f08b56939901831be1e8b941ae00 /libavcodec/apedec.c
parent9652d4fcfc9c07a726b35efc4ac644d9751b36d7 (diff)
downloadffmpeg-c42e2625130204733916e6ffb1a86ccdffe5fe71.tar.gz
add support for Monkey's Audio versions from 3.93
Diffstat (limited to 'libavcodec/apedec.c')
-rw-r--r--libavcodec/apedec.c91
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,