summaryrefslogtreecommitdiff
path: root/libavcodec/flacdec.c
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2015-05-17 13:10:33 +0200
committerMichael Niedermayer <michaelni@gmx.at>2015-05-17 13:42:32 +0200
commitb6fcb2bb6db1bf28e2d11f244448703998ea5428 (patch)
treee0f2b1b0895b1bae819ecef08d030de82a7556e7 /libavcodec/flacdec.c
parent83356cf6cceb835e9bbed0ca94accb2cc32fcf03 (diff)
avcodec/flacdec: Attempt to auto-detect old buggy flac
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavcodec/flacdec.c')
-rw-r--r--libavcodec/flacdec.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/libavcodec/flacdec.c b/libavcodec/flacdec.c
index 36d2928137..30fe41618d 100644
--- a/libavcodec/flacdec.c
+++ b/libavcodec/flacdec.c
@@ -315,6 +315,33 @@ static int decode_subframe_fixed(FLACContext *s, int32_t *decoded,
return 0;
}
+static void lpc_analyze_remodulate(int32_t *decoded, const int coeffs[32],
+ int order, int qlevel, int len, int bps)
+{
+ int i, j;
+ int ebps = 1 << (bps-1);
+ unsigned sigma = 0;
+
+ for (i = order; i < len; i++)
+ sigma |= decoded[i] + ebps;
+
+ if (sigma < 2*ebps)
+ return;
+
+ for (i = len - 1; i >= order; i--) {
+ int64_t p = 0;
+ for (j = 0; j < order; j++)
+ p += coeffs[j] * (int64_t)decoded[i-order+j];
+ decoded[i] -= p >> qlevel;
+ }
+ for (i = order; i < len; i++, decoded++) {
+ int32_t p = 0;
+ for (j = 0; j < order; j++)
+ p += coeffs[j] * (uint32_t)decoded[j];
+ decoded[j] += p >> qlevel;
+ }
+}
+
static int decode_subframe_lpc(FLACContext *s, int32_t *decoded, int pred_order,
int bps)
{
@@ -352,6 +379,8 @@ static int decode_subframe_lpc(FLACContext *s, int32_t *decoded, int pred_order,
s->dsp.lpc16(decoded, coeffs, pred_order, qlevel, s->blocksize);
} else {
s->dsp.lpc32(decoded, coeffs, pred_order, qlevel, s->blocksize);
+ if (s->flac_stream_info.bps <= 16)
+ lpc_analyze_remodulate(decoded, coeffs, pred_order, qlevel, s->blocksize, bps);
}
return 0;