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