deinterlace: Do passthrough in auto mode if downstream only supports interlaced
[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  * Copyright (C) 2011 Robert Swain <robert.swain@collabora.co.uk>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 /**
24  * SECTION:element-deinterlace
25  *
26  * deinterlace deinterlaces interlaced video frames to progressive video frames.
27  * For this different algorithms can be selected which will be described later.
28  *
29  * <refsect2>
30  * <title>Example launch line</title>
31  * |[
32  * gst-launch-1.0 -v filesrc location=/path/to/file ! decodebin ! videoconvert ! deinterlace ! videoconvert ! autovideosink
33  * ]| This pipeline deinterlaces a video file with the default deinterlacing options.
34  * </refsect2>
35  */
36
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40
41 #include "gstdeinterlace.h"
42 #include "tvtime/plugins.h"
43
44 #include <string.h>
45
46 #if HAVE_ORC
47 #include <orc/orc.h>
48 #endif
49
50 GST_DEBUG_CATEGORY_STATIC (deinterlace_debug);
51 #define GST_CAT_DEFAULT (deinterlace_debug)
52
53 /* Properties */
54
55 #define DEFAULT_MODE            GST_DEINTERLACE_MODE_AUTO
56 #define DEFAULT_METHOD          GST_DEINTERLACE_LINEAR
57 #define DEFAULT_FIELDS          GST_DEINTERLACE_ALL
58 #define DEFAULT_FIELD_LAYOUT    GST_DEINTERLACE_LAYOUT_AUTO
59 #define DEFAULT_LOCKING         GST_DEINTERLACE_LOCKING_NONE
60 #define DEFAULT_IGNORE_OBSCURE  TRUE
61 #define DEFAULT_DROP_ORPHANS    TRUE
62
63 enum
64 {
65   PROP_0,
66   PROP_MODE,
67   PROP_METHOD,
68   PROP_FIELDS,
69   PROP_FIELD_LAYOUT,
70   PROP_LOCKING,
71   PROP_IGNORE_OBSCURE,
72   PROP_DROP_ORPHANS
73 };
74
75 #define GST_DEINTERLACE_BUFFER_STATE_P    (1<<0)
76 #define GST_DEINTERLACE_BUFFER_STATE_I    (1<<1)
77 #define GST_DEINTERLACE_BUFFER_STATE_TC_B (1<<2)
78 #define GST_DEINTERLACE_BUFFER_STATE_TC_T (1<<3)
79 #define GST_DEINTERLACE_BUFFER_STATE_TC_P (1<<4)
80 #define GST_DEINTERLACE_BUFFER_STATE_TC_M (1<<5)
81 #define GST_DEINTERLACE_BUFFER_STATE_RFF  (1<<6)
82
83 #define GST_ONE \
84   (GST_DEINTERLACE_BUFFER_STATE_TC_T | GST_DEINTERLACE_BUFFER_STATE_TC_B)
85 #define GST_PRG \
86   (GST_DEINTERLACE_BUFFER_STATE_P | GST_DEINTERLACE_BUFFER_STATE_TC_P)
87 #define GST_INT \
88   (GST_DEINTERLACE_BUFFER_STATE_I | GST_DEINTERLACE_BUFFER_STATE_TC_M)
89 #define GST_RFF (GST_DEINTERLACE_BUFFER_STATE_RFF)
90
91 #define GST_DEINTERLACE_OBSCURE_THRESHOLD 5
92
93 static const TelecinePattern telecine_patterns[] = {
94   /* 60i -> 60p or 50i -> 50p (NOTE THE WEIRD RATIOS) */
95   {"1:1", 1, 2, 1, {GST_ONE,}},
96   /* 60i -> 30p or 50i -> 25p */
97   {"2:2", 1, 1, 1, {GST_INT,}},
98   /* 60i telecine -> 24p */
99   {"2:3-RFF", 4, 4, 5, {GST_PRG, GST_RFF, GST_PRG, GST_RFF,}},
100   {"2:3", 5, 4, 5, {GST_PRG, GST_PRG, GST_ONE, GST_ONE, GST_PRG,}},
101   {"3:2:2:3-RFF", 4, 4, 5, {GST_RFF, GST_PRG, GST_PRG, GST_RFF,}},
102   {"3:2:2:3", 5, 4, 5, {GST_PRG, GST_ONE, GST_INT, GST_ONE, GST_PRG,}},
103   /* fieldanalysis should indicate this using RFF on the second and fourth
104    * buffers and not send the third buffer at all. it will be identified as
105    * 3:2:2:3-RFF */
106   /* {"2:3:3:2", 5, 4, 5, {GST_PRG, GST_PRG, GST_DRP, GST_PRG, GST_PRG,}}, */
107
108   /* The following patterns are obscure and are ignored if ignore-obscure is
109    * set to true. If any patterns are added above this line, check and edit
110    * GST_DEINTERLACE_OBSCURE_THRESHOLD */
111
112   /* 50i Euro pulldown -> 24p */
113   {"2-11:3", 25, 24, 25, {GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_PRG,
114               GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_PRG,
115               GST_PRG, GST_PRG, GST_ONE, GST_INT, GST_INT,
116               GST_INT, GST_INT, GST_INT, GST_INT, GST_INT,
117           GST_INT, GST_INT, GST_INT, GST_ONE, GST_PRG,}},
118 #if 0
119   /* haven't figured out how fieldanalysis should handle these yet */
120   /* 60i (NTSC 30000/1001) -> 16p (16000/1001) */
121   {"3:4-3", 15, 8, 15, {GST_PRG, GST_DRP, GST_PRG, GST_DRP, GST_PRG,
122               GST_DRP, GST_PRG, GST_DRP, GST_PRG, GST_DRP,
123           GST_PRG, GST_DRP, GST_PRG, GST_DRP, GST_PRG,}},
124   /* 50i (PAL) -> 16p */
125   {"3-7:4", 25, 16, 25, {GST_PRG, GST_DRP, GST_PRG, GST_PRG, GST_DRP,
126               GST_PRG, GST_PRG, GST_DRP, GST_PRG, GST_PRG,
127               GST_DRP, GST_PRG, GST_DRP, GST_PRG, GST_PRG,
128               GST_DRP, GST_PRG, GST_PRG, GST_DRP, GST_PRG,
129           GST_PRG, GST_DRP, GST_PRG, GST_PRG, GST_DRP,}},
130   /* NTSC 60i -> 18p */
131   {"3:3:4", 5, 3, 5, {GST_PRG, GST_DRP, GST_PRG, GST_DRP, GST_PRG,}},
132   /* NTSC 60i -> 20p */
133   {"3:3", 3, 2, 3, {GST_PRG, GST_DRP, GST_PRG,}},
134 #endif
135   /* NTSC 60i -> 27.5 */
136   {"3:2-4", 11, 10, 11, {GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_PRG,
137               GST_PRG, GST_ONE, GST_INT, GST_INT, GST_INT,
138           GST_ONE,}},
139   /* PAL 50i -> 27.5 */
140   {"1:2-4", 9, 9, 10, {GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_INT,
141           GST_INT, GST_INT, GST_INT, GST_INT,}},
142 };
143
144 static const GEnumValue methods_types[] = {
145   {GST_DEINTERLACE_TOMSMOCOMP, "Motion Adaptive: Motion Search",
146       "tomsmocomp"},
147   {GST_DEINTERLACE_GREEDY_H, "Motion Adaptive: Advanced Detection",
148       "greedyh"},
149   {GST_DEINTERLACE_GREEDY_L, "Motion Adaptive: Simple Detection", "greedyl"},
150   {GST_DEINTERLACE_VFIR, "Blur Vertical", "vfir"},
151   {GST_DEINTERLACE_LINEAR, "Television: Full resolution", "linear"},
152   {GST_DEINTERLACE_LINEAR_BLEND, "Blur: Temporal (Do Not Use)",
153       "linearblend"},
154   {GST_DEINTERLACE_SCALER_BOB, "Double lines", "scalerbob"},
155   {GST_DEINTERLACE_WEAVE, "Weave (Do Not Use)", "weave"},
156   {GST_DEINTERLACE_WEAVE_TFF, "Progressive: Top Field First (Do Not Use)",
157       "weavetff"},
158   {GST_DEINTERLACE_WEAVE_BFF, "Progressive: Bottom Field First (Do Not Use)",
159       "weavebff"},
160   {0, NULL, NULL},
161 };
162
163 static const GEnumValue locking_types[] = {
164   {GST_DEINTERLACE_LOCKING_NONE,
165       "No pattern locking", "none"},
166   {GST_DEINTERLACE_LOCKING_AUTO,
167         "Choose passive/active locking depending on whether upstream is live",
168       "auto"},
169   {GST_DEINTERLACE_LOCKING_ACTIVE,
170         "Block until pattern-locked. Use accurate timestamp interpolation within a pattern repeat.",
171       "active"},
172   {GST_DEINTERLACE_LOCKING_PASSIVE,
173         "Do not block. Use naïve timestamp adjustment until pattern-locked based on state history.",
174       "passive"},
175   {0, NULL, NULL},
176 };
177
178
179 #define GST_TYPE_DEINTERLACE_METHODS (gst_deinterlace_methods_get_type ())
180 static GType
181 gst_deinterlace_methods_get_type (void)
182 {
183   static GType deinterlace_methods_type = 0;
184
185   if (!deinterlace_methods_type) {
186     deinterlace_methods_type =
187         g_enum_register_static ("GstDeinterlaceMethods", methods_types);
188   }
189   return deinterlace_methods_type;
190 }
191
192 #define GST_TYPE_DEINTERLACE_FIELDS (gst_deinterlace_fields_get_type ())
193 static GType
194 gst_deinterlace_fields_get_type (void)
195 {
196   static GType deinterlace_fields_type = 0;
197
198   static const GEnumValue fields_types[] = {
199     {GST_DEINTERLACE_ALL, "All fields", "all"},
200     {GST_DEINTERLACE_TF, "Top fields only", "top"},
201     {GST_DEINTERLACE_BF, "Bottom fields only", "bottom"},
202     {0, NULL, NULL},
203   };
204
205   if (!deinterlace_fields_type) {
206     deinterlace_fields_type =
207         g_enum_register_static ("GstDeinterlaceFields", fields_types);
208   }
209   return deinterlace_fields_type;
210 }
211
212 #define GST_TYPE_DEINTERLACE_FIELD_LAYOUT (gst_deinterlace_field_layout_get_type ())
213 static GType
214 gst_deinterlace_field_layout_get_type (void)
215 {
216   static GType deinterlace_field_layout_type = 0;
217
218   static const GEnumValue field_layout_types[] = {
219     {GST_DEINTERLACE_LAYOUT_AUTO, "Auto detection", "auto"},
220     {GST_DEINTERLACE_LAYOUT_TFF, "Top field first", "tff"},
221     {GST_DEINTERLACE_LAYOUT_BFF, "Bottom field first", "bff"},
222     {0, NULL, NULL},
223   };
224
225   if (!deinterlace_field_layout_type) {
226     deinterlace_field_layout_type =
227         g_enum_register_static ("GstDeinterlaceFieldLayout",
228         field_layout_types);
229   }
230   return deinterlace_field_layout_type;
231 }
232
233 #define GST_TYPE_DEINTERLACE_MODES (gst_deinterlace_modes_get_type ())
234 static GType
235 gst_deinterlace_modes_get_type (void)
236 {
237   static GType deinterlace_modes_type = 0;
238
239   static const GEnumValue modes_types[] = {
240     {GST_DEINTERLACE_MODE_AUTO, "Auto detection (best effort)", "auto"},
241     {GST_DEINTERLACE_MODE_INTERLACED, "Force deinterlacing", "interlaced"},
242     {GST_DEINTERLACE_MODE_DISABLED, "Run in passthrough mode", "disabled"},
243     {GST_DEINTERLACE_MODE_AUTO_STRICT, "Auto detection (strict)",
244         "auto-strict"},
245     {0, NULL, NULL},
246   };
247
248   if (!deinterlace_modes_type) {
249     deinterlace_modes_type =
250         g_enum_register_static ("GstDeinterlaceModes", modes_types);
251   }
252   return deinterlace_modes_type;
253 }
254
255 #define GST_TYPE_DEINTERLACE_LOCKING (gst_deinterlace_locking_get_type ())
256 static GType
257 gst_deinterlace_locking_get_type (void)
258 {
259   static GType deinterlace_locking_type = 0;
260
261   if (!deinterlace_locking_type) {
262     deinterlace_locking_type =
263         g_enum_register_static ("GstDeinterlaceLocking", locking_types);
264   }
265
266   return deinterlace_locking_type;
267 }
268
269 #define DEINTERLACE_VIDEO_FORMATS \
270     "{ AYUV, ARGB, ABGR, RGBA, BGRA, Y444, xRGB, xBGR, RGBx, BGRx, RGB, " \
271     "BGR, YUY2, YVYU, UYVY, Y42B, I420, YV12, Y41B, NV12, NV21 }"
272
273 #define DEINTERLACE_CAPS GST_VIDEO_CAPS_MAKE(DEINTERLACE_VIDEO_FORMATS)
274
275 #define DEINTERLACE_ALL_CAPS DEINTERLACE_CAPS ";" \
276     GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY", GST_VIDEO_FORMATS_ALL)
277
278 static GstStaticCaps progressive_caps =
279 GST_STATIC_CAPS ("video/x-raw(ANY),interlace-mode=(string)progressive");
280 static GstStaticCaps deinterlace_caps = GST_STATIC_CAPS (DEINTERLACE_CAPS);
281
282 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
283     GST_PAD_SRC,
284     GST_PAD_ALWAYS,
285     GST_STATIC_CAPS (DEINTERLACE_ALL_CAPS)
286     );
287
288 static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
289     GST_PAD_SINK,
290     GST_PAD_ALWAYS,
291     GST_STATIC_CAPS (DEINTERLACE_ALL_CAPS)
292     );
293
294 static void gst_deinterlace_finalize (GObject * self);
295 static void gst_deinterlace_set_property (GObject * self, guint prop_id,
296     const GValue * value, GParamSpec * pspec);
297 static void gst_deinterlace_get_property (GObject * self, guint prop_id,
298     GValue * value, GParamSpec * pspec);
299
300 static GstCaps *gst_deinterlace_getcaps (GstDeinterlace * self, GstPad * pad,
301     GstCaps * filter);
302 static gboolean gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad,
303     GstCaps * caps);
304 static gboolean gst_deinterlace_sink_event (GstPad * pad, GstObject * parent,
305     GstEvent * event);
306 static gboolean gst_deinterlace_sink_query (GstPad * pad, GstObject * parent,
307     GstQuery * query);
308 static GstFlowReturn gst_deinterlace_chain (GstPad * pad, GstObject * parent,
309     GstBuffer * buffer);
310 static GstStateChangeReturn gst_deinterlace_change_state (GstElement * element,
311     GstStateChange transition);
312 static gboolean gst_deinterlace_set_allocation (GstDeinterlace * self,
313     GstBufferPool * pool, GstAllocator * allocator,
314     GstAllocationParams * params);
315
316 static gboolean gst_deinterlace_src_event (GstPad * pad, GstObject * parent,
317     GstEvent * event);
318 static gboolean gst_deinterlace_src_query (GstPad * pad, GstObject * parent,
319     GstQuery * query);
320
321 static GstFlowReturn gst_deinterlace_output_frame (GstDeinterlace * self,
322     gboolean flushing);
323 static void gst_deinterlace_reset (GstDeinterlace * self);
324 static void gst_deinterlace_update_qos (GstDeinterlace * self,
325     gdouble proportion, GstClockTimeDiff diff, GstClockTime time);
326 static void gst_deinterlace_reset_qos (GstDeinterlace * self);
327 static void gst_deinterlace_read_qos (GstDeinterlace * self,
328     gdouble * proportion, GstClockTime * time);
329
330 #define IS_TELECINE(m) ((m) == GST_VIDEO_INTERLACE_MODE_MIXED && self->pattern > 1)
331
332 /* FIXME: what's the point of the childproxy interface here? What can you
333  * actually do with it? The method objects seem to have no properties */
334 #if 0
335 static void gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
336     gpointer iface_data);
337
338 static void
339 _do_init (GType object_type)
340 {
341   const GInterfaceInfo child_proxy_interface_info = {
342     (GInterfaceInitFunc) gst_deinterlace_child_proxy_interface_init,
343     NULL,                       /* interface_finalize */
344     NULL                        /* interface_data */
345   };
346
347   g_type_add_interface_static (object_type, GST_TYPE_CHILD_PROXY,
348       &child_proxy_interface_info);
349 }
350 #endif
351
352 G_DEFINE_TYPE (GstDeinterlace, gst_deinterlace, GST_TYPE_ELEMENT);
353
354 #define parent_class gst_deinterlace_parent_class
355
356 static const struct
357 {
358   GType (*get_type) (void);
359 } _method_types[] = {
360   {
361   gst_deinterlace_method_tomsmocomp_get_type}, {
362   gst_deinterlace_method_greedy_h_get_type}, {
363   gst_deinterlace_method_greedy_l_get_type}, {
364   gst_deinterlace_method_vfir_get_type}, {
365   gst_deinterlace_method_linear_get_type}, {
366   gst_deinterlace_method_linear_blend_get_type}, {
367   gst_deinterlace_method_scaler_bob_get_type}, {
368   gst_deinterlace_method_weave_get_type}, {
369   gst_deinterlace_method_weave_tff_get_type}, {
370   gst_deinterlace_method_weave_bff_get_type}
371 };
372
373 static void
374 gst_deinterlace_set_method (GstDeinterlace * self, GstDeinterlaceMethods method)
375 {
376   GType method_type;
377   gint width, height;
378   GstVideoFormat format;
379
380   GST_DEBUG_OBJECT (self, "Setting new method %d", method);
381
382   width = GST_VIDEO_INFO_WIDTH (&self->vinfo);
383   height = GST_VIDEO_INFO_HEIGHT (&self->vinfo);
384   format = GST_VIDEO_INFO_FORMAT (&self->vinfo);
385
386   if (self->method) {
387     if (self->method_id == method &&
388         gst_deinterlace_method_supported (G_TYPE_FROM_INSTANCE (self->method),
389             format, width, height)) {
390       GST_DEBUG_OBJECT (self, "Reusing current method");
391       return;
392     }
393 #if 0
394     gst_child_proxy_child_removed (GST_OBJECT (self),
395         GST_OBJECT (self->method));
396     gst_object_unparent (GST_OBJECT (self->method));
397     self->method = NULL;
398 #endif
399   }
400
401   method_type =
402       _method_types[method].get_type !=
403       NULL ? _method_types[method].get_type () : G_TYPE_INVALID;
404   if (method_type == G_TYPE_INVALID
405       || !gst_deinterlace_method_supported (method_type, format,
406           width, height)) {
407     GType tmp;
408     gint i;
409
410     method_type = G_TYPE_INVALID;
411
412     GST_WARNING_OBJECT (self, "Method doesn't support requested format");
413     for (i = 0; i < G_N_ELEMENTS (_method_types); i++) {
414       if (_method_types[i].get_type == NULL)
415         continue;
416       tmp = _method_types[i].get_type ();
417       if (gst_deinterlace_method_supported (tmp, format, width, height)) {
418         GST_DEBUG_OBJECT (self, "Using method %d", i);
419         method_type = tmp;
420         method = i;
421         break;
422       }
423     }
424     /* If we get here we must have invalid caps! */
425     g_assert (method_type != G_TYPE_INVALID);
426   }
427
428   self->method = g_object_new (method_type, "name", "method", NULL);
429   self->method_id = method;
430
431   gst_object_set_parent (GST_OBJECT (self->method), GST_OBJECT (self));
432 #if 0
433   gst_child_proxy_child_added (GST_OBJECT (self), GST_OBJECT (self->method));
434 #endif
435
436   if (self->method)
437     gst_deinterlace_method_setup (self->method, &self->vinfo);
438 }
439
440 static gboolean
441 gst_deinterlace_clip_buffer (GstDeinterlace * self, GstBuffer * buffer)
442 {
443   gboolean ret = TRUE;
444   GstClockTime start, stop;
445   guint64 cstart, cstop;
446
447   GST_DEBUG_OBJECT (self,
448       "Clipping buffer to the current segment: %" GST_TIME_FORMAT " -- %"
449       GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
450       GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
451   GST_DEBUG_OBJECT (self, "Current segment: %" GST_SEGMENT_FORMAT,
452       &self->segment);
453
454   if (G_UNLIKELY (self->segment.format != GST_FORMAT_TIME))
455     goto beach;
456   if (G_UNLIKELY (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer)))
457     goto beach;
458
459   start = GST_BUFFER_TIMESTAMP (buffer);
460   stop = start + GST_BUFFER_DURATION (buffer);
461
462   if (!(ret = gst_segment_clip (&self->segment, GST_FORMAT_TIME,
463               start, stop, &cstart, &cstop)))
464     goto beach;
465
466   GST_BUFFER_TIMESTAMP (buffer) = cstart;
467   if (GST_CLOCK_TIME_IS_VALID (cstop))
468     GST_BUFFER_DURATION (buffer) = cstop - cstart;
469
470 beach:
471   if (ret)
472     GST_DEBUG_OBJECT (self,
473         "Clipped buffer to the current segment: %" GST_TIME_FORMAT " -- %"
474         GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
475         GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
476   else
477     GST_DEBUG_OBJECT (self, "Buffer outside the current segment -- dropping");
478
479   return ret;
480 }
481
482 static void
483 gst_deinterlace_class_init (GstDeinterlaceClass * klass)
484 {
485   GObjectClass *gobject_class = (GObjectClass *) klass;
486
487   GstElementClass *element_class = (GstElementClass *) klass;
488
489   gst_element_class_add_pad_template (element_class,
490       gst_static_pad_template_get (&src_templ));
491   gst_element_class_add_pad_template (element_class,
492       gst_static_pad_template_get (&sink_templ));
493
494   gst_element_class_set_static_metadata (element_class,
495       "Deinterlacer",
496       "Filter/Effect/Video/Deinterlace",
497       "Deinterlace Methods ported from DScaler/TvTime",
498       "Martin Eikermann <meiker@upb.de>, "
499       "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
500
501   gobject_class->set_property = gst_deinterlace_set_property;
502   gobject_class->get_property = gst_deinterlace_get_property;
503   gobject_class->finalize = gst_deinterlace_finalize;
504
505   /**
506    * GstDeinterlace:mode:
507    *
508    * This selects whether the deinterlacing methods should
509    * always be applied or if they should only be applied
510    * on content that has the "interlaced" flag on the caps.
511    */
512   g_object_class_install_property (gobject_class, PROP_MODE,
513       g_param_spec_enum ("mode",
514           "Mode",
515           "Deinterlace Mode",
516           GST_TYPE_DEINTERLACE_MODES,
517           DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
518       );
519
520   /**
521    * GstDeinterlace:method:
522    *
523    * Selects the different deinterlacing algorithms that can be used.
524    * These provide different quality and CPU usage.
525    *
526    * Some methods provide parameters which can be set by getting
527    * the "method" child via the #GstChildProxy interface and
528    * setting the appropiate properties on it.
529    *
530    * <itemizedlist>
531    * <listitem>
532    * <para>
533    * tomsmocomp
534    * Motion Adaptive: Motion Search
535    * </para>
536    * </listitem>
537    * <listitem>
538    * <para>
539    * greedyh
540    * Motion Adaptive: Advanced Detection
541    * </para>
542    * </listitem>
543    * <listitem>
544    * <para>
545    * greedyl
546    * Motion Adaptive: Simple Detection
547    * </para>
548    * </listitem>
549    * <listitem>
550    * <para>
551    * vfir
552    * Blur vertical
553    * </para>
554    * </listitem>
555    * <listitem>
556    * <para>
557    * linear
558    * Linear interpolation
559    * </para>
560    * </listitem>
561    * <listitem>
562    * <para>
563    * linearblend
564    * Linear interpolation in time domain.  Any motion causes significant
565    * ghosting, so this method should not be used.
566    * </para>
567    * </listitem>
568    * <listitem>
569    * <para>
570    * scalerbob
571    * Double lines
572    * </para>
573    * </listitem>
574    * <listitem>
575    * <para>
576    * weave
577    * Weave.  Bad quality, do not use.
578    * </para>
579    * </listitem>
580    * <listitem>
581    * <para>
582    * weavetff
583    * Progressive: Top Field First.  Bad quality, do not use.
584    * </para>
585    * </listitem>
586    * <listitem>
587    * <para>
588    * weavebff
589    * Progressive: Bottom Field First.  Bad quality, do not use.
590    * </para>
591    * </listitem>
592    * </itemizedlist>
593    */
594   g_object_class_install_property (gobject_class, PROP_METHOD,
595       g_param_spec_enum ("method",
596           "Method",
597           "Deinterlace Method",
598           GST_TYPE_DEINTERLACE_METHODS,
599           DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
600       );
601
602   /**
603    * GstDeinterlace:fields:
604    *
605    * This selects which fields should be output. If "all" is selected
606    * the output framerate will be double.
607    */
608   g_object_class_install_property (gobject_class, PROP_FIELDS,
609       g_param_spec_enum ("fields",
610           "fields",
611           "Fields to use for deinterlacing",
612           GST_TYPE_DEINTERLACE_FIELDS,
613           DEFAULT_FIELDS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
614       );
615
616   /**
617    * GstDeinterlace:layout:
618    *
619    * This selects which fields is the first in time.
620    *
621    */
622   g_object_class_install_property (gobject_class, PROP_FIELD_LAYOUT,
623       g_param_spec_enum ("tff",
624           "tff",
625           "Deinterlace top field first",
626           GST_TYPE_DEINTERLACE_FIELD_LAYOUT,
627           DEFAULT_FIELD_LAYOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
628       );
629
630   /**
631    * GstDeinterlace:locking:
632    *
633    * This selects which approach to pattern locking is used which affects
634    * processing latency and accuracy of timestamp adjustment for telecine
635    * streams.
636    */
637   g_object_class_install_property (gobject_class, PROP_LOCKING,
638       g_param_spec_enum ("locking", "locking", "Pattern locking mode",
639           GST_TYPE_DEINTERLACE_LOCKING, DEFAULT_LOCKING,
640           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
641
642   /**
643    * GstDeinterlace:ignore-obscure:
644    *
645    * This selects whether to ignore obscure/rare telecine patterns.
646    * NTSC 2:3 pulldown variants are the only really common patterns.
647    */
648   g_object_class_install_property (gobject_class, PROP_IGNORE_OBSCURE,
649       g_param_spec_boolean ("ignore-obscure", "ignore-obscure",
650           "Ignore obscure telecine patterns (only consider P, I and 2:3 "
651           "variants).", DEFAULT_IGNORE_OBSCURE,
652           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
653
654   /**
655    * GstDeinterlace:drop-orphans:
656    *
657    * This selects whether to drop orphan fields at the beginning of telecine
658    * patterns in active locking mode.
659    */
660   g_object_class_install_property (gobject_class, PROP_DROP_ORPHANS,
661       g_param_spec_boolean ("drop-orphans", "drop-orphans",
662           "Drop orphan fields at the beginning of telecine patterns in "
663           "active locking mode.", DEFAULT_DROP_ORPHANS,
664           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
665
666   element_class->change_state =
667       GST_DEBUG_FUNCPTR (gst_deinterlace_change_state);
668 }
669
670 #if 0
671 static GstObject *
672 gst_deinterlace_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
673     guint index)
674 {
675   GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
676
677   g_return_val_if_fail (index == 0, NULL);
678
679   return gst_object_ref (self->method);
680 }
681
682 static guint
683 gst_deinterlace_child_proxy_get_children_count (GstChildProxy * child_proxy)
684 {
685   GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
686
687   return ((self->method) ? 1 : 0);
688 }
689
690 static void
691 gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
692     gpointer iface_data)
693 {
694   GstChildProxyInterface *iface = g_iface;
695
696   iface->get_child_by_index = gst_deinterlace_child_proxy_get_child_by_index;
697   iface->get_children_count = gst_deinterlace_child_proxy_get_children_count;
698 }
699 #endif
700
701 static void
702 gst_deinterlace_init (GstDeinterlace * self)
703 {
704   self->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
705   gst_pad_set_chain_function (self->sinkpad,
706       GST_DEBUG_FUNCPTR (gst_deinterlace_chain));
707   gst_pad_set_event_function (self->sinkpad,
708       GST_DEBUG_FUNCPTR (gst_deinterlace_sink_event));
709   gst_pad_set_query_function (self->sinkpad,
710       GST_DEBUG_FUNCPTR (gst_deinterlace_sink_query));
711   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
712
713   self->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
714   gst_pad_set_event_function (self->srcpad,
715       GST_DEBUG_FUNCPTR (gst_deinterlace_src_event));
716   gst_pad_set_query_function (self->srcpad,
717       GST_DEBUG_FUNCPTR (gst_deinterlace_src_query));
718   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
719
720   self->mode = DEFAULT_MODE;
721   self->user_set_method_id = DEFAULT_METHOD;
722   gst_video_info_init (&self->vinfo);
723   gst_deinterlace_set_method (self, self->user_set_method_id);
724   self->fields = DEFAULT_FIELDS;
725   self->field_layout = DEFAULT_FIELD_LAYOUT;
726   self->locking = DEFAULT_LOCKING;
727   self->ignore_obscure = DEFAULT_IGNORE_OBSCURE;
728   self->drop_orphans = DEFAULT_DROP_ORPHANS;
729
730   self->low_latency = -1;
731   self->pattern = -1;
732   self->pattern_phase = -1;
733   self->pattern_count = 0;
734   self->output_count = 0;
735   self->pattern_base_ts = GST_CLOCK_TIME_NONE;
736   self->pattern_buf_dur = GST_CLOCK_TIME_NONE;
737   self->still_frame_mode = FALSE;
738
739   gst_deinterlace_reset (self);
740 }
741
742 static GstVideoFrame *
743 gst_video_frame_new_and_map (GstVideoInfo * vinfo, GstBuffer * buffer,
744     GstMapFlags flags)
745 {
746   GstVideoFrame *frame = g_malloc0 (sizeof (GstVideoFrame));
747   gst_video_frame_map (frame, vinfo, buffer, flags);
748   return frame;
749 }
750
751 static void
752 gst_video_frame_unmap_and_free (GstVideoFrame * frame)
753 {
754   gst_video_frame_unmap (frame);
755   g_free (frame);
756 }
757
758 static void
759 gst_deinterlace_reset_history (GstDeinterlace * self, gboolean drop_all)
760 {
761   gint i;
762
763   if (!drop_all) {
764     GST_DEBUG_OBJECT (self, "Flushing history (count %d)", self->history_count);
765     while (self->history_count > 0) {
766       if (gst_deinterlace_output_frame (self, TRUE) != GST_FLOW_OK) {
767         /* Encountered error, or flushing -> skip and drop all remaining */
768         drop_all = TRUE;
769         break;
770       }
771     }
772   }
773   if (drop_all) {
774     GST_DEBUG_OBJECT (self, "Resetting history (count %d)",
775         self->history_count);
776
777     for (i = 0; i < self->history_count; i++) {
778       if (self->field_history[i].frame) {
779         gst_video_frame_unmap_and_free (self->field_history[i].frame);
780         self->field_history[i].frame = NULL;
781       }
782     }
783   }
784   memset (self->field_history, 0,
785       GST_DEINTERLACE_MAX_FIELD_HISTORY * sizeof (GstDeinterlaceField));
786   self->history_count = 0;
787   memset (self->buf_states, 0,
788       GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY *
789       sizeof (GstDeinterlaceBufferState));
790   self->state_count = 0;
791   self->pattern_lock = FALSE;
792   self->pattern_refresh = TRUE;
793   self->cur_field_idx = -1;
794
795   if (!self->still_frame_mode && self->last_buffer) {
796     gst_buffer_unref (self->last_buffer);
797     self->last_buffer = NULL;
798   }
799 }
800
801 static void
802 gst_deinterlace_reset (GstDeinterlace * self)
803 {
804   GST_DEBUG_OBJECT (self, "Resetting internal state");
805
806   gst_video_info_init (&self->vinfo);
807
808   self->passthrough = FALSE;
809
810   self->reconfigure = FALSE;
811   if ((gint) self->new_mode != -1)
812     self->mode = self->new_mode;
813   if ((gint) self->new_fields != -1)
814     self->fields = self->new_fields;
815   self->new_mode = -1;
816   self->new_fields = -1;
817
818   gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
819
820   if (self->request_caps)
821     gst_caps_unref (self->request_caps);
822   self->request_caps = NULL;
823
824   gst_deinterlace_reset_history (self, TRUE);
825
826   gst_deinterlace_reset_qos (self);
827
828   self->need_more = FALSE;
829   self->have_eos = FALSE;
830
831   gst_deinterlace_set_allocation (self, NULL, NULL, NULL);
832 }
833
834 static void
835 gst_deinterlace_set_property (GObject * object, guint prop_id,
836     const GValue * value, GParamSpec * pspec)
837 {
838   GstDeinterlace *self;
839
840   self = GST_DEINTERLACE (object);
841
842   switch (prop_id) {
843     case PROP_MODE:{
844       gint new_mode;
845
846       GST_OBJECT_LOCK (self);
847       new_mode = g_value_get_enum (value);
848       if (self->mode != new_mode && gst_pad_has_current_caps (self->srcpad)) {
849         self->reconfigure = TRUE;
850         self->new_mode = new_mode;
851       } else {
852         self->mode = new_mode;
853       }
854       GST_OBJECT_UNLOCK (self);
855       break;
856     }
857     case PROP_METHOD:
858       self->user_set_method_id = g_value_get_enum (value);
859       gst_deinterlace_set_method (self, self->user_set_method_id);
860       break;
861     case PROP_FIELDS:{
862       gint new_fields;
863
864       GST_OBJECT_LOCK (self);
865       new_fields = g_value_get_enum (value);
866       if (self->fields != new_fields && gst_pad_has_current_caps (self->srcpad)) {
867         self->reconfigure = TRUE;
868         self->new_fields = new_fields;
869       } else {
870         self->fields = new_fields;
871       }
872       GST_OBJECT_UNLOCK (self);
873       break;
874     }
875     case PROP_FIELD_LAYOUT:
876       self->field_layout = g_value_get_enum (value);
877       break;
878     case PROP_LOCKING:
879       self->locking = g_value_get_enum (value);
880       break;
881     case PROP_IGNORE_OBSCURE:
882       self->ignore_obscure = g_value_get_boolean (value);
883       break;
884     case PROP_DROP_ORPHANS:
885       self->drop_orphans = g_value_get_boolean (value);
886       break;
887     default:
888       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
889   }
890
891 }
892
893 static void
894 gst_deinterlace_get_property (GObject * object, guint prop_id,
895     GValue * value, GParamSpec * pspec)
896 {
897   GstDeinterlace *self;
898
899   self = GST_DEINTERLACE (object);
900
901   switch (prop_id) {
902     case PROP_MODE:
903       g_value_set_enum (value, self->mode);
904       break;
905     case PROP_METHOD:
906       g_value_set_enum (value, self->user_set_method_id);
907       break;
908     case PROP_FIELDS:
909       g_value_set_enum (value, self->fields);
910       break;
911     case PROP_FIELD_LAYOUT:
912       g_value_set_enum (value, self->field_layout);
913       break;
914     case PROP_LOCKING:
915       g_value_set_enum (value, self->locking);
916       break;
917     case PROP_IGNORE_OBSCURE:
918       g_value_set_boolean (value, self->ignore_obscure);
919       break;
920     case PROP_DROP_ORPHANS:
921       g_value_set_boolean (value, self->drop_orphans);
922       break;
923     default:
924       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
925   }
926 }
927
928 static void
929 gst_deinterlace_finalize (GObject * object)
930 {
931   GstDeinterlace *self = GST_DEINTERLACE (object);
932
933   gst_deinterlace_reset (self);
934
935   if (self->method) {
936     gst_object_unparent (GST_OBJECT (self->method));
937     self->method = NULL;
938   }
939
940   G_OBJECT_CLASS (parent_class)->finalize (object);
941 }
942
943 static void
944 gst_deinterlace_update_pattern_timestamps (GstDeinterlace * self)
945 {
946   gint state_idx;
947   if (self->low_latency) {
948     /* in low-latency mode the buffer state history contains old buffer
949      * states as well as the current one and perhaps some future ones.
950      * the current buffer's state is given by the number of field pairs
951      * rounded up, minus 1. the below is equivalent */
952     state_idx = (self->history_count - 1) >> 1;
953   } else {
954     /* in high-latency mode state_count - 1 is the current buffer's state */
955     state_idx = self->state_count - 1;
956   }
957
958   self->pattern_base_ts = self->buf_states[state_idx].timestamp;
959   if (self->buf_states[state_idx].state != GST_RFF) {
960     self->pattern_buf_dur =
961         (self->buf_states[state_idx].duration *
962         telecine_patterns[self->pattern].ratio_d) /
963         telecine_patterns[self->pattern].ratio_n;
964   } else {
965     self->pattern_buf_dur =
966         (self->buf_states[state_idx].duration *
967         telecine_patterns[self->pattern].ratio_d * 2) /
968         (telecine_patterns[self->pattern].ratio_n * 3);
969   }
970   GST_DEBUG_OBJECT (self,
971       "Starting a new pattern repeat with base ts %" GST_TIME_FORMAT
972       " and dur %" GST_TIME_FORMAT, GST_TIME_ARGS (self->pattern_base_ts),
973       GST_TIME_ARGS (self->pattern_buf_dur));
974 }
975
976 static GstVideoFrame *
977 gst_deinterlace_pop_history (GstDeinterlace * self)
978 {
979   GstVideoFrame *frame;
980
981   g_return_val_if_fail (self->history_count > 0, NULL);
982
983   GST_DEBUG_OBJECT (self, "Pop last history frame -- current history size %d",
984       self->history_count);
985
986   frame = self->field_history[self->history_count - 1].frame;
987
988   self->history_count--;
989   if (self->locking != GST_DEINTERLACE_LOCKING_NONE && (!self->history_count
990           || GST_VIDEO_FRAME_PLANE_DATA (frame, 0) !=
991           GST_VIDEO_FRAME_PLANE_DATA (self->field_history[self->history_count -
992                   1].frame, 0))) {
993     if (!self->low_latency)
994       self->state_count--;
995     if (self->pattern_lock) {
996       self->pattern_count++;
997       if (self->pattern != -1
998           && self->pattern_count >= telecine_patterns[self->pattern].length) {
999         self->pattern_count = 0;
1000         self->output_count = 0;
1001       }
1002     }
1003   }
1004
1005   GST_DEBUG_OBJECT (self, "Returning frame: %p %" GST_TIME_FORMAT
1006       " with duration %" GST_TIME_FORMAT " and size %" G_GSIZE_FORMAT, frame,
1007       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (frame->buffer)),
1008       GST_TIME_ARGS (GST_BUFFER_DURATION (frame->buffer)),
1009       GST_VIDEO_FRAME_SIZE (frame));
1010
1011   return frame;
1012 }
1013
1014 static void
1015 gst_deinterlace_get_buffer_state (GstDeinterlace * self, GstVideoFrame * frame,
1016     guint8 * state, GstVideoInterlaceMode * i_mode)
1017 {
1018   GstVideoInterlaceMode interlacing_mode;
1019
1020   if (!(i_mode || state))
1021     return;
1022
1023   interlacing_mode = GST_VIDEO_INFO_INTERLACE_MODE (&frame->info);
1024   if (self->mode == GST_DEINTERLACE_MODE_INTERLACED)
1025     interlacing_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
1026
1027   if (state) {
1028     if (interlacing_mode == GST_VIDEO_INTERLACE_MODE_MIXED) {
1029       if (GST_VIDEO_FRAME_IS_RFF (frame)) {
1030         *state = GST_DEINTERLACE_BUFFER_STATE_RFF;
1031       } else if (GST_VIDEO_FRAME_IS_ONEFIELD (frame)) {
1032         /* tc top if tff, tc bottom otherwise */
1033         if (GST_VIDEO_FRAME_IS_TFF (frame)) {
1034           *state = GST_DEINTERLACE_BUFFER_STATE_TC_T;
1035         } else {
1036           *state = GST_DEINTERLACE_BUFFER_STATE_TC_B;
1037         }
1038       } else if (GST_VIDEO_FRAME_IS_INTERLACED (frame)) {
1039         *state = GST_DEINTERLACE_BUFFER_STATE_TC_M;
1040       } else {
1041         *state = GST_DEINTERLACE_BUFFER_STATE_TC_P;
1042       }
1043     } else {
1044       if (interlacing_mode == GST_VIDEO_INTERLACE_MODE_INTERLEAVED) {
1045         *state = GST_DEINTERLACE_BUFFER_STATE_I;
1046       } else {
1047         *state = GST_DEINTERLACE_BUFFER_STATE_P;
1048       }
1049     }
1050   }
1051
1052   if (i_mode)
1053     *i_mode = interlacing_mode;
1054 }
1055
1056 #define STATE_TO_STRING(s) ((s) == GST_DEINTERLACE_BUFFER_STATE_P ? "P" : \
1057   (s) == GST_DEINTERLACE_BUFFER_STATE_I ? "I" : \
1058   (s) == GST_DEINTERLACE_BUFFER_STATE_TC_B ? "B" : \
1059   (s) == GST_DEINTERLACE_BUFFER_STATE_TC_T ? "T" : \
1060   (s) == GST_DEINTERLACE_BUFFER_STATE_TC_P ? "TCP" : \
1061   (s) == GST_DEINTERLACE_BUFFER_STATE_TC_M ? "TCM" : "RFF")
1062
1063 #define MODE_TO_STRING(m) ((m) == GST_VIDEO_INTERLACE_MODE_MIXED ? "MIXED" : \
1064   (m) == GST_VIDEO_INTERLACE_MODE_INTERLEAVED ? "I" : \
1065   (m) == GST_VIDEO_INTERLACE_MODE_FIELDS ? "FIELDS" : "P")
1066
1067 static void
1068 gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer)
1069 {
1070   int i = 1;
1071   GstDeinterlaceFieldLayout field_layout = self->field_layout;
1072   gboolean tff;
1073   gboolean onefield;
1074   GstVideoFrame *frame = NULL;
1075   GstVideoFrame *field1, *field2 = NULL;
1076   guint fields_to_push;
1077   gint field1_flags, field2_flags;
1078   GstVideoInterlaceMode interlacing_mode;
1079   guint8 buf_state;
1080
1081   /* we will only read from this buffer and write into fresh output buffers
1082    * if this is not the case, change the map flags as appropriate
1083    */
1084   frame = gst_video_frame_new_and_map (&self->vinfo, buffer, GST_MAP_READ);
1085   /* we can manage the buffer ref count using the maps from here on */
1086   gst_buffer_unref (buffer);
1087
1088   tff = GST_VIDEO_FRAME_IS_TFF (frame);
1089   onefield = GST_VIDEO_FRAME_IS_ONEFIELD (frame);
1090   fields_to_push = (onefield) ? 1 : 2;
1091
1092   g_return_if_fail (self->history_count <
1093       GST_DEINTERLACE_MAX_FIELD_HISTORY - fields_to_push);
1094
1095   gst_deinterlace_get_buffer_state (self, frame, &buf_state, &interlacing_mode);
1096
1097   GST_DEBUG_OBJECT (self,
1098       "Pushing new frame as %d fields to the history (count before %d): ptr %p at %"
1099       GST_TIME_FORMAT " with duration %" GST_TIME_FORMAT
1100       ", size %" G_GSIZE_FORMAT ", state %s, interlacing mode %s",
1101       fields_to_push, self->history_count, frame,
1102       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
1103       GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
1104       gst_buffer_get_size (buffer),
1105       STATE_TO_STRING (buf_state), MODE_TO_STRING (interlacing_mode));
1106
1107   /* move up for new state */
1108   memmove (&self->buf_states[1], &self->buf_states[0],
1109       (GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY - 1) *
1110       sizeof (GstDeinterlaceBufferState));
1111   self->buf_states[0].state = buf_state;
1112   self->buf_states[0].timestamp = GST_BUFFER_TIMESTAMP (buffer);
1113   self->buf_states[0].duration = GST_BUFFER_DURATION (buffer);
1114   if (self->state_count < GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY)
1115     self->state_count++;
1116
1117   for (i = GST_DEINTERLACE_MAX_FIELD_HISTORY - 1; i >= fields_to_push; i--) {
1118     self->field_history[i].frame =
1119         self->field_history[i - fields_to_push].frame;
1120     self->field_history[i].flags =
1121         self->field_history[i - fields_to_push].flags;
1122   }
1123
1124   if (field_layout == GST_DEINTERLACE_LAYOUT_AUTO) {
1125     if (!GST_VIDEO_INFO_IS_INTERLACED (&self->vinfo)) {
1126       GST_WARNING_OBJECT (self, "Can't detect field layout -- assuming TFF");
1127       field_layout = GST_DEINTERLACE_LAYOUT_TFF;
1128     } else if (tff) {
1129       field_layout = GST_DEINTERLACE_LAYOUT_TFF;
1130     } else {
1131       field_layout = GST_DEINTERLACE_LAYOUT_BFF;
1132     }
1133   }
1134
1135   field1 = frame;
1136   field2 = gst_video_frame_new_and_map (&self->vinfo, buffer, GST_MAP_READ);
1137   if (field_layout == GST_DEINTERLACE_LAYOUT_TFF) {
1138     GST_DEBUG_OBJECT (self, "Top field first");
1139     field1_flags = PICTURE_INTERLACED_TOP;
1140     field2_flags = PICTURE_INTERLACED_BOTTOM;
1141   } else {
1142     GST_DEBUG_OBJECT (self, "Bottom field first");
1143     field1_flags = PICTURE_INTERLACED_BOTTOM;
1144     field2_flags = PICTURE_INTERLACED_TOP;
1145   }
1146
1147   if (!onefield) {
1148     GST_DEBUG_OBJECT (self, "Two fields");
1149     self->field_history[1].frame = field1;
1150     self->field_history[1].flags = field1_flags;
1151
1152     self->field_history[0].frame = field2;
1153     self->field_history[0].flags = field2_flags;
1154   } else {                      /* onefield */
1155     GST_DEBUG_OBJECT (self, "One field");
1156     self->field_history[0].frame = field1;
1157     self->field_history[0].flags = field1_flags;
1158     gst_video_frame_unmap_and_free (field2);
1159   }
1160
1161   self->history_count += fields_to_push;
1162   self->cur_field_idx += fields_to_push;
1163
1164   GST_DEBUG_OBJECT (self, "Pushed buffer -- current history size %d, index %d",
1165       self->history_count, self->cur_field_idx);
1166
1167   if (self->last_buffer)
1168     gst_buffer_unref (self->last_buffer);
1169   self->last_buffer = gst_buffer_ref (buffer);
1170 }
1171
1172 static void
1173 gst_deinterlace_update_qos (GstDeinterlace * self, gdouble proportion,
1174     GstClockTimeDiff diff, GstClockTime timestamp)
1175 {
1176   GST_DEBUG_OBJECT (self,
1177       "Updating QoS: proportion %lf, diff %" GST_STIME_FORMAT ", timestamp %"
1178       GST_TIME_FORMAT, proportion, GST_STIME_ARGS (diff),
1179       GST_TIME_ARGS (timestamp));
1180
1181   GST_OBJECT_LOCK (self);
1182   self->proportion = proportion;
1183   if (G_LIKELY (timestamp != GST_CLOCK_TIME_NONE)) {
1184     if (G_UNLIKELY (diff > 0))
1185       self->earliest_time =
1186           timestamp + 2 * diff + ((self->fields ==
1187               GST_DEINTERLACE_ALL) ? self->field_duration : 2 *
1188           self->field_duration);
1189     else
1190       self->earliest_time = timestamp + diff;
1191   } else {
1192     self->earliest_time = GST_CLOCK_TIME_NONE;
1193   }
1194   GST_OBJECT_UNLOCK (self);
1195 }
1196
1197 static void
1198 gst_deinterlace_reset_qos (GstDeinterlace * self)
1199 {
1200   gst_deinterlace_update_qos (self, 0.5, 0, GST_CLOCK_TIME_NONE);
1201   self->processed = 0;
1202   self->dropped = 0;
1203 }
1204
1205 static void
1206 gst_deinterlace_read_qos (GstDeinterlace * self, gdouble * proportion,
1207     GstClockTime * time)
1208 {
1209   GST_OBJECT_LOCK (self);
1210   *proportion = self->proportion;
1211   *time = self->earliest_time;
1212   GST_OBJECT_UNLOCK (self);
1213 }
1214
1215 /* Perform qos calculations before processing the next frame. Returns TRUE if
1216  * the frame should be processed, FALSE if the frame can be dropped entirely */
1217 static gboolean
1218 gst_deinterlace_do_qos (GstDeinterlace * self, const GstBuffer * buffer)
1219 {
1220   GstClockTime qostime, earliest_time;
1221   GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
1222   gdouble proportion;
1223
1224   /* no timestamp, can't do QoS => process frame */
1225   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) {
1226     GST_LOG_OBJECT (self, "invalid timestamp, can't do QoS, process frame");
1227     goto keep_frame;
1228   }
1229
1230   /* get latest QoS observation values */
1231   gst_deinterlace_read_qos (self, &proportion, &earliest_time);
1232
1233   /* skip qos if we have no observation (yet) => process frame */
1234   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) {
1235     GST_LOG_OBJECT (self, "no observation yet, process frame");
1236     goto keep_frame;
1237   }
1238
1239   /* qos is done on running time */
1240   qostime = gst_segment_to_running_time (&self->segment, GST_FORMAT_TIME,
1241       timestamp);
1242
1243   /* see how our next timestamp relates to the latest qos timestamp */
1244   GST_LOG_OBJECT (self, "qostime %" GST_TIME_FORMAT ", earliest %"
1245       GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
1246
1247   if (qostime != GST_CLOCK_TIME_NONE && qostime <= earliest_time) {
1248     GstClockTime stream_time, jitter;
1249     GstMessage *qos_msg;
1250
1251     GST_DEBUG_OBJECT (self, "we are late, drop frame");
1252     self->dropped++;
1253     stream_time =
1254         gst_segment_to_stream_time (&self->segment, GST_FORMAT_TIME, timestamp);
1255     jitter = GST_CLOCK_DIFF (qostime, earliest_time);
1256     qos_msg =
1257         gst_message_new_qos (GST_OBJECT (self), FALSE, qostime, stream_time,
1258         timestamp, GST_BUFFER_DURATION (buffer));
1259     gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000);
1260     gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS,
1261         self->processed, self->dropped);
1262     gst_element_post_message (GST_ELEMENT (self), qos_msg);
1263     return FALSE;
1264   }
1265
1266   GST_LOG_OBJECT (self, "process frame");
1267 keep_frame:
1268   self->processed++;
1269   return TRUE;
1270 }
1271
1272 static gboolean
1273 gst_deinterlace_fix_timestamps (GstDeinterlace * self,
1274     GstVideoFrame * field1, GstVideoFrame * field2)
1275 {
1276   GstVideoFrame *field3, *field4;
1277   GstVideoInterlaceMode interlacing_mode;
1278
1279   if (self->pattern_lock && self->pattern > -1) {
1280     /* accurate pattern-locked timestamp adjustment */
1281     if (!self->pattern_count)
1282       gst_deinterlace_update_pattern_timestamps (self);
1283
1284     GST_BUFFER_TIMESTAMP (field1->buffer) =
1285         self->pattern_base_ts + self->output_count * self->pattern_buf_dur;
1286     GST_BUFFER_DURATION (field1->buffer) = self->pattern_buf_dur;
1287     self->output_count++;
1288   } else {
1289     /* naive (but low-latency) timestamp adjustment based on subsequent
1290      * fields/buffers */
1291     if (field2
1292         && GST_VIDEO_FRAME_PLANE_DATA (field1,
1293             0) != GST_VIDEO_FRAME_PLANE_DATA (field2, 0)) {
1294       if (GST_BUFFER_TIMESTAMP (field1->buffer) +
1295           GST_BUFFER_DURATION (field1->buffer) ==
1296           GST_BUFFER_TIMESTAMP (field2->buffer)) {
1297         GST_BUFFER_TIMESTAMP (field1->buffer) =
1298             GST_BUFFER_TIMESTAMP (field2->buffer) =
1299             (GST_BUFFER_TIMESTAMP (field1->buffer) +
1300             GST_BUFFER_TIMESTAMP (field2->buffer)) / 2;
1301       } else {
1302         GST_BUFFER_TIMESTAMP (field2->buffer) =
1303             GST_BUFFER_TIMESTAMP (field1->buffer);
1304       }
1305     }
1306
1307     if (self->history_count < 3) {
1308       GST_DEBUG_OBJECT (self, "Need more fields (have %d, need 3)",
1309           self->history_count);
1310       return FALSE;
1311     }
1312
1313     field3 = self->field_history[self->history_count - 3].frame;
1314     interlacing_mode = GST_VIDEO_INFO_INTERLACE_MODE (&field3->info);
1315     if (IS_TELECINE (interlacing_mode)) {
1316       if (self->history_count < 4) {
1317         GST_DEBUG_OBJECT (self, "Need more fields (have %d, need 4)",
1318             self->history_count);
1319         return FALSE;
1320       }
1321
1322       field4 = self->field_history[self->history_count - 4].frame;
1323       if (GST_VIDEO_FRAME_PLANE_DATA (field3,
1324               0) != GST_VIDEO_FRAME_PLANE_DATA (field4, 0)) {
1325         /* telecine fields in separate buffers */
1326         GST_BUFFER_TIMESTAMP (field3->buffer) =
1327             (GST_BUFFER_TIMESTAMP (field3->buffer) +
1328             GST_BUFFER_TIMESTAMP (field4->buffer)) / 2;
1329       }
1330     }
1331
1332     GST_BUFFER_DURATION (field1->buffer) =
1333         GST_BUFFER_TIMESTAMP (field3->buffer) -
1334         GST_BUFFER_TIMESTAMP (field1->buffer);
1335   }
1336
1337   GST_DEBUG_OBJECT (self,
1338       "Field 1 adjusted to ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT,
1339       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1->buffer)),
1340       GST_TIME_ARGS (GST_BUFFER_DURATION (field1->buffer)));
1341   return TRUE;
1342 }
1343
1344 static void
1345 gst_deinterlace_get_pattern_lock (GstDeinterlace * self, gboolean * flush_one)
1346 {
1347   /* loop over all possible patterns and all possible phases
1348    * giving each a score. the highest score gets the lock */
1349   /* the score is calculated as the number of matched buffers in the
1350    * sequence starting at the phase offset with those from the history
1351    * then the longest duration pattern match is taken. if there is more than
1352    * one pattern matching all buffers, we take the longest pattern of those.
1353    * matches to complete patterns are preferred. if no non-trivial pattern is
1354    * matched, trivial patterns are tested. */
1355   gint i, j, k, score, pattern, phase;
1356   const gint state_count = self->state_count;
1357   const gint n_required = self->ignore_obscure ?
1358       GST_DEINTERLACE_OBSCURE_THRESHOLD :
1359       GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY;
1360
1361   /* set unknown pattern as this is used in logic outside this function */
1362   self->pattern = -1;
1363
1364   /* wait for more buffers */
1365   if (!self->have_eos && state_count < n_required) {
1366     GST_DEBUG_OBJECT (self, "Need more buffers in state history - %d/%d",
1367         state_count, n_required);
1368     return;
1369   }
1370
1371   score = pattern = phase = -1;
1372
1373   /* loop over all patterns */
1374   for (i = 0; i < G_N_ELEMENTS (telecine_patterns); i++) {
1375     const guint8 length = telecine_patterns[i].length;
1376
1377     if (self->ignore_obscure && i >= GST_DEINTERLACE_OBSCURE_THRESHOLD)
1378       break;
1379
1380     if (state_count < length)
1381       continue;
1382
1383     /* loop over all phases */
1384     for (j = 0; j < length; j++) {
1385       /* low-latency mode looks at past buffers, high latency at future buffers */
1386       const gint state_idx =
1387           self->low_latency ? (self->history_count - 1) >> 1 : state_count - 1;
1388       /* loop over history, breaking on differing buffer states */
1389       for (k = 0; k < length && k < state_count; k++) {
1390         const guint8 hist = self->buf_states[state_idx - k].state;
1391         const guint8 patt = telecine_patterns[i].states[(j + k) % length];
1392         if (!(hist & patt))
1393           break;
1394       }
1395
1396       /* make complete matches more signficant */
1397       if (k == length)
1398         k += GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY;
1399
1400       /* take as new best pattern if the number of matched buffers is more than
1401        * for other patterns */
1402       if (k > score) {
1403         score = k;
1404         pattern = i;
1405         phase = j;
1406       }
1407     }
1408   }
1409
1410   if (pattern < 0) {
1411     GST_WARNING_OBJECT (self, "Failed to select a pattern");
1412     return;
1413   }
1414
1415   GST_DEBUG_OBJECT (self,
1416       "Final pattern match result: pa %d, ph %d, l %d, s %d", pattern, phase,
1417       telecine_patterns[pattern].length, score);
1418   self->pattern = pattern;
1419   self->pattern_phase = phase;
1420   self->pattern_count = 0;
1421   self->output_count = 0;
1422   self->pattern_lock = TRUE;
1423
1424   for (i = 0; i < telecine_patterns[pattern].length; i++) {
1425     gint state_idx =
1426         self->low_latency ? (self->history_count - 1) >> 1 : self->state_count -
1427         1;
1428     state_idx -= i;
1429     GST_LOG_OBJECT (self, "buf[%d] %s", i,
1430         STATE_TO_STRING (self->buf_states[state_idx].state));
1431   }
1432
1433   /* check for the case that the first field of the pattern is an orphan */
1434   if (pattern > 1
1435       && telecine_patterns[pattern].states[phase] & (GST_ONE | GST_INT)) {
1436     gint i = phase, field_count = 0;
1437     guint8 state = telecine_patterns[pattern].states[i];
1438
1439     do {
1440       if (state & GST_ONE) {
1441         field_count++;
1442 #if 0
1443       } else if (!(state & GST_DRP)) {
1444 #endif
1445       } else {
1446         field_count += 2;
1447       }
1448       i++;
1449       i %= telecine_patterns[pattern].length;
1450       state = telecine_patterns[pattern].states[i];
1451     } while (!(state & GST_PRG));
1452
1453     /* if field_count is odd, we have an orphan field at the beginning of the
1454      * sequence
1455      * note - don't do this in low-latency mode as we are somewhere within the
1456      * pattern already */
1457     if (!self->low_latency && (*flush_one = field_count & 1)) {
1458       GST_DEBUG_OBJECT (self, "Orphan field detected at the beginning of the "
1459           "pattern - it will be deinterlaced.");
1460     }
1461   }
1462 }
1463
1464 static GstFlowReturn
1465 gst_deinterlace_output_frame (GstDeinterlace * self, gboolean flushing)
1466 {
1467   GstClockTime timestamp;
1468   GstFlowReturn ret;
1469   gint fields_required;
1470   GstBuffer *buf, *outbuf;
1471   GstVideoFrame *outframe = NULL;
1472   GstDeinterlaceField *field1, *field2;
1473   GstVideoInterlaceMode interlacing_mode;
1474   guint8 buf_state;
1475   gboolean hl_no_lock;          /* indicates high latency timestamp adjustment but no pattern lock (could be ONEF or I) */
1476   gboolean same_buffer;         /* are field1 and field2 in the same buffer? */
1477   gboolean flush_one;           /* used for flushing one field when in high latency mode and not locked */
1478   TelecinePattern pattern;
1479   guint8 phase, count;
1480   const GstDeinterlaceLocking locking = self->locking;
1481
1482   memset (&pattern, 0, sizeof (pattern));
1483
1484 restart:
1485   ret = GST_FLOW_OK;
1486   hl_no_lock = FALSE;
1487   flush_one = FALSE;
1488   self->need_more = FALSE;
1489   phase = self->pattern_phase;
1490   count = self->pattern_count;
1491
1492   if (!self->history_count) {
1493     GST_DEBUG_OBJECT (self, "History is empty, waiting for more buffers!");
1494     goto need_more;
1495   }
1496
1497   field1 = &self->field_history[self->history_count - 1];
1498
1499   if (locking != GST_DEINTERLACE_LOCKING_NONE) {
1500     GstCaps *sinkcaps;
1501
1502     if (!self->state_count) {
1503       GST_ERROR_OBJECT (self,
1504           "BROKEN! Fields in history + no states should not happen!");
1505       return GST_FLOW_ERROR;
1506     }
1507
1508     gst_deinterlace_get_buffer_state (self, field1->frame, &buf_state,
1509         &interlacing_mode);
1510
1511     if (self->pattern != -1)
1512       pattern = telecine_patterns[self->pattern];
1513
1514     /* patterns 0 and 1 are interlaced, the rest are telecine */
1515     if (self->pattern > 1)
1516       interlacing_mode = GST_VIDEO_INTERLACE_MODE_MIXED;
1517
1518     if (self->pattern == -1 || self->pattern_refresh
1519         || !(buf_state & pattern.states[(phase + count) % pattern.length])) {
1520       if (self->pattern == -1) {
1521         GST_DEBUG_OBJECT (self, "No pattern lock - refresh lock");
1522       } else if (self->pattern_refresh) {
1523         GST_DEBUG_OBJECT (self, "Pattern refresh - refresh lock");
1524       } else {
1525         GST_DEBUG_OBJECT (self, "Unexpected buffer state - refresh lock");
1526       }
1527       /* no pattern, pattern refresh set or unexpected buffer state */
1528       self->pattern_lock = FALSE;
1529       self->pattern_refresh = TRUE;
1530
1531       /* refresh pattern lock */
1532       gst_deinterlace_get_pattern_lock (self, &flush_one);
1533
1534       if (self->pattern != -1) {
1535         /* locked onto a valid pattern so refresh complete */
1536         GST_DEBUG_OBJECT (self, "Pattern locked! %s starting at %d",
1537             telecine_patterns[self->pattern].nick, self->pattern_phase);
1538         self->pattern_refresh = FALSE;
1539       } else if (!self->low_latency) {
1540         if (!self->pattern_lock) {
1541           goto need_more;
1542         } else {
1543           hl_no_lock = TRUE;
1544         }
1545       }
1546
1547       /* setcaps on sink and src pads */
1548       sinkcaps = gst_pad_get_current_caps (self->sinkpad);
1549       if (!gst_deinterlace_setcaps (self, self->sinkpad, sinkcaps)) {
1550         gst_caps_unref (sinkcaps);
1551         return GST_FLOW_NOT_NEGOTIATED;
1552       }
1553
1554       gst_caps_unref (sinkcaps);
1555
1556       if (flush_one && self->drop_orphans) {
1557         GST_DEBUG_OBJECT (self, "Dropping orphan first field");
1558         self->cur_field_idx--;
1559         gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1560         goto restart;
1561       }
1562     }
1563   } else {
1564     gst_deinterlace_get_buffer_state (self, field1->frame, NULL,
1565         &interlacing_mode);
1566   }
1567
1568   same_buffer = self->history_count >= 2
1569       && (GST_VIDEO_FRAME_PLANE_DATA (field1->frame, 0) ==
1570       GST_VIDEO_FRAME_PLANE_DATA (self->field_history[self->history_count -
1571               2].frame, 0));
1572
1573   if ((flushing && self->history_count == 1) || (flush_one
1574           && !self->drop_orphans) || (hl_no_lock && (self->history_count == 1
1575               || !same_buffer))) {
1576     /* This case is for flushing a single field:
1577      * - flushing and 1 field in the history
1578      * - flush one (due to orphans in the pattern) and do not drop orphans
1579      * - high-latency pattern locking with no possible lock given the current
1580      *   state and either only one field in the history or the tip two fields
1581      *   are in separate buffers */
1582     GST_DEBUG_OBJECT (self, "Flushing one field using linear method");
1583     gst_deinterlace_set_method (self, GST_DEINTERLACE_LINEAR);
1584     fields_required = gst_deinterlace_method_get_fields_required (self->method);
1585   } else if (interlacing_mode == GST_VIDEO_INTERLACE_MODE_PROGRESSIVE ||
1586       (interlacing_mode == GST_VIDEO_INTERLACE_MODE_MIXED &&
1587           !GST_VIDEO_FRAME_IS_INTERLACED (field1->frame))) {
1588     /* This case is for processing progressive buffers, telecine or plain
1589      * progressive */
1590     GstVideoFrame *field1_frame;
1591     GstBuffer *field1_buffer;
1592
1593     /* progressive */
1594     fields_required = 2;
1595
1596     /* Not enough fields in the history */
1597     if (!flushing && self->history_count < fields_required) {
1598       GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
1599           self->history_count, self->cur_field_idx + fields_required);
1600       goto need_more;
1601     }
1602
1603     field2 = &self->field_history[self->history_count - 2];
1604     if (GST_VIDEO_FRAME_PLANE_DATA (field1->frame,
1605             0) != GST_VIDEO_FRAME_PLANE_DATA (field2->frame, 0)) {
1606       /* ERROR - next two fields in field history are not one progressive buffer - weave? */
1607       GST_ERROR_OBJECT (self,
1608           "Progressive buffer but two fields at tip aren't in the same buffer!");
1609     }
1610
1611     if (IS_TELECINE (interlacing_mode)
1612         && !gst_deinterlace_fix_timestamps (self, field1->frame, field2->frame)
1613         && !flushing)
1614       goto need_more;
1615
1616     GST_DEBUG_OBJECT (self,
1617         "Frame type: Progressive; pushing buffer as a frame");
1618     /* pop and push */
1619     self->cur_field_idx--;
1620     field1_frame = gst_deinterlace_pop_history (self);
1621     field1_buffer = field1_frame->buffer;
1622     gst_buffer_ref (field1_buffer);
1623     gst_video_frame_unmap_and_free (field1_frame);
1624     /* field2 is the same buffer as field1, but we need to remove it from the
1625      * history anyway */
1626     self->cur_field_idx--;
1627     gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1628     GST_DEBUG_OBJECT (self,
1629         "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1630         GST_TIME_FORMAT,
1631         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buffer)),
1632         GST_TIME_ARGS (GST_BUFFER_DURATION (field1_buffer)),
1633         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buffer) +
1634             GST_BUFFER_DURATION (field1_buffer)));
1635     return gst_pad_push (self->srcpad, field1_buffer);
1636   } else if (IS_TELECINE (interlacing_mode)
1637       && GST_VIDEO_FRAME_IS_INTERLACED (field1->frame) && !same_buffer) {
1638     /* This case needs to identify telecine mixed buffers that require weaving
1639      * of two fields in different buffers.
1640      * - interlacing mode is mixed
1641      * - locked on to a telecine pattern
1642      * - frame is interlaced
1643      * - fields are in separate buffers
1644      * If we don't yet have a pattern lock, we will have to deinterlace as we
1645      * don't explicitly know we have a telecine sequence and so we drop through
1646      * to the plain deinterlace case */
1647     fields_required = 2;
1648     if (!flushing && self->history_count < fields_required) {
1649       GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
1650           self->history_count, self->cur_field_idx + fields_required);
1651       goto need_more;
1652     }
1653
1654     field2 = &self->field_history[self->history_count - 2];
1655     if (!gst_deinterlace_fix_timestamps (self, field1->frame, field2->frame)
1656         && !flushing)
1657       goto need_more;
1658
1659     /* check field1 and field2 buffer caps and flags are corresponding */
1660     if (field1->flags == field2->flags) {
1661       /* ERROR - fields are of same parity - what should be done here?
1662        * perhaps deinterlace the tip field and start again? */
1663       GST_ERROR_OBJECT (self, "Telecine mixed with fields of same parity!");
1664     }
1665     GST_DEBUG_OBJECT (self,
1666         "Frame type: Telecine Mixed; weaving tip two fields into a frame");
1667     /* set method to WEAVE */
1668     gst_deinterlace_set_method (self, GST_DEINTERLACE_WEAVE);
1669   } else {
1670     /* This is the final catch-all case that applies the selected deinterlacing
1671      * method. At this point the fields to be processed are either definitely
1672      * interlaced or we do not yet know that we have a telecine pattern lock
1673      * and so the best we can do is to deinterlace the fields. */
1674     gst_deinterlace_set_method (self, self->user_set_method_id);
1675     fields_required = gst_deinterlace_method_get_fields_required (self->method);
1676     if (flushing && self->history_count < fields_required) {
1677       /* note: we already checked for flushing with history count == 1 above
1678        * so we must have 2 or more fields in here */
1679       gst_deinterlace_set_method (self, GST_DEINTERLACE_VFIR);
1680       fields_required =
1681           gst_deinterlace_method_get_fields_required (self->method);
1682       GST_DEBUG_OBJECT (self, "Flushing field(s) using %s method",
1683           methods_types[self->method_id].value_nick);
1684     }
1685
1686     /* Not enough fields in the history */
1687     if (!flushing && self->history_count < fields_required) {
1688       GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
1689           self->history_count, self->cur_field_idx + fields_required);
1690       goto need_more;
1691     }
1692
1693     GST_DEBUG_OBJECT (self,
1694         "Frame type: Interlaced; deinterlacing using %s method",
1695         methods_types[self->method_id].value_nick);
1696   }
1697
1698   if (!flushing && self->cur_field_idx < 1) {
1699     goto need_more;
1700   } else if (self->cur_field_idx < 0 && flushing) {
1701     self->cur_field_idx++;
1702   }
1703
1704   if (self->fields == GST_DEINTERLACE_ALL || IS_TELECINE (interlacing_mode))
1705     GST_DEBUG_OBJECT (self, "All fields");
1706   else if (self->fields == GST_DEINTERLACE_TF)
1707     GST_DEBUG_OBJECT (self, "Top fields");
1708   else if (self->fields == GST_DEINTERLACE_BF)
1709     GST_DEBUG_OBJECT (self, "Bottom fields");
1710
1711   if ((self->field_history[self->cur_field_idx].flags == PICTURE_INTERLACED_TOP
1712           && (self->fields == GST_DEINTERLACE_TF
1713               || IS_TELECINE (interlacing_mode)))
1714       || (self->fields == GST_DEINTERLACE_ALL
1715           && !IS_TELECINE (interlacing_mode))) {
1716     GST_DEBUG_OBJECT (self, "deinterlacing top field");
1717
1718     /* create new buffer */
1719     ret = gst_buffer_pool_acquire_buffer (self->pool, &outbuf, NULL);
1720     if (ret != GST_FLOW_OK)
1721       goto no_buffer;
1722
1723     g_return_val_if_fail (self->history_count >=
1724         1 + gst_deinterlace_method_get_latency (self->method), GST_FLOW_ERROR);
1725
1726     buf =
1727         self->field_history[self->history_count - 1 -
1728         gst_deinterlace_method_get_latency (self->method)].frame->buffer;
1729
1730     if (!IS_TELECINE (interlacing_mode)) {
1731       timestamp = GST_BUFFER_TIMESTAMP (buf);
1732
1733       GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1734       if (self->fields == GST_DEINTERLACE_ALL)
1735         GST_BUFFER_DURATION (outbuf) = self->field_duration;
1736       else
1737         GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
1738       GST_DEBUG_OBJECT (self,
1739           "[ADJUST] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1740           GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1741           GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
1742           GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
1743               GST_BUFFER_DURATION (outbuf)));
1744     } else {
1745       GST_BUFFER_TIMESTAMP (outbuf) =
1746           GST_BUFFER_TIMESTAMP (field1->frame->buffer);
1747       GST_BUFFER_DURATION (outbuf) =
1748           GST_BUFFER_DURATION (field1->frame->buffer);
1749     }
1750
1751     /* Check if we need to drop the frame because of QoS */
1752     if (!gst_deinterlace_do_qos (self, buf)) {
1753       self->cur_field_idx--;
1754       gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1755       gst_buffer_unref (outbuf);
1756       outbuf = NULL;
1757       ret = GST_FLOW_OK;
1758     } else {
1759       if (self->cur_field_idx < 0 && flushing) {
1760         if (self->history_count == 1) {
1761           gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1762           goto need_more;
1763         }
1764         self->cur_field_idx++;
1765       }
1766       if (self->cur_field_idx < 0) {
1767         goto need_more;
1768       }
1769       if (!flushing && self->cur_field_idx < 1) {
1770         goto need_more;
1771       }
1772
1773       /* map the frame so the deinterlace methods can write the data to the
1774        * correct memory locations */
1775       outframe =
1776           gst_video_frame_new_and_map (&self->vinfo, outbuf, GST_MAP_WRITE);
1777
1778       /* do magic calculus */
1779       gst_deinterlace_method_deinterlace_frame (self->method,
1780           self->field_history, self->history_count, outframe,
1781           self->cur_field_idx);
1782
1783       gst_video_frame_unmap_and_free (outframe);
1784
1785       self->cur_field_idx--;
1786       /* need to remove the field in the telecine weaving case */
1787       if ((IS_TELECINE (interlacing_mode)
1788               && self->method_id == GST_DEINTERLACE_WEAVE)
1789           || self->cur_field_idx + 1 +
1790           gst_deinterlace_method_get_latency (self->method) <
1791           self->history_count || flushing) {
1792         gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1793       }
1794
1795       if (gst_deinterlace_clip_buffer (self, outbuf)) {
1796         GST_DEBUG_OBJECT (self,
1797             "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1798             GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1799             GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
1800             GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
1801                 GST_BUFFER_DURATION (outbuf)));
1802         ret = gst_pad_push (self->srcpad, outbuf);
1803       } else {
1804         ret = GST_FLOW_OK;
1805         gst_buffer_unref (outbuf);
1806       }
1807
1808       outbuf = NULL;
1809       if (ret != GST_FLOW_OK)
1810         return ret;
1811       if (IS_TELECINE (interlacing_mode)
1812           && self->method_id == GST_DEINTERLACE_WEAVE) {
1813         /* pop off the second field */
1814         GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
1815             self->history_count);
1816         self->cur_field_idx--;
1817         gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1818         interlacing_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
1819         return ret;
1820       }
1821     }
1822
1823     if (flush_one && !self->drop_orphans) {
1824       GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1825       goto restart;
1826     }
1827   }
1828   /* no calculation done: remove excess field */
1829   else if (self->field_history[self->cur_field_idx].flags ==
1830       PICTURE_INTERLACED_TOP && (self->fields == GST_DEINTERLACE_BF
1831           && !IS_TELECINE (interlacing_mode))) {
1832     GST_DEBUG_OBJECT (self, "Removing unused top field");
1833     self->cur_field_idx--;
1834     gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1835
1836     if (flush_one && !self->drop_orphans) {
1837       GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1838       goto restart;
1839     }
1840   }
1841
1842   if (self->history_count < fields_required)
1843     return ret;
1844
1845   if (self->cur_field_idx < 0)
1846     return ret;
1847
1848   /* deinterlace bottom_field */
1849   if ((self->field_history[self->cur_field_idx].flags ==
1850           PICTURE_INTERLACED_BOTTOM && (self->fields == GST_DEINTERLACE_BF
1851               || IS_TELECINE (interlacing_mode)))
1852       || (self->fields == GST_DEINTERLACE_ALL
1853           && !IS_TELECINE (interlacing_mode))) {
1854     GST_DEBUG_OBJECT (self, "deinterlacing bottom field");
1855
1856     /* create new buffer */
1857     ret = gst_buffer_pool_acquire_buffer (self->pool, &outbuf, NULL);
1858     if (ret != GST_FLOW_OK)
1859       goto no_buffer;
1860
1861     g_return_val_if_fail (self->history_count >=
1862         gst_deinterlace_method_get_latency (self->method) + 1, GST_FLOW_ERROR);
1863
1864     buf =
1865         self->field_history[self->history_count - 1 -
1866         gst_deinterlace_method_get_latency (self->method)].frame->buffer;
1867     if (!IS_TELECINE (interlacing_mode)) {
1868       timestamp = GST_BUFFER_TIMESTAMP (buf);
1869
1870       if (self->fields == GST_DEINTERLACE_ALL) {
1871         GST_BUFFER_TIMESTAMP (outbuf) = timestamp + self->field_duration;
1872         GST_BUFFER_DURATION (outbuf) = self->field_duration;
1873       } else {
1874         GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1875         GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
1876       }
1877       GST_DEBUG_OBJECT (self,
1878           "[ADJUST] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1879           GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1880           GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
1881           GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
1882               GST_BUFFER_DURATION (outbuf)));
1883     } else {
1884       GST_BUFFER_TIMESTAMP (outbuf) =
1885           GST_BUFFER_TIMESTAMP (field1->frame->buffer);
1886       GST_BUFFER_DURATION (outbuf) =
1887           GST_BUFFER_DURATION (field1->frame->buffer);
1888     }
1889
1890     /* Check if we need to drop the frame because of QoS */
1891     if (!gst_deinterlace_do_qos (self, buf)) {
1892       self->cur_field_idx--;
1893       gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1894       gst_buffer_unref (outbuf);
1895       outbuf = NULL;
1896       ret = GST_FLOW_OK;
1897     } else {
1898       /* map the frame so the deinterlace methods can write the data to the
1899        * correct memory locations */
1900       outframe =
1901           gst_video_frame_new_and_map (&self->vinfo, outbuf, GST_MAP_WRITE);
1902
1903       /* do magic calculus */
1904       gst_deinterlace_method_deinterlace_frame (self->method,
1905           self->field_history, self->history_count, outframe,
1906           self->cur_field_idx);
1907
1908       gst_video_frame_unmap_and_free (outframe);
1909
1910       self->cur_field_idx--;
1911       /* need to remove the field in the telecine weaving case */
1912       if ((IS_TELECINE (interlacing_mode)
1913               && self->method_id == GST_DEINTERLACE_WEAVE)
1914           || self->cur_field_idx + 1 +
1915           gst_deinterlace_method_get_latency (self->method) <
1916           self->history_count) {
1917         gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1918       }
1919
1920       if (gst_deinterlace_clip_buffer (self, outbuf)) {
1921         GST_DEBUG_OBJECT (self,
1922             "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1923             GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1924             GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
1925             GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
1926                 GST_BUFFER_DURATION (outbuf)));
1927         ret = gst_pad_push (self->srcpad, outbuf);
1928       } else {
1929         ret = GST_FLOW_OK;
1930         gst_buffer_unref (outbuf);
1931       }
1932
1933       outbuf = NULL;
1934       if (ret != GST_FLOW_OK)
1935         return ret;
1936       if (IS_TELECINE (interlacing_mode)
1937           && self->method_id == GST_DEINTERLACE_WEAVE) {
1938         /* pop off the second field */
1939         GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
1940             self->history_count);
1941         self->cur_field_idx--;
1942         gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1943         interlacing_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
1944         return ret;
1945       }
1946     }
1947
1948     if (flush_one && !self->drop_orphans) {
1949       GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1950       goto restart;
1951     }
1952   }
1953   /* no calculation done: remove excess field */
1954   else if (self->field_history[self->cur_field_idx].flags ==
1955       PICTURE_INTERLACED_BOTTOM && (self->fields == GST_DEINTERLACE_TF
1956           && !IS_TELECINE (interlacing_mode))) {
1957     GST_DEBUG_OBJECT (self, "Removing unused bottom field");
1958     self->cur_field_idx--;
1959     gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1960
1961     if (flush_one && !self->drop_orphans) {
1962       GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1963       goto restart;
1964     }
1965   }
1966
1967   return ret;
1968
1969 need_more:
1970   {
1971     self->need_more = TRUE;
1972     return ret;
1973   }
1974 no_buffer:
1975   {
1976     GST_DEBUG_OBJECT (self, "could not allocate buffer");
1977     return ret;
1978   }
1979 }
1980
1981 static gboolean
1982 gst_deinterlace_get_latency (GstDeinterlace * self)
1983 {
1984   if (self->locking == GST_DEINTERLACE_LOCKING_AUTO) {
1985     GstQuery *query;
1986
1987     query = gst_query_new_latency ();
1988     if ((gst_pad_peer_query (self->sinkpad, query))) {
1989       gboolean is_live;
1990       /* if upstream is live, we use low-latency passive locking mode
1991        * else high-latency active locking mode */
1992       gst_query_parse_latency (query, &is_live, NULL, NULL);
1993       GST_DEBUG_OBJECT (self, "Latency query indicates stream is %s",
1994           is_live ? "live - using passive locking" :
1995           "not live - using active locking");
1996       gst_query_unref (query);
1997       return is_live;
1998     } else {
1999       /* conservatively use passive locking if the query fails */
2000       GST_WARNING_OBJECT (self,
2001           "Latency query failed - fall back to using passive locking");
2002       gst_query_unref (query);
2003       return TRUE;
2004     }
2005   } else {
2006     return self->locking - 2;
2007   }
2008 }
2009
2010 static GstFlowReturn
2011 gst_deinterlace_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2012 {
2013   GstDeinterlace *self = GST_DEINTERLACE (parent);
2014   GstFlowReturn ret = GST_FLOW_OK;
2015
2016   GST_OBJECT_LOCK (self);
2017   if (self->reconfigure || gst_pad_check_reconfigure (self->srcpad)) {
2018     GstCaps *caps;
2019
2020     if ((gint) self->new_fields != -1)
2021       self->fields = self->new_fields;
2022     if ((gint) self->new_mode != -1)
2023       self->mode = self->new_mode;
2024     self->new_mode = -1;
2025     self->new_fields = -1;
2026
2027     self->reconfigure = FALSE;
2028     GST_OBJECT_UNLOCK (self);
2029     caps = gst_pad_get_current_caps (self->sinkpad);
2030     if (caps != NULL) {
2031       if (!gst_deinterlace_setcaps (self, self->sinkpad, caps)) {
2032         gst_caps_unref (caps);
2033         return GST_FLOW_NOT_NEGOTIATED;
2034       }
2035       gst_caps_unref (caps);
2036     } else {
2037       return GST_FLOW_FLUSHING;
2038     }
2039   } else {
2040     GST_OBJECT_UNLOCK (self);
2041   }
2042
2043   GST_DEBUG_OBJECT (self,
2044       "[IN] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
2045       GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
2046       GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
2047       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)));
2048
2049   if (self->still_frame_mode || self->passthrough) {
2050     GST_DEBUG_OBJECT (self,
2051         "Frame type: Progressive?; pushing buffer using pass-through");
2052     GST_DEBUG_OBJECT (self,
2053         "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
2054         GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
2055         GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
2056         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)));
2057
2058     return gst_pad_push (self->srcpad, buf);
2059   }
2060
2061   if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
2062     GST_DEBUG_OBJECT (self, "DISCONT buffer, resetting history");
2063     gst_deinterlace_reset_history (self, FALSE);
2064   }
2065
2066   gst_deinterlace_push_history (self, buf);
2067   buf = NULL;
2068
2069   do {
2070     ret = gst_deinterlace_output_frame (self, FALSE);
2071   } while (!self->need_more && self->history_count > 0 && ret == GST_FLOW_OK);
2072
2073   return ret;
2074 }
2075
2076 static gboolean
2077 gst_deinterlace_acceptcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps)
2078 {
2079   gboolean ret;
2080   GstCaps *ourcaps;
2081
2082   /* In AUTO/DISABLED mode we accept everything that is compatible with
2083    * our template caps. In INTERLACED mode we force deinterlacing, meaning
2084    * we can only possibly support the deinterlace caps.
2085    * In AUTO_STRICT mode we accept all progressive formats, but only those
2086    * interlaced format that we can actually deinterlace */
2087   if (self->mode == GST_DEINTERLACE_MODE_DISABLED
2088       || self->mode == GST_DEINTERLACE_MODE_AUTO) {
2089     ourcaps = gst_pad_get_pad_template_caps (pad);
2090     ret = gst_caps_can_intersect (caps, ourcaps);
2091     gst_caps_unref (ourcaps);
2092   } else if (self->mode == GST_DEINTERLACE_MODE_INTERLACED) {
2093     ourcaps = gst_static_caps_get (&deinterlace_caps);
2094     ret = gst_caps_can_intersect (caps, ourcaps);
2095     gst_caps_unref (ourcaps);
2096   } else if (self->mode == GST_DEINTERLACE_MODE_AUTO_STRICT) {
2097     ourcaps = gst_static_caps_get (&progressive_caps);
2098     ret = gst_caps_can_intersect (caps, ourcaps);
2099     gst_caps_unref (ourcaps);
2100
2101     if (!ret) {
2102       ourcaps = gst_static_caps_get (&deinterlace_caps);
2103       ret = gst_caps_can_intersect (caps, ourcaps);
2104       gst_caps_unref (ourcaps);
2105     }
2106   } else {
2107     g_assert_not_reached ();
2108   }
2109
2110   GST_DEBUG_OBJECT (pad, "accept-caps result:%d for caps %" GST_PTR_FORMAT,
2111       ret, caps);
2112
2113   return ret;
2114 }
2115
2116 static gboolean
2117 gst_deinterlace_fraction_double (gint * n_out, gint * d_out, gboolean half)
2118 {
2119   gint n, d, gcd;
2120
2121   n = *n_out;
2122   d = *d_out;
2123
2124   if (d == 0)
2125     return FALSE;
2126
2127   if (n == 0)
2128     return TRUE;
2129
2130   gcd = gst_util_greatest_common_divisor (n, d);
2131   n /= gcd;
2132   d /= gcd;
2133
2134   if (half) {
2135     if (G_MAXINT / 2 >= ABS (d)) {
2136       d *= 2;
2137     } else if (n >= 2 && n != G_MAXINT) {
2138       n /= 2;
2139     } else {
2140       d = G_MAXINT;
2141     }
2142   } else {
2143     if (G_MAXINT / 2 >= ABS (n)) {
2144       n *= 2;
2145     } else if (d >= 2 && d != G_MAXINT) {
2146       d /= 2;
2147     } else {
2148       n = G_MAXINT;
2149     }
2150   }
2151
2152   *n_out = n;
2153   *d_out = d;
2154
2155   return TRUE;
2156 }
2157
2158 static GstCaps *
2159 gst_deinterlace_caps_double_framerate (GstCaps * caps, gboolean half)
2160 {
2161   guint len;
2162
2163   for (len = gst_caps_get_size (caps); len > 0; len--) {
2164     GstStructure *s = gst_caps_get_structure (caps, len - 1);
2165     const GValue *val;
2166
2167     val = gst_structure_get_value (s, "framerate");
2168     if (!val)
2169       continue;
2170
2171     if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION) {
2172       gint n, d;
2173
2174       n = gst_value_get_fraction_numerator (val);
2175       d = gst_value_get_fraction_denominator (val);
2176
2177       if (!gst_deinterlace_fraction_double (&n, &d, half)) {
2178         gst_caps_remove_structure (caps, len - 1);
2179         continue;
2180       }
2181
2182       gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
2183     } else if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION_RANGE) {
2184       const GValue *min, *max;
2185       GValue nrange = { 0, }, nmin = {
2186       0,}, nmax = {
2187       0,};
2188       gint n, d;
2189
2190       g_value_init (&nrange, GST_TYPE_FRACTION_RANGE);
2191       g_value_init (&nmin, GST_TYPE_FRACTION);
2192       g_value_init (&nmax, GST_TYPE_FRACTION);
2193
2194       min = gst_value_get_fraction_range_min (val);
2195       max = gst_value_get_fraction_range_max (val);
2196
2197       n = gst_value_get_fraction_numerator (min);
2198       d = gst_value_get_fraction_denominator (min);
2199
2200       if (!gst_deinterlace_fraction_double (&n, &d, half)) {
2201         g_value_unset (&nrange);
2202         g_value_unset (&nmax);
2203         g_value_unset (&nmin);
2204         gst_caps_remove_structure (caps, len - 1);
2205         continue;
2206       }
2207
2208       gst_value_set_fraction (&nmin, n, d);
2209
2210       n = gst_value_get_fraction_numerator (max);
2211       d = gst_value_get_fraction_denominator (max);
2212
2213       if (!gst_deinterlace_fraction_double (&n, &d, half)) {
2214         g_value_unset (&nrange);
2215         g_value_unset (&nmax);
2216         g_value_unset (&nmin);
2217         gst_caps_remove_structure (caps, len - 1);
2218         continue;
2219       }
2220
2221       gst_value_set_fraction (&nmax, n, d);
2222       gst_value_set_fraction_range (&nrange, &nmin, &nmax);
2223
2224       gst_structure_take_value (s, "framerate", &nrange);
2225
2226       g_value_unset (&nmin);
2227       g_value_unset (&nmax);
2228     } else if (G_VALUE_TYPE (val) == GST_TYPE_LIST) {
2229       const GValue *lval;
2230       GValue nlist = { 0, };
2231       GValue nval = { 0, };
2232       gint i;
2233
2234       g_value_init (&nlist, GST_TYPE_LIST);
2235       for (i = gst_value_list_get_size (val); i > 0; i--) {
2236         gint n, d;
2237
2238         lval = gst_value_list_get_value (val, i - 1);
2239
2240         if (G_VALUE_TYPE (lval) != GST_TYPE_FRACTION)
2241           continue;
2242
2243         n = gst_value_get_fraction_numerator (lval);
2244         d = gst_value_get_fraction_denominator (lval);
2245
2246         /* Double/Half the framerate but if this fails simply
2247          * skip this value from the list */
2248         if (!gst_deinterlace_fraction_double (&n, &d, half)) {
2249           continue;
2250         }
2251
2252         g_value_init (&nval, GST_TYPE_FRACTION);
2253
2254         gst_value_set_fraction (&nval, n, d);
2255         gst_value_list_append_and_take_value (&nlist, &nval);
2256       }
2257       gst_structure_take_value (s, "framerate", &nlist);
2258     }
2259   }
2260
2261   return caps;
2262 }
2263
2264 static GstCaps *
2265 gst_deinterlace_getcaps (GstDeinterlace * self, GstPad * pad, GstCaps * filter)
2266 {
2267   GstCaps *ret, *caps;
2268   GstPad *otherpad;
2269   gint len;
2270   GstCaps *ourcaps;
2271   GstCaps *peercaps;
2272   GstCaps *tmp, *tmp2;
2273
2274   otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad;
2275
2276   ourcaps = gst_pad_get_pad_template_caps (pad);
2277   peercaps = gst_pad_peer_query_caps (otherpad, NULL);
2278
2279   /* Filter any peercaps that are available with our template
2280    * to get started with the subset of caps we actually support */
2281   if (peercaps) {
2282     GST_DEBUG_OBJECT (pad, "Peer has caps %" GST_PTR_FORMAT, peercaps);
2283     caps = gst_caps_make_writable (gst_caps_intersect (ourcaps, peercaps));
2284     gst_caps_unref (peercaps);
2285     gst_caps_unref (ourcaps);
2286     peercaps = ourcaps = NULL;
2287   } else {
2288     caps = gst_caps_make_writable (ourcaps);
2289     ourcaps = NULL;
2290   }
2291
2292   GST_DEBUG_OBJECT (pad,
2293       "Transforming caps %" GST_PTR_FORMAT " with filter %" GST_PTR_FORMAT,
2294       caps, filter);
2295
2296   /* If deinterlacing is disabled, we just passthrough the
2297    * caps and everything */
2298   if (self->mode == GST_DEINTERLACE_MODE_DISABLED) {
2299     ret = caps;
2300     caps = NULL;
2301     goto done;
2302   }
2303
2304   /* If deinterlacing is enforced, we can only accept the
2305    * caps for which we can actually do deinterlacing */
2306   if (self->mode == GST_DEINTERLACE_MODE_INTERLACED) {
2307     tmp = gst_static_caps_get (&deinterlace_caps);
2308     ret = gst_caps_intersect_full (caps, tmp, GST_CAPS_INTERSECT_FIRST);
2309     gst_caps_unref (tmp);
2310     tmp = NULL;
2311     gst_caps_unref (caps);
2312     caps = NULL;
2313     goto done;
2314   }
2315
2316   g_assert (self->mode == GST_DEINTERLACE_MODE_AUTO
2317       || self->mode == GST_DEINTERLACE_MODE_AUTO_STRICT);
2318
2319   /* For the auto mode we have to do a bit more than that */
2320   ret = gst_caps_new_empty ();
2321
2322   /* We can accept any structure if
2323    * - they are progressive already
2324    *
2325    */
2326   tmp = gst_static_caps_get (&progressive_caps);
2327   tmp2 = gst_caps_intersect_full (caps, tmp, GST_CAPS_INTERSECT_FIRST);
2328   gst_caps_unref (tmp);
2329   tmp = NULL;
2330   ret = gst_caps_merge (ret, tmp2);
2331   tmp2 = NULL;
2332
2333   /* or
2334    * - they have sysmem caps features and a format for which we support
2335    *   deinterlacing
2336    * or
2337    * - they have ANY caps features, in which case we support it for
2338    *   sysmem caps features for formats we support
2339    *
2340    * NOTE: These are the caps where we actually would do deinterlacing
2341    * ourselves. If fields == ALL we would double the framerate so would
2342    * have to half the framerate constraints from downstream here
2343    */
2344   tmp = gst_static_caps_get (&deinterlace_caps);
2345   tmp2 = gst_caps_intersect_full (caps, tmp, GST_CAPS_INTERSECT_FIRST);
2346   gst_caps_unref (tmp);
2347   tmp = NULL;
2348
2349   for (len = gst_caps_get_size (caps); len > 0; len--) {
2350     GstStructure *s = gst_caps_get_structure (caps, len - 1);
2351
2352     if (pad == self->sinkpad)
2353       gst_structure_remove_field (s, "interlace-mode");
2354     else
2355       gst_structure_set (s, "interlace-mode", G_TYPE_STRING, "progressive",
2356           NULL);
2357   }
2358
2359   if (self->fields == GST_DEINTERLACE_ALL) {
2360     tmp2 = gst_deinterlace_caps_double_framerate (tmp2, (pad == self->sinkpad));
2361   }
2362
2363   ret = gst_caps_merge (ret, tmp2);
2364   tmp2 = NULL;
2365
2366   /* or
2367    * - anything else in which case we would just passthrough again if we're
2368    *   only in AUTO and not AUTO_STRICT mode
2369    */
2370   if (self->mode == GST_DEINTERLACE_MODE_AUTO)
2371     ret = gst_caps_merge (ret, gst_caps_copy (caps));
2372
2373   gst_caps_unref (caps);
2374   caps = NULL;
2375
2376 done:
2377
2378   if (filter) {
2379     GstCaps *tmp;
2380
2381     GST_LOG_OBJECT (pad, "intersecting with %" GST_PTR_FORMAT, filter);
2382     tmp = gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
2383     gst_caps_unref (ret);
2384     ret = tmp;
2385   }
2386
2387   GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret);
2388
2389   return ret;
2390 }
2391
2392 /* takes ownership of the pool, allocator and query */
2393 static gboolean
2394 gst_deinterlace_set_allocation (GstDeinterlace * self,
2395     GstBufferPool * pool, GstAllocator * allocator,
2396     GstAllocationParams * params)
2397 {
2398   GstAllocator *oldalloc;
2399   GstBufferPool *oldpool;
2400
2401   GST_OBJECT_LOCK (self);
2402   oldpool = self->pool;
2403   self->pool = pool;
2404
2405   oldalloc = self->allocator;
2406   self->allocator = allocator;
2407
2408   if (params)
2409     self->params = *params;
2410   else
2411     gst_allocation_params_init (&self->params);
2412   GST_OBJECT_UNLOCK (self);
2413
2414   if (oldpool) {
2415     GST_DEBUG_OBJECT (self, "deactivating old pool %p", oldpool);
2416     gst_buffer_pool_set_active (oldpool, FALSE);
2417     gst_object_unref (oldpool);
2418   }
2419   if (oldalloc) {
2420     gst_object_unref (oldalloc);
2421   }
2422   if (pool) {
2423     GST_DEBUG_OBJECT (self, "activating new pool %p", pool);
2424     gst_buffer_pool_set_active (pool, TRUE);
2425   }
2426   return TRUE;
2427 }
2428
2429 static gboolean
2430 gst_deinterlace_do_bufferpool (GstDeinterlace * self, GstCaps * outcaps)
2431 {
2432   GstQuery *query;
2433   gboolean result = TRUE;
2434   GstBufferPool *pool;
2435   GstAllocator *allocator;
2436   GstAllocationParams params;
2437   GstStructure *config;
2438   guint size, min, max;
2439
2440   if (self->passthrough) {
2441     /* we are in passthrough, the input buffer is never copied and always passed
2442      * along. We never allocate an output buffer on the srcpad. What we do is
2443      * let the upstream element decide if it wants to use a bufferpool and
2444      * then we will proxy the downstream pool */
2445     GST_DEBUG_OBJECT (self, "we're passthough, delay bufferpool");
2446     gst_deinterlace_set_allocation (self, NULL, NULL, NULL);
2447     return TRUE;
2448   }
2449
2450   /* not passthrough, we need to allocate */
2451   /* find a pool for the negotiated caps now */
2452   GST_DEBUG_OBJECT (self, "doing allocation query");
2453   query = gst_query_new_allocation (outcaps, TRUE);
2454   if (!gst_pad_peer_query (self->srcpad, query)) {
2455     /* not a problem, just debug a little */
2456     GST_DEBUG_OBJECT (self, "peer ALLOCATION query failed");
2457   }
2458
2459   GST_DEBUG_OBJECT (self, "ALLOCATION (%d) params: %" GST_PTR_FORMAT, result,
2460       query);
2461
2462   /* we got configuration from our peer or the decide_allocation method,
2463    * parse them */
2464   if (gst_query_get_n_allocation_params (query) > 0) {
2465     gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);
2466   } else {
2467     allocator = NULL;
2468     gst_allocation_params_init (&params);
2469   }
2470
2471   if (gst_query_get_n_allocation_pools (query) > 0)
2472     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
2473   else {
2474     pool = NULL;
2475     size = GST_VIDEO_INFO_SIZE (&self->vinfo);
2476     min =
2477         MAX ((gst_deinterlace_method_get_fields_required (self->method) +
2478             1) / 2 + 1, 4);
2479     max = 0;
2480   }
2481
2482   if (pool == NULL) {
2483     /* no pool, we can make our own */
2484     GST_DEBUG_OBJECT (self, "no pool, making new pool");
2485     pool = gst_video_buffer_pool_new ();
2486   }
2487
2488   /* now configure */
2489   config = gst_buffer_pool_get_config (pool);
2490   gst_buffer_pool_config_set_params (config, outcaps, size, min, max);
2491   gst_buffer_pool_config_set_allocator (config, allocator, &params);
2492   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
2493   gst_buffer_pool_set_config (pool, config);
2494
2495   /* now store */
2496   result = gst_deinterlace_set_allocation (self, pool, allocator, &params);
2497
2498   gst_query_unref (query);
2499
2500   return result;
2501 }
2502
2503
2504 static gboolean
2505 gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps)
2506 {
2507   GstCaps *srccaps = NULL;
2508   GstVideoInterlaceMode interlacing_mode;
2509   gint fps_n, fps_d;
2510
2511   if (self->locking != GST_DEINTERLACE_LOCKING_NONE) {
2512     if (self->low_latency == -1)
2513       self->low_latency = gst_deinterlace_get_latency (self);
2514
2515     if (self->pattern_lock) {
2516       /* refresh has been successful - we have a lock now */
2517       self->pattern_refresh = FALSE;
2518     } else {
2519       /* if we were not refreshing (!pattern_refresh) the caps have changed
2520        * so we need to refresh and we don't have a lock anymore
2521        * otherwise we have pattern_fresh and !pattern_lock anyway */
2522       self->pattern_refresh = TRUE;
2523       self->pattern_lock = FALSE;
2524     }
2525   }
2526
2527   if (!gst_video_info_from_caps (&self->vinfo, caps))
2528     goto invalid_caps;
2529
2530   fps_n = GST_VIDEO_INFO_FPS_N (&self->vinfo);
2531   fps_d = GST_VIDEO_INFO_FPS_D (&self->vinfo);
2532
2533   /* Update passthrough information */
2534   if (self->mode == GST_DEINTERLACE_MODE_DISABLED) {
2535     self->passthrough = TRUE;
2536     GST_DEBUG_OBJECT (self, "Passthrough because mode=disabled");
2537   } else if (self->mode == GST_DEINTERLACE_MODE_INTERLACED) {
2538     GstCaps *tmp = gst_static_caps_get (&deinterlace_caps);
2539
2540     if (!gst_caps_can_intersect (caps, tmp)) {
2541       gst_caps_unref (tmp);
2542       GST_ERROR_OBJECT (self, "Unsupported caps for mode=interlaced");
2543       goto invalid_caps;
2544     }
2545
2546     self->passthrough = FALSE;
2547     GST_DEBUG_OBJECT (self, "Not passthrough because mode=interlaced");
2548   } else if (self->mode == GST_DEINTERLACE_MODE_AUTO
2549       || self->mode == GST_DEINTERLACE_MODE_AUTO_STRICT) {
2550     GstCaps *tmp = gst_static_caps_get (&deinterlace_caps);
2551
2552     /* Already progressive? Passthrough */
2553     if (!GST_VIDEO_INFO_IS_INTERLACED (&self->vinfo)) {
2554       GST_DEBUG_OBJECT (self,
2555           "Passthrough because mode=auto and progressive caps");
2556       self->passthrough = TRUE;
2557     } else if (gst_caps_can_intersect (caps, tmp)) {
2558       GstCaps *peercaps;
2559
2560       peercaps = gst_pad_peer_query_caps (self->srcpad, NULL);
2561       if (peercaps) {
2562         GstCaps *templcaps = gst_pad_get_pad_template_caps (self->srcpad);
2563         GstCaps *allowed_caps;
2564         GstCaps *tmp2;
2565         GstStructure *s;
2566
2567         allowed_caps = gst_caps_intersect (templcaps, peercaps);
2568         gst_caps_unref (templcaps);
2569         gst_caps_unref (peercaps);
2570         peercaps = allowed_caps;
2571         allowed_caps = gst_caps_intersect (peercaps, tmp);
2572         gst_caps_unref (peercaps);
2573
2574         tmp2 = gst_caps_copy (caps);
2575         s = gst_caps_get_structure (tmp2, 0);
2576         gst_structure_set (s, "interlace-mode", G_TYPE_STRING, "progressive",
2577             NULL);
2578         gst_structure_remove_field (s, "framerate");
2579
2580         /* Downstream does not support progressive caps but supports
2581          * the upstream caps, go passthrough.
2582          * TODO: We might want to check the framerate compatibility
2583          * of the caps too here
2584          */
2585         if (gst_caps_can_intersect (allowed_caps, caps)
2586             && !gst_caps_can_intersect (allowed_caps, tmp2)) {
2587           GST_DEBUG_OBJECT (self,
2588               "Passthrough because mode=auto, "
2589               "downstream does not support progressive caps and interlaced caps");
2590           self->passthrough = TRUE;
2591         } else {
2592           GST_DEBUG_OBJECT (self, "Not passthrough because mode=auto, "
2593               "downstream supports progressive caps and interlaced caps");
2594           self->passthrough = FALSE;
2595         }
2596
2597         gst_caps_unref (allowed_caps);
2598         gst_caps_unref (tmp2);
2599       } else {
2600         GST_DEBUG_OBJECT (self,
2601             "Not passthrough because mode=auto and interlaced caps");
2602         self->passthrough = FALSE;
2603       }
2604     } else {
2605       if (self->mode == GST_DEINTERLACE_MODE_AUTO) {
2606         GST_WARNING_OBJECT (self,
2607             "Passthrough because mode=auto and unsupported interlaced caps");
2608         self->passthrough = TRUE;
2609       } else {
2610         gst_caps_unref (tmp);
2611         GST_ERROR_OBJECT (self,
2612             "Unsupported interlaced caps in mode=auto-strict");
2613         goto invalid_caps;
2614       }
2615     }
2616
2617     gst_caps_unref (tmp);
2618   } else {
2619     g_assert_not_reached ();
2620   }
2621
2622   interlacing_mode = GST_VIDEO_INFO_INTERLACE_MODE (&self->vinfo);
2623
2624   if (!self->passthrough) {
2625     if (self->pattern_lock) {
2626       srccaps = gst_caps_copy (caps);
2627       if (self->pattern != -1
2628           && G_UNLIKELY (!gst_util_fraction_multiply (fps_n, fps_d,
2629                   telecine_patterns[self->pattern].ratio_n,
2630                   telecine_patterns[self->pattern].ratio_d, &fps_n, &fps_d)))
2631         GST_ERROR_OBJECT (self,
2632             "Multiplying the framerate by the telecine pattern ratio overflowed!");
2633       gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, fps_n,
2634           fps_d, NULL);
2635     } else if (self->locking == GST_DEINTERLACE_LOCKING_ACTIVE
2636         || self->low_latency == 0) {
2637       /* in high latency pattern locking mode if we don't have a pattern lock,
2638        * the sink pad caps are the best we know */
2639       srccaps = gst_caps_copy (caps);
2640     } else if (self->low_latency > 0
2641         && interlacing_mode == GST_VIDEO_INTERLACE_MODE_MIXED
2642         && self->pattern == -1) {
2643       /* for initial buffers of a telecine pattern, until there is a lock we
2644        * we output naïvely adjusted timestamps in low-latency pattern locking
2645        * mode */
2646       srccaps = gst_caps_copy (caps);
2647       gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
2648     } else if (self->fields == GST_DEINTERLACE_ALL) {
2649       if (!gst_deinterlace_fraction_double (&fps_n, &fps_d, FALSE))
2650         goto invalid_caps;
2651
2652       srccaps = gst_caps_copy (caps);
2653
2654       gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, fps_n,
2655           fps_d, NULL);
2656     } else {
2657       srccaps = gst_caps_copy (caps);
2658     }
2659
2660     /* If not passthrough, we are going to output progressive content */
2661     srccaps = gst_caps_make_writable (srccaps);
2662     gst_caps_set_simple (srccaps, "interlace-mode", G_TYPE_STRING,
2663         "progressive", NULL);
2664
2665     gst_deinterlace_set_method (self, self->method_id);
2666     gst_deinterlace_method_setup (self->method, &self->vinfo);
2667   } else {
2668     srccaps = gst_caps_ref (caps);
2669   }
2670
2671   if (fps_n != 0) {
2672     self->field_duration = gst_util_uint64_scale (GST_SECOND, fps_d, fps_n);
2673   } else {
2674     self->field_duration = 0;
2675   }
2676
2677   GST_DEBUG_OBJECT (pad, "Sink caps: %" GST_PTR_FORMAT, caps);
2678   GST_DEBUG_OBJECT (pad, "Src  caps: %" GST_PTR_FORMAT, srccaps);
2679
2680   if (!gst_pad_set_caps (self->srcpad, srccaps))
2681     goto set_caps_failed;
2682
2683   if (!gst_deinterlace_do_bufferpool (self, srccaps))
2684     goto no_bufferpool;
2685
2686   gst_caps_unref (srccaps);
2687
2688   return TRUE;
2689
2690 invalid_caps:
2691   {
2692     GST_ERROR_OBJECT (pad, "Invalid caps: %" GST_PTR_FORMAT, caps);
2693     if (srccaps)
2694       gst_caps_unref (srccaps);
2695     return FALSE;
2696   }
2697 set_caps_failed:
2698   {
2699     GST_ERROR_OBJECT (pad, "Failed to set caps: %" GST_PTR_FORMAT, srccaps);
2700     if (srccaps)
2701       gst_caps_unref (srccaps);
2702     return FALSE;
2703   }
2704 no_bufferpool:
2705   {
2706     GST_ERROR_OBJECT (pad, "could not negotiate bufferpool");
2707     if (srccaps)
2708       gst_caps_unref (srccaps);
2709     return FALSE;
2710   }
2711 }
2712
2713 static gboolean
2714 gst_deinterlace_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
2715 {
2716   gboolean res = TRUE;
2717   GstDeinterlace *self = GST_DEINTERLACE (parent);
2718
2719   GST_LOG_OBJECT (pad, "received %s event: %" GST_PTR_FORMAT,
2720       GST_EVENT_TYPE_NAME (event), event);
2721
2722   switch (GST_EVENT_TYPE (event)) {
2723     case GST_EVENT_CAPS:
2724     {
2725       GstCaps *caps = NULL;
2726
2727       gst_event_parse_caps (event, &caps);
2728       res = gst_deinterlace_setcaps (self, pad, caps);
2729       gst_event_unref (event);
2730       break;
2731     }
2732     case GST_EVENT_SEGMENT:
2733     {
2734       const GstSegment *segment;
2735
2736       gst_event_parse_segment (event, &segment);
2737
2738       gst_deinterlace_reset_qos (self);
2739       gst_deinterlace_reset_history (self, FALSE);
2740
2741       if (segment->format == GST_FORMAT_TIME) {
2742         GST_DEBUG_OBJECT (pad,
2743             "Got SEGMENT event in TIME format, passing on (%"
2744             GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")",
2745             GST_TIME_ARGS (segment->start), GST_TIME_ARGS (segment->stop));
2746         gst_segment_copy_into (segment, &self->segment);
2747       } else {
2748         GST_WARNING_OBJECT (pad, "Got SEGMENT event in %s format",
2749             gst_format_get_name (segment->format));
2750         gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
2751       }
2752
2753       res = gst_pad_push_event (self->srcpad, event);
2754       break;
2755     }
2756     case GST_EVENT_CUSTOM_DOWNSTREAM:{
2757       gboolean still_state;
2758
2759       if (gst_video_event_parse_still_frame (event, &still_state)) {
2760         GST_DEBUG_OBJECT (self, "Received still frame event, state %d",
2761             still_state);
2762
2763         if (still_state) {
2764           GstFlowReturn ret;
2765
2766           GST_DEBUG_OBJECT (self, "Handling still frame");
2767           self->still_frame_mode = TRUE;
2768           gst_deinterlace_reset_history (self, FALSE);
2769           if (self->last_buffer) {
2770             ret =
2771                 gst_pad_push (self->srcpad, gst_buffer_ref (self->last_buffer));
2772             GST_DEBUG_OBJECT (self, "Pushed still frame, result: %s",
2773                 gst_flow_get_name (ret));
2774           } else {
2775             GST_WARNING_OBJECT (self, "No pending buffer!");
2776           }
2777         } else {
2778           GST_DEBUG_OBJECT (self, "Ending still frames");
2779           self->still_frame_mode = FALSE;
2780         }
2781       }
2782
2783       res = gst_pad_push_event (self->srcpad, event);
2784       break;
2785     }
2786     case GST_EVENT_EOS:
2787       self->have_eos = TRUE;
2788       gst_deinterlace_reset_history (self, FALSE);
2789       res = gst_pad_push_event (self->srcpad, event);
2790       break;
2791
2792     case GST_EVENT_FLUSH_STOP:
2793       if (self->still_frame_mode) {
2794         GST_DEBUG_OBJECT (self, "Ending still frames");
2795         self->still_frame_mode = FALSE;
2796       }
2797       gst_deinterlace_reset_qos (self);
2798       res = gst_pad_push_event (self->srcpad, event);
2799       gst_deinterlace_reset_history (self, TRUE);
2800       break;
2801
2802     default:
2803       res = gst_pad_event_default (pad, parent, event);
2804       break;
2805   }
2806
2807   return res;
2808 }
2809
2810 static gboolean
2811 gst_deinterlace_propose_allocation (GstDeinterlace * self, GstQuery * query)
2812 {
2813   GstBufferPool *pool;
2814   GstCaps *caps;
2815   GstVideoInfo info;
2816   guint size;
2817   GstStructure *config;
2818
2819   gst_query_parse_allocation (query, &caps, NULL);
2820
2821   if (caps == NULL)
2822     return FALSE;
2823
2824   if (!gst_video_info_from_caps (&info, caps))
2825     return FALSE;
2826
2827   size = GST_VIDEO_INFO_SIZE (&info);
2828
2829   pool = gst_video_buffer_pool_new ();
2830
2831   gst_query_add_allocation_pool (query, pool, size, 0, 0);
2832
2833   config = gst_buffer_pool_get_config (pool);
2834   gst_buffer_pool_config_set_params (config, caps, size,
2835       (gst_deinterlace_method_get_fields_required (self->method) + 1) / 2 + 1,
2836       0);
2837   gst_buffer_pool_set_config (pool, config);
2838
2839   gst_object_unref (pool);
2840   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
2841
2842   return TRUE;
2843 }
2844
2845 static gboolean
2846 gst_deinterlace_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
2847 {
2848   GstDeinterlace *self = GST_DEINTERLACE (parent);
2849   gboolean res = FALSE;
2850
2851   GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
2852
2853   switch (GST_QUERY_TYPE (query)) {
2854     case GST_QUERY_CAPS:
2855     {
2856       GstCaps *filter, *caps;
2857
2858       gst_query_parse_caps (query, &filter);
2859       caps = gst_deinterlace_getcaps (self, pad, filter);
2860       gst_query_set_caps_result (query, caps);
2861       gst_caps_unref (caps);
2862       res = TRUE;
2863       break;
2864     }
2865     case GST_QUERY_ACCEPT_CAPS:
2866     {
2867       GstCaps *caps;
2868       gboolean ret;
2869
2870       gst_query_parse_accept_caps (query, &caps);
2871       ret = gst_deinterlace_acceptcaps (self, pad, caps);
2872       gst_query_set_accept_caps_result (query, ret);
2873       res = TRUE;
2874       break;
2875     }
2876     case GST_QUERY_ALLOCATION:
2877       if (self->passthrough)
2878         res = gst_pad_peer_query (self->srcpad, query);
2879       else
2880         res = gst_deinterlace_propose_allocation (self, query);
2881       break;
2882     default:
2883       res = gst_pad_query_default (pad, parent, query);
2884       break;
2885   }
2886   return res;
2887 }
2888
2889 static GstStateChangeReturn
2890 gst_deinterlace_change_state (GstElement * element, GstStateChange transition)
2891 {
2892   GstStateChangeReturn ret;
2893   GstDeinterlace *self = GST_DEINTERLACE (element);
2894
2895   switch (transition) {
2896     case GST_STATE_CHANGE_NULL_TO_READY:
2897       break;
2898     case GST_STATE_CHANGE_READY_TO_PAUSED:
2899       break;
2900     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2901       break;
2902     default:
2903       break;
2904   }
2905
2906   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2907   if (ret != GST_STATE_CHANGE_SUCCESS)
2908     return ret;
2909
2910   switch (transition) {
2911     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2912       break;
2913     case GST_STATE_CHANGE_PAUSED_TO_READY:
2914       gst_deinterlace_reset (self);
2915       break;
2916     case GST_STATE_CHANGE_READY_TO_NULL:
2917     default:
2918       break;
2919   }
2920
2921   return ret;
2922 }
2923
2924 static gboolean
2925 gst_deinterlace_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
2926 {
2927   GstDeinterlace *self = GST_DEINTERLACE (parent);
2928   gboolean res;
2929
2930   GST_DEBUG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
2931
2932   switch (GST_EVENT_TYPE (event)) {
2933     case GST_EVENT_QOS:{
2934       GstClockTimeDiff diff;
2935       GstClockTime timestamp;
2936       GstQOSType type;
2937       gdouble proportion;
2938
2939       gst_event_parse_qos (event, &type, &proportion, &diff, &timestamp);
2940
2941       gst_deinterlace_update_qos (self, proportion, diff, timestamp);
2942     }
2943       /* fall through */
2944     default:
2945       res = gst_pad_event_default (pad, parent, event);
2946       break;
2947   }
2948
2949   return res;
2950 }
2951
2952 static gboolean
2953 gst_deinterlace_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
2954 {
2955   GstDeinterlace *self = GST_DEINTERLACE (parent);
2956   gboolean res = FALSE;
2957
2958   GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
2959
2960   switch (GST_QUERY_TYPE (query)) {
2961     case GST_QUERY_LATENCY:
2962       if (!self->passthrough) {
2963         GstClockTime min, max;
2964         gboolean live;
2965         GstPad *peer;
2966
2967         if ((peer = gst_pad_get_peer (self->sinkpad))) {
2968           if ((res = gst_pad_query (peer, query))) {
2969             GstClockTime latency;
2970             gint fields_required = 0;
2971             gint method_latency = 0;
2972
2973             if (self->method) {
2974               fields_required =
2975                   gst_deinterlace_method_get_fields_required (self->method);
2976               method_latency =
2977                   gst_deinterlace_method_get_latency (self->method);
2978             }
2979
2980             gst_query_parse_latency (query, &live, &min, &max);
2981
2982             GST_DEBUG_OBJECT (self, "Peer latency: min %"
2983                 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
2984                 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
2985
2986             /* add our own latency */
2987             latency = (fields_required + method_latency) * self->field_duration;
2988
2989             GST_DEBUG_OBJECT (self, "Our latency: min %" GST_TIME_FORMAT
2990                 ", max %" GST_TIME_FORMAT,
2991                 GST_TIME_ARGS (latency), GST_TIME_ARGS (latency));
2992
2993             min += latency;
2994             if (max != GST_CLOCK_TIME_NONE)
2995               max += latency;
2996
2997             GST_DEBUG_OBJECT (self, "Calculated total latency : min %"
2998                 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
2999                 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
3000
3001             gst_query_set_latency (query, live, min, max);
3002           }
3003           gst_object_unref (peer);
3004         } else {
3005           res = FALSE;
3006         }
3007         break;
3008       }
3009     default:
3010       res = gst_pad_query_default (pad, parent, query);
3011       break;
3012   }
3013
3014   return res;
3015 }
3016
3017 static gboolean
3018 plugin_init (GstPlugin * plugin)
3019 {
3020   GST_DEBUG_CATEGORY_INIT (deinterlace_debug, "deinterlace", 0, "Deinterlacer");
3021
3022 #if HAVE_ORC
3023   orc_init ();
3024 #endif
3025
3026   if (!gst_element_register (plugin, "deinterlace", GST_RANK_NONE,
3027           GST_TYPE_DEINTERLACE)) {
3028     return FALSE;
3029   }
3030
3031   return TRUE;
3032 }
3033
3034 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
3035     GST_VERSION_MINOR,
3036     deinterlace,
3037     "Deinterlacer", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
3038     GST_PACKAGE_ORIGIN);