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