summaryrefslogtreecommitdiff
path: root/libavfilter/vf_tinterlace.c
diff options
context:
space:
mode:
authorThomas Mundt <tmundt75@gmail.com>2017-08-30 03:37:18 +0200
committerMichael Niedermayer <michael@niedermayer.cc>2017-09-15 22:40:21 +0200
commita7f6bfdc185a04a703bedd712ee306435372af12 (patch)
tree6acb620c777348c07a8fdd6250e23bf082c6e4ed /libavfilter/vf_tinterlace.c
parent1a85fb7e1eb375b37ee9863ce8e6e7ada1742dbe (diff)
avfilter/interlace: prevent over-sharpening with the complex low-pass filter
The complex vertical low-pass filter slightly over-sharpens the picture. This becomes visible when several transcodings are cascaded and the error potentises, e.g. some generations of HD->SD SD->HD. To prevent this behaviour the destination pixel must not exceed the source pixel when the average of the pixels above and below is less than the source pixel. And the other way around. Tested and approved in a visual transcoding cascade test by video professionals. SSIM/PSNR test with the first generation of an HD->SD file as a reference against the 6th generation(3 x SD->HD HD->SD): Results without the patch: SSIM Y:0.956508 (13.615881) U:0.991601 (20.757750) V:0.993004 (21.551382) All:0.974405 (15.918463) PSNR y:31.838009 u:48.424280 v:48.962711 average:34.759466 min:31.699297 max:40.857847 Results with the patch: SSIM Y:0.970051 (15.236232) U:0.991883 (20.905857) V:0.993174 (21.658049) All:0.981290 (17.279202) PSNR y:34.412108 u:48.504454 v:48.969496 average:37.264644 min:34.310637 max:42.373392 Signed-off-by: Thomas Mundt <tmundt75@gmail.com> Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
Diffstat (limited to 'libavfilter/vf_tinterlace.c')
-rw-r--r--libavfilter/vf_tinterlace.c17
1 files changed, 13 insertions, 4 deletions
diff --git a/libavfilter/vf_tinterlace.c b/libavfilter/vf_tinterlace.c
index 65997076ad..81d2d773e0 100644
--- a/libavfilter/vf_tinterlace.c
+++ b/libavfilter/vf_tinterlace.c
@@ -110,14 +110,23 @@ static void lowpass_line_complex_c(uint8_t *dstp, ptrdiff_t width, const uint8_t
const uint8_t *srcp_below = srcp + pref;
const uint8_t *srcp_above2 = srcp + mref * 2;
const uint8_t *srcp_below2 = srcp + pref * 2;
- int i;
+ int i, srcp_x, srcp_ab;
for (i = 0; i < width; i++) {
// this calculation is an integer representation of
// '0.75 * current + 0.25 * above + 0.25 * below - 0.125 * above2 - 0.125 * below2'
// '4 +' is for rounding.
- dstp[i] = av_clip_uint8((4 + (srcp[i] << 2)
- + ((srcp[i] + srcp_above[i] + srcp_below[i]) << 1)
- - srcp_above2[i] - srcp_below2[i]) >> 3);
+ srcp_x = srcp[i] << 1;
+ srcp_ab = srcp_above[i] + srcp_below[i];
+ dstp[i] = av_clip_uint8((4 + ((srcp[i] + srcp_x + srcp_ab) << 1)
+ - srcp_above2[i] - srcp_below2[i]) >> 3);
+ // Prevent over-sharpening:
+ // dst must not exceed src when the average of above and below
+ // is less than src. And the other way around.
+ if (srcp_ab > srcp_x) {
+ if (dstp[i] < srcp[i])
+ dstp[i] = srcp[i];
+ } else if (dstp[i] > srcp[i])
+ dstp[i] = srcp[i];
}
}