wasapi2: Fallback to IAudioClient interface if IAudioClient3 API is unavailable
[platform/upstream/gstreamer.git] / gst / yadif / gstyadif.c
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
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
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   gst_type_mark_as_plugin_api (GST_TYPE_DEINTERLACE_MODES, 0);
164 }
165
166 static void
167 gst_yadif_init (GstYadif * yadif)
168 {
169 }
170
171 void
172 gst_yadif_set_property (GObject * object, guint property_id,
173     const GValue * value, GParamSpec * pspec)
174 {
175   GstYadif *yadif = GST_YADIF (object);
176
177   switch (property_id) {
178     case PROP_MODE:
179       yadif->mode = g_value_get_enum (value);
180       break;
181     default:
182       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
183       break;
184   }
185 }
186
187 void
188 gst_yadif_get_property (GObject * object, guint property_id,
189     GValue * value, GParamSpec * pspec)
190 {
191   GstYadif *yadif = GST_YADIF (object);
192
193   switch (property_id) {
194     case PROP_MODE:
195       g_value_set_enum (value, yadif->mode);
196       break;
197     default:
198       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
199       break;
200   }
201 }
202
203 void
204 gst_yadif_dispose (GObject * object)
205 {
206   /* GstYadif *yadif = GST_YADIF (object); */
207
208   /* clean up as possible.  may be called multiple times */
209
210   G_OBJECT_CLASS (gst_yadif_parent_class)->dispose (object);
211 }
212
213 void
214 gst_yadif_finalize (GObject * object)
215 {
216   /* GstYadif *yadif = GST_YADIF (object); */
217
218   /* clean up object here */
219
220   G_OBJECT_CLASS (gst_yadif_parent_class)->finalize (object);
221 }
222
223
224 static GstCaps *
225 gst_yadif_transform_caps (GstBaseTransform * trans,
226     GstPadDirection direction, GstCaps * caps, GstCaps * filter)
227 {
228   GstCaps *othercaps;
229
230   othercaps = gst_caps_copy (caps);
231
232   if (direction == GST_PAD_SRC) {
233     GValue value = G_VALUE_INIT;
234     GValue v = G_VALUE_INIT;
235
236     g_value_init (&value, GST_TYPE_LIST);
237     g_value_init (&v, G_TYPE_STRING);
238
239     g_value_set_string (&v, "interleaved");
240     gst_value_list_append_value (&value, &v);
241     g_value_set_string (&v, "mixed");
242     gst_value_list_append_value (&value, &v);
243     g_value_set_string (&v, "progressive");
244     gst_value_list_append_value (&value, &v);
245
246     gst_caps_set_value (othercaps, "interlace-mode", &value);
247     g_value_unset (&value);
248     g_value_unset (&v);
249   } else {
250     gst_caps_set_simple (othercaps, "interlace-mode", G_TYPE_STRING,
251         "progressive", NULL);
252   }
253
254   return othercaps;
255 }
256
257 static gboolean
258 gst_yadif_set_caps (GstBaseTransform * trans, GstCaps * incaps,
259     GstCaps * outcaps)
260 {
261   GstYadif *yadif = GST_YADIF (trans);
262
263   gst_video_info_from_caps (&yadif->video_info, incaps);
264
265   return TRUE;
266 }
267
268 static gboolean
269 gst_yadif_get_unit_size (GstBaseTransform * trans, GstCaps * caps, gsize * size)
270 {
271   GstVideoInfo info;
272
273   if (gst_video_info_from_caps (&info, caps)) {
274     *size = GST_VIDEO_INFO_SIZE (&info);
275
276     return TRUE;
277   }
278   return FALSE;
279 }
280
281 static gboolean
282 gst_yadif_start (GstBaseTransform * trans)
283 {
284
285   return TRUE;
286 }
287
288 static gboolean
289 gst_yadif_stop (GstBaseTransform * trans)
290 {
291
292   return TRUE;
293 }
294
295 void yadif_filter (GstYadif * yadif, int parity, int tff);
296
297 static GstFlowReturn
298 gst_yadif_transform (GstBaseTransform * trans, GstBuffer * inbuf,
299     GstBuffer * outbuf)
300 {
301   GstYadif *yadif = GST_YADIF (trans);
302   int parity;
303   int tff;
304
305   parity = 0;
306   tff = 0;
307
308   if (!gst_video_frame_map (&yadif->dest_frame, &yadif->video_info, outbuf,
309           GST_MAP_WRITE))
310     goto dest_map_failed;
311
312   if (!gst_video_frame_map (&yadif->cur_frame, &yadif->video_info, inbuf,
313           GST_MAP_READ))
314     goto src_map_failed;
315
316   yadif->next_frame = yadif->cur_frame;
317   yadif->prev_frame = yadif->cur_frame;
318
319   yadif_filter (yadif, parity, tff);
320
321   gst_video_frame_unmap (&yadif->dest_frame);
322   gst_video_frame_unmap (&yadif->cur_frame);
323   return GST_FLOW_OK;
324
325 dest_map_failed:
326   {
327     GST_ERROR_OBJECT (yadif, "failed to map dest");
328     return GST_FLOW_ERROR;
329   }
330 src_map_failed:
331   {
332     GST_ERROR_OBJECT (yadif, "failed to map src");
333     gst_video_frame_unmap (&yadif->dest_frame);
334     return GST_FLOW_ERROR;
335   }
336 }
337
338
339 static gboolean
340 plugin_init (GstPlugin * plugin)
341 {
342
343   return gst_element_register (plugin, "yadif", GST_RANK_NONE, GST_TYPE_YADIF);
344 }
345
346 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
347     GST_VERSION_MINOR,
348     yadif,
349     "YADIF deinterlacing filter",
350     plugin_init, VERSION, "GPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN)