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>
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.
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.
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.
24 * SECTION:element-deinterlace
26 * deinterlace deinterlaces interlaced video frames to progressive video frames.
27 * For this different algorithms can be selected which will be described later.
30 * <title>Example launch line</title>
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.
41 #include "gstdeinterlace.h"
42 #include "tvtime/plugins.h"
50 GST_DEBUG_CATEGORY_STATIC (deinterlace_debug);
51 #define GST_CAT_DEFAULT (deinterlace_debug)
55 #define DEFAULT_MODE GST_DEINTERLACE_MODE_AUTO
56 #define DEFAULT_METHOD GST_DEINTERLACE_LINEAR
57 #define DEFAULT_FIELDS GST_DEINTERLACE_ALL
58 #define DEFAULT_FIELD_LAYOUT GST_DEINTERLACE_LAYOUT_AUTO
59 #define DEFAULT_LOCKING GST_DEINTERLACE_LOCKING_NONE
60 #define DEFAULT_IGNORE_OBSCURE TRUE
61 #define DEFAULT_DROP_ORPHANS TRUE
75 #define GST_DEINTERLACE_BUFFER_STATE_P (1<<0)
76 #define GST_DEINTERLACE_BUFFER_STATE_I (1<<1)
77 #define GST_DEINTERLACE_BUFFER_STATE_TC_B (1<<2)
78 #define GST_DEINTERLACE_BUFFER_STATE_TC_T (1<<3)
79 #define GST_DEINTERLACE_BUFFER_STATE_TC_P (1<<4)
80 #define GST_DEINTERLACE_BUFFER_STATE_TC_M (1<<5)
81 #define GST_DEINTERLACE_BUFFER_STATE_RFF (1<<6)
84 (GST_DEINTERLACE_BUFFER_STATE_TC_T | GST_DEINTERLACE_BUFFER_STATE_TC_B)
86 (GST_DEINTERLACE_BUFFER_STATE_P | GST_DEINTERLACE_BUFFER_STATE_TC_P)
88 (GST_DEINTERLACE_BUFFER_STATE_I | GST_DEINTERLACE_BUFFER_STATE_TC_M)
89 #define GST_RFF (GST_DEINTERLACE_BUFFER_STATE_RFF)
91 #define GST_DEINTERLACE_OBSCURE_THRESHOLD 5
93 static const TelecinePattern telecine_patterns[] = {
94 /* 60i -> 60p or 50i -> 50p (NOTE THE WEIRD RATIOS) */
95 {"1:1", 1, 2, 1, {GST_ONE,}},
96 /* 60i -> 30p or 50i -> 25p */
97 {"2:2", 1, 1, 1, {GST_INT,}},
98 /* 60i telecine -> 24p */
99 {"2:3-RFF", 4, 4, 5, {GST_PRG, GST_RFF, GST_PRG, GST_RFF,}},
100 {"2:3", 5, 4, 5, {GST_PRG, GST_PRG, GST_ONE, GST_ONE, GST_PRG,}},
101 {"3:2:2:3-RFF", 4, 4, 5, {GST_RFF, GST_PRG, GST_PRG, GST_RFF,}},
102 {"3:2:2:3", 5, 4, 5, {GST_PRG, GST_ONE, GST_INT, GST_ONE, GST_PRG,}},
103 /* fieldanalysis should indicate this using RFF on the second and fourth
104 * buffers and not send the third buffer at all. it will be identified as
106 /* {"2:3:3:2", 5, 4, 5, {GST_PRG, GST_PRG, GST_DRP, GST_PRG, GST_PRG,}}, */
108 /* The following patterns are obscure and are ignored if ignore-obscure is
109 * set to true. If any patterns are added above this line, check and edit
110 * GST_DEINTERLACE_OBSCURE_THRESHOLD */
112 /* 50i Euro pulldown -> 24p */
113 {"2-11:3", 25, 24, 25, {GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_PRG,
114 GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_PRG,
115 GST_PRG, GST_PRG, GST_ONE, GST_INT, GST_INT,
116 GST_INT, GST_INT, GST_INT, GST_INT, GST_INT,
117 GST_INT, GST_INT, GST_INT, GST_ONE, GST_PRG,}},
119 /* haven't figured out how fieldanalysis should handle these yet */
120 /* 60i (NTSC 30000/1001) -> 16p (16000/1001) */
121 {"3:4-3", 15, 8, 15, {GST_PRG, GST_DRP, GST_PRG, GST_DRP, GST_PRG,
122 GST_DRP, GST_PRG, GST_DRP, GST_PRG, GST_DRP,
123 GST_PRG, GST_DRP, GST_PRG, GST_DRP, GST_PRG,}},
124 /* 50i (PAL) -> 16p */
125 {"3-7:4", 25, 16, 25, {GST_PRG, GST_DRP, GST_PRG, GST_PRG, GST_DRP,
126 GST_PRG, GST_PRG, GST_DRP, GST_PRG, GST_PRG,
127 GST_DRP, GST_PRG, GST_DRP, GST_PRG, GST_PRG,
128 GST_DRP, GST_PRG, GST_PRG, GST_DRP, GST_PRG,
129 GST_PRG, GST_DRP, GST_PRG, GST_PRG, GST_DRP,}},
130 /* NTSC 60i -> 18p */
131 {"3:3:4", 5, 3, 5, {GST_PRG, GST_DRP, GST_PRG, GST_DRP, GST_PRG,}},
132 /* NTSC 60i -> 20p */
133 {"3:3", 3, 2, 3, {GST_PRG, GST_DRP, GST_PRG,}},
135 /* NTSC 60i -> 27.5 */
136 {"3:2-4", 11, 10, 11, {GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_PRG,
137 GST_PRG, GST_ONE, GST_INT, GST_INT, GST_INT,
139 /* PAL 50i -> 27.5 */
140 {"1:2-4", 9, 9, 10, {GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_INT,
141 GST_INT, GST_INT, GST_INT, GST_INT,}},
144 static const GEnumValue methods_types[] = {
145 {GST_DEINTERLACE_TOMSMOCOMP, "Motion Adaptive: Motion Search",
147 {GST_DEINTERLACE_GREEDY_H, "Motion Adaptive: Advanced Detection",
149 {GST_DEINTERLACE_GREEDY_L, "Motion Adaptive: Simple Detection", "greedyl"},
150 {GST_DEINTERLACE_VFIR, "Blur Vertical", "vfir"},
151 {GST_DEINTERLACE_LINEAR, "Linear", "linear"},
152 {GST_DEINTERLACE_LINEAR_BLEND, "Blur: Temporal (Do Not Use)",
154 {GST_DEINTERLACE_SCALER_BOB, "Double lines", "scalerbob"},
155 {GST_DEINTERLACE_WEAVE, "Weave (Do Not Use)", "weave"},
156 {GST_DEINTERLACE_WEAVE_TFF, "Progressive: Top Field First (Do Not Use)",
158 {GST_DEINTERLACE_WEAVE_BFF, "Progressive: Bottom Field First (Do Not Use)",
163 static const GEnumValue locking_types[] = {
164 {GST_DEINTERLACE_LOCKING_NONE,
165 "No pattern locking", "none"},
166 {GST_DEINTERLACE_LOCKING_AUTO,
167 "Choose passive/active locking depending on whether upstream is live",
169 {GST_DEINTERLACE_LOCKING_ACTIVE,
170 "Block until pattern-locked. Use accurate timestamp interpolation within a pattern repeat.",
172 {GST_DEINTERLACE_LOCKING_PASSIVE,
173 "Do not block. Use naïve timestamp adjustment until pattern-locked based on state history.",
179 #define GST_TYPE_DEINTERLACE_METHODS (gst_deinterlace_methods_get_type ())
181 gst_deinterlace_methods_get_type (void)
183 static GType deinterlace_methods_type = 0;
185 if (!deinterlace_methods_type) {
186 deinterlace_methods_type =
187 g_enum_register_static ("GstDeinterlaceMethods", methods_types);
189 return deinterlace_methods_type;
192 #define GST_TYPE_DEINTERLACE_FIELDS (gst_deinterlace_fields_get_type ())
194 gst_deinterlace_fields_get_type (void)
196 static GType deinterlace_fields_type = 0;
198 static const GEnumValue fields_types[] = {
199 {GST_DEINTERLACE_ALL, "All fields", "all"},
200 {GST_DEINTERLACE_TF, "Top fields only", "top"},
201 {GST_DEINTERLACE_BF, "Bottom fields only", "bottom"},
202 {GST_DEINTERLACE_FIELDS_AUTO, "Automatically detect", "auto"},
206 if (!deinterlace_fields_type) {
207 deinterlace_fields_type =
208 g_enum_register_static ("GstDeinterlaceFields", fields_types);
210 return deinterlace_fields_type;
213 #define GST_TYPE_DEINTERLACE_FIELD_LAYOUT (gst_deinterlace_field_layout_get_type ())
215 gst_deinterlace_field_layout_get_type (void)
217 static GType deinterlace_field_layout_type = 0;
219 static const GEnumValue field_layout_types[] = {
220 {GST_DEINTERLACE_LAYOUT_AUTO, "Auto detection", "auto"},
221 {GST_DEINTERLACE_LAYOUT_TFF, "Top field first", "tff"},
222 {GST_DEINTERLACE_LAYOUT_BFF, "Bottom field first", "bff"},
226 if (!deinterlace_field_layout_type) {
227 deinterlace_field_layout_type =
228 g_enum_register_static ("GstDeinterlaceFieldLayout",
231 return deinterlace_field_layout_type;
234 #define GST_TYPE_DEINTERLACE_MODES (gst_deinterlace_modes_get_type ())
236 gst_deinterlace_modes_get_type (void)
238 static GType deinterlace_modes_type = 0;
240 static const GEnumValue modes_types[] = {
241 {GST_DEINTERLACE_MODE_AUTO, "Auto detection (best effort)", "auto"},
242 {GST_DEINTERLACE_MODE_INTERLACED, "Force deinterlacing", "interlaced"},
243 {GST_DEINTERLACE_MODE_DISABLED, "Run in passthrough mode", "disabled"},
244 {GST_DEINTERLACE_MODE_AUTO_STRICT, "Auto detection (strict)",
249 if (!deinterlace_modes_type) {
250 deinterlace_modes_type =
251 g_enum_register_static ("GstDeinterlaceModes", modes_types);
253 return deinterlace_modes_type;
256 #define GST_TYPE_DEINTERLACE_LOCKING (gst_deinterlace_locking_get_type ())
258 gst_deinterlace_locking_get_type (void)
260 static GType deinterlace_locking_type = 0;
262 if (!deinterlace_locking_type) {
263 deinterlace_locking_type =
264 g_enum_register_static ("GstDeinterlaceLocking", locking_types);
267 return deinterlace_locking_type;
270 #define DEINTERLACE_VIDEO_FORMATS \
271 "{ AYUV, ARGB, ABGR, RGBA, BGRA, Y444, xRGB, xBGR, RGBx, BGRx, RGB, " \
272 "BGR, YUY2, YVYU, UYVY, Y42B, I420, YV12, Y41B, NV12, NV21 }"
274 #define DEINTERLACE_CAPS GST_VIDEO_CAPS_MAKE(DEINTERLACE_VIDEO_FORMATS)
276 #define DEINTERLACE_ALL_CAPS DEINTERLACE_CAPS ";" \
277 GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY", GST_VIDEO_FORMATS_ALL)
279 static GstStaticCaps progressive_caps =
280 GST_STATIC_CAPS ("video/x-raw(ANY),interlace-mode=(string)progressive");
281 static GstStaticCaps deinterlace_caps = GST_STATIC_CAPS (DEINTERLACE_CAPS);
283 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
286 GST_STATIC_CAPS (DEINTERLACE_ALL_CAPS)
289 static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
292 GST_STATIC_CAPS (DEINTERLACE_ALL_CAPS)
295 static void gst_deinterlace_finalize (GObject * self);
296 static void gst_deinterlace_set_property (GObject * self, guint prop_id,
297 const GValue * value, GParamSpec * pspec);
298 static void gst_deinterlace_get_property (GObject * self, guint prop_id,
299 GValue * value, GParamSpec * pspec);
301 static GstCaps *gst_deinterlace_getcaps (GstDeinterlace * self, GstPad * pad,
303 static gboolean gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad,
305 static gboolean gst_deinterlace_sink_event (GstPad * pad, GstObject * parent,
307 static gboolean gst_deinterlace_sink_query (GstPad * pad, GstObject * parent,
309 static GstFlowReturn gst_deinterlace_chain (GstPad * pad, GstObject * parent,
311 static GstStateChangeReturn gst_deinterlace_change_state (GstElement * element,
312 GstStateChange transition);
313 static gboolean gst_deinterlace_set_allocation (GstDeinterlace * self,
314 GstBufferPool * pool, GstAllocator * allocator,
315 GstAllocationParams * params);
317 static gboolean gst_deinterlace_src_event (GstPad * pad, GstObject * parent,
319 static gboolean gst_deinterlace_src_query (GstPad * pad, GstObject * parent,
322 static GstFlowReturn gst_deinterlace_output_frame (GstDeinterlace * self,
324 static void gst_deinterlace_reset (GstDeinterlace * self);
325 static void gst_deinterlace_update_qos (GstDeinterlace * self,
326 gdouble proportion, GstClockTimeDiff diff, GstClockTime time);
327 static void gst_deinterlace_reset_qos (GstDeinterlace * self);
328 static void gst_deinterlace_read_qos (GstDeinterlace * self,
329 gdouble * proportion, GstClockTime * time);
331 #define IS_TELECINE(m) ((m) == GST_VIDEO_INTERLACE_MODE_MIXED && self->pattern > 1)
333 /* FIXME: what's the point of the childproxy interface here? What can you
334 * actually do with it? The method objects seem to have no properties */
336 static void gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
337 gpointer iface_data);
340 _do_init (GType object_type)
342 const GInterfaceInfo child_proxy_interface_info = {
343 (GInterfaceInitFunc) gst_deinterlace_child_proxy_interface_init,
344 NULL, /* interface_finalize */
345 NULL /* interface_data */
348 g_type_add_interface_static (object_type, GST_TYPE_CHILD_PROXY,
349 &child_proxy_interface_info);
353 G_DEFINE_TYPE (GstDeinterlace, gst_deinterlace, GST_TYPE_ELEMENT);
355 #define parent_class gst_deinterlace_parent_class
359 GType (*get_type) (void);
360 } _method_types[] = {
362 gst_deinterlace_method_tomsmocomp_get_type}, {
363 gst_deinterlace_method_greedy_h_get_type}, {
364 gst_deinterlace_method_greedy_l_get_type}, {
365 gst_deinterlace_method_vfir_get_type}, {
366 gst_deinterlace_method_linear_get_type}, {
367 gst_deinterlace_method_linear_blend_get_type}, {
368 gst_deinterlace_method_scaler_bob_get_type}, {
369 gst_deinterlace_method_weave_get_type}, {
370 gst_deinterlace_method_weave_tff_get_type}, {
371 gst_deinterlace_method_weave_bff_get_type}
375 gst_deinterlace_set_method (GstDeinterlace * self, GstDeinterlaceMethods method)
379 GstVideoFormat format;
381 GST_DEBUG_OBJECT (self, "Setting new method %d", method);
383 width = GST_VIDEO_INFO_WIDTH (&self->vinfo);
384 height = GST_VIDEO_INFO_HEIGHT (&self->vinfo);
385 format = GST_VIDEO_INFO_FORMAT (&self->vinfo);
388 if (self->method_id == method &&
389 gst_deinterlace_method_supported (G_TYPE_FROM_INSTANCE (self->method),
390 format, width, height)) {
391 GST_DEBUG_OBJECT (self, "Reusing current method");
395 gst_child_proxy_child_removed (GST_OBJECT (self),
396 GST_OBJECT (self->method));
397 gst_object_unparent (GST_OBJECT (self->method));
403 _method_types[method].get_type !=
404 NULL ? _method_types[method].get_type () : G_TYPE_INVALID;
405 if (method_type == G_TYPE_INVALID
406 || !gst_deinterlace_method_supported (method_type, format,
411 method_type = G_TYPE_INVALID;
413 GST_WARNING_OBJECT (self, "Method doesn't support requested format");
414 for (i = 0; i < G_N_ELEMENTS (_method_types); i++) {
415 if (_method_types[i].get_type == NULL)
417 tmp = _method_types[i].get_type ();
418 if (gst_deinterlace_method_supported (tmp, format, width, height)) {
419 GST_DEBUG_OBJECT (self, "Using method %d", i);
425 /* If we get here we must have invalid caps! */
426 g_assert (method_type != G_TYPE_INVALID);
429 self->method = g_object_new (method_type, "name", "method", NULL);
430 self->method_id = method;
432 gst_object_set_parent (GST_OBJECT (self->method), GST_OBJECT (self));
434 gst_child_proxy_child_added (GST_OBJECT (self), GST_OBJECT (self->method));
438 gst_deinterlace_method_setup (self->method, &self->vinfo);
442 gst_deinterlace_clip_buffer (GstDeinterlace * self, GstBuffer * buffer)
445 GstClockTime start, stop;
446 guint64 cstart, cstop;
448 GST_DEBUG_OBJECT (self,
449 "Clipping buffer to the current segment: %" GST_TIME_FORMAT " -- %"
450 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
451 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
452 GST_DEBUG_OBJECT (self, "Current segment: %" GST_SEGMENT_FORMAT,
455 if (G_UNLIKELY (self->segment.format != GST_FORMAT_TIME))
457 if (G_UNLIKELY (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer)))
460 start = GST_BUFFER_TIMESTAMP (buffer);
461 stop = start + GST_BUFFER_DURATION (buffer);
463 if (!(ret = gst_segment_clip (&self->segment, GST_FORMAT_TIME,
464 start, stop, &cstart, &cstop)))
467 GST_BUFFER_TIMESTAMP (buffer) = cstart;
468 if (GST_CLOCK_TIME_IS_VALID (cstop))
469 GST_BUFFER_DURATION (buffer) = cstop - cstart;
473 GST_DEBUG_OBJECT (self,
474 "Clipped buffer to the current segment: %" GST_TIME_FORMAT " -- %"
475 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
476 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
478 GST_DEBUG_OBJECT (self, "Buffer outside the current segment -- dropping");
484 gst_deinterlace_class_init (GstDeinterlaceClass * klass)
486 GObjectClass *gobject_class = (GObjectClass *) klass;
488 GstElementClass *element_class = (GstElementClass *) klass;
490 gst_element_class_add_static_pad_template (element_class, &src_templ);
491 gst_element_class_add_static_pad_template (element_class, &sink_templ);
493 gst_element_class_set_static_metadata (element_class,
495 "Filter/Effect/Video/Deinterlace",
496 "Deinterlace Methods ported from DScaler/TvTime",
497 "Martin Eikermann <meiker@upb.de>, "
498 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
500 gobject_class->set_property = gst_deinterlace_set_property;
501 gobject_class->get_property = gst_deinterlace_get_property;
502 gobject_class->finalize = gst_deinterlace_finalize;
505 * GstDeinterlace:mode:
507 * This selects whether the deinterlacing methods should
508 * always be applied or if they should only be applied
509 * on content that has the "interlaced" flag on the caps.
511 g_object_class_install_property (gobject_class, PROP_MODE,
512 g_param_spec_enum ("mode",
515 GST_TYPE_DEINTERLACE_MODES,
516 DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
520 * GstDeinterlace:method:
522 * Selects the different deinterlacing algorithms that can be used.
523 * These provide different quality and CPU usage.
525 * Some methods provide parameters which can be set by getting
526 * the "method" child via the #GstChildProxy interface and
527 * setting the appropiate properties on it.
533 * Motion Adaptive: Motion Search
539 * Motion Adaptive: Advanced Detection
545 * Motion Adaptive: Simple Detection
557 * Linear interpolation
563 * Linear interpolation in time domain. Any motion causes significant
564 * ghosting, so this method should not be used.
576 * Weave. Bad quality, do not use.
582 * Progressive: Top Field First. Bad quality, do not use.
588 * Progressive: Bottom Field First. Bad quality, do not use.
593 g_object_class_install_property (gobject_class, PROP_METHOD,
594 g_param_spec_enum ("method",
596 "Deinterlace Method",
597 GST_TYPE_DEINTERLACE_METHODS,
598 DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
602 * GstDeinterlace:fields:
604 * This selects which fields should be output. If "all" is selected
605 * the output framerate will be double.
607 g_object_class_install_property (gobject_class, PROP_FIELDS,
608 g_param_spec_enum ("fields",
610 "Fields to use for deinterlacing",
611 GST_TYPE_DEINTERLACE_FIELDS,
612 DEFAULT_FIELDS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
616 * GstDeinterlace:layout:
618 * This selects which fields is the first in time.
621 g_object_class_install_property (gobject_class, PROP_FIELD_LAYOUT,
622 g_param_spec_enum ("tff",
624 "Deinterlace top field first",
625 GST_TYPE_DEINTERLACE_FIELD_LAYOUT,
626 DEFAULT_FIELD_LAYOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
630 * GstDeinterlace:locking:
632 * This selects which approach to pattern locking is used which affects
633 * processing latency and accuracy of timestamp adjustment for telecine
636 g_object_class_install_property (gobject_class, PROP_LOCKING,
637 g_param_spec_enum ("locking", "locking", "Pattern locking mode",
638 GST_TYPE_DEINTERLACE_LOCKING, DEFAULT_LOCKING,
639 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
642 * GstDeinterlace:ignore-obscure:
644 * This selects whether to ignore obscure/rare telecine patterns.
645 * NTSC 2:3 pulldown variants are the only really common patterns.
647 g_object_class_install_property (gobject_class, PROP_IGNORE_OBSCURE,
648 g_param_spec_boolean ("ignore-obscure", "ignore-obscure",
649 "Ignore obscure telecine patterns (only consider P, I and 2:3 "
650 "variants).", DEFAULT_IGNORE_OBSCURE,
651 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
654 * GstDeinterlace:drop-orphans:
656 * This selects whether to drop orphan fields at the beginning of telecine
657 * patterns in active locking mode.
659 g_object_class_install_property (gobject_class, PROP_DROP_ORPHANS,
660 g_param_spec_boolean ("drop-orphans", "drop-orphans",
661 "Drop orphan fields at the beginning of telecine patterns in "
662 "active locking mode.", DEFAULT_DROP_ORPHANS,
663 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
665 element_class->change_state =
666 GST_DEBUG_FUNCPTR (gst_deinterlace_change_state);
671 gst_deinterlace_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
674 GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
676 g_return_val_if_fail (index == 0, NULL);
678 return gst_object_ref (self->method);
682 gst_deinterlace_child_proxy_get_children_count (GstChildProxy * child_proxy)
684 GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
686 return ((self->method) ? 1 : 0);
690 gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
693 GstChildProxyInterface *iface = g_iface;
695 iface->get_child_by_index = gst_deinterlace_child_proxy_get_child_by_index;
696 iface->get_children_count = gst_deinterlace_child_proxy_get_children_count;
701 gst_deinterlace_init (GstDeinterlace * self)
703 self->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
704 gst_pad_set_chain_function (self->sinkpad,
705 GST_DEBUG_FUNCPTR (gst_deinterlace_chain));
706 gst_pad_set_event_function (self->sinkpad,
707 GST_DEBUG_FUNCPTR (gst_deinterlace_sink_event));
708 gst_pad_set_query_function (self->sinkpad,
709 GST_DEBUG_FUNCPTR (gst_deinterlace_sink_query));
710 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
712 self->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
713 gst_pad_set_event_function (self->srcpad,
714 GST_DEBUG_FUNCPTR (gst_deinterlace_src_event));
715 gst_pad_set_query_function (self->srcpad,
716 GST_DEBUG_FUNCPTR (gst_deinterlace_src_query));
717 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
719 self->mode = DEFAULT_MODE;
720 self->user_set_method_id = DEFAULT_METHOD;
721 gst_video_info_init (&self->vinfo);
722 gst_deinterlace_set_method (self, self->user_set_method_id);
723 self->fields = DEFAULT_FIELDS;
724 self->user_set_fields = DEFAULT_FIELDS;
725 self->field_layout = DEFAULT_FIELD_LAYOUT;
726 self->locking = DEFAULT_LOCKING;
727 self->ignore_obscure = DEFAULT_IGNORE_OBSCURE;
728 self->drop_orphans = DEFAULT_DROP_ORPHANS;
730 self->low_latency = -1;
732 self->pattern_phase = -1;
733 self->pattern_count = 0;
734 self->output_count = 0;
735 self->pattern_base_ts = GST_CLOCK_TIME_NONE;
736 self->pattern_buf_dur = GST_CLOCK_TIME_NONE;
737 self->still_frame_mode = FALSE;
738 self->telecine_tc_warned = FALSE;
740 gst_deinterlace_reset (self);
743 static GstVideoFrame *
744 gst_video_frame_new_and_map (GstVideoInfo * vinfo, GstBuffer * buffer,
747 GstVideoFrame *frame = g_malloc0 (sizeof (GstVideoFrame));
748 if (!gst_video_frame_map (frame, vinfo, buffer, flags)) {
750 g_return_val_if_reached (NULL);
757 gst_video_frame_unmap_and_free (GstVideoFrame * frame)
759 gst_video_frame_unmap (frame);
763 static GstVideoFrame *
764 gst_deinterlace_pop_history (GstDeinterlace * self)
766 GstVideoFrame *frame;
768 g_return_val_if_fail (self->history_count > 0, NULL);
770 GST_DEBUG_OBJECT (self, "Pop last history frame -- current history size %d",
771 self->history_count);
773 frame = self->field_history[self->history_count - 1].frame;
775 self->history_count--;
776 if (self->locking != GST_DEINTERLACE_LOCKING_NONE && (!self->history_count
777 || GST_VIDEO_FRAME_PLANE_DATA (frame, 0) !=
778 GST_VIDEO_FRAME_PLANE_DATA (self->field_history[self->history_count -
780 if (!self->low_latency)
782 if (self->pattern_lock) {
783 self->pattern_count++;
784 if (self->pattern != -1
785 && self->pattern_count >= telecine_patterns[self->pattern].length) {
786 self->pattern_count = 0;
787 self->output_count = 0;
792 GST_DEBUG_OBJECT (self, "Returning frame: %p %" GST_TIME_FORMAT
793 " with duration %" GST_TIME_FORMAT " and size %" G_GSIZE_FORMAT, frame,
794 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (frame->buffer)),
795 GST_TIME_ARGS (GST_BUFFER_DURATION (frame->buffer)),
796 GST_VIDEO_FRAME_SIZE (frame));
802 gst_deinterlace_delete_meta_at (GstDeinterlace * self, gint idx)
804 if (self->field_history[idx].frame) {
805 if (self->field_history[idx].tc) {
806 gst_video_time_code_free (self->field_history[idx].tc);
807 self->field_history[idx].tc = NULL;
809 if (self->field_history[idx].caption) {
810 g_free (self->field_history[idx].caption->data);
811 g_free (self->field_history[idx].caption);
812 self->field_history[idx].caption = NULL;
818 gst_deinterlace_pop_and_clear (GstDeinterlace * self)
822 if (self->history_count <= 0)
825 idx = self->history_count - 1;
826 gst_deinterlace_delete_meta_at (self, idx);
828 /* FIXME: pop_history should return a structure with the frame and its meta.
829 * Currently we're just doing guesswork with the indices. Maybe just
830 * refactor the history functionality to make something clearer */
831 gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
835 gst_deinterlace_reset_history (GstDeinterlace * self, gboolean drop_all)
840 GST_DEBUG_OBJECT (self, "Flushing history (count %d)", self->history_count);
841 while (self->history_count > 0) {
842 if (gst_deinterlace_output_frame (self, TRUE) != GST_FLOW_OK) {
843 /* Encountered error, or flushing -> skip and drop all remaining */
850 GST_DEBUG_OBJECT (self, "Resetting history (count %d)",
851 self->history_count);
853 for (i = 0; i < self->history_count; i++) {
854 if (self->field_history[i].frame) {
855 gst_video_frame_unmap_and_free (self->field_history[i].frame);
856 self->field_history[i].frame = NULL;
857 gst_deinterlace_delete_meta_at (self, i);
861 memset (self->field_history, 0,
862 GST_DEINTERLACE_MAX_FIELD_HISTORY * sizeof (GstDeinterlaceField));
863 self->history_count = 0;
864 memset (self->buf_states, 0,
865 GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY *
866 sizeof (GstDeinterlaceBufferState));
867 self->state_count = 0;
868 self->pattern_lock = FALSE;
869 self->pattern_refresh = TRUE;
870 self->cur_field_idx = -1;
872 if (!self->still_frame_mode && self->last_buffer) {
873 gst_buffer_unref (self->last_buffer);
874 self->last_buffer = NULL;
879 gst_deinterlace_reset (GstDeinterlace * self)
881 GST_DEBUG_OBJECT (self, "Resetting internal state");
883 gst_video_info_init (&self->vinfo);
885 self->passthrough = FALSE;
887 self->reconfigure = FALSE;
888 if ((gint) self->new_mode != -1)
889 self->mode = self->new_mode;
890 if ((gint) self->new_fields != -1)
891 self->user_set_fields = self->new_fields;
893 self->new_fields = -1;
895 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
897 if (self->request_caps)
898 gst_caps_unref (self->request_caps);
899 self->request_caps = NULL;
901 gst_deinterlace_reset_history (self, TRUE);
903 gst_deinterlace_reset_qos (self);
905 self->need_more = FALSE;
906 self->have_eos = FALSE;
908 self->discont = TRUE;
909 self->telecine_tc_warned = FALSE;
911 gst_deinterlace_set_allocation (self, NULL, NULL, NULL);
915 gst_deinterlace_set_property (GObject * object, guint prop_id,
916 const GValue * value, GParamSpec * pspec)
918 GstDeinterlace *self;
920 self = GST_DEINTERLACE (object);
926 GST_OBJECT_LOCK (self);
927 new_mode = g_value_get_enum (value);
928 if (self->mode != new_mode && gst_pad_has_current_caps (self->srcpad)) {
929 self->reconfigure = TRUE;
930 self->new_mode = new_mode;
932 self->mode = new_mode;
934 GST_OBJECT_UNLOCK (self);
938 self->user_set_method_id = g_value_get_enum (value);
939 gst_deinterlace_set_method (self, self->user_set_method_id);
944 GST_OBJECT_LOCK (self);
945 new_fields = g_value_get_enum (value);
946 if (self->user_set_fields != new_fields
947 && gst_pad_has_current_caps (self->srcpad)) {
948 self->reconfigure = TRUE;
949 self->new_fields = new_fields;
951 self->user_set_fields = new_fields;
953 GST_OBJECT_UNLOCK (self);
956 case PROP_FIELD_LAYOUT:
957 self->field_layout = g_value_get_enum (value);
960 self->locking = g_value_get_enum (value);
962 case PROP_IGNORE_OBSCURE:
963 self->ignore_obscure = g_value_get_boolean (value);
965 case PROP_DROP_ORPHANS:
966 self->drop_orphans = g_value_get_boolean (value);
969 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
975 gst_deinterlace_get_property (GObject * object, guint prop_id,
976 GValue * value, GParamSpec * pspec)
978 GstDeinterlace *self;
980 self = GST_DEINTERLACE (object);
984 g_value_set_enum (value, self->mode);
987 g_value_set_enum (value, self->user_set_method_id);
990 g_value_set_enum (value, self->user_set_fields);
992 case PROP_FIELD_LAYOUT:
993 g_value_set_enum (value, self->field_layout);
996 g_value_set_enum (value, self->locking);
998 case PROP_IGNORE_OBSCURE:
999 g_value_set_boolean (value, self->ignore_obscure);
1001 case PROP_DROP_ORPHANS:
1002 g_value_set_boolean (value, self->drop_orphans);
1005 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
1010 gst_deinterlace_finalize (GObject * object)
1012 GstDeinterlace *self = GST_DEINTERLACE (object);
1014 gst_deinterlace_reset (self);
1017 gst_object_unparent (GST_OBJECT (self->method));
1018 self->method = NULL;
1021 G_OBJECT_CLASS (parent_class)->finalize (object);
1025 gst_deinterlace_update_pattern_timestamps (GstDeinterlace * self)
1028 if (self->low_latency) {
1029 /* in low-latency mode the buffer state history contains old buffer
1030 * states as well as the current one and perhaps some future ones.
1031 * the current buffer's state is given by the number of field pairs
1032 * rounded up, minus 1. the below is equivalent */
1033 state_idx = (self->history_count - 1) >> 1;
1035 /* in high-latency mode state_count - 1 is the current buffer's state */
1036 state_idx = self->state_count - 1;
1039 self->pattern_base_ts = self->buf_states[state_idx].timestamp;
1040 if (self->buf_states[state_idx].state != GST_RFF) {
1041 self->pattern_buf_dur =
1042 (self->buf_states[state_idx].duration *
1043 telecine_patterns[self->pattern].ratio_d) /
1044 telecine_patterns[self->pattern].ratio_n;
1046 self->pattern_buf_dur =
1047 (self->buf_states[state_idx].duration *
1048 telecine_patterns[self->pattern].ratio_d * 2) /
1049 (telecine_patterns[self->pattern].ratio_n * 3);
1051 GST_DEBUG_OBJECT (self,
1052 "Starting a new pattern repeat with base ts %" GST_TIME_FORMAT
1053 " and dur %" GST_TIME_FORMAT, GST_TIME_ARGS (self->pattern_base_ts),
1054 GST_TIME_ARGS (self->pattern_buf_dur));
1058 gst_deinterlace_get_buffer_state (GstDeinterlace * self, GstVideoFrame * frame,
1059 guint8 * state, GstVideoInterlaceMode * i_mode)
1061 GstVideoInterlaceMode interlacing_mode;
1063 if (!(i_mode || state))
1066 interlacing_mode = GST_VIDEO_INFO_INTERLACE_MODE (&frame->info);
1067 if (self->mode == GST_DEINTERLACE_MODE_INTERLACED)
1068 interlacing_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
1071 if (interlacing_mode == GST_VIDEO_INTERLACE_MODE_MIXED) {
1072 if (GST_VIDEO_FRAME_IS_RFF (frame)) {
1073 *state = GST_DEINTERLACE_BUFFER_STATE_RFF;
1074 } else if (GST_VIDEO_FRAME_IS_ONEFIELD (frame)) {
1075 /* tc top if tff, tc bottom otherwise */
1076 if (GST_VIDEO_FRAME_IS_TFF (frame)) {
1077 *state = GST_DEINTERLACE_BUFFER_STATE_TC_T;
1079 *state = GST_DEINTERLACE_BUFFER_STATE_TC_B;
1081 } else if (GST_VIDEO_FRAME_IS_INTERLACED (frame)) {
1082 *state = GST_DEINTERLACE_BUFFER_STATE_TC_M;
1084 *state = GST_DEINTERLACE_BUFFER_STATE_TC_P;
1087 if (interlacing_mode == GST_VIDEO_INTERLACE_MODE_INTERLEAVED) {
1088 *state = GST_DEINTERLACE_BUFFER_STATE_I;
1090 *state = GST_DEINTERLACE_BUFFER_STATE_P;
1096 *i_mode = interlacing_mode;
1099 #define STATE_TO_STRING(s) ((s) == GST_DEINTERLACE_BUFFER_STATE_P ? "P" : \
1100 (s) == GST_DEINTERLACE_BUFFER_STATE_I ? "I" : \
1101 (s) == GST_DEINTERLACE_BUFFER_STATE_TC_B ? "B" : \
1102 (s) == GST_DEINTERLACE_BUFFER_STATE_TC_T ? "T" : \
1103 (s) == GST_DEINTERLACE_BUFFER_STATE_TC_P ? "TCP" : \
1104 (s) == GST_DEINTERLACE_BUFFER_STATE_TC_M ? "TCM" : "RFF")
1106 #define MODE_TO_STRING(m) ((m) == GST_VIDEO_INTERLACE_MODE_MIXED ? "MIXED" : \
1107 (m) == GST_VIDEO_INTERLACE_MODE_INTERLEAVED ? "I" : \
1108 (m) == GST_VIDEO_INTERLACE_MODE_FIELDS ? "FIELDS" : "P")
1111 gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer)
1114 GstDeinterlaceFieldLayout field_layout = self->field_layout;
1117 GstVideoFrame *frame = NULL;
1118 GstVideoFrame *field1, *field2 = NULL;
1119 guint fields_to_push;
1120 guint field1_flags, field2_flags;
1121 GstVideoInterlaceMode interlacing_mode;
1124 /* we will only read from this buffer and write into fresh output buffers
1125 * if this is not the case, change the map flags as appropriate
1127 frame = gst_video_frame_new_and_map (&self->vinfo, buffer, GST_MAP_READ);
1129 tff = GST_VIDEO_FRAME_IS_TFF (frame);
1130 onefield = GST_VIDEO_FRAME_IS_ONEFIELD (frame);
1131 fields_to_push = (onefield) ? 1 : 2;
1133 g_return_if_fail (self->history_count <
1134 GST_DEINTERLACE_MAX_FIELD_HISTORY - fields_to_push);
1136 gst_deinterlace_get_buffer_state (self, frame, &buf_state, &interlacing_mode);
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, frame,
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));
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++;
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;
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;
1176 field_layout = GST_DEINTERLACE_LAYOUT_TFF;
1178 field_layout = GST_DEINTERLACE_LAYOUT_BFF;
1183 field2 = gst_video_frame_new_and_map (&self->vinfo, buffer, GST_MAP_READ);
1184 if (field_layout == GST_DEINTERLACE_LAYOUT_TFF) {
1185 GST_DEBUG_OBJECT (self, "Top field first");
1186 field1_flags = PICTURE_INTERLACED_TOP;
1187 field2_flags = PICTURE_INTERLACED_BOTTOM;
1189 GST_DEBUG_OBJECT (self, "Bottom field first");
1190 field1_flags = PICTURE_INTERLACED_BOTTOM;
1191 field2_flags = PICTURE_INTERLACED_TOP;
1194 /* Swap for reverse playback */
1195 if (self->segment.rate < 0) {
1196 field1_flags = field1_flags ^ field2_flags;
1197 field2_flags = field1_flags ^ field2_flags;
1198 field1_flags = field1_flags ^ field2_flags;
1202 GstVideoTimeCodeMeta *meta = gst_buffer_get_video_time_code_meta (buffer);
1203 GstVideoCaptionMeta *cc_meta = gst_buffer_get_video_caption_meta (buffer);
1205 GST_DEBUG_OBJECT (self, "Two fields");
1206 self->field_history[1].frame = field1;
1207 self->field_history[1].flags = field1_flags;
1209 self->field_history[0].frame = field2;
1210 self->field_history[0].flags = field2_flags;
1213 self->field_history[0].tc = gst_video_time_code_copy (&meta->tc);
1214 self->field_history[0].tc->config.flags &=
1215 ~GST_VIDEO_TIME_CODE_FLAGS_INTERLACED;
1216 self->field_history[1].tc = gst_video_time_code_copy (&meta->tc);
1217 self->field_history[1].tc->config.flags &=
1218 ~GST_VIDEO_TIME_CODE_FLAGS_INTERLACED;
1222 self->field_history[0].caption = g_new (GstVideoCaptionMeta, 1);
1223 self->field_history[0].caption->data = g_malloc (cc_meta->size);
1224 self->field_history[0].caption->caption_type = cc_meta->caption_type;
1225 self->field_history[0].caption->size = cc_meta->size;
1226 memcpy (self->field_history[0].caption->data, cc_meta->data,
1228 self->field_history[1].caption = g_new (GstVideoCaptionMeta, 1);
1229 self->field_history[1].caption->data = g_malloc (cc_meta->size);
1230 self->field_history[1].caption->caption_type = cc_meta->caption_type;
1231 self->field_history[1].caption->size = cc_meta->size;
1232 memcpy (self->field_history[1].caption->data, cc_meta->data,
1235 } else { /* onefield */
1236 GstVideoTimeCodeMeta *meta = gst_buffer_get_video_time_code_meta (buffer);
1237 GstVideoCaptionMeta *cc_meta = gst_buffer_get_video_caption_meta (buffer);
1239 GST_DEBUG_OBJECT (self, "One field");
1240 self->field_history[0].frame = field1;
1241 self->field_history[0].flags = field1_flags;
1243 self->field_history[0].tc = gst_video_time_code_copy (&meta->tc);
1244 self->field_history[0].tc->config.flags &=
1245 ~GST_VIDEO_TIME_CODE_FLAGS_INTERLACED;
1249 self->field_history[0].caption = g_new (GstVideoCaptionMeta, 1);
1250 self->field_history[0].caption->data = g_malloc (cc_meta->size);
1251 self->field_history[0].caption->caption_type = cc_meta->caption_type;
1252 self->field_history[0].caption->size = cc_meta->size;
1253 memcpy (self->field_history[0].caption->data, cc_meta->data,
1256 gst_video_frame_unmap_and_free (field2);
1259 /* we can manage the buffer ref count using the maps from here on */
1260 gst_buffer_unref (buffer);
1262 self->history_count += fields_to_push;
1263 self->cur_field_idx += fields_to_push;
1265 GST_DEBUG_OBJECT (self, "Pushed buffer -- current history size %d, index %d",
1266 self->history_count, self->cur_field_idx);
1268 if (self->last_buffer)
1269 gst_buffer_unref (self->last_buffer);
1270 self->last_buffer = gst_buffer_ref (buffer);
1274 gst_deinterlace_update_qos (GstDeinterlace * self, gdouble proportion,
1275 GstClockTimeDiff diff, GstClockTime timestamp)
1277 GST_DEBUG_OBJECT (self,
1278 "Updating QoS: proportion %lf, diff %" GST_STIME_FORMAT ", timestamp %"
1279 GST_TIME_FORMAT, proportion, GST_STIME_ARGS (diff),
1280 GST_TIME_ARGS (timestamp));
1282 GST_OBJECT_LOCK (self);
1283 self->proportion = proportion;
1284 if (G_LIKELY (timestamp != GST_CLOCK_TIME_NONE)) {
1285 if (G_UNLIKELY (diff > 0))
1286 self->earliest_time =
1287 timestamp + 2 * diff + ((self->fields ==
1288 GST_DEINTERLACE_ALL) ? self->field_duration : 2 *
1289 self->field_duration);
1291 self->earliest_time = timestamp + diff;
1293 self->earliest_time = GST_CLOCK_TIME_NONE;
1295 GST_OBJECT_UNLOCK (self);
1299 gst_deinterlace_reset_qos (GstDeinterlace * self)
1301 gst_deinterlace_update_qos (self, 0.5, 0, GST_CLOCK_TIME_NONE);
1302 self->processed = 0;
1307 gst_deinterlace_read_qos (GstDeinterlace * self, gdouble * proportion,
1308 GstClockTime * time)
1310 GST_OBJECT_LOCK (self);
1311 *proportion = self->proportion;
1312 *time = self->earliest_time;
1313 GST_OBJECT_UNLOCK (self);
1316 /* Perform qos calculations before processing the next frame. Returns TRUE if
1317 * the frame should be processed, FALSE if the frame can be dropped entirely */
1319 gst_deinterlace_do_qos (GstDeinterlace * self, const GstBuffer * buffer)
1321 GstClockTime qostime, earliest_time;
1322 GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
1325 /* no timestamp, can't do QoS => process frame */
1326 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) {
1327 GST_LOG_OBJECT (self, "invalid timestamp, can't do QoS, process frame");
1331 /* get latest QoS observation values */
1332 gst_deinterlace_read_qos (self, &proportion, &earliest_time);
1334 /* skip qos if we have no observation (yet) => process frame */
1335 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) {
1336 GST_LOG_OBJECT (self, "no observation yet, process frame");
1340 /* qos is done on running time */
1341 qostime = gst_segment_to_running_time (&self->segment, GST_FORMAT_TIME,
1344 /* see how our next timestamp relates to the latest qos timestamp */
1345 GST_LOG_OBJECT (self, "qostime %" GST_TIME_FORMAT ", earliest %"
1346 GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
1348 if (qostime != GST_CLOCK_TIME_NONE && qostime <= earliest_time) {
1349 GstClockTime stream_time, jitter;
1350 GstMessage *qos_msg;
1352 GST_DEBUG_OBJECT (self, "we are late, drop frame");
1355 gst_segment_to_stream_time (&self->segment, GST_FORMAT_TIME, timestamp);
1356 jitter = GST_CLOCK_DIFF (qostime, earliest_time);
1358 gst_message_new_qos (GST_OBJECT (self), FALSE, qostime, stream_time,
1359 timestamp, GST_BUFFER_DURATION (buffer));
1360 gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000);
1361 gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS,
1362 self->processed, self->dropped);
1363 gst_element_post_message (GST_ELEMENT (self), qos_msg);
1367 GST_LOG_OBJECT (self, "process frame");
1374 gst_deinterlace_fix_timestamps (GstDeinterlace * self,
1375 GstVideoFrame * field1, GstVideoFrame * field2)
1377 GstVideoFrame *field3, *field4;
1378 GstVideoInterlaceMode interlacing_mode;
1380 /* FIXME: This is broken for rate < 0 */
1381 if (self->pattern_lock && self->pattern > -1) {
1382 /* accurate pattern-locked timestamp adjustment */
1383 if (!self->pattern_count)
1384 gst_deinterlace_update_pattern_timestamps (self);
1386 GST_BUFFER_TIMESTAMP (field1->buffer) =
1387 self->pattern_base_ts + self->output_count * self->pattern_buf_dur;
1388 GST_BUFFER_DURATION (field1->buffer) = self->pattern_buf_dur;
1389 self->output_count++;
1391 /* naive (but low-latency) timestamp adjustment based on subsequent
1394 && GST_VIDEO_FRAME_PLANE_DATA (field1,
1395 0) != GST_VIDEO_FRAME_PLANE_DATA (field2, 0)) {
1396 if (GST_BUFFER_TIMESTAMP (field1->buffer) +
1397 GST_BUFFER_DURATION (field1->buffer) ==
1398 GST_BUFFER_TIMESTAMP (field2->buffer)) {
1399 GST_BUFFER_TIMESTAMP (field1->buffer) =
1400 GST_BUFFER_TIMESTAMP (field2->buffer) =
1401 (GST_BUFFER_TIMESTAMP (field1->buffer) +
1402 GST_BUFFER_TIMESTAMP (field2->buffer)) / 2;
1404 GST_BUFFER_TIMESTAMP (field2->buffer) =
1405 GST_BUFFER_TIMESTAMP (field1->buffer);
1409 if (self->history_count < 3) {
1410 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need 3)",
1411 self->history_count);
1415 field3 = self->field_history[self->history_count - 3].frame;
1416 interlacing_mode = GST_VIDEO_INFO_INTERLACE_MODE (&field3->info);
1417 if (IS_TELECINE (interlacing_mode)) {
1418 if (self->history_count < 4) {
1419 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need 4)",
1420 self->history_count);
1424 field4 = self->field_history[self->history_count - 4].frame;
1425 if (GST_VIDEO_FRAME_PLANE_DATA (field3,
1426 0) != GST_VIDEO_FRAME_PLANE_DATA (field4, 0)) {
1427 /* telecine fields in separate buffers */
1428 GST_BUFFER_TIMESTAMP (field3->buffer) =
1429 (GST_BUFFER_TIMESTAMP (field3->buffer) +
1430 GST_BUFFER_TIMESTAMP (field4->buffer)) / 2;
1434 GST_BUFFER_DURATION (field1->buffer) =
1435 GST_BUFFER_TIMESTAMP (field3->buffer) -
1436 GST_BUFFER_TIMESTAMP (field1->buffer);
1439 GST_DEBUG_OBJECT (self,
1440 "Field 1 adjusted to ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT,
1441 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1->buffer)),
1442 GST_TIME_ARGS (GST_BUFFER_DURATION (field1->buffer)));
1447 gst_deinterlace_get_pattern_lock (GstDeinterlace * self, gboolean * flush_one)
1449 /* loop over all possible patterns and all possible phases
1450 * giving each a score. the highest score gets the lock */
1451 /* the score is calculated as the number of matched buffers in the
1452 * sequence starting at the phase offset with those from the history
1453 * then the longest duration pattern match is taken. if there is more than
1454 * one pattern matching all buffers, we take the longest pattern of those.
1455 * matches to complete patterns are preferred. if no non-trivial pattern is
1456 * matched, trivial patterns are tested. */
1457 gint i, j, k, score, pattern, phase;
1458 const gint state_count = self->state_count;
1459 const gint n_required = self->ignore_obscure ?
1460 GST_DEINTERLACE_OBSCURE_THRESHOLD :
1461 GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY;
1463 /* set unknown pattern as this is used in logic outside this function */
1466 /* wait for more buffers */
1467 if (!self->have_eos && state_count < n_required) {
1468 GST_DEBUG_OBJECT (self, "Need more buffers in state history - %d/%d",
1469 state_count, n_required);
1473 score = pattern = phase = -1;
1475 /* loop over all patterns */
1476 for (i = 0; i < G_N_ELEMENTS (telecine_patterns); i++) {
1477 const guint8 length = telecine_patterns[i].length;
1479 if (self->ignore_obscure && i >= GST_DEINTERLACE_OBSCURE_THRESHOLD)
1482 if (state_count < length)
1485 /* loop over all phases */
1486 for (j = 0; j < length; j++) {
1487 /* low-latency mode looks at past buffers, high latency at future buffers */
1488 const gint state_idx =
1489 self->low_latency ? (self->history_count - 1) >> 1 : state_count - 1;
1490 /* loop over history, breaking on differing buffer states */
1491 for (k = 0; k < length && k < state_count; k++) {
1492 const guint8 hist = self->buf_states[state_idx - k].state;
1493 const guint8 patt = telecine_patterns[i].states[(j + k) % length];
1498 /* make complete matches more signficant */
1500 k += GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY;
1502 /* take as new best pattern if the number of matched buffers is more than
1503 * for other patterns */
1513 GST_WARNING_OBJECT (self, "Failed to select a pattern");
1517 GST_DEBUG_OBJECT (self,
1518 "Final pattern match result: pa %d, ph %d, l %d, s %d", pattern, phase,
1519 telecine_patterns[pattern].length, score);
1520 self->pattern = pattern;
1521 self->pattern_phase = phase;
1522 self->pattern_count = 0;
1523 self->output_count = 0;
1524 self->pattern_lock = TRUE;
1526 for (i = 0; i < telecine_patterns[pattern].length; i++) {
1528 self->low_latency ? (self->history_count - 1) >> 1 : self->state_count -
1531 GST_LOG_OBJECT (self, "buf[%d] %s", i,
1532 STATE_TO_STRING (self->buf_states[state_idx].state));
1535 /* check for the case that the first field of the pattern is an orphan */
1537 && telecine_patterns[pattern].states[phase] & (GST_ONE | GST_INT)) {
1538 gint i = phase, field_count = 0;
1539 guint8 state = telecine_patterns[pattern].states[i];
1542 if (state & GST_ONE) {
1545 } else if (!(state & GST_DRP)) {
1551 i %= telecine_patterns[pattern].length;
1552 state = telecine_patterns[pattern].states[i];
1553 } while (!(state & GST_PRG));
1555 /* if field_count is odd, we have an orphan field at the beginning of the
1557 * note - don't do this in low-latency mode as we are somewhere within the
1558 * pattern already */
1559 if (!self->low_latency && (*flush_one = field_count & 1)) {
1560 GST_DEBUG_OBJECT (self, "Orphan field detected at the beginning of the "
1561 "pattern - it will be deinterlaced.");
1566 static GstFlowReturn
1567 gst_deinterlace_output_frame (GstDeinterlace * self, gboolean flushing)
1569 GstClockTime timestamp;
1571 gint fields_required;
1572 GstBuffer *buf, *outbuf;
1573 GstVideoFrame *outframe = NULL;
1574 GstDeinterlaceField *field1, *field2;
1575 GstVideoInterlaceMode interlacing_mode;
1577 gboolean hl_no_lock; /* indicates high latency timestamp adjustment but no pattern lock (could be ONEF or I) */
1578 gboolean same_buffer; /* are field1 and field2 in the same buffer? */
1579 gboolean flush_one; /* used for flushing one field when in high latency mode and not locked */
1580 TelecinePattern pattern;
1581 guint8 phase, count;
1582 const GstDeinterlaceLocking locking = self->locking;
1583 gboolean cc_added = FALSE;
1585 memset (&pattern, 0, sizeof (pattern));
1591 self->need_more = FALSE;
1592 phase = self->pattern_phase;
1593 count = self->pattern_count;
1595 if (!self->history_count) {
1596 GST_DEBUG_OBJECT (self, "History is empty, waiting for more buffers!");
1600 field1 = &self->field_history[self->history_count - 1];
1602 if (locking != GST_DEINTERLACE_LOCKING_NONE) {
1605 if (!self->state_count) {
1606 GST_ERROR_OBJECT (self,
1607 "BROKEN! Fields in history + no states should not happen!");
1608 return GST_FLOW_ERROR;
1611 gst_deinterlace_get_buffer_state (self, field1->frame, &buf_state,
1614 if (self->pattern != -1)
1615 pattern = telecine_patterns[self->pattern];
1617 /* patterns 0 and 1 are interlaced, the rest are telecine */
1618 if (self->pattern > 1)
1619 interlacing_mode = GST_VIDEO_INTERLACE_MODE_MIXED;
1621 if (self->pattern == -1 || self->pattern_refresh
1622 || !(buf_state & pattern.states[(phase + count) % pattern.length])) {
1623 if (self->pattern == -1) {
1624 GST_DEBUG_OBJECT (self, "No pattern lock - refresh lock");
1625 } else if (self->pattern_refresh) {
1626 GST_DEBUG_OBJECT (self, "Pattern refresh - refresh lock");
1628 GST_DEBUG_OBJECT (self, "Unexpected buffer state - refresh lock");
1630 /* no pattern, pattern refresh set or unexpected buffer state */
1631 self->pattern_lock = FALSE;
1632 self->pattern_refresh = TRUE;
1634 /* refresh pattern lock */
1635 gst_deinterlace_get_pattern_lock (self, &flush_one);
1637 if (self->pattern != -1) {
1638 /* locked onto a valid pattern so refresh complete */
1639 GST_DEBUG_OBJECT (self, "Pattern locked! %s starting at %d",
1640 telecine_patterns[self->pattern].nick, self->pattern_phase);
1641 self->pattern_refresh = FALSE;
1642 } else if (!self->low_latency) {
1643 if (!self->pattern_lock) {
1650 /* setcaps on sink and src pads */
1651 sinkcaps = gst_pad_get_current_caps (self->sinkpad);
1652 if (!sinkcaps || !gst_deinterlace_setcaps (self, self->sinkpad, sinkcaps)) {
1654 gst_caps_unref (sinkcaps);
1655 return GST_FLOW_NOT_NEGOTIATED;
1658 gst_caps_unref (sinkcaps);
1660 if (flush_one && self->drop_orphans) {
1661 GST_DEBUG_OBJECT (self, "Dropping orphan first field");
1662 self->cur_field_idx--;
1663 gst_deinterlace_pop_and_clear (self);
1668 gst_deinterlace_get_buffer_state (self, field1->frame, NULL,
1672 same_buffer = self->history_count >= 2
1673 && (GST_VIDEO_FRAME_PLANE_DATA (field1->frame, 0) ==
1674 GST_VIDEO_FRAME_PLANE_DATA (self->field_history[self->history_count -
1677 if ((flushing && self->history_count == 1) || (flush_one
1678 && !self->drop_orphans) || (hl_no_lock && (self->history_count == 1
1679 || !same_buffer))) {
1680 /* This case is for flushing a single field:
1681 * - flushing and 1 field in the history
1682 * - flush one (due to orphans in the pattern) and do not drop orphans
1683 * - high-latency pattern locking with no possible lock given the current
1684 * state and either only one field in the history or the tip two fields
1685 * are in separate buffers */
1686 GST_DEBUG_OBJECT (self, "Flushing one field using linear method");
1687 gst_deinterlace_set_method (self, GST_DEINTERLACE_LINEAR);
1688 fields_required = gst_deinterlace_method_get_fields_required (self->method);
1689 } else if (interlacing_mode == GST_VIDEO_INTERLACE_MODE_PROGRESSIVE ||
1690 (interlacing_mode == GST_VIDEO_INTERLACE_MODE_MIXED &&
1691 !GST_VIDEO_FRAME_IS_INTERLACED (field1->frame))) {
1692 /* This case is for processing progressive buffers, telecine or plain
1694 GstVideoFrame *field1_frame;
1695 GstBuffer *field1_buffer;
1698 fields_required = 2;
1700 /* Not enough fields in the history */
1701 if (!flushing && self->history_count < fields_required) {
1702 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
1703 self->history_count, self->cur_field_idx + fields_required);
1707 field2 = &self->field_history[self->history_count - 2];
1708 if (GST_VIDEO_FRAME_PLANE_DATA (field1->frame,
1709 0) != GST_VIDEO_FRAME_PLANE_DATA (field2->frame, 0)) {
1710 /* ERROR - next two fields in field history are not one progressive buffer - weave? */
1711 GST_ERROR_OBJECT (self,
1712 "Progressive buffer but two fields at tip aren't in the same buffer!");
1715 if (IS_TELECINE (interlacing_mode)
1716 && !gst_deinterlace_fix_timestamps (self, field1->frame, field2->frame)
1720 GST_DEBUG_OBJECT (self,
1721 "Frame type: Progressive; pushing buffer as a frame");
1723 gst_deinterlace_delete_meta_at (self, self->history_count - 1);
1724 self->cur_field_idx--;
1725 field1_frame = gst_deinterlace_pop_history (self);
1726 field1_buffer = field1_frame->buffer;
1727 gst_buffer_ref (field1_buffer);
1728 gst_video_frame_unmap_and_free (field1_frame);
1730 /* field2 is the same buffer as field1, but we need to remove it from the
1732 self->cur_field_idx--;
1733 gst_deinterlace_pop_and_clear (self);
1734 GST_DEBUG_OBJECT (self,
1735 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1737 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buffer)),
1738 GST_TIME_ARGS (GST_BUFFER_DURATION (field1_buffer)),
1739 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buffer) +
1740 GST_BUFFER_DURATION (field1_buffer)));
1741 if (self->discont) {
1742 GST_BUFFER_FLAG_SET (field1_buffer, GST_BUFFER_FLAG_DISCONT);
1743 self->discont = FALSE;
1745 return gst_pad_push (self->srcpad, field1_buffer);
1746 } else if (IS_TELECINE (interlacing_mode)
1747 && GST_VIDEO_FRAME_IS_INTERLACED (field1->frame) && !same_buffer) {
1748 /* This case needs to identify telecine mixed buffers that require weaving
1749 * of two fields in different buffers.
1750 * - interlacing mode is mixed
1751 * - locked on to a telecine pattern
1752 * - frame is interlaced
1753 * - fields are in separate buffers
1754 * If we don't yet have a pattern lock, we will have to deinterlace as we
1755 * don't explicitly know we have a telecine sequence and so we drop through
1756 * to the plain deinterlace case */
1757 fields_required = 2;
1758 if (!flushing && self->history_count < fields_required) {
1759 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
1760 self->history_count, self->cur_field_idx + fields_required);
1764 field2 = &self->field_history[self->history_count - 2];
1765 if (!gst_deinterlace_fix_timestamps (self, field1->frame, field2->frame)
1769 /* check field1 and field2 buffer caps and flags are corresponding */
1770 if (field1->flags == field2->flags) {
1771 /* ERROR - fields are of same parity - what should be done here?
1772 * perhaps deinterlace the tip field and start again? */
1773 GST_ERROR_OBJECT (self, "Telecine mixed with fields of same parity!");
1775 GST_DEBUG_OBJECT (self,
1776 "Frame type: Telecine Mixed; weaving tip two fields into a frame");
1777 /* set method to WEAVE */
1778 gst_deinterlace_set_method (self, GST_DEINTERLACE_WEAVE);
1780 /* This is the final catch-all case that applies the selected deinterlacing
1781 * method. At this point the fields to be processed are either definitely
1782 * interlaced or we do not yet know that we have a telecine pattern lock
1783 * and so the best we can do is to deinterlace the fields. */
1784 gst_deinterlace_set_method (self, self->user_set_method_id);
1785 fields_required = gst_deinterlace_method_get_fields_required (self->method);
1786 if (flushing && self->history_count < fields_required) {
1787 /* note: we already checked for flushing with history count == 1 above
1788 * so we must have 2 or more fields in here */
1789 gst_deinterlace_set_method (self, GST_DEINTERLACE_VFIR);
1791 gst_deinterlace_method_get_fields_required (self->method);
1792 GST_DEBUG_OBJECT (self, "Flushing field(s) using %s method",
1793 methods_types[self->method_id].value_nick);
1796 /* Not enough fields in the history */
1797 if (!flushing && self->history_count < fields_required) {
1798 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
1799 self->history_count, self->cur_field_idx + fields_required);
1803 GST_DEBUG_OBJECT (self,
1804 "Frame type: Interlaced; deinterlacing using %s method",
1805 methods_types[self->method_id].value_nick);
1808 if (!flushing && self->cur_field_idx < 1) {
1810 } else if (self->cur_field_idx < 0 && flushing) {
1811 self->cur_field_idx++;
1814 if (self->fields == GST_DEINTERLACE_ALL || IS_TELECINE (interlacing_mode))
1815 GST_DEBUG_OBJECT (self, "All fields");
1816 else if (self->fields == GST_DEINTERLACE_TF)
1817 GST_DEBUG_OBJECT (self, "Top fields");
1818 else if (self->fields == GST_DEINTERLACE_BF)
1819 GST_DEBUG_OBJECT (self, "Bottom fields");
1821 if ((self->field_history[self->cur_field_idx].flags == PICTURE_INTERLACED_TOP
1822 && (self->fields == GST_DEINTERLACE_TF
1823 || IS_TELECINE (interlacing_mode)))
1824 || (self->fields == GST_DEINTERLACE_ALL
1825 && !IS_TELECINE (interlacing_mode))) {
1828 GST_DEBUG_OBJECT (self, "deinterlacing top field");
1830 /* create new buffer */
1831 ret = gst_buffer_pool_acquire_buffer (self->pool, &outbuf, NULL);
1832 if (ret != GST_FLOW_OK)
1835 g_return_val_if_fail (self->history_count >=
1836 1 + gst_deinterlace_method_get_latency (self->method), GST_FLOW_ERROR);
1839 self->history_count - 1 -
1840 gst_deinterlace_method_get_latency (self->method);
1841 buf = self->field_history[index].frame->buffer;
1843 if (self->field_history[index].tc) {
1844 gst_buffer_add_video_time_code_meta (outbuf,
1845 self->field_history[index].tc);
1847 if (self->field_history[index].caption) {
1848 g_assert (self->field_history[index].caption->data != NULL);
1849 g_assert (!cc_added);
1850 gst_buffer_add_video_caption_meta (outbuf,
1851 self->field_history[index].caption->caption_type,
1852 self->field_history[index].caption->data,
1853 self->field_history[index].caption->size);
1856 if (IS_TELECINE (interlacing_mode) && !self->telecine_tc_warned) {
1857 self->telecine_tc_warned = TRUE;
1858 GST_FIXME_OBJECT (self,
1859 "Detected telecine timecodes when deinterlacing. This is not "
1860 "supported yet. Resulting timecode may be wrong");
1862 if (self->fields == GST_DEINTERLACE_ALL) {
1863 GstVideoTimeCodeMeta *meta = gst_buffer_get_video_time_code_meta (outbuf);
1865 meta->tc.config.fps_n = 2 * meta->tc.config.fps_n;
1866 meta->tc.frames = 2 * meta->tc.frames;
1869 if (!IS_TELECINE (interlacing_mode)) {
1870 timestamp = GST_BUFFER_TIMESTAMP (buf);
1872 if (self->fields == GST_DEINTERLACE_ALL) {
1873 if (self->segment.rate < 0)
1874 GST_BUFFER_TIMESTAMP (outbuf) = timestamp + self->field_duration;
1876 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1877 GST_BUFFER_DURATION (outbuf) = self->field_duration;
1879 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1880 GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
1882 GST_DEBUG_OBJECT (self,
1883 "[ADJUST] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1884 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1885 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
1886 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
1887 GST_BUFFER_DURATION (outbuf)));
1889 GST_BUFFER_TIMESTAMP (outbuf) =
1890 GST_BUFFER_TIMESTAMP (field1->frame->buffer);
1891 GST_BUFFER_DURATION (outbuf) =
1892 GST_BUFFER_DURATION (field1->frame->buffer);
1895 /* Check if we need to drop the frame because of QoS */
1896 if (!gst_deinterlace_do_qos (self, buf)) {
1897 self->cur_field_idx--;
1898 gst_deinterlace_pop_and_clear (self);
1899 gst_buffer_unref (outbuf);
1903 if (self->cur_field_idx < 0 && flushing) {
1904 if (self->history_count == 1) {
1905 gst_deinterlace_pop_and_clear (self);
1908 self->cur_field_idx++;
1910 if (self->cur_field_idx < 0) {
1913 if (!flushing && self->cur_field_idx < 1) {
1917 /* map the frame so the deinterlace methods can write the data to the
1918 * correct memory locations */
1920 gst_video_frame_new_and_map (&self->vinfo, outbuf, GST_MAP_WRITE);
1922 /* do magic calculus */
1923 gst_deinterlace_method_deinterlace_frame (self->method,
1924 self->field_history, self->history_count, outframe,
1925 self->cur_field_idx);
1927 gst_video_frame_unmap_and_free (outframe);
1929 self->cur_field_idx--;
1930 /* need to remove the field in the telecine weaving case */
1931 if ((IS_TELECINE (interlacing_mode)
1932 && self->method_id == GST_DEINTERLACE_WEAVE)
1933 || self->cur_field_idx + 1 +
1934 gst_deinterlace_method_get_latency (self->method) <
1935 self->history_count || flushing) {
1936 gst_deinterlace_pop_and_clear (self);
1939 if (gst_deinterlace_clip_buffer (self, outbuf)) {
1940 GST_DEBUG_OBJECT (self,
1941 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1942 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1943 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
1944 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
1945 GST_BUFFER_DURATION (outbuf)));
1946 if (self->discont) {
1947 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1948 self->discont = FALSE;
1950 ret = gst_pad_push (self->srcpad, outbuf);
1953 gst_buffer_unref (outbuf);
1957 if (ret != GST_FLOW_OK)
1959 if (IS_TELECINE (interlacing_mode)
1960 && self->method_id == GST_DEINTERLACE_WEAVE) {
1961 /* pop off the second field */
1962 GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
1963 self->history_count);
1964 self->cur_field_idx--;
1965 gst_deinterlace_pop_and_clear (self);
1966 interlacing_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
1971 if (flush_one && !self->drop_orphans) {
1972 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1976 /* no calculation done: remove excess field */
1977 else if (self->field_history[self->cur_field_idx].flags ==
1978 PICTURE_INTERLACED_TOP && (self->fields == GST_DEINTERLACE_BF
1979 && !IS_TELECINE (interlacing_mode))) {
1980 GST_DEBUG_OBJECT (self, "Removing unused top field");
1981 self->cur_field_idx--;
1982 gst_deinterlace_pop_and_clear (self);
1984 if (flush_one && !self->drop_orphans) {
1985 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1990 if (self->history_count < fields_required)
1993 if (self->cur_field_idx < 0)
1996 /* deinterlace bottom_field */
1997 if ((self->field_history[self->cur_field_idx].flags ==
1998 PICTURE_INTERLACED_BOTTOM && (self->fields == GST_DEINTERLACE_BF
1999 || IS_TELECINE (interlacing_mode)))
2000 || (self->fields == GST_DEINTERLACE_ALL
2001 && !IS_TELECINE (interlacing_mode))) {
2004 GST_DEBUG_OBJECT (self, "deinterlacing bottom field");
2006 /* create new buffer */
2007 ret = gst_buffer_pool_acquire_buffer (self->pool, &outbuf, NULL);
2008 if (ret != GST_FLOW_OK)
2011 g_return_val_if_fail (self->history_count >=
2012 gst_deinterlace_method_get_latency (self->method) + 1, GST_FLOW_ERROR);
2015 self->history_count - 1 -
2016 gst_deinterlace_method_get_latency (self->method);
2017 buf = self->field_history[index].frame->buffer;
2019 if (self->field_history[index].tc) {
2020 gst_buffer_add_video_time_code_meta (outbuf,
2021 self->field_history[index].tc);
2023 if (self->field_history[index].caption && !cc_added) {
2024 g_assert (self->field_history[index].caption->data != NULL);
2025 gst_buffer_add_video_caption_meta (outbuf,
2026 self->field_history[index].caption->caption_type,
2027 self->field_history[index].caption->data,
2028 self->field_history[index].caption->size);
2031 if (IS_TELECINE (interlacing_mode) && !self->telecine_tc_warned) {
2032 self->telecine_tc_warned = TRUE;
2033 GST_FIXME_OBJECT (self,
2034 "Detected telecine timecodes when deinterlacing. This is not "
2035 "supported yet. Resulting timecode may be wrong");
2037 if (self->fields == GST_DEINTERLACE_ALL) {
2038 GstVideoTimeCodeMeta *meta = gst_buffer_get_video_time_code_meta (outbuf);
2040 meta->tc.config.fps_n = 2 * meta->tc.config.fps_n;
2041 meta->tc.frames = 2 * meta->tc.frames + 1;
2044 if (!IS_TELECINE (interlacing_mode)) {
2045 timestamp = GST_BUFFER_TIMESTAMP (buf);
2047 if (self->fields == GST_DEINTERLACE_ALL) {
2048 if (self->segment.rate < 0)
2049 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
2051 GST_BUFFER_TIMESTAMP (outbuf) = timestamp + self->field_duration;
2052 GST_BUFFER_DURATION (outbuf) = self->field_duration;
2054 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
2055 GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
2057 GST_DEBUG_OBJECT (self,
2058 "[ADJUST] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
2059 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
2060 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
2061 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
2062 GST_BUFFER_DURATION (outbuf)));
2064 GST_BUFFER_TIMESTAMP (outbuf) =
2065 GST_BUFFER_TIMESTAMP (field1->frame->buffer);
2066 GST_BUFFER_DURATION (outbuf) =
2067 GST_BUFFER_DURATION (field1->frame->buffer);
2070 /* Check if we need to drop the frame because of QoS */
2071 if (!gst_deinterlace_do_qos (self, buf)) {
2072 self->cur_field_idx--;
2073 gst_deinterlace_pop_and_clear (self);
2074 gst_buffer_unref (outbuf);
2078 /* map the frame so the deinterlace methods can write the data to the
2079 * correct memory locations */
2081 gst_video_frame_new_and_map (&self->vinfo, outbuf, GST_MAP_WRITE);
2083 /* do magic calculus */
2084 gst_deinterlace_method_deinterlace_frame (self->method,
2085 self->field_history, self->history_count, outframe,
2086 self->cur_field_idx);
2088 gst_video_frame_unmap_and_free (outframe);
2090 self->cur_field_idx--;
2091 /* need to remove the field in the telecine weaving case */
2092 if ((IS_TELECINE (interlacing_mode)
2093 && self->method_id == GST_DEINTERLACE_WEAVE)
2094 || self->cur_field_idx + 1 +
2095 gst_deinterlace_method_get_latency (self->method) <
2096 self->history_count) {
2097 gst_deinterlace_pop_and_clear (self);
2100 if (gst_deinterlace_clip_buffer (self, outbuf)) {
2101 GST_DEBUG_OBJECT (self,
2102 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
2103 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
2104 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
2105 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
2106 GST_BUFFER_DURATION (outbuf)));
2107 ret = gst_pad_push (self->srcpad, outbuf);
2110 gst_buffer_unref (outbuf);
2114 if (ret != GST_FLOW_OK)
2116 if (IS_TELECINE (interlacing_mode)
2117 && self->method_id == GST_DEINTERLACE_WEAVE) {
2118 /* pop off the second field */
2119 GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
2120 self->history_count);
2121 self->cur_field_idx--;
2122 gst_deinterlace_pop_and_clear (self);
2123 interlacing_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
2128 if (flush_one && !self->drop_orphans) {
2129 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
2133 /* no calculation done: remove excess field */
2134 else if (self->field_history[self->cur_field_idx].flags ==
2135 PICTURE_INTERLACED_BOTTOM && (self->fields == GST_DEINTERLACE_TF
2136 && !IS_TELECINE (interlacing_mode))) {
2137 GST_DEBUG_OBJECT (self, "Removing unused bottom field");
2138 self->cur_field_idx--;
2139 gst_deinterlace_pop_and_clear (self);
2141 if (flush_one && !self->drop_orphans) {
2142 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
2151 self->need_more = TRUE;
2156 GST_DEBUG_OBJECT (self, "could not allocate buffer");
2162 gst_deinterlace_get_latency (GstDeinterlace * self)
2164 if (self->locking == GST_DEINTERLACE_LOCKING_AUTO) {
2167 query = gst_query_new_latency ();
2168 if ((gst_pad_peer_query (self->sinkpad, query))) {
2170 /* if upstream is live, we use low-latency passive locking mode
2171 * else high-latency active locking mode */
2172 gst_query_parse_latency (query, &is_live, NULL, NULL);
2173 GST_DEBUG_OBJECT (self, "Latency query indicates stream is %s",
2174 is_live ? "live - using passive locking" :
2175 "not live - using active locking");
2176 gst_query_unref (query);
2179 /* conservatively use passive locking if the query fails */
2180 GST_WARNING_OBJECT (self,
2181 "Latency query failed - fall back to using passive locking");
2182 gst_query_unref (query);
2186 return self->locking - 2;
2190 static GstFlowReturn
2191 gst_deinterlace_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2193 GstDeinterlace *self = GST_DEINTERLACE (parent);
2194 GstFlowReturn ret = GST_FLOW_OK;
2196 GST_OBJECT_LOCK (self);
2197 if (self->reconfigure || gst_pad_check_reconfigure (self->srcpad)) {
2200 if ((gint) self->new_fields != -1)
2201 self->user_set_fields = self->new_fields;
2202 if ((gint) self->new_mode != -1)
2203 self->mode = self->new_mode;
2204 self->new_mode = -1;
2205 self->new_fields = -1;
2207 self->reconfigure = FALSE;
2208 GST_OBJECT_UNLOCK (self);
2209 caps = gst_pad_get_current_caps (self->sinkpad);
2211 if (!gst_deinterlace_setcaps (self, self->sinkpad, caps)) {
2212 gst_pad_mark_reconfigure (self->srcpad);
2213 gst_caps_unref (caps);
2214 if (GST_PAD_IS_FLUSHING (self->srcpad))
2215 return GST_FLOW_FLUSHING;
2217 return GST_FLOW_NOT_NEGOTIATED;
2219 gst_caps_unref (caps);
2221 gst_pad_mark_reconfigure (self->srcpad);
2222 return GST_FLOW_FLUSHING;
2225 GST_OBJECT_UNLOCK (self);
2228 GST_DEBUG_OBJECT (self,
2229 "[IN] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
2230 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
2231 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
2232 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)));
2234 if (self->still_frame_mode || self->passthrough) {
2235 GST_DEBUG_OBJECT (self,
2236 "Frame type: Progressive?; pushing buffer using pass-through");
2237 GST_DEBUG_OBJECT (self,
2238 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
2239 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
2240 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
2241 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)));
2243 return gst_pad_push (self->srcpad, buf);
2246 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
2247 GST_DEBUG_OBJECT (self, "DISCONT buffer, resetting history");
2248 gst_deinterlace_reset_history (self, FALSE);
2249 self->discont = TRUE;
2252 gst_deinterlace_push_history (self, buf);
2256 ret = gst_deinterlace_output_frame (self, FALSE);
2257 } while (!self->need_more && self->history_count > 0 && ret == GST_FLOW_OK);
2263 gst_deinterlace_acceptcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps)
2268 /* In AUTO/DISABLED mode we accept everything that is compatible with
2269 * our template caps. In INTERLACED mode we force deinterlacing, meaning
2270 * we can only possibly support the deinterlace caps.
2271 * In AUTO_STRICT mode we accept all progressive formats, but only those
2272 * interlaced format that we can actually deinterlace */
2273 if (self->mode == GST_DEINTERLACE_MODE_DISABLED
2274 || self->mode == GST_DEINTERLACE_MODE_AUTO) {
2275 ourcaps = gst_pad_get_pad_template_caps (pad);
2276 ret = gst_caps_is_subset (caps, ourcaps);
2277 gst_caps_unref (ourcaps);
2278 } else if (self->mode == GST_DEINTERLACE_MODE_INTERLACED) {
2279 ourcaps = gst_static_caps_get (&deinterlace_caps);
2280 ret = gst_caps_is_subset (caps, ourcaps);
2281 gst_caps_unref (ourcaps);
2282 } else if (self->mode == GST_DEINTERLACE_MODE_AUTO_STRICT) {
2283 ourcaps = gst_static_caps_get (&progressive_caps);
2284 ret = gst_caps_is_subset (caps, ourcaps);
2285 gst_caps_unref (ourcaps);
2288 ourcaps = gst_static_caps_get (&deinterlace_caps);
2289 ret = gst_caps_is_subset (caps, ourcaps);
2290 gst_caps_unref (ourcaps);
2293 g_assert_not_reached ();
2296 GST_DEBUG_OBJECT (pad, "accept-caps result:%d for caps %" GST_PTR_FORMAT,
2303 gst_deinterlace_fraction_double (gint * n_out, gint * d_out, gboolean half)
2316 gcd = gst_util_greatest_common_divisor (n, d);
2321 if (G_MAXINT / 2 >= ABS (d)) {
2323 } else if (n >= 2 && n != G_MAXINT) {
2329 if (G_MAXINT / 2 >= ABS (n)) {
2331 } else if (d >= 2 && d != G_MAXINT) {
2345 gst_deinterlace_caps_double_framerate (GstCaps * caps, gboolean half)
2349 for (len = gst_caps_get_size (caps); len > 0; len--) {
2350 GstStructure *s = gst_caps_get_structure (caps, len - 1);
2353 val = gst_structure_get_value (s, "framerate");
2357 if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION) {
2360 n = gst_value_get_fraction_numerator (val);
2361 d = gst_value_get_fraction_denominator (val);
2363 if (!gst_deinterlace_fraction_double (&n, &d, half)) {
2364 gst_caps_remove_structure (caps, len - 1);
2368 gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
2369 } else if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION_RANGE) {
2370 const GValue *min, *max;
2371 GValue nrange = { 0, }, nmin = {
2376 g_value_init (&nrange, GST_TYPE_FRACTION_RANGE);
2377 g_value_init (&nmin, GST_TYPE_FRACTION);
2378 g_value_init (&nmax, GST_TYPE_FRACTION);
2380 min = gst_value_get_fraction_range_min (val);
2381 max = gst_value_get_fraction_range_max (val);
2383 n = gst_value_get_fraction_numerator (min);
2384 d = gst_value_get_fraction_denominator (min);
2386 if (!gst_deinterlace_fraction_double (&n, &d, half)) {
2387 g_value_unset (&nrange);
2388 g_value_unset (&nmax);
2389 g_value_unset (&nmin);
2390 gst_caps_remove_structure (caps, len - 1);
2394 gst_value_set_fraction (&nmin, n, d);
2396 n = gst_value_get_fraction_numerator (max);
2397 d = gst_value_get_fraction_denominator (max);
2399 if (!gst_deinterlace_fraction_double (&n, &d, half)) {
2400 g_value_unset (&nrange);
2401 g_value_unset (&nmax);
2402 g_value_unset (&nmin);
2403 gst_caps_remove_structure (caps, len - 1);
2407 gst_value_set_fraction (&nmax, n, d);
2408 gst_value_set_fraction_range (&nrange, &nmin, &nmax);
2410 gst_structure_take_value (s, "framerate", &nrange);
2412 g_value_unset (&nmin);
2413 g_value_unset (&nmax);
2414 } else if (G_VALUE_TYPE (val) == GST_TYPE_LIST) {
2416 GValue nlist = { 0, };
2417 GValue nval = { 0, };
2420 g_value_init (&nlist, GST_TYPE_LIST);
2421 for (i = gst_value_list_get_size (val); i > 0; i--) {
2424 lval = gst_value_list_get_value (val, i - 1);
2426 if (G_VALUE_TYPE (lval) != GST_TYPE_FRACTION)
2429 n = gst_value_get_fraction_numerator (lval);
2430 d = gst_value_get_fraction_denominator (lval);
2432 /* Double/Half the framerate but if this fails simply
2433 * skip this value from the list */
2434 if (!gst_deinterlace_fraction_double (&n, &d, half)) {
2438 g_value_init (&nval, GST_TYPE_FRACTION);
2440 gst_value_set_fraction (&nval, n, d);
2441 gst_value_list_append_and_take_value (&nlist, &nval);
2443 gst_structure_take_value (s, "framerate", &nlist);
2451 gst_deinterlace_getcaps (GstDeinterlace * self, GstPad * pad, GstCaps * filter)
2453 GstCaps *ret, *caps;
2458 GstCaps *tmp, *tmp2;
2460 otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad;
2462 ourcaps = gst_pad_get_pad_template_caps (pad);
2463 peercaps = gst_pad_peer_query_caps (otherpad, NULL);
2465 /* Filter any peercaps that are available with our template
2466 * to get started with the subset of caps we actually support */
2468 GST_DEBUG_OBJECT (pad, "Peer has caps %" GST_PTR_FORMAT, peercaps);
2469 caps = gst_caps_make_writable (gst_caps_intersect (ourcaps, peercaps));
2470 gst_caps_unref (peercaps);
2471 gst_caps_unref (ourcaps);
2472 peercaps = ourcaps = NULL;
2474 caps = gst_caps_make_writable (ourcaps);
2478 GST_DEBUG_OBJECT (pad,
2479 "Transforming caps %" GST_PTR_FORMAT " with filter %" GST_PTR_FORMAT,
2482 /* If deinterlacing is disabled, we just passthrough the
2483 * caps and everything */
2484 if (self->mode == GST_DEINTERLACE_MODE_DISABLED) {
2490 /* If deinterlacing is enforced, we can only accept the
2491 * caps for which we can actually do deinterlacing */
2492 if (self->mode == GST_DEINTERLACE_MODE_INTERLACED) {
2493 tmp = gst_static_caps_get (&deinterlace_caps);
2494 ret = gst_caps_intersect_full (caps, tmp, GST_CAPS_INTERSECT_FIRST);
2495 gst_caps_unref (tmp);
2497 gst_caps_unref (caps);
2502 g_assert (self->mode == GST_DEINTERLACE_MODE_AUTO
2503 || self->mode == GST_DEINTERLACE_MODE_AUTO_STRICT);
2505 /* For the auto mode we have to do a bit more than that */
2506 ret = gst_caps_new_empty ();
2508 /* We can accept any structure if
2509 * - they are progressive already
2512 tmp = gst_static_caps_get (&progressive_caps);
2513 tmp2 = gst_caps_intersect_full (caps, tmp, GST_CAPS_INTERSECT_FIRST);
2514 gst_caps_unref (tmp);
2516 ret = gst_caps_merge (ret, tmp2);
2520 * - they have sysmem caps features and a format for which we support
2523 * - they have ANY caps features, in which case we support it for
2524 * sysmem caps features for formats we support
2526 * NOTE: These are the caps where we actually would do deinterlacing
2527 * ourselves. If fields == ALL we would double the framerate so would
2528 * have to half the framerate constraints from downstream here
2530 tmp = gst_static_caps_get (&deinterlace_caps);
2531 tmp2 = gst_caps_intersect_full (caps, tmp, GST_CAPS_INTERSECT_FIRST);
2532 gst_caps_unref (tmp);
2535 for (len = gst_caps_get_size (tmp2); len > 0; len--) {
2536 GstStructure *s = gst_caps_get_structure (tmp2, len - 1);
2538 if (pad == self->sinkpad)
2539 gst_structure_remove_field (s, "interlace-mode");
2541 gst_structure_set (s, "interlace-mode", G_TYPE_STRING, "progressive",
2545 if (self->user_set_fields == GST_DEINTERLACE_ALL) {
2546 tmp2 = gst_deinterlace_caps_double_framerate (tmp2, (pad == self->sinkpad));
2548 if (self->user_set_fields == GST_DEINTERLACE_FIELDS_AUTO) {
2549 tmp = gst_caps_copy (tmp2);
2550 tmp = gst_deinterlace_caps_double_framerate (tmp, (pad == self->sinkpad));
2553 ret = gst_caps_merge (ret, tmp2);
2556 ret = gst_caps_merge (ret, tmp);
2561 * - anything else in which case we would just passthrough again if we're
2562 * only in AUTO and not AUTO_STRICT mode
2564 if (self->mode == GST_DEINTERLACE_MODE_AUTO)
2565 ret = gst_caps_merge (ret, gst_caps_copy (caps));
2567 gst_caps_unref (caps);
2575 GST_LOG_OBJECT (pad, "intersecting with %" GST_PTR_FORMAT, filter);
2576 tmp = gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
2577 gst_caps_unref (ret);
2581 GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret);
2586 /* takes ownership of the pool, allocator and query */
2588 gst_deinterlace_set_allocation (GstDeinterlace * self,
2589 GstBufferPool * pool, GstAllocator * allocator,
2590 GstAllocationParams * params)
2592 GstAllocator *oldalloc;
2593 GstBufferPool *oldpool;
2595 GST_OBJECT_LOCK (self);
2596 oldpool = self->pool;
2599 oldalloc = self->allocator;
2600 self->allocator = allocator;
2603 self->params = *params;
2605 gst_allocation_params_init (&self->params);
2606 GST_OBJECT_UNLOCK (self);
2609 GST_DEBUG_OBJECT (self, "deactivating old pool %p", oldpool);
2610 gst_buffer_pool_set_active (oldpool, FALSE);
2611 gst_object_unref (oldpool);
2614 gst_object_unref (oldalloc);
2617 GST_DEBUG_OBJECT (self, "activating new pool %p", pool);
2618 gst_buffer_pool_set_active (pool, TRUE);
2624 gst_deinterlace_do_bufferpool (GstDeinterlace * self, GstCaps * outcaps)
2627 gboolean result = TRUE;
2628 GstBufferPool *pool;
2629 GstAllocator *allocator;
2630 GstAllocationParams params;
2631 GstStructure *config;
2632 guint size, min, max;
2634 if (self->passthrough) {
2635 /* we are in passthrough, the input buffer is never copied and always passed
2636 * along. We never allocate an output buffer on the srcpad. What we do is
2637 * let the upstream element decide if it wants to use a bufferpool and
2638 * then we will proxy the downstream pool */
2639 GST_DEBUG_OBJECT (self, "we're passthough, delay bufferpool");
2640 gst_deinterlace_set_allocation (self, NULL, NULL, NULL);
2644 /* not passthrough, we need to allocate */
2645 /* find a pool for the negotiated caps now */
2646 GST_DEBUG_OBJECT (self, "doing allocation query");
2647 query = gst_query_new_allocation (outcaps, TRUE);
2648 if (!gst_pad_peer_query (self->srcpad, query)) {
2649 /* not a problem, just debug a little */
2650 GST_DEBUG_OBJECT (self, "peer ALLOCATION query failed");
2653 GST_DEBUG_OBJECT (self, "ALLOCATION (%d) params: %" GST_PTR_FORMAT, result,
2656 /* we got configuration from our peer or the decide_allocation method,
2658 if (gst_query_get_n_allocation_params (query) > 0) {
2659 gst_query_parse_nth_allocation_param (query, 0, &allocator, ¶ms);
2662 gst_allocation_params_init (¶ms);
2665 if (gst_query_get_n_allocation_pools (query) > 0)
2666 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
2669 size = GST_VIDEO_INFO_SIZE (&self->vinfo);
2671 MAX ((gst_deinterlace_method_get_fields_required (self->method) +
2677 /* no pool, we can make our own */
2678 GST_DEBUG_OBJECT (self, "no pool, making new pool");
2679 pool = gst_video_buffer_pool_new ();
2683 config = gst_buffer_pool_get_config (pool);
2684 gst_buffer_pool_config_set_params (config, outcaps, size, min, max);
2685 gst_buffer_pool_config_set_allocator (config, allocator, ¶ms);
2686 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
2687 gst_buffer_pool_set_config (pool, config);
2690 result = gst_deinterlace_set_allocation (self, pool, allocator, ¶ms);
2692 gst_query_unref (query);
2699 gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps)
2701 GstCaps *srccaps = NULL;
2702 GstVideoInterlaceMode interlacing_mode;
2704 GstCaps *peercaps, *current_caps;
2706 gst_pad_check_reconfigure (self->srcpad);
2708 if ((current_caps = gst_pad_get_current_caps (pad))) {
2709 if (gst_caps_is_equal (caps, current_caps)) {
2710 GST_DEBUG_OBJECT (pad, "Got same caps again, returning");
2711 gst_caps_unref (current_caps);
2714 gst_deinterlace_reset_history (self, FALSE);
2715 gst_caps_unref (current_caps);
2717 peercaps = gst_pad_peer_query_caps (self->srcpad, NULL);
2719 /* Make sure the peer caps are compatible with the template caps */
2721 GstCaps *tmp = gst_pad_get_pad_template_caps (self->srcpad);
2722 GstCaps *tmp2 = gst_caps_intersect (peercaps, tmp);
2724 gst_caps_unref (peercaps);
2726 gst_caps_unref (tmp);
2728 if (gst_caps_is_empty (tmp2)) {
2729 gst_caps_unref (tmp2);
2730 GST_ERROR_OBJECT (self, "Peer caps not compatible with template caps");
2736 if (self->locking != GST_DEINTERLACE_LOCKING_NONE) {
2737 if (self->low_latency == -1)
2738 self->low_latency = gst_deinterlace_get_latency (self);
2740 if (self->pattern_lock) {
2741 /* refresh has been successful - we have a lock now */
2742 self->pattern_refresh = FALSE;
2744 /* if we were not refreshing (!pattern_refresh) the caps have changed
2745 * so we need to refresh and we don't have a lock anymore
2746 * otherwise we have pattern_fresh and !pattern_lock anyway */
2747 self->pattern_refresh = TRUE;
2748 self->pattern_lock = FALSE;
2752 if (!gst_video_info_from_caps (&self->vinfo, caps))
2755 fps_n = GST_VIDEO_INFO_FPS_N (&self->vinfo);
2756 fps_d = GST_VIDEO_INFO_FPS_D (&self->vinfo);
2758 /* Update passthrough information */
2759 if (self->mode == GST_DEINTERLACE_MODE_DISABLED) {
2760 self->passthrough = TRUE;
2761 GST_DEBUG_OBJECT (self, "Passthrough because mode=disabled");
2762 } else if (self->mode == GST_DEINTERLACE_MODE_INTERLACED) {
2763 GstCaps *tmp = gst_static_caps_get (&deinterlace_caps);
2765 if (!gst_caps_can_intersect (caps, tmp)) {
2766 gst_caps_unref (tmp);
2767 GST_ERROR_OBJECT (self, "Unsupported caps for mode=interlaced");
2771 self->passthrough = FALSE;
2772 GST_DEBUG_OBJECT (self, "Not passthrough because mode=interlaced");
2773 } else if (self->mode == GST_DEINTERLACE_MODE_AUTO
2774 || self->mode == GST_DEINTERLACE_MODE_AUTO_STRICT) {
2775 GstCaps *tmp = gst_static_caps_get (&deinterlace_caps);
2777 /* Already progressive? Passthrough */
2778 if (!GST_VIDEO_INFO_IS_INTERLACED (&self->vinfo)) {
2779 GST_DEBUG_OBJECT (self,
2780 "Passthrough because mode=auto and progressive caps");
2781 self->passthrough = TRUE;
2782 } else if (gst_caps_can_intersect (caps, tmp)) {
2784 GstCaps *allowed_caps;
2788 allowed_caps = gst_caps_intersect (peercaps, tmp);
2790 tmp2 = gst_caps_copy (caps);
2791 s = gst_caps_get_structure (tmp2, 0);
2792 gst_structure_set (s, "interlace-mode", G_TYPE_STRING, "progressive",
2794 gst_structure_remove_field (s, "framerate");
2796 /* Downstream does not support progressive caps but supports
2797 * the upstream caps, go passthrough.
2798 * TODO: We might want to check the framerate compatibility
2799 * of the caps too here
2801 if (gst_caps_can_intersect (allowed_caps, caps)
2802 && !gst_caps_can_intersect (allowed_caps, tmp2)) {
2803 GST_DEBUG_OBJECT (self,
2804 "Passthrough because mode=auto, "
2805 "downstream does not support progressive caps and interlaced caps");
2806 self->passthrough = TRUE;
2808 GST_DEBUG_OBJECT (self, "Not passthrough because mode=auto, "
2809 "downstream supports progressive caps and interlaced caps");
2810 self->passthrough = FALSE;
2813 gst_caps_unref (allowed_caps);
2814 gst_caps_unref (tmp2);
2816 GST_DEBUG_OBJECT (self,
2817 "Not passthrough because mode=auto and interlaced caps");
2818 self->passthrough = FALSE;
2821 if (self->mode == GST_DEINTERLACE_MODE_AUTO) {
2822 GST_WARNING_OBJECT (self,
2823 "Passthrough because mode=auto and unsupported interlaced caps");
2824 self->passthrough = TRUE;
2826 gst_caps_unref (tmp);
2827 GST_ERROR_OBJECT (self,
2828 "Unsupported interlaced caps in mode=auto-strict");
2833 gst_caps_unref (tmp);
2835 g_assert_not_reached ();
2838 interlacing_mode = GST_VIDEO_INFO_INTERLACE_MODE (&self->vinfo);
2840 if (!self->passthrough) {
2841 if (self->pattern_lock) {
2842 srccaps = gst_caps_copy (caps);
2843 if (self->pattern != -1
2844 && G_UNLIKELY (!gst_util_fraction_multiply (fps_n, fps_d,
2845 telecine_patterns[self->pattern].ratio_n,
2846 telecine_patterns[self->pattern].ratio_d, &fps_n, &fps_d)))
2847 GST_ERROR_OBJECT (self,
2848 "Multiplying the framerate by the telecine pattern ratio overflowed!");
2849 gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, fps_n,
2851 } else if (self->locking == GST_DEINTERLACE_LOCKING_ACTIVE
2852 || self->low_latency == 0) {
2853 /* in high latency pattern locking mode if we don't have a pattern lock,
2854 * the sink pad caps are the best we know */
2855 srccaps = gst_caps_copy (caps);
2856 } else if (self->low_latency > 0
2857 && interlacing_mode == GST_VIDEO_INTERLACE_MODE_MIXED
2858 && self->pattern == -1) {
2859 /* for initial buffers of a telecine pattern, until there is a lock we
2860 * we output naïvely adjusted timestamps in low-latency pattern locking
2862 srccaps = gst_caps_copy (caps);
2863 gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
2864 } else if (self->user_set_fields == GST_DEINTERLACE_FIELDS_AUTO) {
2865 srccaps = gst_caps_copy (caps);
2867 gboolean can_be_tf = FALSE;
2869 /* We already know that we are not passthrough: interlace-mode will
2871 gst_caps_set_simple (srccaps, "interlace-mode", G_TYPE_STRING,
2872 "progressive", NULL);
2874 if (gst_caps_can_intersect (peercaps, srccaps)) {
2875 GST_DEBUG_OBJECT (self, "Can deinterlace top fields");
2878 srccaps = gst_deinterlace_caps_double_framerate (srccaps, FALSE);
2879 if (!gst_caps_can_intersect (peercaps, srccaps)) {
2881 GST_DEBUG_OBJECT (self, "Will deinterlace top fields");
2882 gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, fps_n,
2884 self->fields = GST_DEINTERLACE_TF;
2886 GST_DEBUG_OBJECT (self,
2887 "Can't negotiate upstream and downstream caps");
2888 gst_caps_unref (srccaps);
2892 GST_DEBUG_OBJECT (self, "Deinterlacing all fields");
2893 self->fields = GST_DEINTERLACE_ALL;
2896 GST_DEBUG_OBJECT (self,
2897 "No peer caps yet, falling back to deinterlacing all fields");
2898 self->fields = GST_DEINTERLACE_ALL;
2899 srccaps = gst_deinterlace_caps_double_framerate (srccaps, FALSE);
2902 self->fields = self->user_set_fields;
2903 srccaps = gst_caps_copy (caps);
2904 if (self->fields == GST_DEINTERLACE_ALL)
2905 srccaps = gst_deinterlace_caps_double_framerate (srccaps, FALSE);
2908 /* If not passthrough, we are going to output progressive content */
2909 gst_caps_set_simple (srccaps, "interlace-mode", G_TYPE_STRING,
2910 "progressive", NULL);
2912 gst_deinterlace_set_method (self, self->method_id);
2913 gst_deinterlace_method_setup (self->method, &self->vinfo);
2915 srccaps = gst_caps_ref (caps);
2919 self->field_duration = gst_util_uint64_scale (GST_SECOND, fps_d, 2 * fps_n);
2921 self->field_duration = 0;
2924 GST_DEBUG_OBJECT (pad, "Sink caps: %" GST_PTR_FORMAT, caps);
2925 GST_DEBUG_OBJECT (pad, "Src caps: %" GST_PTR_FORMAT, srccaps);
2927 if (!gst_pad_set_caps (self->srcpad, srccaps))
2928 goto set_caps_failed;
2930 if (!gst_deinterlace_do_bufferpool (self, srccaps))
2934 gst_caps_unref (peercaps);
2935 gst_caps_unref (srccaps);
2942 gst_caps_unref (peercaps);
2943 GST_ERROR_OBJECT (pad, "Invalid caps: %" GST_PTR_FORMAT, caps);
2944 gst_pad_mark_reconfigure (self->srcpad);
2949 GST_ERROR_OBJECT (pad, "Failed to set caps: %" GST_PTR_FORMAT, srccaps);
2951 gst_caps_unref (peercaps);
2952 gst_caps_unref (srccaps);
2953 gst_pad_mark_reconfigure (self->srcpad);
2958 GST_ERROR_OBJECT (pad, "could not negotiate bufferpool");
2960 gst_caps_unref (peercaps);
2961 gst_caps_unref (srccaps);
2962 gst_pad_mark_reconfigure (self->srcpad);
2968 gst_deinterlace_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
2970 gboolean res = TRUE;
2971 GstDeinterlace *self = GST_DEINTERLACE (parent);
2973 GST_LOG_OBJECT (pad, "received %s event: %" GST_PTR_FORMAT,
2974 GST_EVENT_TYPE_NAME (event), event);
2976 switch (GST_EVENT_TYPE (event)) {
2977 case GST_EVENT_CAPS:
2979 GstCaps *caps = NULL;
2981 gst_event_parse_caps (event, &caps);
2982 res = gst_deinterlace_setcaps (self, pad, caps);
2983 gst_event_unref (event);
2986 case GST_EVENT_SEGMENT:
2988 const GstSegment *segment;
2990 gst_event_parse_segment (event, &segment);
2992 gst_deinterlace_reset_qos (self);
2993 gst_deinterlace_reset_history (self, FALSE);
2995 if (segment->format == GST_FORMAT_TIME) {
2996 GST_DEBUG_OBJECT (pad,
2997 "Got SEGMENT event in TIME format, passing on (%"
2998 GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")",
2999 GST_TIME_ARGS (segment->start), GST_TIME_ARGS (segment->stop));
3000 gst_segment_copy_into (segment, &self->segment);
3002 GST_WARNING_OBJECT (pad, "Got SEGMENT event in %s format",
3003 gst_format_get_name (segment->format));
3004 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
3007 res = gst_pad_push_event (self->srcpad, event);
3010 case GST_EVENT_CUSTOM_DOWNSTREAM:{
3011 gboolean still_state;
3013 if (gst_video_event_parse_still_frame (event, &still_state)) {
3014 GST_DEBUG_OBJECT (self, "Received still frame event, state %d",
3020 GST_DEBUG_OBJECT (self, "Handling still frame");
3021 self->still_frame_mode = TRUE;
3022 gst_deinterlace_reset_history (self, FALSE);
3023 if (self->last_buffer) {
3025 gst_pad_push (self->srcpad, gst_buffer_ref (self->last_buffer));
3026 GST_DEBUG_OBJECT (self, "Pushed still frame, result: %s",
3027 gst_flow_get_name (ret));
3029 GST_WARNING_OBJECT (self, "No pending buffer!");
3032 GST_DEBUG_OBJECT (self, "Ending still frames");
3033 self->still_frame_mode = FALSE;
3037 res = gst_pad_push_event (self->srcpad, event);
3041 self->have_eos = TRUE;
3042 gst_deinterlace_reset_history (self, FALSE);
3043 res = gst_pad_push_event (self->srcpad, event);
3046 case GST_EVENT_FLUSH_STOP:
3047 if (self->still_frame_mode) {
3048 GST_DEBUG_OBJECT (self, "Ending still frames");
3049 self->still_frame_mode = FALSE;
3051 self->telecine_tc_warned = FALSE;
3052 gst_deinterlace_reset_qos (self);
3053 res = gst_pad_push_event (self->srcpad, event);
3054 gst_deinterlace_reset_history (self, TRUE);
3058 res = gst_pad_event_default (pad, parent, event);
3066 gst_deinterlace_propose_allocation (GstDeinterlace * self, GstQuery * query)
3068 GstBufferPool *pool;
3072 GstStructure *config;
3074 gst_query_parse_allocation (query, &caps, NULL);
3079 if (!gst_video_info_from_caps (&info, caps))
3082 size = GST_VIDEO_INFO_SIZE (&info);
3084 pool = gst_video_buffer_pool_new ();
3086 gst_query_add_allocation_pool (query, pool, size, 0, 0);
3088 config = gst_buffer_pool_get_config (pool);
3089 gst_buffer_pool_config_set_params (config, caps, size,
3090 (gst_deinterlace_method_get_fields_required (self->method) + 1) / 2 + 1,
3092 gst_buffer_pool_set_config (pool, config);
3094 gst_object_unref (pool);
3095 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
3101 gst_deinterlace_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
3103 GstDeinterlace *self = GST_DEINTERLACE (parent);
3104 gboolean res = FALSE;
3106 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
3108 switch (GST_QUERY_TYPE (query)) {
3109 case GST_QUERY_CAPS:
3111 GstCaps *filter, *caps;
3113 gst_query_parse_caps (query, &filter);
3114 caps = gst_deinterlace_getcaps (self, pad, filter);
3115 gst_query_set_caps_result (query, caps);
3116 gst_caps_unref (caps);
3120 case GST_QUERY_ACCEPT_CAPS:
3125 gst_query_parse_accept_caps (query, &caps);
3126 ret = gst_deinterlace_acceptcaps (self, pad, caps);
3127 gst_query_set_accept_caps_result (query, ret);
3131 case GST_QUERY_ALLOCATION:
3132 if (self->passthrough)
3133 res = gst_pad_peer_query (self->srcpad, query);
3135 res = gst_deinterlace_propose_allocation (self, query);
3138 res = gst_pad_query_default (pad, parent, query);
3144 static GstStateChangeReturn
3145 gst_deinterlace_change_state (GstElement * element, GstStateChange transition)
3147 GstStateChangeReturn ret;
3148 GstDeinterlace *self = GST_DEINTERLACE (element);
3150 switch (transition) {
3151 case GST_STATE_CHANGE_NULL_TO_READY:
3153 case GST_STATE_CHANGE_READY_TO_PAUSED:
3155 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
3161 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3162 if (ret != GST_STATE_CHANGE_SUCCESS)
3165 switch (transition) {
3166 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
3168 case GST_STATE_CHANGE_PAUSED_TO_READY:
3169 gst_deinterlace_reset (self);
3171 case GST_STATE_CHANGE_READY_TO_NULL:
3180 gst_deinterlace_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
3182 GstDeinterlace *self = GST_DEINTERLACE (parent);
3185 GST_DEBUG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
3187 switch (GST_EVENT_TYPE (event)) {
3188 case GST_EVENT_QOS:{
3189 GstClockTimeDiff diff;
3190 GstClockTime timestamp;
3194 gst_event_parse_qos (event, &type, &proportion, &diff, ×tamp);
3196 gst_deinterlace_update_qos (self, proportion, diff, timestamp);
3200 res = gst_pad_event_default (pad, parent, event);
3208 gst_deinterlace_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
3210 GstDeinterlace *self = GST_DEINTERLACE (parent);
3211 gboolean res = FALSE;
3213 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
3215 switch (GST_QUERY_TYPE (query)) {
3216 case GST_QUERY_LATENCY:
3217 if (!self->passthrough) {
3218 GstClockTime min, max;
3222 if ((peer = gst_pad_get_peer (self->sinkpad))) {
3223 if ((res = gst_pad_query (peer, query))) {
3224 GstClockTime latency;
3225 gint fields_required = 0;
3226 gint method_latency = 0;
3230 gst_deinterlace_method_get_fields_required (self->method);
3232 gst_deinterlace_method_get_latency (self->method);
3235 gst_query_parse_latency (query, &live, &min, &max);
3237 GST_DEBUG_OBJECT (self, "Peer latency: min %"
3238 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
3239 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
3241 /* add our own latency */
3242 latency = (fields_required + method_latency) * self->field_duration;
3244 GST_DEBUG_OBJECT (self, "Our latency: min %" GST_TIME_FORMAT
3245 ", max %" GST_TIME_FORMAT,
3246 GST_TIME_ARGS (latency), GST_TIME_ARGS (latency));
3249 if (max != GST_CLOCK_TIME_NONE)
3252 GST_DEBUG_OBJECT (self, "Calculated total latency : min %"
3253 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
3254 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
3256 gst_query_set_latency (query, live, min, max);
3258 gst_object_unref (peer);
3265 res = gst_pad_query_default (pad, parent, query);
3273 plugin_init (GstPlugin * plugin)
3275 GST_DEBUG_CATEGORY_INIT (deinterlace_debug, "deinterlace", 0, "Deinterlacer");
3281 if (!gst_element_register (plugin, "deinterlace", GST_RANK_NONE,
3282 GST_TYPE_DEINTERLACE)) {
3289 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
3292 "Deinterlacer", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
3293 GST_PACKAGE_ORIGIN);