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