deinterlace: analyse RFF fields in correct order
[platform/upstream/gstreamer.git] / gst / deinterlace / gstdeinterlace.c
1 /*
2  * GStreamer
3  * Copyright (C) 2005 Martin Eikermann <meiker@upb.de>
4  * Copyright (C) 2008-2010 Sebastian Dröge <slomo@collabora.co.uk>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /**
23  * SECTION:element-deinterlace
24  *
25  * deinterlace deinterlaces interlaced video frames to progressive video frames.
26  * For this different algorithms can be selected which will be described later.
27  *
28  * <refsect2>
29  * <title>Example launch line</title>
30  * |[
31  * gst-launch -v filesrc location=/path/to/file ! decodebin2 ! ffmpegcolorspace ! deinterlace ! ffmpegcolorspace ! autovideosink
32  * ]| This pipeline deinterlaces a video file with the default deinterlacing options.
33  * </refsect2>
34  */
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include "gstdeinterlace.h"
41 #include "tvtime/plugins.h"
42
43 #include <string.h>
44
45 #if HAVE_ORC
46 #include <orc/orc.h>
47 #endif
48
49 GST_DEBUG_CATEGORY_STATIC (deinterlace_debug);
50 #define GST_CAT_DEFAULT (deinterlace_debug)
51
52 /* Properties */
53
54 #define DEFAULT_MODE            GST_DEINTERLACE_MODE_AUTO
55 #define DEFAULT_METHOD          GST_DEINTERLACE_GREEDY_H
56 #define DEFAULT_FIELDS          GST_DEINTERLACE_ALL
57 #define DEFAULT_FIELD_LAYOUT    GST_DEINTERLACE_LAYOUT_AUTO
58
59 enum
60 {
61   PROP_0,
62   PROP_MODE,
63   PROP_METHOD,
64   PROP_FIELDS,
65   PROP_FIELD_LAYOUT,
66   PROP_LAST
67 };
68
69 static const GEnumValue methods_types[] = {
70   {GST_DEINTERLACE_TOMSMOCOMP, "Motion Adaptive: Motion Search",
71       "tomsmocomp"},
72   {GST_DEINTERLACE_GREEDY_H, "Motion Adaptive: Advanced Detection",
73       "greedyh"},
74   {GST_DEINTERLACE_GREEDY_L, "Motion Adaptive: Simple Detection", "greedyl"},
75   {GST_DEINTERLACE_VFIR, "Blur Vertical", "vfir"},
76   {GST_DEINTERLACE_LINEAR, "Television: Full resolution", "linear"},
77   {GST_DEINTERLACE_LINEAR_BLEND, "Blur: Temporal (Do Not Use)",
78       "linearblend"},
79   {GST_DEINTERLACE_SCALER_BOB, "Double lines", "scalerbob"},
80   {GST_DEINTERLACE_WEAVE, "Weave (Do Not Use)", "weave"},
81   {GST_DEINTERLACE_WEAVE_TFF, "Progressive: Top Field First (Do Not Use)",
82       "weavetff"},
83   {GST_DEINTERLACE_WEAVE_BFF, "Progressive: Bottom Field First (Do Not Use)",
84       "weavebff"},
85   {0, NULL, NULL},
86 };
87
88
89 #define GST_TYPE_DEINTERLACE_METHODS (gst_deinterlace_methods_get_type ())
90 static GType
91 gst_deinterlace_methods_get_type (void)
92 {
93   static GType deinterlace_methods_type = 0;
94
95   if (!deinterlace_methods_type) {
96     deinterlace_methods_type =
97         g_enum_register_static ("GstDeinterlaceMethods", methods_types);
98   }
99   return deinterlace_methods_type;
100 }
101
102 #define GST_TYPE_DEINTERLACE_FIELDS (gst_deinterlace_fields_get_type ())
103 static GType
104 gst_deinterlace_fields_get_type (void)
105 {
106   static GType deinterlace_fields_type = 0;
107
108   static const GEnumValue fields_types[] = {
109     {GST_DEINTERLACE_ALL, "All fields", "all"},
110     {GST_DEINTERLACE_TF, "Top fields only", "top"},
111     {GST_DEINTERLACE_BF, "Bottom fields only", "bottom"},
112     {0, NULL, NULL},
113   };
114
115   if (!deinterlace_fields_type) {
116     deinterlace_fields_type =
117         g_enum_register_static ("GstDeinterlaceFields", fields_types);
118   }
119   return deinterlace_fields_type;
120 }
121
122 #define GST_TYPE_DEINTERLACE_FIELD_LAYOUT (gst_deinterlace_field_layout_get_type ())
123 static GType
124 gst_deinterlace_field_layout_get_type (void)
125 {
126   static GType deinterlace_field_layout_type = 0;
127
128   static const GEnumValue field_layout_types[] = {
129     {GST_DEINTERLACE_LAYOUT_AUTO, "Auto detection", "auto"},
130     {GST_DEINTERLACE_LAYOUT_TFF, "Top field first", "tff"},
131     {GST_DEINTERLACE_LAYOUT_BFF, "Bottom field first", "bff"},
132     {0, NULL, NULL},
133   };
134
135   if (!deinterlace_field_layout_type) {
136     deinterlace_field_layout_type =
137         g_enum_register_static ("GstDeinterlaceFieldLayout",
138         field_layout_types);
139   }
140   return deinterlace_field_layout_type;
141 }
142
143 #define GST_TYPE_DEINTERLACE_MODES (gst_deinterlace_modes_get_type ())
144 static GType
145 gst_deinterlace_modes_get_type (void)
146 {
147   static GType deinterlace_modes_type = 0;
148
149   static const GEnumValue modes_types[] = {
150     {GST_DEINTERLACE_MODE_AUTO, "Auto detection", "auto"},
151     {GST_DEINTERLACE_MODE_INTERLACED, "Force deinterlacing", "interlaced"},
152     {GST_DEINTERLACE_MODE_DISABLED, "Run in passthrough mode", "disabled"},
153     {0, NULL, NULL},
154   };
155
156   if (!deinterlace_modes_type) {
157     deinterlace_modes_type =
158         g_enum_register_static ("GstDeinterlaceModes", modes_types);
159   }
160   return deinterlace_modes_type;
161 }
162
163 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
164     GST_PAD_SRC,
165     GST_PAD_ALWAYS,
166     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";" GST_VIDEO_CAPS_YUV ("Y444")
167         ";" GST_VIDEO_CAPS_YUV ("YUY2") ";" GST_VIDEO_CAPS_YUV ("YVYU") ";"
168         GST_VIDEO_CAPS_YUV ("UYVY") ";"
169         GST_VIDEO_CAPS_YUV ("Y42B") ";" GST_VIDEO_CAPS_YUV ("I420") ";"
170         GST_VIDEO_CAPS_YUV ("YV12") ";" GST_VIDEO_CAPS_YUV ("Y41B") ";"
171         GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_ABGR ";"
172         GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_BGRA ";"
173         GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_xBGR ";"
174         GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx ";"
175         GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR)
176     );
177
178 static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
179     GST_PAD_SINK,
180     GST_PAD_ALWAYS,
181     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";" GST_VIDEO_CAPS_YUV ("Y444")
182         ";" GST_VIDEO_CAPS_YUV ("YUY2") ";" GST_VIDEO_CAPS_YUV ("YVYU") ";"
183         GST_VIDEO_CAPS_YUV ("UYVY") ";"
184         GST_VIDEO_CAPS_YUV ("Y42B") ";" GST_VIDEO_CAPS_YUV ("I420") ";"
185         GST_VIDEO_CAPS_YUV ("YV12") ";" GST_VIDEO_CAPS_YUV ("Y41B") ";"
186         GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_ABGR ";"
187         GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_BGRA ";"
188         GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_xBGR ";"
189         GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx ";"
190         GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR)
191     );
192
193 static void gst_deinterlace_finalize (GObject * self);
194 static void gst_deinterlace_set_property (GObject * self, guint prop_id,
195     const GValue * value, GParamSpec * pspec);
196 static void gst_deinterlace_get_property (GObject * self, guint prop_id,
197     GValue * value, GParamSpec * pspec);
198
199 static GstCaps *gst_deinterlace_getcaps (GstPad * pad);
200 static gboolean gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps);
201 static gboolean gst_deinterlace_sink_event (GstPad * pad, GstEvent * event);
202 static gboolean gst_deinterlace_sink_query (GstPad * pad, GstQuery * query);
203 static GstFlowReturn gst_deinterlace_chain (GstPad * pad, GstBuffer * buffer);
204 static GstFlowReturn gst_deinterlace_alloc_buffer (GstPad * pad, guint64 offset,
205     guint size, GstCaps * caps, GstBuffer ** buf);
206 static GstStateChangeReturn gst_deinterlace_change_state (GstElement * element,
207     GstStateChange transition);
208
209 static gboolean gst_deinterlace_src_event (GstPad * pad, GstEvent * event);
210 static gboolean gst_deinterlace_src_query (GstPad * pad, GstQuery * query);
211 static const GstQueryType *gst_deinterlace_src_query_types (GstPad * pad);
212
213 static GstFlowReturn gst_deinterlace_output_frame (GstDeinterlace * self,
214     gboolean flushing);
215 static void gst_deinterlace_reset (GstDeinterlace * self);
216 static void gst_deinterlace_update_qos (GstDeinterlace * self,
217     gdouble proportion, GstClockTimeDiff diff, GstClockTime time);
218 static void gst_deinterlace_reset_qos (GstDeinterlace * self);
219 static void gst_deinterlace_read_qos (GstDeinterlace * self,
220     gdouble * proportion, GstClockTime * time);
221
222 static void gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
223     gpointer iface_data);
224
225 static void
226 _do_init (GType object_type)
227 {
228   const GInterfaceInfo child_proxy_interface_info = {
229     (GInterfaceInitFunc) gst_deinterlace_child_proxy_interface_init,
230     NULL,                       /* interface_finalize */
231     NULL                        /* interface_data */
232   };
233
234   g_type_add_interface_static (object_type, GST_TYPE_CHILD_PROXY,
235       &child_proxy_interface_info);
236 }
237
238 GST_BOILERPLATE_FULL (GstDeinterlace, gst_deinterlace, GstElement,
239     GST_TYPE_ELEMENT, _do_init);
240
241 static const struct
242 {
243   GType (*get_type) (void);
244 } _method_types[] = {
245   {
246   gst_deinterlace_method_tomsmocomp_get_type}, {
247   gst_deinterlace_method_greedy_h_get_type}, {
248   gst_deinterlace_method_greedy_l_get_type}, {
249   gst_deinterlace_method_vfir_get_type}, {
250   gst_deinterlace_method_linear_get_type}, {
251   gst_deinterlace_method_linear_blend_get_type}, {
252   gst_deinterlace_method_scaler_bob_get_type}, {
253   gst_deinterlace_method_weave_get_type}, {
254   gst_deinterlace_method_weave_tff_get_type}, {
255   gst_deinterlace_method_weave_bff_get_type}
256 };
257
258 static void
259 gst_deinterlace_set_method (GstDeinterlace * self, GstDeinterlaceMethods method)
260 {
261   GType method_type;
262
263   GST_DEBUG_OBJECT (self, "Setting new method %d", method);
264
265   if (self->method) {
266     if (self->method_id == method &&
267         gst_deinterlace_method_supported (G_TYPE_FROM_INSTANCE (self->method),
268             self->format, self->width, self->height)) {
269       GST_DEBUG_OBJECT (self, "Reusing current method");
270       return;
271     }
272
273     gst_child_proxy_child_removed (GST_OBJECT (self),
274         GST_OBJECT (self->method));
275     gst_object_unparent (GST_OBJECT (self->method));
276     self->method = NULL;
277   }
278
279   method_type =
280       _method_types[method].get_type !=
281       NULL ? _method_types[method].get_type () : G_TYPE_INVALID;
282   if (method_type == G_TYPE_INVALID
283       || !gst_deinterlace_method_supported (method_type, self->format,
284           self->width, self->height)) {
285     GType tmp;
286     gint i;
287
288     method_type = G_TYPE_INVALID;
289
290     GST_WARNING_OBJECT (self, "Method doesn't support requested format");
291     for (i = 0; i < G_N_ELEMENTS (_method_types); i++) {
292       if (_method_types[i].get_type == NULL)
293         continue;
294       tmp = _method_types[i].get_type ();
295       if (gst_deinterlace_method_supported (tmp, self->format, self->width,
296               self->height)) {
297         GST_DEBUG_OBJECT (self, "Using method %d", i);
298         method_type = tmp;
299         break;
300       }
301     }
302     /* If we get here we must have invalid caps! */
303     g_assert (method_type != G_TYPE_INVALID);
304   }
305
306   self->method = g_object_new (method_type, NULL);
307   self->method_id = method;
308
309   gst_object_set_name (GST_OBJECT (self->method), "method");
310   gst_object_set_parent (GST_OBJECT (self->method), GST_OBJECT (self));
311   gst_child_proxy_child_added (GST_OBJECT (self), GST_OBJECT (self->method));
312
313   if (self->method)
314     gst_deinterlace_method_setup (self->method, self->format, self->width,
315         self->height);
316 }
317
318 static gboolean
319 gst_deinterlace_clip_buffer (GstDeinterlace * self, GstBuffer * buffer)
320 {
321   gboolean ret = TRUE;
322   GstClockTime start, stop;
323   gint64 cstart, cstop;
324
325   GST_DEBUG_OBJECT (self,
326       "Clipping buffer to the current segment: %" GST_TIME_FORMAT " -- %"
327       GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
328       GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
329   GST_DEBUG_OBJECT (self, "Current segment: %" GST_SEGMENT_FORMAT,
330       &self->segment);
331
332   if (G_UNLIKELY (self->segment.format != GST_FORMAT_TIME))
333     goto beach;
334   if (G_UNLIKELY (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer)))
335     goto beach;
336
337   start = GST_BUFFER_TIMESTAMP (buffer);
338   stop = start + GST_BUFFER_DURATION (buffer);
339
340   if (!(ret = gst_segment_clip (&self->segment, GST_FORMAT_TIME,
341               start, stop, &cstart, &cstop)))
342     goto beach;
343
344   GST_BUFFER_TIMESTAMP (buffer) = cstart;
345   if (GST_CLOCK_TIME_IS_VALID (cstop))
346     GST_BUFFER_DURATION (buffer) = cstop - cstart;
347
348 beach:
349   if (ret)
350     GST_DEBUG_OBJECT (self,
351         "Clipped buffer to the current segment: %" GST_TIME_FORMAT " -- %"
352         GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
353         GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
354   else
355     GST_DEBUG_OBJECT (self, "Buffer outside the current segment -- dropping");
356
357   return ret;
358 }
359
360 static void
361 gst_deinterlace_base_init (gpointer klass)
362 {
363   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
364
365   gst_element_class_add_pad_template (element_class,
366       gst_static_pad_template_get (&src_templ));
367   gst_element_class_add_pad_template (element_class,
368       gst_static_pad_template_get (&sink_templ));
369
370   gst_element_class_set_details_simple (element_class,
371       "Deinterlacer",
372       "Filter/Video",
373       "Deinterlace Methods ported from DScaler/TvTime",
374       "Martin Eikermann <meiker@upb.de>, "
375       "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
376 }
377
378 static void
379 gst_deinterlace_class_init (GstDeinterlaceClass * klass)
380 {
381   GObjectClass *gobject_class = (GObjectClass *) klass;
382
383   GstElementClass *element_class = (GstElementClass *) klass;
384
385   gobject_class->set_property = gst_deinterlace_set_property;
386   gobject_class->get_property = gst_deinterlace_get_property;
387   gobject_class->finalize = gst_deinterlace_finalize;
388
389   /**
390    * GstDeinterlace:mode
391    * 
392    * This selects whether the deinterlacing methods should
393    * always be applied or if they should only be applied
394    * on content that has the "interlaced" flag on the caps.
395    *
396    */
397   g_object_class_install_property (gobject_class, PROP_MODE,
398       g_param_spec_enum ("mode",
399           "Mode",
400           "Deinterlace Mode",
401           GST_TYPE_DEINTERLACE_MODES,
402           DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
403       );
404
405   /**
406    * GstDeinterlace:method
407    * 
408    * Selects the different deinterlacing algorithms that can be used.
409    * These provide different quality and CPU usage.
410    *
411    * Some methods provide parameters which can be set by getting
412    * the "method" child via the #GstChildProxy interface and
413    * setting the appropiate properties on it.
414    *
415    * <itemizedlist>
416    * <listitem>
417    * <para>
418    * tomsmocomp
419    * Motion Adaptive: Motion Search
420    * </para>
421    * </listitem>
422    * <listitem>
423    * <para>
424    * greedyh
425    * Motion Adaptive: Advanced Detection
426    * </para>
427    * </listitem>
428    * <listitem>
429    * <para>
430    * greedyl
431    * Motion Adaptive: Simple Detection
432    * </para>
433    * </listitem>
434    * <listitem>
435    * <para>
436    * vfir
437    * Blur vertical
438    * </para>
439    * </listitem>
440    * <listitem>
441    * <para>
442    * linear
443    * Linear interpolation
444    * </para>
445    * </listitem>
446    * <listitem>
447    * <para>
448    * linearblend
449    * Linear interpolation in time domain.  Any motion causes significant
450    * ghosting, so this method should not be used.
451    * </para>
452    * </listitem>
453    * <listitem>
454    * <para>
455    * scalerbob
456    * Double lines
457    * </para>
458    * </listitem>
459    * <listitem>
460    * <para>
461    * weave
462    * Weave.  Bad quality, do not use.
463    * </para>
464    * </listitem>
465    * <listitem>
466    * <para>
467    * weavetff
468    * Progressive: Top Field First.  Bad quality, do not use.
469    * </para>
470    * </listitem>
471    * <listitem>
472    * <para>
473    * weavebff
474    * Progressive: Bottom Field First.  Bad quality, do not use.
475    * </para>
476    * </listitem>
477    * </itemizedlist>
478    */
479   g_object_class_install_property (gobject_class, PROP_METHOD,
480       g_param_spec_enum ("method",
481           "Method",
482           "Deinterlace Method",
483           GST_TYPE_DEINTERLACE_METHODS,
484           DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
485       );
486
487   /**
488    * GstDeinterlace:fields
489    *
490    * This selects which fields should be output. If "all" is selected
491    * the output framerate will be double.
492    *
493    */
494   g_object_class_install_property (gobject_class, PROP_FIELDS,
495       g_param_spec_enum ("fields",
496           "fields",
497           "Fields to use for deinterlacing",
498           GST_TYPE_DEINTERLACE_FIELDS,
499           DEFAULT_FIELDS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
500       );
501
502   /**
503    * GstDeinterlace:layout
504    *
505    * This selects which fields is the first in time.
506    *
507    */
508   g_object_class_install_property (gobject_class, PROP_FIELD_LAYOUT,
509       g_param_spec_enum ("tff",
510           "tff",
511           "Deinterlace top field first",
512           GST_TYPE_DEINTERLACE_FIELD_LAYOUT,
513           DEFAULT_FIELD_LAYOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
514       );
515
516   element_class->change_state =
517       GST_DEBUG_FUNCPTR (gst_deinterlace_change_state);
518 }
519
520 static GstObject *
521 gst_deinterlace_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
522     guint index)
523 {
524   GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
525
526   g_return_val_if_fail (index == 0, NULL);
527
528   return gst_object_ref (self->method);
529 }
530
531 static guint
532 gst_deinterlace_child_proxy_get_children_count (GstChildProxy * child_proxy)
533 {
534   GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
535
536   return ((self->method) ? 1 : 0);
537 }
538
539 static void
540 gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
541     gpointer iface_data)
542 {
543   GstChildProxyInterface *iface = g_iface;
544
545   iface->get_child_by_index = gst_deinterlace_child_proxy_get_child_by_index;
546   iface->get_children_count = gst_deinterlace_child_proxy_get_children_count;
547 }
548
549 static void
550 gst_deinterlace_init (GstDeinterlace * self, GstDeinterlaceClass * klass)
551 {
552   self->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
553   gst_pad_set_chain_function (self->sinkpad,
554       GST_DEBUG_FUNCPTR (gst_deinterlace_chain));
555   gst_pad_set_event_function (self->sinkpad,
556       GST_DEBUG_FUNCPTR (gst_deinterlace_sink_event));
557   gst_pad_set_setcaps_function (self->sinkpad,
558       GST_DEBUG_FUNCPTR (gst_deinterlace_setcaps));
559   gst_pad_set_getcaps_function (self->sinkpad,
560       GST_DEBUG_FUNCPTR (gst_deinterlace_getcaps));
561   gst_pad_set_query_function (self->sinkpad,
562       GST_DEBUG_FUNCPTR (gst_deinterlace_sink_query));
563   gst_pad_set_bufferalloc_function (self->sinkpad,
564       GST_DEBUG_FUNCPTR (gst_deinterlace_alloc_buffer));
565   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
566
567   self->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
568   gst_pad_set_event_function (self->srcpad,
569       GST_DEBUG_FUNCPTR (gst_deinterlace_src_event));
570   gst_pad_set_query_type_function (self->srcpad,
571       GST_DEBUG_FUNCPTR (gst_deinterlace_src_query_types));
572   gst_pad_set_query_function (self->srcpad,
573       GST_DEBUG_FUNCPTR (gst_deinterlace_src_query));
574   gst_pad_set_getcaps_function (self->srcpad,
575       GST_DEBUG_FUNCPTR (gst_deinterlace_getcaps));
576   gst_pad_set_setcaps_function (self->srcpad,
577       GST_DEBUG_FUNCPTR (gst_deinterlace_setcaps));
578   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
579
580   self->mode = DEFAULT_MODE;
581   self->user_set_method_id = DEFAULT_METHOD;
582   gst_deinterlace_set_method (self, self->user_set_method_id);
583   self->fields = DEFAULT_FIELDS;
584   self->field_layout = DEFAULT_FIELD_LAYOUT;
585
586   self->still_frame_mode = FALSE;
587
588   gst_deinterlace_reset (self);
589 }
590
591 static void
592 gst_deinterlace_reset_history (GstDeinterlace * self, gboolean drop_all)
593 {
594   gint i;
595
596   if (drop_all) {
597     GST_DEBUG_OBJECT (self, "Resetting history (count %d)",
598         self->history_count);
599
600     for (i = 0; i < self->history_count; i++) {
601       if (self->field_history[i].buf) {
602         gst_buffer_unref (self->field_history[i].buf);
603         self->field_history[i].buf = NULL;
604       }
605     }
606   } else {
607     GST_DEBUG_OBJECT (self, "Flushing history (count %d)", self->history_count);
608     while (self->history_count > 0)
609       gst_deinterlace_output_frame (self, TRUE);
610   }
611   memset (self->field_history, 0,
612       GST_DEINTERLACE_MAX_FIELD_HISTORY * sizeof (GstDeinterlaceField));
613   self->history_count = 0;
614
615   if (!self->still_frame_mode && self->last_buffer) {
616     gst_buffer_unref (self->last_buffer);
617     self->last_buffer = NULL;
618   }
619 }
620
621 static void
622 gst_deinterlace_update_passthrough (GstDeinterlace * self)
623 {
624   self->passthrough = (self->mode == GST_DEINTERLACE_MODE_DISABLED
625       || (!self->interlaced && self->mode != GST_DEINTERLACE_MODE_INTERLACED));
626   GST_DEBUG_OBJECT (self, "Passthrough: %d", self->passthrough);
627 }
628
629 static void
630 gst_deinterlace_reset (GstDeinterlace * self)
631 {
632   GST_DEBUG_OBJECT (self, "Resetting internal state");
633
634   self->format = GST_VIDEO_FORMAT_UNKNOWN;
635   self->width = 0;
636   self->height = 0;
637   self->frame_size = 0;
638   self->fps_n = self->fps_d = 0;
639   self->passthrough = FALSE;
640
641   self->reconfigure = FALSE;
642   if (self->new_mode != -1)
643     self->mode = self->new_mode;
644   if (self->new_fields != -1)
645     self->fields = self->new_fields;
646   self->new_mode = -1;
647   self->new_fields = -1;
648
649   gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
650
651   if (self->sink_caps)
652     gst_caps_unref (self->sink_caps);
653   self->sink_caps = NULL;
654
655   if (self->src_caps)
656     gst_caps_unref (self->src_caps);
657   self->src_caps = NULL;
658
659   if (self->request_caps)
660     gst_caps_unref (self->request_caps);
661   self->request_caps = NULL;
662
663   gst_deinterlace_reset_history (self, TRUE);
664
665   gst_deinterlace_reset_qos (self);
666 }
667
668 static void
669 gst_deinterlace_set_property (GObject * object, guint prop_id,
670     const GValue * value, GParamSpec * pspec)
671 {
672   GstDeinterlace *self;
673
674   g_return_if_fail (GST_IS_DEINTERLACE (object));
675   self = GST_DEINTERLACE (object);
676
677   switch (prop_id) {
678     case PROP_MODE:{
679       gint new_mode;
680
681       GST_OBJECT_LOCK (self);
682       new_mode = g_value_get_enum (value);
683       if (self->mode != new_mode && GST_PAD_CAPS (self->srcpad)) {
684         self->reconfigure = TRUE;
685         self->new_mode = new_mode;
686       } else {
687         self->mode = new_mode;
688         gst_deinterlace_update_passthrough (self);
689       }
690       GST_OBJECT_UNLOCK (self);
691       break;
692     }
693     case PROP_METHOD:
694       self->user_set_method_id = g_value_get_enum (value);
695       gst_deinterlace_set_method (self, self->user_set_method_id);
696       break;
697     case PROP_FIELDS:{
698       gint new_fields;
699
700       GST_OBJECT_LOCK (self);
701       new_fields = g_value_get_enum (value);
702       if (self->fields != new_fields && GST_PAD_CAPS (self->srcpad)) {
703         self->reconfigure = TRUE;
704         self->new_fields = new_fields;
705       } else {
706         self->fields = new_fields;
707       }
708       GST_OBJECT_UNLOCK (self);
709       break;
710     }
711     case PROP_FIELD_LAYOUT:
712       self->field_layout = g_value_get_enum (value);
713       break;
714     default:
715       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
716   }
717
718 }
719
720 static void
721 gst_deinterlace_get_property (GObject * object, guint prop_id,
722     GValue * value, GParamSpec * pspec)
723 {
724   GstDeinterlace *self;
725
726   g_return_if_fail (GST_IS_DEINTERLACE (object));
727   self = GST_DEINTERLACE (object);
728
729   switch (prop_id) {
730     case PROP_MODE:
731       g_value_set_enum (value, self->mode);
732       break;
733     case PROP_METHOD:
734       g_value_set_enum (value, self->user_set_method_id);
735       break;
736     case PROP_FIELDS:
737       g_value_set_enum (value, self->fields);
738       break;
739     case PROP_FIELD_LAYOUT:
740       g_value_set_enum (value, self->field_layout);
741       break;
742     default:
743       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
744   }
745 }
746
747 static void
748 gst_deinterlace_finalize (GObject * object)
749 {
750   GstDeinterlace *self = GST_DEINTERLACE (object);
751
752   gst_deinterlace_reset (self);
753
754   if (self->method) {
755     gst_object_unparent (GST_OBJECT (self->method));
756     self->method = NULL;
757   }
758
759   G_OBJECT_CLASS (parent_class)->finalize (object);
760 }
761
762 static GstBuffer *
763 gst_deinterlace_pop_history (GstDeinterlace * self)
764 {
765   GstBuffer *buffer;
766
767   g_return_val_if_fail (self->history_count > 0, NULL);
768
769   GST_DEBUG_OBJECT (self, "Pop last history buffer -- current history size %d",
770       self->history_count);
771
772   buffer = self->field_history[self->history_count - 1].buf;
773
774   self->history_count--;
775
776   GST_DEBUG_OBJECT (self, "Returning buffer: %" GST_TIME_FORMAT
777       " with duration %" GST_TIME_FORMAT " and size %u",
778       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
779       GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer));
780
781   return buffer;
782 }
783
784 static void
785 gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer)
786 {
787   int i = 1;
788   GstClockTime timestamp;
789   GstDeinterlaceFieldLayout field_layout = self->field_layout;
790   gboolean repeated = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_RFF);
791   gboolean tff = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_TFF);
792   gboolean onefield =
793       GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_ONEFIELD);
794   GstBuffer *field1, *field2;
795   guint fields_to_push = (onefield) ? 1 : (!repeated) ? 2 : 3;
796   gint field1_flags, field2_flags;
797
798   g_return_if_fail (self->history_count <
799       GST_DEINTERLACE_MAX_FIELD_HISTORY - fields_to_push);
800
801   GST_DEBUG_OBJECT (self, "Pushing new buffer to the history: %" GST_TIME_FORMAT
802       " with duration %" GST_TIME_FORMAT " and size %u",
803       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
804       GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer));
805
806   for (i = GST_DEINTERLACE_MAX_FIELD_HISTORY - 1; i >= fields_to_push; i--) {
807     self->field_history[i].buf = self->field_history[i - fields_to_push].buf;
808     self->field_history[i].flags =
809         self->field_history[i - fields_to_push].flags;
810   }
811
812   if (field_layout == GST_DEINTERLACE_LAYOUT_AUTO) {
813     if (!self->interlaced) {
814       GST_WARNING_OBJECT (self, "Can't detect field layout -- assuming TFF");
815       field_layout = GST_DEINTERLACE_LAYOUT_TFF;
816     } else if (tff) {
817       field_layout = GST_DEINTERLACE_LAYOUT_TFF;
818     } else {
819       field_layout = GST_DEINTERLACE_LAYOUT_BFF;
820     }
821   }
822
823   if (field_layout == GST_DEINTERLACE_LAYOUT_TFF) {
824     GST_DEBUG_OBJECT (self, "Top field first");
825     field1 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
826     field1_flags = PICTURE_INTERLACED_TOP;
827     field2 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
828     field2_flags = PICTURE_INTERLACED_BOTTOM;
829   } else {
830     GST_DEBUG_OBJECT (self, "Bottom field first");
831     field1 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
832     field1_flags = PICTURE_INTERLACED_BOTTOM;
833     field2 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
834     field2_flags = PICTURE_INTERLACED_TOP;
835   }
836
837   /* Timestamps are assigned to the field buffers under the assumption that
838      the timestamp of the buffer equals the first fields timestamp */
839
840   timestamp = GST_BUFFER_TIMESTAMP (buffer);
841   GST_BUFFER_TIMESTAMP (field1) = timestamp;
842   GST_BUFFER_TIMESTAMP (field2) = timestamp + self->field_duration;
843
844   if (repeated) {
845     self->field_history[2].buf = field1;
846     self->field_history[2].flags = field1_flags;
847
848     self->field_history[1].buf = field2;
849     self->field_history[1].flags = field2_flags;
850
851     self->field_history[0].buf =
852         gst_buffer_make_metadata_writable (gst_buffer_ref (field1));
853     GST_BUFFER_TIMESTAMP (self->field_history[0].buf) +=
854         2 * self->field_duration;
855     self->field_history[0].flags = field1_flags;
856   } else if (!onefield) {
857     self->field_history[1].buf = field1;
858     self->field_history[1].flags = field1_flags;
859
860     self->field_history[0].buf = field2;
861     self->field_history[0].flags = field2_flags;
862   } else {                      /* onefield */
863     self->field_history[0].buf = field1;
864     self->field_history[0].flags = field1_flags;
865     gst_buffer_unref (field2);
866   }
867
868   self->history_count += fields_to_push;
869
870   GST_DEBUG_OBJECT (self, "Pushed buffer -- current history size %d",
871       self->history_count);
872
873   if (self->last_buffer)
874     gst_buffer_unref (self->last_buffer);
875   self->last_buffer = buffer;
876 }
877
878 static void
879 gst_deinterlace_update_qos (GstDeinterlace * self, gdouble proportion,
880     GstClockTimeDiff diff, GstClockTime timestamp)
881 {
882   GST_DEBUG_OBJECT (self,
883       "Updating QoS: proportion %lf, diff %s%" GST_TIME_FORMAT ", timestamp %"
884       GST_TIME_FORMAT, proportion, (diff < 0) ? "-" : "",
885       GST_TIME_ARGS (ABS (diff)), GST_TIME_ARGS (timestamp));
886
887   GST_OBJECT_LOCK (self);
888   self->proportion = proportion;
889   if (G_LIKELY (timestamp != GST_CLOCK_TIME_NONE)) {
890     if (G_UNLIKELY (diff > 0))
891       self->earliest_time =
892           timestamp + 2 * diff + ((self->fields ==
893               GST_DEINTERLACE_ALL) ? self->field_duration : 2 *
894           self->field_duration);
895     else
896       self->earliest_time = timestamp + diff;
897   } else {
898     self->earliest_time = GST_CLOCK_TIME_NONE;
899   }
900   GST_OBJECT_UNLOCK (self);
901 }
902
903 static void
904 gst_deinterlace_reset_qos (GstDeinterlace * self)
905 {
906   gst_deinterlace_update_qos (self, 0.5, 0, GST_CLOCK_TIME_NONE);
907 }
908
909 static void
910 gst_deinterlace_read_qos (GstDeinterlace * self, gdouble * proportion,
911     GstClockTime * time)
912 {
913   GST_OBJECT_LOCK (self);
914   *proportion = self->proportion;
915   *time = self->earliest_time;
916   GST_OBJECT_UNLOCK (self);
917 }
918
919 /* Perform qos calculations before processing the next frame. Returns TRUE if
920  * the frame should be processed, FALSE if the frame can be dropped entirely */
921 static gboolean
922 gst_deinterlace_do_qos (GstDeinterlace * self, GstClockTime timestamp)
923 {
924   GstClockTime qostime, earliest_time;
925   gdouble proportion;
926
927   /* no timestamp, can't do QoS => process frame */
928   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) {
929     GST_LOG_OBJECT (self, "invalid timestamp, can't do QoS, process frame");
930     return TRUE;
931   }
932
933   /* get latest QoS observation values */
934   gst_deinterlace_read_qos (self, &proportion, &earliest_time);
935
936   /* skip qos if we have no observation (yet) => process frame */
937   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) {
938     GST_LOG_OBJECT (self, "no observation yet, process frame");
939     return TRUE;
940   }
941
942   /* qos is done on running time */
943   qostime = gst_segment_to_running_time (&self->segment, GST_FORMAT_TIME,
944       timestamp);
945
946   /* see how our next timestamp relates to the latest qos timestamp */
947   GST_LOG_OBJECT (self, "qostime %" GST_TIME_FORMAT ", earliest %"
948       GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
949
950   if (qostime != GST_CLOCK_TIME_NONE && qostime <= earliest_time) {
951     GST_DEBUG_OBJECT (self, "we are late, drop frame");
952     return FALSE;
953   }
954
955   GST_LOG_OBJECT (self, "process frame");
956   return TRUE;
957 }
958
959 static GstFlowReturn
960 gst_deinterlace_output_frame (GstDeinterlace * self, gboolean flushing)
961 {
962   GstClockTime timestamp;
963   GstFlowReturn ret = GST_FLOW_OK;
964   gint fields_required = 0;
965   gint cur_field_idx = 0;
966   GstBuffer *buf, *outbuf;
967
968   gst_deinterlace_set_method (self, self->user_set_method_id);
969   fields_required = gst_deinterlace_method_get_fields_required (self->method);
970
971   if (self->history_count < fields_required) {
972     if (flushing) {
973       /* FIXME: if there are any methods implemented that output different
974        * dimensions (e.g. half height) that require more than one field of
975        * history, it is desirable to degrade to something that outputs
976        * half-height also */
977       gst_deinterlace_set_method (self,
978           self->history_count >= 2 ?
979           GST_DEINTERLACE_VFIR : GST_DEINTERLACE_LINEAR);
980       fields_required =
981           gst_deinterlace_method_get_fields_required (self->method);
982       GST_DEBUG_OBJECT (self, "Flushing field(s) using %s method",
983           methods_types[self->method_id].value_nick);
984     } else {
985       /* Not enough fields in the history */
986       GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
987           self->history_count, fields_required);
988       return GST_FLOW_OK;
989     }
990   }
991
992   while (self->history_count >= fields_required) {
993     if (self->fields == GST_DEINTERLACE_ALL)
994       GST_DEBUG_OBJECT (self, "All fields");
995     else if (self->fields == GST_DEINTERLACE_TF)
996       GST_DEBUG_OBJECT (self, "Top fields");
997     else if (self->fields == GST_DEINTERLACE_BF)
998       GST_DEBUG_OBJECT (self, "Bottom fields");
999
1000     cur_field_idx = self->history_count - fields_required;
1001
1002     if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_TOP
1003             && self->fields == GST_DEINTERLACE_TF) ||
1004         self->fields == GST_DEINTERLACE_ALL) {
1005       GST_DEBUG_OBJECT (self, "deinterlacing top field");
1006
1007       /* create new buffer */
1008       ret = gst_pad_alloc_buffer (self->srcpad,
1009           GST_BUFFER_OFFSET_NONE, self->frame_size, self->src_caps, &outbuf);
1010       if (ret != GST_FLOW_OK)
1011         return ret;
1012
1013       if (self->src_caps != GST_BUFFER_CAPS (outbuf) &&
1014           !gst_caps_is_equal (self->src_caps, GST_BUFFER_CAPS (outbuf))) {
1015         gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf));
1016         GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT,
1017             self->request_caps);
1018
1019         gst_buffer_unref (outbuf);
1020         outbuf = gst_buffer_try_new_and_alloc (self->frame_size);
1021
1022         if (!outbuf)
1023           return GST_FLOW_ERROR;
1024
1025         gst_buffer_set_caps (outbuf, self->src_caps);
1026       }
1027
1028       g_return_val_if_fail (self->history_count - 1 -
1029           gst_deinterlace_method_get_latency (self->method) >= 0,
1030           GST_FLOW_ERROR);
1031
1032       buf =
1033           self->field_history[self->history_count - 1 -
1034           gst_deinterlace_method_get_latency (self->method)].buf;
1035       timestamp = GST_BUFFER_TIMESTAMP (buf);
1036
1037       GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1038       if (self->fields == GST_DEINTERLACE_ALL)
1039         GST_BUFFER_DURATION (outbuf) = self->field_duration;
1040       else
1041         GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
1042
1043       /* Check if we need to drop the frame because of QoS */
1044       if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
1045         gst_buffer_unref (gst_deinterlace_pop_history (self));
1046         gst_buffer_unref (outbuf);
1047         outbuf = NULL;
1048         ret = GST_FLOW_OK;
1049       } else {
1050         /* do magic calculus */
1051         gst_deinterlace_method_deinterlace_frame (self->method,
1052             self->field_history, self->history_count, outbuf);
1053
1054         gst_buffer_unref (gst_deinterlace_pop_history (self));
1055
1056         if (gst_deinterlace_clip_buffer (self, outbuf)) {
1057           ret = gst_pad_push (self->srcpad, outbuf);
1058         } else {
1059           ret = GST_FLOW_OK;
1060           gst_buffer_unref (outbuf);
1061         }
1062
1063         outbuf = NULL;
1064         if (ret != GST_FLOW_OK)
1065           return ret;
1066       }
1067     }
1068     /* no calculation done: remove excess field */
1069     else if (self->field_history[cur_field_idx].flags ==
1070         PICTURE_INTERLACED_TOP && self->fields == GST_DEINTERLACE_BF) {
1071       GST_DEBUG_OBJECT (self, "Removing unused top field");
1072       gst_buffer_unref (gst_deinterlace_pop_history (self));
1073     }
1074
1075     cur_field_idx = self->history_count - fields_required;
1076     if (self->history_count < fields_required)
1077       break;
1078
1079     /* deinterlace bottom_field */
1080     if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_BOTTOM
1081             && self->fields == GST_DEINTERLACE_BF) ||
1082         self->fields == GST_DEINTERLACE_ALL) {
1083       GST_DEBUG_OBJECT (self, "deinterlacing bottom field");
1084
1085       /* create new buffer */
1086       ret = gst_pad_alloc_buffer (self->srcpad,
1087           GST_BUFFER_OFFSET_NONE, self->frame_size, self->src_caps, &outbuf);
1088       if (ret != GST_FLOW_OK)
1089         return ret;
1090
1091       if (self->src_caps != GST_BUFFER_CAPS (outbuf) &&
1092           !gst_caps_is_equal (self->src_caps, GST_BUFFER_CAPS (outbuf))) {
1093         gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf));
1094         GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT,
1095             self->request_caps);
1096
1097         gst_buffer_unref (outbuf);
1098         outbuf = gst_buffer_try_new_and_alloc (self->frame_size);
1099
1100         if (!outbuf)
1101           return GST_FLOW_ERROR;
1102
1103         gst_buffer_set_caps (outbuf, self->src_caps);
1104       }
1105
1106       g_return_val_if_fail (self->history_count - 1 -
1107           gst_deinterlace_method_get_latency (self->method) >= 0,
1108           GST_FLOW_ERROR);
1109
1110       buf =
1111           self->field_history[self->history_count - 1 -
1112           gst_deinterlace_method_get_latency (self->method)].buf;
1113       timestamp = GST_BUFFER_TIMESTAMP (buf);
1114
1115       GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1116       if (self->fields == GST_DEINTERLACE_ALL)
1117         GST_BUFFER_DURATION (outbuf) = self->field_duration;
1118       else
1119         GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
1120
1121       /* Check if we need to drop the frame because of QoS */
1122       if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
1123         gst_buffer_unref (gst_deinterlace_pop_history (self));
1124         gst_buffer_unref (outbuf);
1125         outbuf = NULL;
1126         ret = GST_FLOW_OK;
1127       } else {
1128         /* do magic calculus */
1129         gst_deinterlace_method_deinterlace_frame (self->method,
1130             self->field_history, self->history_count, outbuf);
1131
1132         gst_buffer_unref (gst_deinterlace_pop_history (self));
1133
1134         if (gst_deinterlace_clip_buffer (self, outbuf)) {
1135           ret = gst_pad_push (self->srcpad, outbuf);
1136         } else {
1137           ret = GST_FLOW_OK;
1138           gst_buffer_unref (outbuf);
1139         }
1140
1141         outbuf = NULL;
1142         if (ret != GST_FLOW_OK)
1143           return ret;
1144       }
1145     }
1146     /* no calculation done: remove excess field */
1147     else if (self->field_history[cur_field_idx].flags ==
1148         PICTURE_INTERLACED_BOTTOM && self->fields == GST_DEINTERLACE_TF) {
1149       GST_DEBUG_OBJECT (self, "Removing unused bottom field");
1150       gst_buffer_unref (gst_deinterlace_pop_history (self));
1151     }
1152   }
1153
1154   return ret;
1155 }
1156
1157 static GstFlowReturn
1158 gst_deinterlace_chain (GstPad * pad, GstBuffer * buf)
1159 {
1160   GstDeinterlace *self = GST_DEINTERLACE (GST_PAD_PARENT (pad));
1161
1162   GST_OBJECT_LOCK (self);
1163   if (self->reconfigure) {
1164     if (self->new_fields != -1)
1165       self->fields = self->new_fields;
1166     if (self->new_mode != -1)
1167       self->mode = self->new_mode;
1168     self->new_mode = self->new_fields = -1;
1169
1170     self->reconfigure = FALSE;
1171     GST_OBJECT_UNLOCK (self);
1172     if (GST_PAD_CAPS (self->srcpad))
1173       gst_deinterlace_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad));
1174   } else {
1175     GST_OBJECT_UNLOCK (self);
1176   }
1177
1178   if (self->still_frame_mode || self->passthrough)
1179     return gst_pad_push (self->srcpad, buf);
1180
1181   if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
1182     GST_DEBUG_OBJECT (self, "DISCONT buffer, resetting history");
1183     gst_deinterlace_reset_history (self, FALSE);
1184   }
1185
1186   gst_deinterlace_push_history (self, buf);
1187   buf = NULL;
1188
1189   return gst_deinterlace_output_frame (self, FALSE);
1190 }
1191
1192 static gint
1193 gst_greatest_common_divisor (gint a, gint b)
1194 {
1195   while (b != 0) {
1196     int temp = a;
1197
1198     a = b;
1199     b = temp % b;
1200   }
1201
1202   return ABS (a);
1203 }
1204
1205 static gboolean
1206 gst_fraction_double (gint * n_out, gint * d_out, gboolean half)
1207 {
1208   gint n, d, gcd;
1209
1210   n = *n_out;
1211   d = *d_out;
1212
1213   if (d == 0)
1214     return FALSE;
1215
1216   if (n == 0 || (n == G_MAXINT && d == 1))
1217     return TRUE;
1218
1219   gcd = gst_greatest_common_divisor (n, d);
1220   n /= gcd;
1221   d /= gcd;
1222
1223   if (!half) {
1224     if (G_MAXINT / 2 >= ABS (n)) {
1225       n *= 2;
1226     } else if (d >= 2) {
1227       d /= 2;
1228     } else {
1229       return FALSE;
1230     }
1231   } else {
1232     if (G_MAXINT / 2 >= ABS (d)) {
1233       d *= 2;
1234     } else if (n >= 2) {
1235       n /= 2;
1236     } else {
1237       return FALSE;
1238     }
1239   }
1240
1241   *n_out = n;
1242   *d_out = d;
1243
1244   return TRUE;
1245 }
1246
1247 static GstCaps *
1248 gst_deinterlace_getcaps (GstPad * pad)
1249 {
1250   GstCaps *ret;
1251   GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1252   GstPad *otherpad;
1253   gint len;
1254   const GstCaps *ourcaps;
1255   GstCaps *peercaps;
1256
1257   GST_OBJECT_LOCK (self);
1258
1259   otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad;
1260
1261   ourcaps = gst_pad_get_pad_template_caps (pad);
1262   peercaps = gst_pad_peer_get_caps (otherpad);
1263
1264   if (peercaps) {
1265     GST_DEBUG_OBJECT (pad, "Peer has caps %" GST_PTR_FORMAT, peercaps);
1266     ret = gst_caps_intersect (ourcaps, peercaps);
1267     gst_caps_unref (peercaps);
1268   } else {
1269     ret = gst_caps_copy (ourcaps);
1270   }
1271
1272   GST_OBJECT_UNLOCK (self);
1273
1274   for (len = gst_caps_get_size (ret); len > 0; len--) {
1275     GstStructure *s = gst_caps_get_structure (ret, len - 1);
1276
1277     if (pad == self->sinkpad || self->passthrough)
1278       gst_structure_remove_field (s, "interlaced");
1279     else
1280       gst_structure_set (s, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL);
1281
1282     if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) {
1283       const GValue *val;
1284
1285       val = gst_structure_get_value (s, "framerate");
1286       if (!val)
1287         continue;
1288
1289       if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION) {
1290         gint n, d;
1291
1292         n = gst_value_get_fraction_numerator (val);
1293         d = gst_value_get_fraction_denominator (val);
1294
1295         if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
1296           goto error;
1297         }
1298
1299         gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
1300       } else if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION_RANGE) {
1301         const GValue *min, *max;
1302         GValue nrange = { 0, }, nmin = {
1303         0,}, nmax = {
1304         0,};
1305         gint n, d;
1306
1307         g_value_init (&nrange, GST_TYPE_FRACTION_RANGE);
1308         g_value_init (&nmin, GST_TYPE_FRACTION);
1309         g_value_init (&nmax, GST_TYPE_FRACTION);
1310
1311         min = gst_value_get_fraction_range_min (val);
1312         max = gst_value_get_fraction_range_max (val);
1313
1314         n = gst_value_get_fraction_numerator (min);
1315         d = gst_value_get_fraction_denominator (min);
1316
1317         if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
1318           g_value_unset (&nrange);
1319           g_value_unset (&nmax);
1320           g_value_unset (&nmin);
1321           goto error;
1322         }
1323
1324         gst_value_set_fraction (&nmin, n, d);
1325
1326         n = gst_value_get_fraction_numerator (max);
1327         d = gst_value_get_fraction_denominator (max);
1328
1329         if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
1330           g_value_unset (&nrange);
1331           g_value_unset (&nmax);
1332           g_value_unset (&nmin);
1333           goto error;
1334         }
1335
1336         gst_value_set_fraction (&nmax, n, d);
1337         gst_value_set_fraction_range (&nrange, &nmin, &nmax);
1338
1339         gst_structure_set_value (s, "framerate", &nrange);
1340
1341         g_value_unset (&nmin);
1342         g_value_unset (&nmax);
1343         g_value_unset (&nrange);
1344       } else if (G_VALUE_TYPE (val) == GST_TYPE_LIST) {
1345         const GValue *lval;
1346         GValue nlist = { 0, };
1347         GValue nval = { 0, };
1348         gint i;
1349
1350         g_value_init (&nlist, GST_TYPE_LIST);
1351         for (i = gst_value_list_get_size (val); i > 0; i--) {
1352           gint n, d;
1353
1354           lval = gst_value_list_get_value (val, i);
1355
1356           if (G_VALUE_TYPE (lval) != GST_TYPE_FRACTION)
1357             continue;
1358
1359           n = gst_value_get_fraction_numerator (lval);
1360           d = gst_value_get_fraction_denominator (lval);
1361
1362           /* Double/Half the framerate but if this fails simply
1363            * skip this value from the list */
1364           if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
1365             continue;
1366           }
1367
1368           g_value_init (&nval, GST_TYPE_FRACTION);
1369
1370           gst_value_set_fraction (&nval, n, d);
1371           gst_value_list_append_value (&nlist, &nval);
1372           g_value_unset (&nval);
1373         }
1374         gst_structure_set_value (s, "framerate", &nlist);
1375         g_value_unset (&nlist);
1376       }
1377     }
1378   }
1379
1380   GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret);
1381
1382   gst_object_unref (self);
1383
1384   return ret;
1385
1386 error:
1387   GST_ERROR_OBJECT (pad, "Unable to transform peer caps");
1388   gst_caps_unref (ret);
1389   return NULL;
1390 }
1391
1392 static gboolean
1393 gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps)
1394 {
1395   gboolean res = TRUE;
1396   GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1397   GstPad *otherpad;
1398   GstCaps *othercaps;
1399
1400   otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad;
1401
1402   res =
1403       gst_video_format_parse_caps (caps, &self->format, &self->width,
1404       &self->height);
1405   res &= gst_video_parse_caps_framerate (caps, &self->fps_n, &self->fps_d);
1406   if (pad == self->sinkpad)
1407     res &= gst_video_format_parse_caps_interlaced (caps, &self->interlaced);
1408   if (!res)
1409     goto invalid_caps;
1410
1411   gst_deinterlace_update_passthrough (self);
1412
1413   if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) {
1414     gint fps_n = self->fps_n, fps_d = self->fps_d;
1415
1416     if (!gst_fraction_double (&fps_n, &fps_d, otherpad != self->srcpad))
1417       goto invalid_caps;
1418
1419     othercaps = gst_caps_copy (caps);
1420
1421     gst_caps_set_simple (othercaps, "framerate", GST_TYPE_FRACTION, fps_n,
1422         fps_d, NULL);
1423   } else {
1424     othercaps = gst_caps_ref (caps);
1425   }
1426
1427   if (otherpad == self->srcpad && self->mode != GST_DEINTERLACE_MODE_DISABLED) {
1428     othercaps = gst_caps_make_writable (othercaps);
1429     gst_caps_set_simple (othercaps, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL);
1430   }
1431
1432   gst_deinterlace_reset_history (self, FALSE);
1433
1434   if (!gst_pad_set_caps (otherpad, othercaps))
1435     goto caps_not_accepted;
1436
1437   self->frame_size =
1438       gst_video_format_get_size (self->format, self->width, self->height);
1439
1440   if (self->fields == GST_DEINTERLACE_ALL && otherpad == self->srcpad)
1441     self->field_duration =
1442         gst_util_uint64_scale (GST_SECOND, self->fps_d, self->fps_n);
1443   else
1444     self->field_duration =
1445         gst_util_uint64_scale (GST_SECOND, self->fps_d, 2 * self->fps_n);
1446
1447   if (pad == self->sinkpad) {
1448     gst_caps_replace (&self->sink_caps, caps);
1449     gst_caps_replace (&self->src_caps, othercaps);
1450   } else {
1451     gst_caps_replace (&self->src_caps, caps);
1452     gst_caps_replace (&self->sink_caps, othercaps);
1453   }
1454
1455   gst_deinterlace_set_method (self, self->method_id);
1456   gst_deinterlace_method_setup (self->method, self->format, self->width,
1457       self->height);
1458
1459   GST_DEBUG_OBJECT (pad, "Set caps: %" GST_PTR_FORMAT, caps);
1460   GST_DEBUG_OBJECT (pad, "Other caps: %" GST_PTR_FORMAT, othercaps);
1461
1462   gst_caps_unref (othercaps);
1463
1464 done:
1465
1466   gst_object_unref (self);
1467   return res;
1468
1469 invalid_caps:
1470   res = FALSE;
1471   GST_ERROR_OBJECT (pad, "Invalid caps: %" GST_PTR_FORMAT, caps);
1472   goto done;
1473
1474 caps_not_accepted:
1475   res = FALSE;
1476   GST_ERROR_OBJECT (pad, "Caps not accepted: %" GST_PTR_FORMAT, othercaps);
1477   gst_caps_unref (othercaps);
1478   goto done;
1479 }
1480
1481 static gboolean
1482 gst_deinterlace_sink_event (GstPad * pad, GstEvent * event)
1483 {
1484   gboolean res = TRUE;
1485   GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1486
1487   GST_LOG_OBJECT (pad, "received %s event: %" GST_PTR_FORMAT,
1488       GST_EVENT_TYPE_NAME (event), event);
1489
1490   switch (GST_EVENT_TYPE (event)) {
1491     case GST_EVENT_NEWSEGMENT:
1492     {
1493       GstFormat fmt;
1494       gboolean is_update;
1495       gint64 start, end, base;
1496       gdouble rate, applied_rate;
1497
1498       gst_event_parse_new_segment_full (event, &is_update, &rate, &applied_rate,
1499           &fmt, &start, &end, &base);
1500
1501       gst_deinterlace_reset_qos (self);
1502       gst_deinterlace_reset_history (self, FALSE);
1503
1504       if (fmt == GST_FORMAT_TIME) {
1505         GST_DEBUG_OBJECT (pad,
1506             "Got NEWSEGMENT event in GST_FORMAT_TIME, passing on (%"
1507             GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")", GST_TIME_ARGS (start),
1508             GST_TIME_ARGS (end));
1509         gst_segment_set_newsegment_full (&self->segment, is_update, rate,
1510             applied_rate, fmt, start, end, base);
1511       } else {
1512         gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1513       }
1514
1515       res = gst_pad_push_event (self->srcpad, event);
1516       break;
1517     }
1518     case GST_EVENT_CUSTOM_DOWNSTREAM:{
1519       gboolean still_state;
1520
1521       if (gst_video_event_parse_still_frame (event, &still_state)) {
1522         GST_DEBUG_OBJECT (self, "Received still frame event, state %d",
1523             still_state);
1524
1525         if (still_state) {
1526           GstFlowReturn ret;
1527
1528           GST_DEBUG_OBJECT (self, "Handling still frame");
1529           self->still_frame_mode = TRUE;
1530           gst_deinterlace_reset_history (self, FALSE);
1531           if (self->last_buffer) {
1532             ret =
1533                 gst_pad_push (self->srcpad, gst_buffer_ref (self->last_buffer));
1534             GST_DEBUG_OBJECT (self, "Pushed still frame, result: %s",
1535                 gst_flow_get_name (ret));
1536           } else {
1537             GST_WARNING_OBJECT (self, "No pending buffer!");
1538           }
1539         } else {
1540           GST_DEBUG_OBJECT (self, "Ending still frames");
1541           self->still_frame_mode = FALSE;
1542         }
1543       }
1544     }
1545       /* fall through */
1546     case GST_EVENT_EOS:
1547       gst_deinterlace_reset_history (self, FALSE);
1548
1549       /* fall through */
1550     default:
1551       res = gst_pad_push_event (self->srcpad, event);
1552       break;
1553
1554     case GST_EVENT_FLUSH_STOP:
1555       if (self->still_frame_mode) {
1556         GST_DEBUG_OBJECT (self, "Ending still frames");
1557         self->still_frame_mode = FALSE;
1558       }
1559       gst_deinterlace_reset_qos (self);
1560       res = gst_pad_push_event (self->srcpad, event);
1561       gst_deinterlace_reset_history (self, TRUE);
1562       break;
1563   }
1564
1565   gst_object_unref (self);
1566   return res;
1567 }
1568
1569 static gboolean
1570 gst_deinterlace_sink_query (GstPad * pad, GstQuery * query)
1571 {
1572   GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1573   gboolean res = FALSE;
1574
1575   GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
1576
1577   switch (GST_QUERY_TYPE (query)) {
1578     default:{
1579       GstPad *peer = gst_pad_get_peer (self->srcpad);
1580
1581       if (peer) {
1582         res = gst_pad_query (peer, query);
1583         gst_object_unref (peer);
1584       } else {
1585         res = FALSE;
1586       }
1587       break;
1588     }
1589   }
1590
1591   gst_object_unref (self);
1592   return res;
1593 }
1594
1595 static GstStateChangeReturn
1596 gst_deinterlace_change_state (GstElement * element, GstStateChange transition)
1597 {
1598   GstStateChangeReturn ret;
1599   GstDeinterlace *self = GST_DEINTERLACE (element);
1600
1601   switch (transition) {
1602     case GST_STATE_CHANGE_NULL_TO_READY:
1603       break;
1604     case GST_STATE_CHANGE_READY_TO_PAUSED:
1605       break;
1606     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1607       break;
1608     default:
1609       break;
1610   }
1611
1612   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1613   if (ret != GST_STATE_CHANGE_SUCCESS)
1614     return ret;
1615
1616   switch (transition) {
1617     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1618       break;
1619     case GST_STATE_CHANGE_PAUSED_TO_READY:
1620       gst_deinterlace_reset (self);
1621       break;
1622     case GST_STATE_CHANGE_READY_TO_NULL:
1623     default:
1624       break;
1625   }
1626
1627   return ret;
1628 }
1629
1630 static gboolean
1631 gst_deinterlace_src_event (GstPad * pad, GstEvent * event)
1632 {
1633   GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1634   gboolean res;
1635
1636   GST_DEBUG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
1637
1638   switch (GST_EVENT_TYPE (event)) {
1639     case GST_EVENT_QOS:{
1640       GstClockTimeDiff diff;
1641       GstClockTime timestamp;
1642       gdouble proportion;
1643
1644       gst_event_parse_qos (event, &proportion, &diff, &timestamp);
1645
1646       gst_deinterlace_update_qos (self, proportion, diff, timestamp);
1647     }
1648       /* fall through */
1649     default:
1650       res = gst_pad_push_event (self->sinkpad, event);
1651       break;
1652   }
1653
1654   gst_object_unref (self);
1655
1656   return res;
1657 }
1658
1659 static gboolean
1660 gst_deinterlace_src_query (GstPad * pad, GstQuery * query)
1661 {
1662   GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1663   gboolean res = FALSE;
1664
1665   GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
1666
1667   switch (GST_QUERY_TYPE (query)) {
1668     case GST_QUERY_LATENCY:
1669       if (!self->passthrough) {
1670         GstClockTime min, max;
1671         gboolean live;
1672         GstPad *peer;
1673
1674         if ((peer = gst_pad_get_peer (self->sinkpad))) {
1675           if ((res = gst_pad_query (peer, query))) {
1676             GstClockTime latency;
1677             gint fields_required = 0;
1678             gint method_latency = 0;
1679
1680             if (self->method) {
1681               fields_required =
1682                   gst_deinterlace_method_get_fields_required (self->method);
1683               method_latency =
1684                   gst_deinterlace_method_get_latency (self->method);
1685             }
1686
1687             gst_query_parse_latency (query, &live, &min, &max);
1688
1689             GST_DEBUG_OBJECT (self, "Peer latency: min %"
1690                 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
1691                 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
1692
1693             /* add our own latency */
1694             latency = (fields_required + method_latency) * self->field_duration;
1695
1696             GST_DEBUG_OBJECT (self, "Our latency: min %" GST_TIME_FORMAT
1697                 ", max %" GST_TIME_FORMAT,
1698                 GST_TIME_ARGS (latency), GST_TIME_ARGS (latency));
1699
1700             min += latency;
1701             if (max != GST_CLOCK_TIME_NONE)
1702               max += latency;
1703
1704             GST_DEBUG_OBJECT (self, "Calculated total latency : min %"
1705                 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
1706                 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
1707
1708             gst_query_set_latency (query, live, min, max);
1709           }
1710           gst_object_unref (peer);
1711         } else {
1712           res = FALSE;
1713         }
1714         break;
1715       }
1716     default:{
1717       GstPad *peer = gst_pad_get_peer (self->sinkpad);
1718
1719       if (peer) {
1720         res = gst_pad_query (peer, query);
1721         gst_object_unref (peer);
1722       } else {
1723         res = FALSE;
1724       }
1725       break;
1726     }
1727   }
1728
1729   gst_object_unref (self);
1730   return res;
1731 }
1732
1733 static const GstQueryType *
1734 gst_deinterlace_src_query_types (GstPad * pad)
1735 {
1736   static const GstQueryType types[] = {
1737     GST_QUERY_LATENCY,
1738     GST_QUERY_NONE
1739   };
1740   return types;
1741 }
1742
1743 static GstFlowReturn
1744 gst_deinterlace_alloc_buffer (GstPad * pad, guint64 offset, guint size,
1745     GstCaps * caps, GstBuffer ** buf)
1746 {
1747   GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1748   GstFlowReturn ret = GST_FLOW_OK;
1749
1750   *buf = NULL;
1751
1752   GST_DEBUG_OBJECT (pad, "alloc with caps %" GST_PTR_FORMAT ", size %u", caps,
1753       size);
1754
1755   if (self->still_frame_mode || self->passthrough) {
1756     ret = gst_pad_alloc_buffer (self->srcpad, offset, size, caps, buf);
1757   } else if (G_LIKELY (!self->request_caps)) {
1758     *buf = gst_buffer_try_new_and_alloc (size);
1759     if (G_UNLIKELY (!*buf)) {
1760       ret = GST_FLOW_ERROR;
1761     } else {
1762       gst_buffer_set_caps (*buf, caps);
1763       GST_BUFFER_OFFSET (*buf) = offset;
1764     }
1765   } else {
1766     gint width, height;
1767     GstVideoFormat fmt;
1768     guint new_frame_size;
1769     GstCaps *new_caps = gst_caps_copy (self->request_caps);
1770
1771     if (self->fields == GST_DEINTERLACE_ALL) {
1772       gint n, d;
1773       GstStructure *s = gst_caps_get_structure (new_caps, 0);
1774
1775       gst_structure_get_fraction (s, "framerate", &n, &d);
1776
1777       if (!gst_fraction_double (&n, &d, TRUE)) {
1778         gst_object_unref (self);
1779         gst_caps_unref (new_caps);
1780         return GST_FLOW_OK;
1781       }
1782
1783       gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
1784     }
1785
1786     if (G_UNLIKELY (!gst_video_format_parse_caps (new_caps, &fmt, &width,
1787                 &height))) {
1788       gst_object_unref (self);
1789       gst_caps_unref (new_caps);
1790       return GST_FLOW_OK;
1791     }
1792
1793     new_frame_size = gst_video_format_get_size (fmt, width, height);
1794
1795     *buf = gst_buffer_try_new_and_alloc (new_frame_size);
1796     if (G_UNLIKELY (!*buf)) {
1797       ret = GST_FLOW_ERROR;
1798     } else {
1799       gst_buffer_set_caps (*buf, new_caps);
1800       gst_caps_unref (self->request_caps);
1801       self->request_caps = NULL;
1802       gst_caps_unref (new_caps);
1803     }
1804   }
1805
1806   gst_object_unref (self);
1807
1808   return ret;
1809 }
1810
1811 static gboolean
1812 plugin_init (GstPlugin * plugin)
1813 {
1814   GST_DEBUG_CATEGORY_INIT (deinterlace_debug, "deinterlace", 0, "Deinterlacer");
1815
1816 #if HAVE_ORC
1817   orc_init ();
1818 #endif
1819
1820   if (!gst_element_register (plugin, "deinterlace", GST_RANK_NONE,
1821           GST_TYPE_DEINTERLACE)) {
1822     return FALSE;
1823   }
1824
1825   return TRUE;
1826 }
1827
1828 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1829     GST_VERSION_MINOR,
1830     "deinterlace",
1831     "Deinterlacer", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
1832     GST_PACKAGE_ORIGIN);