summaryrefslogtreecommitdiffstats
path: root/gst/deinterlace2/gstdeinterlace2.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst/deinterlace2/gstdeinterlace2.c')
-rw-r--r--gst/deinterlace2/gstdeinterlace2.c1509
1 files changed, 0 insertions, 1509 deletions
diff --git a/gst/deinterlace2/gstdeinterlace2.c b/gst/deinterlace2/gstdeinterlace2.c
deleted file mode 100644
index b293b43e..00000000
--- a/gst/deinterlace2/gstdeinterlace2.c
+++ /dev/null
@@ -1,1509 +0,0 @@
-/*
- * GStreamer
- * Copyright (C) 2005 Martin Eikermann <meiker@upb.de>
- * Copyright (C) 2008-2009 Sebastian Dröge <slomo@collabora.co.uk>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-deinterlace2
- *
- * deinterlace2 deinterlaces interlaced video frames to progressive video frames.
- * For this different algorithms can be selected which will be described later.
- *
- * <refsect2>
- * <title>Example launch line</title>
- * |[
- * gst-launch -v filesrc location=/path/to/file ! decodebin2 ! ffmpegcolorspace ! deinterlace2 ! ffmpegcolorspace ! autovideosink
- * ]| This pipeline deinterlaces a video file with the default deinterlacing options.
- * </refsect2>
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gst/gst.h>
-#include <gst/video/video.h>
-#include <liboil/liboil.h>
-
-#include "gstdeinterlace2.h"
-#include "tvtime/plugins.h"
-
-#include <string.h>
-
-GST_DEBUG_CATEGORY_STATIC (deinterlace2_debug);
-#define GST_CAT_DEFAULT (deinterlace2_debug)
-
-/* Object signals and args */
-enum
-{
- LAST_SIGNAL
-};
-
-/* Properties */
-
-#define DEFAULT_MODE GST_DEINTERLACE2_MODE_INTERLACED
-#define DEFAULT_METHOD GST_DEINTERLACE2_GREEDY_H
-#define DEFAULT_FIELDS GST_DEINTERLACE2_ALL
-#define DEFAULT_FIELD_LAYOUT GST_DEINTERLACE2_LAYOUT_AUTO
-
-enum
-{
- PROP_0,
- PROP_MODE,
- PROP_METHOD,
- PROP_FIELDS,
- PROP_FIELD_LAYOUT,
- PROP_LAST
-};
-
-G_DEFINE_TYPE (GstDeinterlaceMethod, gst_deinterlace_method, GST_TYPE_OBJECT);
-
-static void
-gst_deinterlace_method_class_init (GstDeinterlaceMethodClass * klass)
-{
-
-}
-
-static void
-gst_deinterlace_method_init (GstDeinterlaceMethod * self)
-{
-
-}
-
-static void
-gst_deinterlace_method_deinterlace_frame (GstDeinterlaceMethod * self,
- GstDeinterlace2 * parent, GstBuffer * outbuf)
-{
- GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
-
- klass->deinterlace_frame (self, parent, outbuf);
-}
-
-static gint
-gst_deinterlace_method_get_fields_required (GstDeinterlaceMethod * self)
-{
- GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
-
- return klass->fields_required;
-}
-
-static gint
-gst_deinterlace_method_get_latency (GstDeinterlaceMethod * self)
-{
- GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
-
- return klass->latency;
-}
-
-
-G_DEFINE_TYPE (GstDeinterlaceSimpleMethod, gst_deinterlace_simple_method,
- GST_TYPE_DEINTERLACE_METHOD);
-
-static void
-gst_deinterlace_simple_method_interpolate_scanline (GstDeinterlaceMethod * self,
- GstDeinterlace2 * parent, guint8 * out,
- GstDeinterlaceScanlineData * scanlines, gint width)
-{
- oil_memcpy (out, scanlines->m1, parent->row_stride);
-}
-
-static void
-gst_deinterlace_simple_method_copy_scanline (GstDeinterlaceMethod * self,
- GstDeinterlace2 * parent, guint8 * out,
- GstDeinterlaceScanlineData * scanlines, gint width)
-{
- oil_memcpy (out, scanlines->m0, parent->row_stride);
-}
-
-static void
-gst_deinterlace_simple_method_deinterlace_frame (GstDeinterlaceMethod * self,
- GstDeinterlace2 * parent, GstBuffer * outbuf)
-{
- GstDeinterlaceSimpleMethodClass *dsm_class =
- GST_DEINTERLACE_SIMPLE_METHOD_GET_CLASS (self);
- GstDeinterlaceMethodClass *dm_class = GST_DEINTERLACE_METHOD_GET_CLASS (self);
- GstDeinterlaceScanlineData scanlines;
- guint8 *out = GST_BUFFER_DATA (outbuf);
- guint8 *field0 = NULL, *field1 = NULL, *field2 = NULL, *field3 = NULL;
- gint cur_field_idx = parent->history_count - dm_class->fields_required;
- guint cur_field_flags = parent->field_history[cur_field_idx].flags;
- gint line;
-
- field0 = GST_BUFFER_DATA (parent->field_history[cur_field_idx].buf);
-
- g_assert (dm_class->fields_required <= 4);
-
- if (dm_class->fields_required >= 2)
- field1 = GST_BUFFER_DATA (parent->field_history[cur_field_idx + 1].buf);
- if (dm_class->fields_required >= 3)
- field2 = GST_BUFFER_DATA (parent->field_history[cur_field_idx + 2].buf);
- if (dm_class->fields_required >= 4)
- field3 = GST_BUFFER_DATA (parent->field_history[cur_field_idx + 3].buf);
-
-
- if (cur_field_flags == PICTURE_INTERLACED_BOTTOM) {
- /* double the first scanline of the bottom field */
- oil_memcpy (out, field0, parent->row_stride);
- out += parent->row_stride;
- }
-
- oil_memcpy (out, field0, parent->row_stride);
- out += parent->row_stride;
-
- for (line = 2; line <= parent->field_height; line++) {
-
- memset (&scanlines, 0, sizeof (scanlines));
- scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM);
-
- /* interp. scanline */
- scanlines.t0 = field0;
- scanlines.b0 = field0 + parent->field_stride;
-
- if (field1 != NULL) {
- scanlines.tt1 = field1;
- scanlines.m1 = field1 + parent->field_stride;
- scanlines.bb1 = field1 + parent->field_stride * 2;
- field1 += parent->field_stride;
- }
-
- if (field2 != NULL) {
- scanlines.t2 = field2;
- scanlines.b2 = field2 + parent->field_stride;
- }
-
- if (field3 != NULL) {
- scanlines.tt3 = field3;
- scanlines.m3 = field3 + parent->field_stride;
- scanlines.bb3 = field3 + parent->field_stride * 2;
- field3 += parent->field_stride;
- }
-
- /* set valid data for corner cases */
- if (line == 2) {
- scanlines.tt1 = scanlines.bb1;
- scanlines.tt3 = scanlines.bb3;
- } else if (line == parent->field_height) {
- scanlines.bb1 = scanlines.tt1;
- scanlines.bb3 = scanlines.tt3;
- }
-
- dsm_class->interpolate_scanline (self, parent, out, &scanlines,
- parent->frame_width);
- out += parent->row_stride;
-
- memset (&scanlines, 0, sizeof (scanlines));
- scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM);
-
- /* copy a scanline */
- scanlines.tt0 = field0;
- scanlines.m0 = field0 + parent->field_stride;
- scanlines.bb0 = field0 + parent->field_stride * 2;
- field0 += parent->field_stride;
-
- if (field1 != NULL) {
- scanlines.t1 = field1;
- scanlines.b1 = field1 + parent->field_stride;
- }
-
- if (field2 != NULL) {
- scanlines.tt2 = field2;
- scanlines.m2 = field2 + parent->field_stride;
- scanlines.bb2 = field2 + parent->field_stride * 2;
- field2 += parent->field_stride;
- }
-
- if (field3 != NULL) {
- scanlines.t3 = field3;
- scanlines.b3 = field3 + parent->field_stride;
- }
-
- /* set valid data for corner cases */
- if (line == parent->field_height) {
- scanlines.bb0 = scanlines.tt0;
- scanlines.b1 = scanlines.t1;
- scanlines.bb2 = scanlines.tt2;
- scanlines.b3 = scanlines.t3;
- }
-
- dsm_class->copy_scanline (self, parent, out, &scanlines,
- parent->frame_width);
- out += parent->row_stride;
- }
-
- if (cur_field_flags == PICTURE_INTERLACED_TOP) {
- /* double the last scanline of the top field */
- oil_memcpy (out, field0, parent->row_stride);
- }
-}
-
-static void
-gst_deinterlace_simple_method_class_init (GstDeinterlaceSimpleMethodClass *
- klass)
-{
- GstDeinterlaceMethodClass *dm_class = (GstDeinterlaceMethodClass *) klass;
-
- dm_class->deinterlace_frame = gst_deinterlace_simple_method_deinterlace_frame;
- dm_class->fields_required = 2;
-
- klass->interpolate_scanline =
- gst_deinterlace_simple_method_interpolate_scanline;
- klass->copy_scanline = gst_deinterlace_simple_method_copy_scanline;
-}
-
-static void
-gst_deinterlace_simple_method_init (GstDeinterlaceSimpleMethod * self)
-{
-}
-
-#define GST_TYPE_DEINTERLACE2_METHODS (gst_deinterlace2_methods_get_type ())
-static GType
-gst_deinterlace2_methods_get_type (void)
-{
- static GType deinterlace2_methods_type = 0;
-
- static const GEnumValue methods_types[] = {
- {GST_DEINTERLACE2_TOMSMOCOMP, "Motion Adaptive: Motion Search",
- "tomsmocomp"},
- {GST_DEINTERLACE2_GREEDY_H, "Motion Adaptive: Advanced Detection",
- "greedyh"},
- {GST_DEINTERLACE2_GREEDY_L, "Motion Adaptive: Simple Detection", "greedyl"},
- {GST_DEINTERLACE2_VFIR, "Blur Vertical", "vfir"},
- {GST_DEINTERLACE2_LINEAR, "Television: Full resolution", "linear"},
- {GST_DEINTERLACE2_LINEAR_BLEND, "Blur: Temporal", "linearblend"},
- {GST_DEINTERLACE2_SCALER_BOB, "Double lines", "scalerbob"},
- {GST_DEINTERLACE2_WEAVE, "Weave", "weave"},
- {GST_DEINTERLACE2_WEAVE_TFF, "Progressive: Top Field First", "weavetff"},
- {GST_DEINTERLACE2_WEAVE_BFF, "Progressive: Bottom Field First", "weavebff"},
- {0, NULL, NULL},
- };
-
- if (!deinterlace2_methods_type) {
- deinterlace2_methods_type =
- g_enum_register_static ("GstDeinterlace2Methods", methods_types);
- }
- return deinterlace2_methods_type;
-}
-
-#define GST_TYPE_DEINTERLACE2_FIELDS (gst_deinterlace2_fields_get_type ())
-static GType
-gst_deinterlace2_fields_get_type (void)
-{
- static GType deinterlace2_fields_type = 0;
-
- static const GEnumValue fields_types[] = {
- {GST_DEINTERLACE2_ALL, "All fields", "all"},
- {GST_DEINTERLACE2_TF, "Top fields only", "top"},
- {GST_DEINTERLACE2_BF, "Bottom fields only", "bottom"},
- {0, NULL, NULL},
- };
-
- if (!deinterlace2_fields_type) {
- deinterlace2_fields_type =
- g_enum_register_static ("GstDeinterlace2Fields", fields_types);
- }
- return deinterlace2_fields_type;
-}
-
-#define GST_TYPE_DEINTERLACE2_FIELD_LAYOUT (gst_deinterlace2_field_layout_get_type ())
-static GType
-gst_deinterlace2_field_layout_get_type (void)
-{
- static GType deinterlace2_field_layout_type = 0;
-
- static const GEnumValue field_layout_types[] = {
- {GST_DEINTERLACE2_LAYOUT_AUTO, "Auto detection", "auto"},
- {GST_DEINTERLACE2_LAYOUT_TFF, "Top field first", "tff"},
- {GST_DEINTERLACE2_LAYOUT_BFF, "Bottom field first", "bff"},
- {0, NULL, NULL},
- };
-
- if (!deinterlace2_field_layout_type) {
- deinterlace2_field_layout_type =
- g_enum_register_static ("GstDeinterlace2FieldLayout",
- field_layout_types);
- }
- return deinterlace2_field_layout_type;
-}
-
-#define GST_TYPE_DEINTERLACE2_MODES (gst_deinterlace2_modes_get_type ())
-static GType
-gst_deinterlace2_modes_get_type (void)
-{
- static GType deinterlace2_modes_type = 0;
-
- static const GEnumValue modes_types[] = {
- {GST_DEINTERLACE2_MODE_AUTO, "Auto detection", "auto"},
- {GST_DEINTERLACE2_MODE_INTERLACED, "Enfore deinterlacing", "interlaced"},
- {0, NULL, NULL},
- };
-
- if (!deinterlace2_modes_type) {
- deinterlace2_modes_type =
- g_enum_register_static ("GstDeinterlace2Modes", modes_types);
- }
- return deinterlace2_modes_type;
-}
-
-static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("YUY2") ";"
- GST_VIDEO_CAPS_YUV ("YVYU"))
- );
-
-static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("YUY2") ";"
- GST_VIDEO_CAPS_YUV ("YVYU"))
- );
-
-static void gst_deinterlace2_finalize (GObject * self);
-static void gst_deinterlace2_set_property (GObject * self, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_deinterlace2_get_property (GObject * self, guint prop_id,
- GValue * value, GParamSpec * pspec);
-
-static GstCaps *gst_deinterlace2_getcaps (GstPad * pad);
-static gboolean gst_deinterlace2_setcaps (GstPad * pad, GstCaps * caps);
-static gboolean gst_deinterlace2_sink_event (GstPad * pad, GstEvent * event);
-static GstFlowReturn gst_deinterlace2_chain (GstPad * pad, GstBuffer * buffer);
-static GstStateChangeReturn gst_deinterlace2_change_state (GstElement * element,
- GstStateChange transition);
-
-static gboolean gst_deinterlace2_src_event (GstPad * pad, GstEvent * event);
-static gboolean gst_deinterlace2_src_query (GstPad * pad, GstQuery * query);
-static const GstQueryType *gst_deinterlace2_src_query_types (GstPad * pad);
-
-static void gst_deinterlace2_reset (GstDeinterlace2 * self);
-
-static void gst_deinterlace2_child_proxy_interface_init (gpointer g_iface,
- gpointer iface_data);
-
-static void
-_do_init (GType object_type)
-{
- const GInterfaceInfo child_proxy_interface_info = {
- (GInterfaceInitFunc) gst_deinterlace2_child_proxy_interface_init,
- NULL, /* interface_finalize */
- NULL /* interface_data */
- };
-
- g_type_add_interface_static (object_type, GST_TYPE_CHILD_PROXY,
- &child_proxy_interface_info);
-}
-
-GST_BOILERPLATE_FULL (GstDeinterlace2, gst_deinterlace2, GstElement,
- GST_TYPE_ELEMENT, _do_init);
-
-static void
-gst_deinterlace2_set_method (GstDeinterlace2 * self,
- GstDeinterlace2Methods method)
-{
-
- if (self->method) {
- gst_child_proxy_child_removed (GST_OBJECT (self),
- GST_OBJECT (self->method));
- gst_object_unparent (GST_OBJECT (self->method));
- self->method = NULL;
- }
-
- switch (method) {
- case GST_DEINTERLACE2_TOMSMOCOMP:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_TOMSMOCOMP, NULL);
- break;
- case GST_DEINTERLACE2_GREEDY_H:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_GREEDY_H, NULL);
- break;
- case GST_DEINTERLACE2_GREEDY_L:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_GREEDY_L, NULL);
- break;
- case GST_DEINTERLACE2_VFIR:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_VFIR, NULL);
- break;
- case GST_DEINTERLACE2_LINEAR:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_LINEAR, NULL);
- break;
- case GST_DEINTERLACE2_LINEAR_BLEND:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_LINEAR_BLEND, NULL);
- break;
- case GST_DEINTERLACE2_SCALER_BOB:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_SCALER_BOB, NULL);
- break;
- case GST_DEINTERLACE2_WEAVE:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_WEAVE, NULL);
- break;
- case GST_DEINTERLACE2_WEAVE_TFF:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_WEAVE_TFF, NULL);
- break;
- case GST_DEINTERLACE2_WEAVE_BFF:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_WEAVE_BFF, NULL);
- break;
- default:
- GST_WARNING_OBJECT (self, "Invalid Deinterlacer Method");
- return;
- }
-
- self->method_id = method;
-
- gst_object_set_name (GST_OBJECT (self->method), "method");
- gst_object_set_parent (GST_OBJECT (self->method), GST_OBJECT (self));
- gst_child_proxy_child_added (GST_OBJECT (self), GST_OBJECT (self->method));
-}
-
-static void
-gst_deinterlace2_base_init (gpointer klass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&src_templ));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&sink_templ));
-
- gst_element_class_set_details_simple (element_class,
- "Deinterlacer",
- "Filter/Video",
- "Deinterlace Methods ported from DScaler/TvTime",
- "Martin Eikermann <meiker@upb.de>, "
- "Sebastian Dröge <slomo@circular-chaos.org>");
-}
-
-static void
-gst_deinterlace2_class_init (GstDeinterlace2Class * klass)
-{
- GObjectClass *gobject_class = (GObjectClass *) klass;
-
- GstElementClass *element_class = (GstElementClass *) klass;
-
- gobject_class->set_property = gst_deinterlace2_set_property;
- gobject_class->get_property = gst_deinterlace2_get_property;
- gobject_class->finalize = gst_deinterlace2_finalize;
-
- /**
- * GstDeinterlace2:mode
- *
- * This selects whether the deinterlacing methods should
- * always be applied or if they should only be applied
- * on content that has the "interlaced" flag on the caps.
- *
- */
- g_object_class_install_property (gobject_class, PROP_MODE,
- g_param_spec_enum ("mode",
- "Mode",
- "Deinterlace Mode",
- GST_TYPE_DEINTERLACE2_MODES,
- DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
- );
-
- /**
- * GstDeinterlace2:method
- *
- * Selects the different deinterlacing algorithms that can be used.
- * These provide different quality and CPU usage.
- *
- * Some methods provide parameters which can be set by getting
- * the "method" child via the #GstChildProxy interface and
- * setting the appropiate properties on it.
- *
- * <itemizedlist>
- * <listitem>
- * <para>
- * tomsmocomp
- * Motion Adaptive: Motion Search
- * </para>
- * </listitem>
- * <listitem>
- * <para>
- * greedyh
- * Motion Adaptive: Advanced Detection
- * </para>
- * </listitem>
- * <listitem>
- * <para>
- * greedyl
- * Motion Adaptive: Simple Detection
- * </para>
- * </listitem>
- * <listitem>
- * <para>
- * vfir
- * Blur vertical
- * </para>
- * </listitem>
- * <listitem>
- * <para>
- * linear
- * Linear interpolation
- * </para>
- * </listitem>
- * <listitem>
- * <para>
- * linearblend
- * Linear interpolation in time domain
- * </para>
- * </listitem>
- * <listitem>
- * <para>
- * scalerbob
- * Double lines
- * </para>
- * </listitem>
- * <listitem>
- * <para>
- * weave
- * Weave
- * </para>
- * </listitem>
- * <listitem>
- * <para>
- * weavetff
- * Progressive: Top Field First
- * </para>
- * </listitem>
- * <listitem>
- * <para>
- * weavebff
- * Progressive: Bottom Field First
- * </para>
- * </listitem>
- * </itemizedlist>
- */
- g_object_class_install_property (gobject_class, PROP_METHOD,
- g_param_spec_enum ("method",
- "Method",
- "Deinterlace Method",
- GST_TYPE_DEINTERLACE2_METHODS,
- DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
- );
-
- /**
- * GstDeinterlace2:fields
- *
- * This selects which fields should be output. If "all" is selected
- * the output framerate will be double.
- *
- */
- g_object_class_install_property (gobject_class, PROP_FIELDS,
- g_param_spec_enum ("fields",
- "fields",
- "Fields to use for deinterlacing",
- GST_TYPE_DEINTERLACE2_FIELDS,
- DEFAULT_FIELDS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
- );
-
- /**
- * GstDeinterlace2:layout
- *
- * This selects which fields is the first in time.
- *
- */
- g_object_class_install_property (gobject_class, PROP_FIELD_LAYOUT,
- g_param_spec_enum ("tff",
- "tff",
- "Deinterlace top field first",
- GST_TYPE_DEINTERLACE2_FIELD_LAYOUT,
- DEFAULT_FIELD_LAYOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
- );
-
- element_class->change_state =
- GST_DEBUG_FUNCPTR (gst_deinterlace2_change_state);
-}
-
-static GstObject *
-gst_deinterlace2_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
- guint index)
-{
- GstDeinterlace2 *self = GST_DEINTERLACE2 (child_proxy);
-
- g_return_val_if_fail (index == 0, NULL);
-
- return gst_object_ref (self->method);
-}
-
-static guint
-gst_deinterlace2_child_proxy_get_children_count (GstChildProxy * child_proxy)
-{
- return 1;
-}
-
-static void
-gst_deinterlace2_child_proxy_interface_init (gpointer g_iface,
- gpointer iface_data)
-{
- GstChildProxyInterface *iface = g_iface;
-
- iface->get_child_by_index = gst_deinterlace2_child_proxy_get_child_by_index;
- iface->get_children_count = gst_deinterlace2_child_proxy_get_children_count;
-}
-
-static void
-gst_deinterlace2_init (GstDeinterlace2 * self, GstDeinterlace2Class * klass)
-{
- self->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
- gst_pad_set_chain_function (self->sinkpad,
- GST_DEBUG_FUNCPTR (gst_deinterlace2_chain));
- gst_pad_set_event_function (self->sinkpad,
- GST_DEBUG_FUNCPTR (gst_deinterlace2_sink_event));
- gst_pad_set_setcaps_function (self->sinkpad,
- GST_DEBUG_FUNCPTR (gst_deinterlace2_setcaps));
- gst_pad_set_getcaps_function (self->sinkpad,
- GST_DEBUG_FUNCPTR (gst_deinterlace2_getcaps));
- gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
-
- self->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
- gst_pad_set_event_function (self->srcpad,
- GST_DEBUG_FUNCPTR (gst_deinterlace2_src_event));
- gst_pad_set_query_type_function (self->srcpad,
- GST_DEBUG_FUNCPTR (gst_deinterlace2_src_query_types));
- gst_pad_set_query_function (self->srcpad,
- GST_DEBUG_FUNCPTR (gst_deinterlace2_src_query));
- gst_pad_set_setcaps_function (self->srcpad,
- GST_DEBUG_FUNCPTR (gst_deinterlace2_setcaps));
- gst_pad_set_getcaps_function (self->srcpad,
- GST_DEBUG_FUNCPTR (gst_deinterlace2_getcaps));
- gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
-
- gst_element_no_more_pads (GST_ELEMENT (self));
-
- self->mode = DEFAULT_MODE;
- gst_deinterlace2_set_method (self, DEFAULT_METHOD);
- self->fields = DEFAULT_FIELDS;
- self->field_layout = DEFAULT_FIELD_LAYOUT;
-
- gst_deinterlace2_reset (self);
-}
-
-static void
-gst_deinterlace2_reset_history (GstDeinterlace2 * self)
-{
- gint i;
-
- for (i = 0; i < self->history_count; i++) {
- if (self->field_history[i].buf) {
- gst_buffer_unref (self->field_history[i].buf);
- self->field_history[i].buf = NULL;
- }
- }
- memset (self->field_history, 0, MAX_FIELD_HISTORY * sizeof (GstPicture));
- self->history_count = 0;
-}
-
-static void
-gst_deinterlace2_reset (GstDeinterlace2 * self)
-{
- self->row_stride = 0;
- self->frame_width = 0;
- self->frame_height = 0;
- self->frame_rate_n = 0;
- self->frame_rate_d = 0;
- self->field_height = 0;
- self->field_stride = 0;
-
- gst_deinterlace2_reset_history (self);
-}
-
-static void
-gst_deinterlace2_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstDeinterlace2 *self;
-
- g_return_if_fail (GST_IS_DEINTERLACE2 (object));
- self = GST_DEINTERLACE2 (object);
-
- switch (prop_id) {
- case PROP_MODE:
- if (GST_STATE (self) >= GST_STATE_PAUSED) {
- g_warning ("Setting the 'mode' property is only allowed in "
- "states other than PAUSED and PLAYING");
- } else {
- self->mode = g_value_get_enum (value);
- }
- break;
- case PROP_METHOD:
- gst_deinterlace2_set_method (self, g_value_get_enum (value));
- break;
- case PROP_FIELDS:{
- gint oldfields;
-
- GST_OBJECT_LOCK (self);
- oldfields = self->fields;
- self->fields = g_value_get_enum (value);
- if (self->fields != oldfields && GST_PAD_CAPS (self->srcpad))
- gst_deinterlace2_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad));
- GST_OBJECT_UNLOCK (self);
- break;
- }
- case PROP_FIELD_LAYOUT:
- self->field_layout = g_value_get_enum (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
- }
-
-}
-
-static void
-gst_deinterlace2_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstDeinterlace2 *self;
-
- g_return_if_fail (GST_IS_DEINTERLACE2 (object));
- self = GST_DEINTERLACE2 (object);
-
- switch (prop_id) {
- case PROP_MODE:
- g_value_set_enum (value, self->mode);
- break;
- case PROP_METHOD:
- g_value_set_enum (value, self->method_id);
- break;
- case PROP_FIELDS:
- g_value_set_enum (value, self->fields);
- break;
- case PROP_FIELD_LAYOUT:
- g_value_set_enum (value, self->field_layout);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
- }
-}
-
-static void
-gst_deinterlace2_finalize (GObject * object)
-{
- GstDeinterlace2 *self = GST_DEINTERLACE2 (object);
-
- gst_deinterlace2_reset (self);
-
- if (self->method) {
- gst_object_unparent (GST_OBJECT (self->method));
- self->method = NULL;
- }
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static GstBuffer *
-gst_deinterlace2_pop_history (GstDeinterlace2 * self)
-{
- GstBuffer *buffer = NULL;
-
- g_assert (self->history_count > 0);
-
- buffer = self->field_history[self->history_count - 1].buf;
-
- self->history_count--;
- GST_DEBUG_OBJECT (self, "pop, size(history): %d", self->history_count);
-
- return buffer;
-}
-
-#if 0
-static GstBuffer *
-gst_deinterlace2_head_history (GstDeinterlace2 * self)
-{
- return self->field_history[self->history_count - 1].buf;
-}
-#endif
-
-
-/* invariant: field with smallest timestamp is self->field_history[self->history_count-1]
-
-*/
-
-static void
-gst_deinterlace2_push_history (GstDeinterlace2 * self, GstBuffer * buffer)
-{
- int i = 1;
- GstClockTime timestamp;
- GstDeinterlace2FieldLayout field_layout = self->field_layout;
- gboolean repeated = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_RFF);
- gboolean tff = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_TFF);
- gboolean onefield =
- GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_ONEFIELD);
- GstBuffer *field1, *field2;
- guint fields_to_push = (onefield) ? 1 : (!repeated) ? 2 : 3;
- gint field1_flags, field2_flags;
-
- g_assert (self->history_count < MAX_FIELD_HISTORY - fields_to_push);
-
- for (i = MAX_FIELD_HISTORY - 1; i >= fields_to_push; i--) {
- self->field_history[i].buf = self->field_history[i - fields_to_push].buf;
- self->field_history[i].flags =
- self->field_history[i - fields_to_push].flags;
- }
-
- if (field_layout == GST_DEINTERLACE2_LAYOUT_AUTO) {
- if (!self->interlaced) {
- GST_WARNING_OBJECT (self, "Can't detect field layout -- assuming TFF");
- field_layout = GST_DEINTERLACE2_LAYOUT_TFF;
- } else if (tff) {
- field_layout = GST_DEINTERLACE2_LAYOUT_TFF;
- } else {
- field_layout = GST_DEINTERLACE2_LAYOUT_BFF;
- }
- }
-
- if (field_layout == GST_DEINTERLACE2_LAYOUT_TFF) {
- GST_DEBUG_OBJECT (self, "Top field first");
- field1 = gst_buffer_ref (buffer);
- field1_flags = PICTURE_INTERLACED_TOP;
- field2 = gst_buffer_create_sub (buffer, self->row_stride,
- GST_BUFFER_SIZE (buffer) - self->row_stride);
- field2_flags = PICTURE_INTERLACED_BOTTOM;
- } else {
- GST_DEBUG_OBJECT (self, "Bottom field first");
- field1 = gst_buffer_create_sub (buffer, self->row_stride,
- GST_BUFFER_SIZE (buffer) - self->row_stride);
- field1_flags = PICTURE_INTERLACED_BOTTOM;
- field2 = gst_buffer_ref (buffer);
- field2_flags = PICTURE_INTERLACED_TOP;
- }
-
- /* Timestamps are assigned to the field buffers under the assumption that
- the timestamp of the buffer equals the first fields timestamp */
-
- timestamp = GST_BUFFER_TIMESTAMP (buffer);
- GST_BUFFER_TIMESTAMP (field1) = timestamp;
- GST_BUFFER_TIMESTAMP (field2) = timestamp + self->field_duration;
- if (repeated)
- GST_BUFFER_TIMESTAMP (field2) += self->field_duration;
-
- if (repeated) {
- self->field_history[0].buf = field2;
- self->field_history[0].flags = field2_flags;
- self->field_history[1].buf = gst_buffer_ref (field1);
- GST_BUFFER_TIMESTAMP (self->field_history[1].buf) += self->field_duration;
- self->field_history[1].flags = field1_flags;
- self->field_history[2].buf = field1;
- self->field_history[2].flags = field1_flags;
- } else if (!onefield) {
- self->field_history[0].buf = field2;
- self->field_history[0].flags = field2_flags;
- self->field_history[1].buf = field1;
- self->field_history[1].flags = field1_flags;
- } else { /* onefield */
- self->field_history[0].buf = field1;
- self->field_history[0].flags = field1_flags;
- gst_buffer_unref (field2);
- }
-
- self->history_count += fields_to_push;
- GST_DEBUG_OBJECT (self, "push, size(history): %d", self->history_count);
-
- gst_buffer_unref (buffer);
-}
-
-static GstFlowReturn
-gst_deinterlace2_chain (GstPad * pad, GstBuffer * buf)
-{
- GstDeinterlace2 *self = NULL;
- GstClockTime timestamp;
- GstFlowReturn ret = GST_FLOW_OK;
- gint fields_required = 0;
- gint cur_field_idx = 0;
- GstBuffer *outbuf;
-
- self = GST_DEINTERLACE2 (GST_PAD_PARENT (pad));
-
- if (!self->interlaced && self->mode != GST_DEINTERLACE2_MODE_INTERLACED)
- return gst_pad_push (self->srcpad, buf);
-
- if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
- GST_DEBUG_OBJECT (self, "DISCONT buffer, resetting history");
- gst_deinterlace2_reset_history (self);
- }
-
- gst_deinterlace2_push_history (self, buf);
- buf = NULL;
-
- fields_required = gst_deinterlace_method_get_fields_required (self->method);
-
- /* Not enough fields in the history */
- if (self->history_count < fields_required + 1) {
- /* TODO: do bob or just forward frame */
- GST_DEBUG_OBJECT (self, "HistoryCount=%d", self->history_count);
- return GST_FLOW_OK;
- }
-
- while (self->history_count >= fields_required) {
- if (self->fields == GST_DEINTERLACE2_ALL)
- GST_DEBUG_OBJECT (self, "All fields");
- if (self->fields == GST_DEINTERLACE2_TF)
- GST_DEBUG_OBJECT (self, "Top fields");
- if (self->fields == GST_DEINTERLACE2_BF)
- GST_DEBUG_OBJECT (self, "Bottom fields");
-
- cur_field_idx = self->history_count - fields_required;
-
- if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_TOP
- && self->fields == GST_DEINTERLACE2_TF) ||
- self->fields == GST_DEINTERLACE2_ALL) {
- GST_DEBUG_OBJECT (self, "deinterlacing top field");
-
- /* create new buffer */
- ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad,
- GST_BUFFER_OFFSET_NONE, self->frame_size,
- GST_PAD_CAPS (self->srcpad), &outbuf);
- if (ret != GST_FLOW_OK)
- return ret;
-
- /* do magic calculus */
- gst_deinterlace_method_deinterlace_frame (self->method, self, outbuf);
-
- g_assert (self->history_count - 1 -
- gst_deinterlace_method_get_latency (self->method) >= 0);
- buf =
- self->field_history[self->history_count - 1 -
- gst_deinterlace_method_get_latency (self->method)].buf;
- timestamp = GST_BUFFER_TIMESTAMP (buf);
-
- gst_buffer_unref (gst_deinterlace2_pop_history (self));
-
- GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
- if (self->fields == GST_DEINTERLACE2_ALL)
- GST_BUFFER_DURATION (outbuf) = self->field_duration;
- else
- GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
-
- ret = gst_pad_push (self->srcpad, outbuf);
- outbuf = NULL;
- if (ret != GST_FLOW_OK)
- return ret;
- }
- /* no calculation done: remove excess field */
- else if (self->field_history[cur_field_idx].flags ==
- PICTURE_INTERLACED_TOP && self->fields == GST_DEINTERLACE2_BF) {
- GST_DEBUG_OBJECT (self, "Removing unused top field");
- gst_buffer_unref (gst_deinterlace2_pop_history (self));
- }
-
- cur_field_idx = self->history_count - fields_required;
- if (self->history_count < fields_required)
- break;
-
- /* deinterlace bottom_field */
- if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_BOTTOM
- && self->fields == GST_DEINTERLACE2_BF) ||
- self->fields == GST_DEINTERLACE2_ALL) {
- GST_DEBUG_OBJECT (self, "deinterlacing bottom field");
-
- /* create new buffer */
- ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad,
- GST_BUFFER_OFFSET_NONE, self->frame_size,
- GST_PAD_CAPS (self->srcpad), &outbuf);
- if (ret != GST_FLOW_OK)
- return ret;
-
- /* do magic calculus */
- gst_deinterlace_method_deinterlace_frame (self->method, self, outbuf);
-
- g_assert (self->history_count - 1 -
- gst_deinterlace_method_get_latency (self->method) >= 0);
- buf =
- self->field_history[self->history_count - 1 -
- gst_deinterlace_method_get_latency (self->method)].buf;
- timestamp = GST_BUFFER_TIMESTAMP (buf);
-
- gst_buffer_unref (gst_deinterlace2_pop_history (self));
-
- GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
- if (self->fields == GST_DEINTERLACE2_ALL)
- GST_BUFFER_DURATION (outbuf) = self->field_duration;
- else
- GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
-
- ret = gst_pad_push (self->srcpad, outbuf);
- outbuf = NULL;
-
- if (ret != GST_FLOW_OK)
- return ret;
- }
- /* no calculation done: remove excess field */
- else if (self->field_history[cur_field_idx].flags ==
- PICTURE_INTERLACED_BOTTOM && self->fields == GST_DEINTERLACE2_TF) {
- GST_DEBUG_OBJECT (self, "Removing unused bottom field");
- gst_buffer_unref (gst_deinterlace2_pop_history (self));
- }
- }
-
- GST_DEBUG_OBJECT (self, "----chain end ----\n\n");
-
- return ret;
-}
-
-static gint
-gst_greatest_common_divisor (gint a, gint b)
-{
- while (b != 0) {
- int temp = a;
-
- a = b;
- b = temp % b;
- }
-
- return ABS (a);
-}
-
-static gboolean
-gst_fraction_double (gint * n_out, gint * d_out, gboolean half)
-{
- gint n, d, gcd;
-
- n = *n_out;
- d = *d_out;
-
- if (d == 0)
- return FALSE;
-
- if (n == 0 || (n == G_MAXINT && d == 1))
- return TRUE;
-
- gcd = gst_greatest_common_divisor (n, d);
- n /= gcd;
- d /= gcd;
-
- if (!half) {
- if (G_MAXINT / 2 >= ABS (n)) {
- n *= 2;
- } else if (d >= 2) {
- d /= 2;
- } else {
- return FALSE;
- }
- } else {
- if (G_MAXINT / 2 >= ABS (d)) {
- d *= 2;
- } else if (n >= 2) {
- n /= 2;
- } else {
- return FALSE;
- }
- }
-
- *n_out = n;
- *d_out = d;
-
- return TRUE;
-}
-
-static GstCaps *
-gst_deinterlace2_getcaps (GstPad * pad)
-{
- GstCaps *ret;
- GstDeinterlace2 *self = GST_DEINTERLACE2 (gst_pad_get_parent (pad));
- GstPad *otherpad;
- gint len;
- const GstCaps *ourcaps;
- GstCaps *peercaps;
-
- GST_OBJECT_LOCK (self);
-
- otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad;
-
- ourcaps = gst_pad_get_pad_template_caps (pad);
- peercaps = gst_pad_peer_get_caps (otherpad);
-
- if (peercaps) {
- ret = gst_caps_intersect (ourcaps, peercaps);
- gst_caps_unref (peercaps);
- } else {
- ret = gst_caps_copy (ourcaps);
- }
-
- GST_OBJECT_UNLOCK (self);
-
- if ((self->interlaced || self->mode == GST_DEINTERLACE2_MODE_INTERLACED) &&
- self->fields == GST_DEINTERLACE2_ALL) {
- for (len = gst_caps_get_size (ret); len > 0; len--) {
- GstStructure *s = gst_caps_get_structure (ret, len - 1);
- const GValue *val;
-
- val = gst_structure_get_value (s, "framerate");
- if (!val)
- continue;
-
- if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION) {
- gint n, d;
-
- n = gst_value_get_fraction_numerator (val);
- d = gst_value_get_fraction_denominator (val);
-
- if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
- goto error;
- }
-
- gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
- } else if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION_RANGE) {
- const GValue *min, *max;
- GValue nrange = { 0, }, nmin = {
- 0,}, nmax = {
- 0,};
- gint n, d;
-
- g_value_init (&nrange, GST_TYPE_FRACTION_RANGE);
- g_value_init (&nmin, GST_TYPE_FRACTION);
- g_value_init (&nmax, GST_TYPE_FRACTION);
-
- min = gst_value_get_fraction_range_min (val);
- max = gst_value_get_fraction_range_max (val);
-
- n = gst_value_get_fraction_numerator (min);
- d = gst_value_get_fraction_denominator (min);
-
- if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
- g_value_unset (&nrange);
- g_value_unset (&nmax);
- g_value_unset (&nmin);
- goto error;
- }
-
- gst_value_set_fraction (&nmin, n, d);
-
- n = gst_value_get_fraction_numerator (max);
- d = gst_value_get_fraction_denominator (max);
-
- if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
- g_value_unset (&nrange);
- g_value_unset (&nmax);
- g_value_unset (&nmin);
- goto error;
- }
-
- gst_value_set_fraction (&nmax, n, d);
- gst_value_set_fraction_range (&nrange, &nmin, &nmax);
-
- gst_structure_set_value (s, "framerate", &nrange);
-
- g_value_unset (&nmin);
- g_value_unset (&nmax);
- g_value_unset (&nrange);
- } else if (G_VALUE_TYPE (val) == GST_TYPE_LIST) {
- const GValue *lval;
- GValue nlist = { 0, };
- GValue nval = { 0, };
- gint i;
-
- g_value_init (&nlist, GST_TYPE_LIST);
- for (i = gst_value_list_get_size (val); i > 0; i--) {
- gint n, d;
-
- lval = gst_value_list_get_value (val, i);
-
- if (G_VALUE_TYPE (lval) != GST_TYPE_FRACTION)
- continue;
-
- n = gst_value_get_fraction_numerator (lval);
- d = gst_value_get_fraction_denominator (lval);
-
- /* Double/Half the framerate but if this fails simply
- * skip this value from the list */
- if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
- continue;
- }
-
- g_value_init (&nval, GST_TYPE_FRACTION);
-
- gst_value_set_fraction (&nval, n, d);
- gst_value_list_append_value (&nlist, &nval);
- g_value_unset (&nval);
- }
- gst_structure_set_value (s, "framerate", &nlist);
- g_value_unset (&nlist);
- }
- }
- }
-
- GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret);
-
- return ret;
-
-error:
- GST_ERROR_OBJECT (pad, "Unable to transform peer caps");
- gst_caps_unref (ret);
- return NULL;
-}
-
-static gboolean
-gst_deinterlace2_setcaps (GstPad * pad, GstCaps * caps)
-{
- gboolean res = TRUE;
- GstDeinterlace2 *self = GST_DEINTERLACE2 (gst_pad_get_parent (pad));
- GstPad *otherpad;
- GstStructure *structure;
- GstVideoFormat fmt;
- guint32 fourcc;
- GstCaps *othercaps;
-
- otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad;
-
- structure = gst_caps_get_structure (caps, 0);
-
- res = gst_structure_get_int (structure, "width", &self->frame_width);
- res &= gst_structure_get_int (structure, "height", &self->frame_height);
- res &=
- gst_structure_get_fraction (structure, "framerate", &self->frame_rate_n,
- &self->frame_rate_d);
- res &= gst_structure_get_fourcc (structure, "format", &fourcc);
- res &= gst_video_format_parse_caps_interlaced (caps, &self->interlaced);
- if (!res)
- goto invalid_caps;
-
- if ((self->interlaced || self->mode == GST_DEINTERLACE2_MODE_INTERLACED) &&
- self->fields == GST_DEINTERLACE2_ALL) {
- gint fps_n = self->frame_rate_n, fps_d = self->frame_rate_d;
-
- if (!gst_fraction_double (&fps_n, &fps_d, otherpad != self->srcpad))
- goto invalid_caps;
-
- othercaps = gst_caps_copy (caps);
-
- gst_caps_set_simple (othercaps, "framerate", GST_TYPE_FRACTION, fps_n,
- fps_d, NULL);
- } else {
- othercaps = gst_caps_ref (caps);
- }
-
- if (!gst_pad_set_caps (otherpad, othercaps))
- goto caps_not_accepted;
- gst_caps_unref (othercaps);
-
- self->field_height = self->frame_height / 2;
-
- fmt = gst_video_format_from_fourcc (fourcc);
-
- /* TODO: only true if fields are subbuffers of interlaced frames,
- change when the buffer-fields concept has landed */
- self->field_stride =
- gst_video_format_get_row_stride (fmt, 0, self->frame_width) * 2;
-
- /* in bytes */
- self->row_stride =
- gst_video_format_get_row_stride (fmt, 0, self->frame_width);
- self->frame_size =
- gst_video_format_get_size (fmt, self->frame_width, self->frame_height);
-
- if (self->fields == GST_DEINTERLACE2_ALL && otherpad == self->srcpad)
- self->field_duration =
- gst_util_uint64_scale (GST_SECOND, self->frame_rate_d,
- self->frame_rate_n);
- else
- self->field_duration =
- gst_util_uint64_scale (GST_SECOND, self->frame_rate_d,
- 2 * self->frame_rate_n);
-
- GST_DEBUG_OBJECT (self, "Set caps: %" GST_PTR_FORMAT, caps);
-
-done:
-
- gst_object_unref (self);
- return res;
-
-invalid_caps:
- res = FALSE;
- GST_ERROR_OBJECT (pad, "Invalid caps: %" GST_PTR_FORMAT, caps);
- goto done;
-
-caps_not_accepted:
- res = FALSE;
- GST_ERROR_OBJECT (pad, "Caps not accepted: %" GST_PTR_FORMAT, othercaps);
- gst_caps_unref (othercaps);
- goto done;
-}
-
-static gboolean
-gst_deinterlace2_sink_event (GstPad * pad, GstEvent * event)
-{
- gboolean res = TRUE;
- GstDeinterlace2 *self = GST_DEINTERLACE2 (gst_pad_get_parent (pad));
-
- GST_LOG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH_STOP:
- case GST_EVENT_EOS:
- case GST_EVENT_NEWSEGMENT:
- gst_deinterlace2_reset_history (self);
-
- /* fall through */
- default:
- res = gst_pad_event_default (pad, event);
- break;
- }
-
- gst_object_unref (self);
- return res;
-}
-
-static GstStateChangeReturn
-gst_deinterlace2_change_state (GstElement * element, GstStateChange transition)
-{
- GstStateChangeReturn ret;
- GstDeinterlace2 *self = GST_DEINTERLACE2 (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- break;
- default:
- break;
- }
-
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
- if (ret != GST_STATE_CHANGE_SUCCESS)
- return ret;
-
- switch (transition) {
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- gst_deinterlace2_reset (self);
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- default:
- break;
- }
-
- return ret;
-}
-
-static gboolean
-gst_deinterlace2_src_event (GstPad * pad, GstEvent * event)
-{
- GstDeinterlace2 *self = GST_DEINTERLACE2 (gst_pad_get_parent (pad));
- gboolean res;
-
- GST_DEBUG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
-
- switch (GST_EVENT_TYPE (event)) {
- default:
- res = gst_pad_event_default (pad, event);
- break;
- }
-
- gst_object_unref (self);
-
- return res;
-}
-
-static gboolean
-gst_deinterlace2_src_query (GstPad * pad, GstQuery * query)
-{
- GstDeinterlace2 *self = GST_DEINTERLACE2 (gst_pad_get_parent (pad));
- gboolean res = FALSE;
-
- GST_LOG_OBJECT (self, "%s query", GST_QUERY_TYPE_NAME (query));
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_LATENCY:
- if (self->interlaced || self->mode == GST_DEINTERLACE2_MODE_INTERLACED) {
- GstClockTime min, max;
- gboolean live;
- GstPad *peer;
-
- if ((peer = gst_pad_get_peer (self->sinkpad))) {
- if ((res = gst_pad_query (peer, query))) {
- GstClockTime latency;
- gint fields_required = 0;
- gint method_latency = 0;
-
- if (self->method) {
- fields_required =
- gst_deinterlace_method_get_fields_required (self->method);
- method_latency =
- gst_deinterlace_method_get_latency (self->method);
- }
-
- gst_query_parse_latency (query, &live, &min, &max);
-
- GST_DEBUG_OBJECT (self, "Peer latency: min %"
- GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
- GST_TIME_ARGS (min), GST_TIME_ARGS (max));
-
- /* add our own latency */
- latency = (fields_required + method_latency) * self->field_duration;
-
- GST_DEBUG_OBJECT (self, "Our latency: min %" GST_TIME_FORMAT
- ", max %" GST_TIME_FORMAT,
- GST_TIME_ARGS (latency), GST_TIME_ARGS (latency));
-
- min += latency;
- if (max != GST_CLOCK_TIME_NONE)
- max += latency;
- else
- max = latency;
-
- GST_DEBUG_OBJECT (self, "Calculated total latency : min %"
- GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
- GST_TIME_ARGS (min), GST_TIME_ARGS (max));
-
- gst_query_set_latency (query, live, min, max);
- }
- gst_object_unref (peer);
- } else {
- res = gst_pad_query_default (pad, query);
- }
- break;
- }
- default:
- res = gst_pad_query_default (pad, query);
- break;
- }
-
- gst_object_unref (self);
- return res;
-}
-
-static const GstQueryType *
-gst_deinterlace2_src_query_types (GstPad * pad)
-{
- static const GstQueryType types[] = {
- GST_QUERY_LATENCY,
- GST_QUERY_NONE
- };
- return types;
-}
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- GST_DEBUG_CATEGORY_INIT (deinterlace2_debug, "deinterlace2", 0,
- "Deinterlacer");
-
- oil_init ();
-
- if (!gst_element_register (plugin, "deinterlace2", GST_RANK_NONE,
- GST_TYPE_DEINTERLACE2)) {
- return FALSE;
- }
-
- return TRUE;
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- "deinterlace2",
- "Deinterlacer", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
- GST_PACKAGE_ORIGIN);