• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2013 David Schleef <ds@schleef.org>
3  * Copyright (C) 2013 Rdio, Inc. <ingestions@rd.io>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
18  * Boston, MA 02110-1335, USA.
19  */
20 /**
21  * SECTION:element-yadif
22  * @title: yadif
23  *
24  * The yadif element deinterlaces video, using the YADIF deinterlacing
25  * filter copied from Libav.  This element only handles the simple case
26  * of interlace-mode=interleaved video instead of the more complex
27  * inverse telecine and deinterlace cases that are handled by the
28  * deinterlace element.
29  *
30  * ## Example launch line
31  * |[
32  * gst-launch-1.0 -v videotestsrc pattern=ball ! interlace ! yadif ! xvimagesink
33  * ]|
34  * This pipeline creates an interlaced test pattern, and then deinterlaces
35  * it using the yadif filter.
36  *
37  */
38 
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42 
43 #include <gst/gst.h>
44 #include <gst/base/gstbasetransform.h>
45 #include <gst/video/video.h>
46 #include "gstyadif.h"
47 
48 GST_DEBUG_CATEGORY_STATIC (gst_yadif_debug_category);
49 #define GST_CAT_DEFAULT gst_yadif_debug_category
50 
51 /* prototypes */
52 
53 
54 static void gst_yadif_set_property (GObject * object,
55     guint property_id, const GValue * value, GParamSpec * pspec);
56 static void gst_yadif_get_property (GObject * object,
57     guint property_id, GValue * value, GParamSpec * pspec);
58 static void gst_yadif_dispose (GObject * object);
59 static void gst_yadif_finalize (GObject * object);
60 
61 static GstCaps *gst_yadif_transform_caps (GstBaseTransform * trans,
62     GstPadDirection direction, GstCaps * caps, GstCaps * filter);
63 static gboolean gst_yadif_set_caps (GstBaseTransform * trans, GstCaps * incaps,
64     GstCaps * outcaps);
65 static gboolean gst_yadif_get_unit_size (GstBaseTransform * trans,
66     GstCaps * caps, gsize * size);
67 static gboolean gst_yadif_start (GstBaseTransform * trans);
68 static gboolean gst_yadif_stop (GstBaseTransform * trans);
69 static GstFlowReturn gst_yadif_transform (GstBaseTransform * trans,
70     GstBuffer * inbuf, GstBuffer * outbuf);
71 
72 enum
73 {
74   PROP_0,
75   PROP_MODE
76 };
77 
78 #define DEFAULT_MODE GST_DEINTERLACE_MODE_AUTO
79 
80 /* pad templates */
81 
82 static GstStaticPadTemplate gst_yadif_sink_template =
83 GST_STATIC_PAD_TEMPLATE ("sink",
84     GST_PAD_SINK,
85     GST_PAD_ALWAYS,
86     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{Y42B,I420,Y444}")
87         ",interlace-mode=(string){interleaved,mixed,progressive}")
88     );
89 
90 static GstStaticPadTemplate gst_yadif_src_template =
91 GST_STATIC_PAD_TEMPLATE ("src",
92     GST_PAD_SRC,
93     GST_PAD_ALWAYS,
94     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{Y42B,I420,Y444}")
95         ",interlace-mode=(string)progressive")
96     );
97 
98 #define GST_TYPE_DEINTERLACE_MODES (gst_deinterlace_modes_get_type ())
99 static GType
gst_deinterlace_modes_get_type(void)100 gst_deinterlace_modes_get_type (void)
101 {
102   static GType deinterlace_modes_type = 0;
103 
104   static const GEnumValue modes_types[] = {
105     {GST_DEINTERLACE_MODE_AUTO, "Auto detection", "auto"},
106     {GST_DEINTERLACE_MODE_INTERLACED, "Force deinterlacing", "interlaced"},
107     {GST_DEINTERLACE_MODE_DISABLED, "Run in passthrough mode", "disabled"},
108     {0, NULL, NULL},
109   };
110 
111   if (!deinterlace_modes_type) {
112     deinterlace_modes_type =
113         g_enum_register_static ("GstYadifModes", modes_types);
114   }
115   return deinterlace_modes_type;
116 }
117 
118 
119 /* class initialization */
120 
121 G_DEFINE_TYPE_WITH_CODE (GstYadif, gst_yadif, GST_TYPE_BASE_TRANSFORM,
122     GST_DEBUG_CATEGORY_INIT (gst_yadif_debug_category, "yadif", 0,
123         "debug category for yadif element"));
124 
125 static void
gst_yadif_class_init(GstYadifClass * klass)126 gst_yadif_class_init (GstYadifClass * klass)
127 {
128   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
129   GstBaseTransformClass *base_transform_class =
130       GST_BASE_TRANSFORM_CLASS (klass);
131 
132   /* Setting up pads and setting metadata should be moved to
133      base_class_init if you intend to subclass this class. */
134   gst_element_class_add_static_pad_template (GST_ELEMENT_CLASS (klass),
135       &gst_yadif_sink_template);
136   gst_element_class_add_static_pad_template (GST_ELEMENT_CLASS (klass),
137       &gst_yadif_src_template);
138 
139   gst_element_class_set_static_metadata (GST_ELEMENT_CLASS (klass),
140       "YADIF deinterlacer", "Video/Filter",
141       "Deinterlace video using YADIF filter", "David Schleef <ds@schleef.org>");
142 
143   gobject_class->set_property = gst_yadif_set_property;
144   gobject_class->get_property = gst_yadif_get_property;
145   gobject_class->dispose = gst_yadif_dispose;
146   gobject_class->finalize = gst_yadif_finalize;
147   base_transform_class->transform_caps =
148       GST_DEBUG_FUNCPTR (gst_yadif_transform_caps);
149   base_transform_class->set_caps = GST_DEBUG_FUNCPTR (gst_yadif_set_caps);
150   base_transform_class->get_unit_size =
151       GST_DEBUG_FUNCPTR (gst_yadif_get_unit_size);
152   base_transform_class->start = GST_DEBUG_FUNCPTR (gst_yadif_start);
153   base_transform_class->stop = GST_DEBUG_FUNCPTR (gst_yadif_stop);
154   base_transform_class->transform = GST_DEBUG_FUNCPTR (gst_yadif_transform);
155 
156   g_object_class_install_property (gobject_class, PROP_MODE,
157       g_param_spec_enum ("mode", "Deinterlace Mode",
158           "Deinterlace mode",
159           GST_TYPE_DEINTERLACE_MODES,
160           DEFAULT_MODE,
161           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
162 
163 }
164 
165 static void
gst_yadif_init(GstYadif * yadif)166 gst_yadif_init (GstYadif * yadif)
167 {
168 }
169 
170 void
gst_yadif_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)171 gst_yadif_set_property (GObject * object, guint property_id,
172     const GValue * value, GParamSpec * pspec)
173 {
174   GstYadif *yadif = GST_YADIF (object);
175 
176   switch (property_id) {
177     case PROP_MODE:
178       yadif->mode = g_value_get_enum (value);
179       break;
180     default:
181       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
182       break;
183   }
184 }
185 
186 void
gst_yadif_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)187 gst_yadif_get_property (GObject * object, guint property_id,
188     GValue * value, GParamSpec * pspec)
189 {
190   GstYadif *yadif = GST_YADIF (object);
191 
192   switch (property_id) {
193     case PROP_MODE:
194       g_value_set_enum (value, yadif->mode);
195       break;
196     default:
197       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
198       break;
199   }
200 }
201 
202 void
gst_yadif_dispose(GObject * object)203 gst_yadif_dispose (GObject * object)
204 {
205   /* GstYadif *yadif = GST_YADIF (object); */
206 
207   /* clean up as possible.  may be called multiple times */
208 
209   G_OBJECT_CLASS (gst_yadif_parent_class)->dispose (object);
210 }
211 
212 void
gst_yadif_finalize(GObject * object)213 gst_yadif_finalize (GObject * object)
214 {
215   /* GstYadif *yadif = GST_YADIF (object); */
216 
217   /* clean up object here */
218 
219   G_OBJECT_CLASS (gst_yadif_parent_class)->finalize (object);
220 }
221 
222 
223 static GstCaps *
gst_yadif_transform_caps(GstBaseTransform * trans,GstPadDirection direction,GstCaps * caps,GstCaps * filter)224 gst_yadif_transform_caps (GstBaseTransform * trans,
225     GstPadDirection direction, GstCaps * caps, GstCaps * filter)
226 {
227   GstCaps *othercaps;
228 
229   othercaps = gst_caps_copy (caps);
230 
231   if (direction == GST_PAD_SRC) {
232     GValue value = G_VALUE_INIT;
233     GValue v = G_VALUE_INIT;
234 
235     g_value_init (&value, GST_TYPE_LIST);
236     g_value_init (&v, G_TYPE_STRING);
237 
238     g_value_set_string (&v, "interleaved");
239     gst_value_list_append_value (&value, &v);
240     g_value_set_string (&v, "mixed");
241     gst_value_list_append_value (&value, &v);
242     g_value_set_string (&v, "progressive");
243     gst_value_list_append_value (&value, &v);
244 
245     gst_caps_set_value (othercaps, "interlace-mode", &value);
246     g_value_unset (&value);
247     g_value_unset (&v);
248   } else {
249     gst_caps_set_simple (othercaps, "interlace-mode", G_TYPE_STRING,
250         "progressive", NULL);
251   }
252 
253   return othercaps;
254 }
255 
256 static gboolean
gst_yadif_set_caps(GstBaseTransform * trans,GstCaps * incaps,GstCaps * outcaps)257 gst_yadif_set_caps (GstBaseTransform * trans, GstCaps * incaps,
258     GstCaps * outcaps)
259 {
260   GstYadif *yadif = GST_YADIF (trans);
261 
262   gst_video_info_from_caps (&yadif->video_info, incaps);
263 
264   return TRUE;
265 }
266 
267 static gboolean
gst_yadif_get_unit_size(GstBaseTransform * trans,GstCaps * caps,gsize * size)268 gst_yadif_get_unit_size (GstBaseTransform * trans, GstCaps * caps, gsize * size)
269 {
270   GstVideoInfo info;
271 
272   if (gst_video_info_from_caps (&info, caps)) {
273     *size = GST_VIDEO_INFO_SIZE (&info);
274 
275     return TRUE;
276   }
277   return FALSE;
278 }
279 
280 static gboolean
gst_yadif_start(GstBaseTransform * trans)281 gst_yadif_start (GstBaseTransform * trans)
282 {
283 
284   return TRUE;
285 }
286 
287 static gboolean
gst_yadif_stop(GstBaseTransform * trans)288 gst_yadif_stop (GstBaseTransform * trans)
289 {
290 
291   return TRUE;
292 }
293 
294 void yadif_filter (GstYadif * yadif, int parity, int tff);
295 
296 static GstFlowReturn
gst_yadif_transform(GstBaseTransform * trans,GstBuffer * inbuf,GstBuffer * outbuf)297 gst_yadif_transform (GstBaseTransform * trans, GstBuffer * inbuf,
298     GstBuffer * outbuf)
299 {
300   GstYadif *yadif = GST_YADIF (trans);
301   int parity;
302   int tff;
303 
304   parity = 0;
305   tff = 0;
306 
307   if (!gst_video_frame_map (&yadif->dest_frame, &yadif->video_info, outbuf,
308           GST_MAP_WRITE))
309     goto dest_map_failed;
310 
311   if (!gst_video_frame_map (&yadif->cur_frame, &yadif->video_info, inbuf,
312           GST_MAP_READ))
313     goto src_map_failed;
314 
315   yadif->next_frame = yadif->cur_frame;
316   yadif->prev_frame = yadif->cur_frame;
317 
318   yadif_filter (yadif, parity, tff);
319 
320   gst_video_frame_unmap (&yadif->dest_frame);
321   gst_video_frame_unmap (&yadif->cur_frame);
322   return GST_FLOW_OK;
323 
324 dest_map_failed:
325   {
326     GST_ERROR_OBJECT (yadif, "failed to map dest");
327     return GST_FLOW_ERROR;
328   }
329 src_map_failed:
330   {
331     GST_ERROR_OBJECT (yadif, "failed to map src");
332     gst_video_frame_unmap (&yadif->dest_frame);
333     return GST_FLOW_ERROR;
334   }
335 }
336 
337 
338 static gboolean
plugin_init(GstPlugin * plugin)339 plugin_init (GstPlugin * plugin)
340 {
341 
342   return gst_element_register (plugin, "yadif", GST_RANK_NONE, GST_TYPE_YADIF);
343 }
344 
345 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
346     GST_VERSION_MINOR,
347     yadif,
348     "YADIF deinterlacing filter",
349     plugin_init, VERSION, "GPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN)
350