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