summaryrefslogtreecommitdiff
path: root/libavfilter/vf_tinterlace.c
diff options
context:
space:
mode:
authorThomas Mundt <tmundt75@gmail.com>2017-09-19 22:23:23 +0200
committerJames Almer <jamrial@gmail.com>2017-09-23 16:19:58 -0300
commit40bfaa190c61b6eeff1b76b767c12edd6609967d (patch)
tree533340612ea536e60bd9189fb110772e4513a49a /libavfilter/vf_tinterlace.c
parent58ca446672fec10e851b820ce7df64bd2d1f3a70 (diff)
avfilter/interlace: add support for 10 and 12 bit
Reviewed-by: Michael Niedermayer <michael@niedermayer.cc> Signed-off-by: Thomas Mundt <tmundt75@gmail.com> Signed-off-by: James Almer <jamrial@gmail.com>
Diffstat (limited to 'libavfilter/vf_tinterlace.c')
-rw-r--r--libavfilter/vf_tinterlace.c78
1 files changed, 73 insertions, 5 deletions
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);
}
}