From d43ad6e0296b78eddfe59e9cd083654882150499 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 27 Jan 2020 12:29:18 +0530 Subject: [PATCH] deinterlace: add alternate support In this mode each field is carried using its own buffer. Allow deinterlace to negotiate caps with the Interlaced feature and adjust the algorithm fetching lines. Fix #620 --- gst/deinterlace/gstdeinterlace.c | 64 +++++++++++++++++++++++++++++----- gst/deinterlace/gstdeinterlacemethod.c | 8 +++++ 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/gst/deinterlace/gstdeinterlace.c b/gst/deinterlace/gstdeinterlace.c index b3534a7..9dc5c96 100644 --- a/gst/deinterlace/gstdeinterlace.c +++ b/gst/deinterlace/gstdeinterlace.c @@ -1056,6 +1056,7 @@ gst_deinterlace_get_buffer_state (GstDeinterlace * self, GstVideoFrame * frame, #define MODE_TO_STRING(m) ((m) == GST_VIDEO_INTERLACE_MODE_MIXED ? "MIXED" : \ (m) == GST_VIDEO_INTERLACE_MODE_INTERLEAVED ? "I" : \ + (m) == GST_VIDEO_INTERLACE_MODE_ALTERNATE ? "A" : \ (m) == GST_VIDEO_INTERLACE_MODE_FIELDS ? "FIELDS" : "P") static void @@ -2399,6 +2400,22 @@ gst_deinterlace_caps_double_framerate (GstCaps * caps, gboolean half) } static GstCaps * +dup_caps_with_alternate (GstCaps * caps) +{ + GstCaps *with_alternate; + GstCapsFeatures *features; + + with_alternate = gst_caps_copy (caps); + features = gst_caps_features_new (GST_CAPS_FEATURE_FORMAT_INTERLACED, NULL); + gst_caps_set_features_simple (with_alternate, features); + + gst_caps_set_simple (with_alternate, "interlace-mode", G_TYPE_STRING, + "alternate", NULL); + + return with_alternate; +} + +static GstCaps * gst_deinterlace_getcaps (GstDeinterlace * self, GstPad * pad, GstCaps * filter) { GstCaps *ret, *caps; @@ -2518,6 +2535,17 @@ gst_deinterlace_getcaps (GstDeinterlace * self, GstPad * pad, GstCaps * filter) gst_caps_unref (caps); caps = NULL; + if (pad == self->sinkpad) { + GstCaps *can_deinterlace; + + tmp = gst_static_caps_get (&deinterlace_caps); + can_deinterlace = gst_caps_intersect (ret, tmp); + gst_caps_unref (tmp); + + ret = gst_caps_merge (ret, dup_caps_with_alternate (can_deinterlace)); + gst_caps_unref (can_deinterlace); + } + done: if (filter) { @@ -2653,7 +2681,7 @@ gst_deinterlace_do_bufferpool (GstDeinterlace * self, GstCaps * outcaps) static gboolean gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) { - GstCaps *srccaps = NULL; + GstCaps *srccaps = NULL, *caps_no_feat = NULL; GstVideoInterlaceMode interlacing_mode; gint fps_n, fps_d; GstCaps *peercaps, *current_caps; @@ -2713,6 +2741,20 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) GST_VIDEO_INFO_WIDTH (&self->vinfo), GST_VIDEO_INFO_HEIGHT (&self->vinfo)); + if (GST_VIDEO_INFO_INTERLACE_MODE (&self->vinfo) == + GST_VIDEO_INTERLACE_MODE_ALTERNATE) { + /* alternate interlace mode uses a caps feature, remove it when interesecting caps + * and setting the src pad caps. */ + GstCapsFeatures *features; + + caps_no_feat = gst_caps_copy (caps); + + features = gst_caps_get_features (caps_no_feat, 0); + gst_caps_features_remove (features, GST_CAPS_FEATURE_FORMAT_INTERLACED); + } else { + caps_no_feat = gst_caps_ref (caps); + } + fps_n = GST_VIDEO_INFO_FPS_N (&self->vinfo); fps_d = GST_VIDEO_INFO_FPS_D (&self->vinfo); @@ -2723,7 +2765,7 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) } else if (self->mode == GST_DEINTERLACE_MODE_INTERLACED) { GstCaps *tmp = gst_static_caps_get (&deinterlace_caps); - if (!gst_caps_can_intersect (caps, tmp)) { + if (!gst_caps_can_intersect (caps_no_feat, tmp)) { gst_caps_unref (tmp); GST_ERROR_OBJECT (self, "Unsupported caps for mode=interlaced"); goto invalid_caps; @@ -2740,7 +2782,7 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) GST_DEBUG_OBJECT (self, "Passthrough because mode=auto and progressive caps"); self->passthrough = TRUE; - } else if (gst_caps_can_intersect (caps, tmp)) { + } else if (gst_caps_can_intersect (caps_no_feat, tmp)) { if (peercaps) { GstCaps *allowed_caps; GstCaps *tmp2; @@ -2800,7 +2842,7 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) if (!self->passthrough) { if (self->pattern_lock) { - srccaps = gst_caps_copy (caps); + srccaps = gst_caps_copy (caps_no_feat); if (self->pattern != -1 && G_UNLIKELY (!gst_util_fraction_multiply (fps_n, fps_d, telecine_patterns[self->pattern].ratio_n, @@ -2813,17 +2855,17 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) || self->low_latency == 0) { /* in high latency pattern locking mode if we don't have a pattern lock, * the sink pad caps are the best we know */ - srccaps = gst_caps_copy (caps); + srccaps = gst_caps_copy (caps_no_feat); } else if (self->low_latency > 0 && interlacing_mode == GST_VIDEO_INTERLACE_MODE_MIXED && self->pattern == -1) { /* for initial buffers of a telecine pattern, until there is a lock we * we output naïvely adjusted timestamps in low-latency pattern locking * mode */ - srccaps = gst_caps_copy (caps); + srccaps = gst_caps_copy (caps_no_feat); gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, 0, 1, NULL); } else if (self->user_set_fields == GST_DEINTERLACE_FIELDS_AUTO) { - srccaps = gst_caps_copy (caps); + srccaps = gst_caps_copy (caps_no_feat); if (peercaps) { gboolean can_be_tf = FALSE; @@ -2861,7 +2903,7 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) } } else { self->fields = self->user_set_fields; - srccaps = gst_caps_copy (caps); + srccaps = gst_caps_copy (caps_no_feat); if (self->fields == GST_DEINTERLACE_ALL) srccaps = gst_deinterlace_caps_double_framerate (srccaps, FALSE); } @@ -2873,7 +2915,7 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) gst_deinterlace_set_method (self, self->method_id); gst_deinterlace_method_setup (self->method, &self->vinfo); } else { - srccaps = gst_caps_ref (caps); + srccaps = gst_caps_ref (caps_no_feat); } if (fps_n != 0) { @@ -2894,6 +2936,7 @@ gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps) if (peercaps) gst_caps_unref (peercaps); gst_caps_unref (srccaps); + g_clear_pointer (&caps_no_feat, gst_caps_unref); return TRUE; @@ -2901,6 +2944,7 @@ invalid_caps: { if (peercaps) gst_caps_unref (peercaps); + g_clear_pointer (&caps_no_feat, gst_caps_unref); GST_ERROR_OBJECT (pad, "Invalid caps: %" GST_PTR_FORMAT, caps); gst_pad_mark_reconfigure (self->srcpad); return FALSE; @@ -2911,6 +2955,7 @@ set_caps_failed: if (peercaps) gst_caps_unref (peercaps); gst_caps_unref (srccaps); + g_clear_pointer (&caps_no_feat, gst_caps_unref); gst_pad_mark_reconfigure (self->srcpad); return FALSE; } @@ -2920,6 +2965,7 @@ no_bufferpool: if (peercaps) gst_caps_unref (peercaps); gst_caps_unref (srccaps); + g_clear_pointer (&caps_no_feat, gst_caps_unref); gst_pad_mark_reconfigure (self->srcpad); return FALSE; } diff --git a/gst/deinterlace/gstdeinterlacemethod.c b/gst/deinterlace/gstdeinterlacemethod.c index 60105b8..286dc7c 100644 --- a/gst/deinterlace/gstdeinterlacemethod.c +++ b/gst/deinterlace/gstdeinterlacemethod.c @@ -329,6 +329,14 @@ get_line (LinesGetter * lg, gint field_offset, guint plane, gint line, frame = lg->history[idx].frame; g_assert (frame); + if (GST_VIDEO_FRAME_FLAG_IS_SET (frame, GST_VIDEO_FRAME_FLAG_TOP_FIELD) || + GST_VIDEO_FRAME_FLAG_IS_SET (frame, GST_VIDEO_FRAME_FLAG_BOTTOM_FIELD)) { + /* Alternate frame containing a single field, adjust the line index */ + line /= 2; + if (line_offset != 1) + line_offset /= 2; + } + frame_height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, plane); line += line_offset; -- 2.7.4