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