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, ¶ms);
2701 } else {
2702 allocator = NULL;
2703 gst_allocation_params_init (¶ms);
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, ¶ms);
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, ¶ms);
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, ×tamp);
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