From 40bfaa190c61b6eeff1b76b767c12edd6609967d Mon Sep 17 00:00:00 2001 From: Thomas Mundt Date: Tue, 19 Sep 2017 22:23:23 +0200 Subject: avfilter/interlace: add support for 10 and 12 bit Reviewed-by: Michael Niedermayer Signed-off-by: Thomas Mundt Signed-off-by: James Almer --- libavfilter/vf_tinterlace.c | 78 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 5 deletions(-) (limited to 'libavfilter/vf_tinterlace.c') diff --git a/libavfilter/vf_tinterlace.c b/libavfilter/vf_tinterlace.c index f934a06b69..163ab7c184 100644 --- a/libavfilter/vf_tinterlace.c +++ b/libavfilter/vf_tinterlace.c @@ -78,7 +78,12 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUV420P10LE, AV_PIX_FMT_YUV422P10LE, + AV_PIX_FMT_YUV440P10LE, AV_PIX_FMT_YUV444P10LE, + AV_PIX_FMT_YUV420P12LE, AV_PIX_FMT_YUV422P12LE, + AV_PIX_FMT_YUV440P12LE, AV_PIX_FMT_YUV444P12LE, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P, + AV_PIX_FMT_YUVA420P10LE, AV_PIX_FMT_YUVA422P10LE, AV_PIX_FMT_YUVA444P10LE, AV_PIX_FMT_GRAY8, FULL_SCALE_YUVJ_FORMATS, AV_PIX_FMT_NONE }; @@ -90,7 +95,7 @@ static int query_formats(AVFilterContext *ctx) } static void lowpass_line_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp, - ptrdiff_t mref, ptrdiff_t pref) + ptrdiff_t mref, ptrdiff_t pref, int clip_max) { const uint8_t *srcp_above = srcp + mref; const uint8_t *srcp_below = srcp + pref; @@ -103,8 +108,26 @@ static void lowpass_line_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp, } } +static void lowpass_line_c_16(uint8_t *dst8, ptrdiff_t width, const uint8_t *src8, + ptrdiff_t mref, ptrdiff_t pref, int clip_max) +{ + uint16_t *dstp = (uint16_t *)dst8; + const uint16_t *srcp = (const uint16_t *)src8; + const uint16_t *srcp_above = srcp + mref / 2; + const uint16_t *srcp_below = srcp + pref / 2; + int i, src_x; + for (i = 0; i < width; i++) { + // this calculation is an integer representation of + // '0.5 * current + 0.25 * above + 0.25 * below' + // '1 +' is for rounding. + src_x = av_le2ne16(srcp[i]) << 1; + dstp[i] = av_le2ne16((1 + src_x + av_le2ne16(srcp_above[i]) + + av_le2ne16(srcp_below[i])) >> 2); + } +} + static void lowpass_line_complex_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp, - ptrdiff_t mref, ptrdiff_t pref) + ptrdiff_t mref, ptrdiff_t pref, int clip_max) { const uint8_t *srcp_above = srcp + mref; const uint8_t *srcp_below = srcp + pref; @@ -130,6 +153,41 @@ static void lowpass_line_complex_c(uint8_t *dstp, ptrdiff_t width, const uint8_t } } +static void lowpass_line_complex_c_16(uint8_t *dst8, ptrdiff_t width, const uint8_t *src8, + ptrdiff_t mref, ptrdiff_t pref, int clip_max) +{ + uint16_t *dstp = (uint16_t *)dst8; + const uint16_t *srcp = (const uint16_t *)src8; + const uint16_t *srcp_above = srcp + mref / 2; + const uint16_t *srcp_below = srcp + pref / 2; + const uint16_t *srcp_above2 = srcp + mref; + const uint16_t *srcp_below2 = srcp + pref; + int i, dst_le, src_le, src_x, src_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. + src_le = av_le2ne16(srcp[i]); + src_x = src_le << 1; + src_ab = av_le2ne16(srcp_above[i]) + av_le2ne16(srcp_below[i]); + dst_le = av_clip((4 + ((src_le + src_x + src_ab) << 1) + - av_le2ne16(srcp_above2[i]) + - av_le2ne16(srcp_below2[i])) >> 3, 0, clip_max); + // 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 (src_ab > src_x) { + if (dst_le < src_le) + dstp[i] = av_le2ne16(src_le); + else + dstp[i] = av_le2ne16(dst_le); + } else if (dst_le > src_le) { + dstp[i] = av_le2ne16(src_le); + } else + dstp[i] = av_le2ne16(dst_le); + } +} + static av_cold void uninit(AVFilterContext *ctx) { TInterlaceContext *tinterlace = ctx->priv; @@ -198,12 +256,19 @@ static int config_out_props(AVFilterLink *outlink) (tinterlace->flags & TINTERLACE_FLAG_EXACT_TB)) outlink->time_base = tinterlace->preout_time_base; + tinterlace->csp = av_pix_fmt_desc_get(outlink->format); if (tinterlace->flags & TINTERLACE_FLAG_CVLPF) { - tinterlace->lowpass_line = lowpass_line_complex_c; + if (tinterlace->csp->comp[0].depth > 8) + tinterlace->lowpass_line = lowpass_line_complex_c_16; + else + tinterlace->lowpass_line = lowpass_line_complex_c; if (ARCH_X86) ff_tinterlace_init_x86(tinterlace); } else if (tinterlace->flags & TINTERLACE_FLAG_VLPF) { - tinterlace->lowpass_line = lowpass_line_c; + if (tinterlace->csp->comp[0].depth > 8) + tinterlace->lowpass_line = lowpass_line_c_16; + else + tinterlace->lowpass_line = lowpass_line_c; if (ARCH_X86) ff_tinterlace_init_x86(tinterlace); } @@ -250,6 +315,7 @@ void copy_picture_field(TInterlaceContext *tinterlace, const uint8_t *srcp = src[plane]; int srcp_linesize = src_linesize[plane] * k; int dstp_linesize = dst_linesize[plane] * (interleave ? 2 : 1); + int clip_max = (1 << tinterlace->csp->comp[plane].depth) - 1; lines = (lines + (src_field == FIELD_UPPER)) / k; if (src_field == FIELD_LOWER) @@ -267,11 +333,13 @@ void copy_picture_field(TInterlaceContext *tinterlace, if (h >= (lines - x)) mref = 0; // there is no line above else if (h <= (1 + x)) pref = 0; // there is no line below - tinterlace->lowpass_line(dstp, cols, srcp, mref, pref); + tinterlace->lowpass_line(dstp, cols, srcp, mref, pref, clip_max); dstp += dstp_linesize; srcp += srcp_linesize; } } else { + if (tinterlace->csp->comp[plane].depth > 8) + cols *= 2; av_image_copy_plane(dstp, dstp_linesize, srcp, srcp_linesize, cols, lines); } } -- cgit v1.2.3