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., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, 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 -v filesrc location=/path/to/file ! decodebin2 ! ffmpegcolorspace ! deinterlace ! ffmpegcolorspace ! 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
76 #define GST_DEINTERLACE_BUFFER_STATE_P (1<<0)
77 #define GST_DEINTERLACE_BUFFER_STATE_I (1<<1)
78 #define GST_DEINTERLACE_BUFFER_STATE_TC_B (1<<2)
79 #define GST_DEINTERLACE_BUFFER_STATE_TC_T (1<<3)
80 #define GST_DEINTERLACE_BUFFER_STATE_TC_P (1<<4)
81 #define GST_DEINTERLACE_BUFFER_STATE_TC_M (1<<5)
82 #define GST_DEINTERLACE_BUFFER_STATE_DROP (1<<6)
85 (GST_DEINTERLACE_BUFFER_STATE_TC_T | GST_DEINTERLACE_BUFFER_STATE_TC_B)
87 (GST_DEINTERLACE_BUFFER_STATE_P | GST_DEINTERLACE_BUFFER_STATE_TC_P)
89 (GST_DEINTERLACE_BUFFER_STATE_I | GST_DEINTERLACE_BUFFER_STATE_TC_M)
90 #define GST_DRP (GST_DEINTERLACE_BUFFER_STATE_DROP)
92 #define GST_DEINTERLACE_OBSCURE_THRESHOLD 5
94 static const TelecinePattern telecine_patterns[] = {
95 /* 60i -> 60p or 50i -> 50p (NOTE THE WEIRD RATIOS) */
96 {"1:1", 1, 2, 1, {GST_ONE,}},
97 /* 60i -> 30p or 50i -> 25p */
98 {"2:2", 1, 1, 1, {GST_INT,}},
99 /* 60i telecine -> 24p */
100 {"2:3", 5, 4, 5, {GST_PRG, GST_PRG, GST_ONE, GST_ONE, GST_PRG,}},
101 {"3:2:2:3", 5, 4, 5, {GST_PRG, GST_ONE, GST_INT, GST_ONE, GST_PRG,}},
102 {"2:3:3:2", 5, 4, 5, {GST_PRG, GST_PRG, GST_DRP, GST_PRG, GST_PRG,}},
104 /* The following patterns are obscure and are ignored if ignore-obscure is
105 * set to true. If any patterns are added above this line, check and edit
106 * GST_DEINTERLACE_OBSCURE_THRESHOLD */
108 /* 50i Euro pulldown -> 24p */
109 {"2-11:3", 25, 24, 25, {GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_PRG,
110 GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_PRG,
111 GST_PRG, GST_PRG, GST_ONE, GST_INT, GST_INT,
112 GST_INT, GST_INT, GST_INT, GST_INT, GST_INT,
113 GST_INT, GST_INT, GST_INT, GST_ONE, GST_PRG,}},
114 /* 60i (NTSC 30000/1001) -> 16p (16000/1001) */
115 {"3:4-3", 15, 8, 15, {GST_PRG, GST_DRP, GST_PRG, GST_DRP, GST_PRG,
116 GST_DRP, GST_PRG, GST_DRP, GST_PRG, GST_DRP,
117 GST_PRG, GST_DRP, GST_PRG, GST_DRP, GST_PRG,}},
118 /* 50i (PAL) -> 16p */
119 {"3-7:4", 25, 16, 25, {GST_PRG, GST_DRP, GST_PRG, GST_PRG, GST_DRP,
120 GST_PRG, GST_PRG, GST_DRP, GST_PRG, GST_PRG,
121 GST_DRP, GST_PRG, GST_DRP, GST_PRG, GST_PRG,
122 GST_DRP, GST_PRG, GST_PRG, GST_DRP, GST_PRG,
123 GST_PRG, GST_DRP, GST_PRG, GST_PRG, GST_DRP,}},
124 /* NTSC 60i -> 18p */
125 {"3:3:4", 5, 3, 5, {GST_PRG, GST_DRP, GST_PRG, GST_DRP, GST_PRG,}},
126 /* NTSC 60i -> 20p */
127 {"3:3", 3, 2, 3, {GST_PRG, GST_DRP, GST_PRG,}},
128 /* NTSC 60i -> 27.5 */
129 {"3:2-4", 11, 10, 11, {GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_PRG,
130 GST_PRG, GST_ONE, GST_INT, GST_INT, GST_INT,
132 /* PAL 50i -> 27.5 */
133 {"1:2-4", 9, 9, 10, {GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_INT,
134 GST_INT, GST_INT, GST_INT, GST_INT,}},
137 static const GEnumValue methods_types[] = {
138 {GST_DEINTERLACE_TOMSMOCOMP, "Motion Adaptive: Motion Search",
140 {GST_DEINTERLACE_GREEDY_H, "Motion Adaptive: Advanced Detection",
142 {GST_DEINTERLACE_GREEDY_L, "Motion Adaptive: Simple Detection", "greedyl"},
143 {GST_DEINTERLACE_VFIR, "Blur Vertical", "vfir"},
144 {GST_DEINTERLACE_LINEAR, "Television: Full resolution", "linear"},
145 {GST_DEINTERLACE_LINEAR_BLEND, "Blur: Temporal (Do Not Use)",
147 {GST_DEINTERLACE_SCALER_BOB, "Double lines", "scalerbob"},
148 {GST_DEINTERLACE_WEAVE, "Weave (Do Not Use)", "weave"},
149 {GST_DEINTERLACE_WEAVE_TFF, "Progressive: Top Field First (Do Not Use)",
151 {GST_DEINTERLACE_WEAVE_BFF, "Progressive: Bottom Field First (Do Not Use)",
156 static const GEnumValue locking_types[] = {
157 {GST_DEINTERLACE_LOCKING_NONE,
158 "No pattern locking", "none"},
159 {GST_DEINTERLACE_LOCKING_AUTO,
160 "Choose passive/active locking depending on whether upstream is live",
162 {GST_DEINTERLACE_LOCKING_ACTIVE,
163 "Block until pattern-locked. Use accurate timestamp interpolation within a pattern repeat.",
165 {GST_DEINTERLACE_LOCKING_PASSIVE,
166 "Do not block. Use naïve timestamp adjustment until pattern-locked based on state history.",
172 #define GST_TYPE_DEINTERLACE_METHODS (gst_deinterlace_methods_get_type ())
174 gst_deinterlace_methods_get_type (void)
176 static GType deinterlace_methods_type = 0;
178 if (!deinterlace_methods_type) {
179 deinterlace_methods_type =
180 g_enum_register_static ("GstDeinterlaceMethods", methods_types);
182 return deinterlace_methods_type;
185 #define GST_TYPE_DEINTERLACE_FIELDS (gst_deinterlace_fields_get_type ())
187 gst_deinterlace_fields_get_type (void)
189 static GType deinterlace_fields_type = 0;
191 static const GEnumValue fields_types[] = {
192 {GST_DEINTERLACE_ALL, "All fields", "all"},
193 {GST_DEINTERLACE_TF, "Top fields only", "top"},
194 {GST_DEINTERLACE_BF, "Bottom fields only", "bottom"},
198 if (!deinterlace_fields_type) {
199 deinterlace_fields_type =
200 g_enum_register_static ("GstDeinterlaceFields", fields_types);
202 return deinterlace_fields_type;
205 #define GST_TYPE_DEINTERLACE_FIELD_LAYOUT (gst_deinterlace_field_layout_get_type ())
207 gst_deinterlace_field_layout_get_type (void)
209 static GType deinterlace_field_layout_type = 0;
211 static const GEnumValue field_layout_types[] = {
212 {GST_DEINTERLACE_LAYOUT_AUTO, "Auto detection", "auto"},
213 {GST_DEINTERLACE_LAYOUT_TFF, "Top field first", "tff"},
214 {GST_DEINTERLACE_LAYOUT_BFF, "Bottom field first", "bff"},
218 if (!deinterlace_field_layout_type) {
219 deinterlace_field_layout_type =
220 g_enum_register_static ("GstDeinterlaceFieldLayout",
223 return deinterlace_field_layout_type;
226 #define GST_TYPE_DEINTERLACE_MODES (gst_deinterlace_modes_get_type ())
228 gst_deinterlace_modes_get_type (void)
230 static GType deinterlace_modes_type = 0;
232 static const GEnumValue modes_types[] = {
233 {GST_DEINTERLACE_MODE_AUTO, "Auto detection", "auto"},
234 {GST_DEINTERLACE_MODE_INTERLACED, "Force deinterlacing", "interlaced"},
235 {GST_DEINTERLACE_MODE_DISABLED, "Run in passthrough mode", "disabled"},
239 if (!deinterlace_modes_type) {
240 deinterlace_modes_type =
241 g_enum_register_static ("GstDeinterlaceModes", modes_types);
243 return deinterlace_modes_type;
246 #define GST_TYPE_DEINTERLACE_LOCKING (gst_deinterlace_locking_get_type ())
248 gst_deinterlace_locking_get_type (void)
250 static GType deinterlace_locking_type = 0;
252 if (!deinterlace_locking_type) {
253 deinterlace_locking_type =
254 g_enum_register_static ("GstDeinterlaceLocking", locking_types);
257 return deinterlace_locking_type;
261 #define DEINTERLACE_CAPS \
262 GST_VIDEO_CAPS_YUV ("{ AYUV, Y444, YUY2, YVYU, UYVY, Y42B, I420, YV12, Y41B, NV12, NV21 }") ";" \
263 GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_ABGR ";" \
264 GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_BGRA ";" \
265 GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_xBGR ";" \
266 GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx ";" \
267 GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR
269 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
272 GST_STATIC_CAPS (DEINTERLACE_CAPS)
275 static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
278 GST_STATIC_CAPS (DEINTERLACE_CAPS)
281 static void gst_deinterlace_finalize (GObject * self);
282 static void gst_deinterlace_set_property (GObject * self, guint prop_id,
283 const GValue * value, GParamSpec * pspec);
284 static void gst_deinterlace_get_property (GObject * self, guint prop_id,
285 GValue * value, GParamSpec * pspec);
287 static GstCaps *gst_deinterlace_getcaps (GstPad * pad);
288 static gboolean gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps);
289 static gboolean gst_deinterlace_sink_event (GstPad * pad, GstEvent * event);
290 static gboolean gst_deinterlace_sink_query (GstPad * pad, GstQuery * query);
291 static GstFlowReturn gst_deinterlace_chain (GstPad * pad, GstBuffer * buffer);
292 static GstFlowReturn gst_deinterlace_alloc_buffer (GstPad * pad, guint64 offset,
293 guint size, GstCaps * caps, GstBuffer ** buf);
294 static GstStateChangeReturn gst_deinterlace_change_state (GstElement * element,
295 GstStateChange transition);
297 static gboolean gst_deinterlace_src_event (GstPad * pad, GstEvent * event);
298 static gboolean gst_deinterlace_src_query (GstPad * pad, GstQuery * query);
299 static const GstQueryType *gst_deinterlace_src_query_types (GstPad * pad);
301 static GstFlowReturn gst_deinterlace_output_frame (GstDeinterlace * self,
303 static void gst_deinterlace_reset (GstDeinterlace * self);
304 static void gst_deinterlace_update_qos (GstDeinterlace * self,
305 gdouble proportion, GstClockTimeDiff diff, GstClockTime time);
306 static void gst_deinterlace_reset_qos (GstDeinterlace * self);
307 static void gst_deinterlace_read_qos (GstDeinterlace * self,
308 gdouble * proportion, GstClockTime * time);
310 static void gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
311 gpointer iface_data);
314 _do_init (GType object_type)
316 const GInterfaceInfo child_proxy_interface_info = {
317 (GInterfaceInitFunc) gst_deinterlace_child_proxy_interface_init,
318 NULL, /* interface_finalize */
319 NULL /* interface_data */
322 g_type_add_interface_static (object_type, GST_TYPE_CHILD_PROXY,
323 &child_proxy_interface_info);
326 GST_BOILERPLATE_FULL (GstDeinterlace, gst_deinterlace, GstElement,
327 GST_TYPE_ELEMENT, _do_init);
331 GType (*get_type) (void);
332 } _method_types[] = {
334 gst_deinterlace_method_tomsmocomp_get_type}, {
335 gst_deinterlace_method_greedy_h_get_type}, {
336 gst_deinterlace_method_greedy_l_get_type}, {
337 gst_deinterlace_method_vfir_get_type}, {
338 gst_deinterlace_method_linear_get_type}, {
339 gst_deinterlace_method_linear_blend_get_type}, {
340 gst_deinterlace_method_scaler_bob_get_type}, {
341 gst_deinterlace_method_weave_get_type}, {
342 gst_deinterlace_method_weave_tff_get_type}, {
343 gst_deinterlace_method_weave_bff_get_type}
347 gst_deinterlace_set_method (GstDeinterlace * self, GstDeinterlaceMethods method)
351 GST_DEBUG_OBJECT (self, "Setting new method %d", method);
354 if (self->method_id == method &&
355 gst_deinterlace_method_supported (G_TYPE_FROM_INSTANCE (self->method),
356 self->format, self->width, self->height)) {
357 GST_DEBUG_OBJECT (self, "Reusing current method");
361 gst_child_proxy_child_removed (GST_OBJECT (self),
362 GST_OBJECT (self->method));
363 gst_object_unparent (GST_OBJECT (self->method));
368 _method_types[method].get_type !=
369 NULL ? _method_types[method].get_type () : G_TYPE_INVALID;
370 if (method_type == G_TYPE_INVALID
371 || !gst_deinterlace_method_supported (method_type, self->format,
372 self->width, self->height)) {
376 method_type = G_TYPE_INVALID;
378 GST_WARNING_OBJECT (self, "Method doesn't support requested format");
379 for (i = 0; i < G_N_ELEMENTS (_method_types); i++) {
380 if (_method_types[i].get_type == NULL)
382 tmp = _method_types[i].get_type ();
383 if (gst_deinterlace_method_supported (tmp, self->format, self->width,
385 GST_DEBUG_OBJECT (self, "Using method %d", i);
391 /* If we get here we must have invalid caps! */
392 g_assert (method_type != G_TYPE_INVALID);
395 self->method = g_object_new (method_type, "name", "method", NULL);
396 self->method_id = method;
398 gst_object_set_parent (GST_OBJECT (self->method), GST_OBJECT (self));
399 gst_child_proxy_child_added (GST_OBJECT (self), GST_OBJECT (self->method));
402 gst_deinterlace_method_setup (self->method, self->format, self->width,
407 gst_deinterlace_clip_buffer (GstDeinterlace * self, GstBuffer * buffer)
410 GstClockTime start, stop;
411 gint64 cstart, cstop;
413 GST_DEBUG_OBJECT (self,
414 "Clipping buffer to the current segment: %" GST_TIME_FORMAT " -- %"
415 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
416 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
417 GST_DEBUG_OBJECT (self, "Current segment: %" GST_SEGMENT_FORMAT,
420 if (G_UNLIKELY (self->segment.format != GST_FORMAT_TIME))
422 if (G_UNLIKELY (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer)))
425 start = GST_BUFFER_TIMESTAMP (buffer);
426 stop = start + GST_BUFFER_DURATION (buffer);
428 if (!(ret = gst_segment_clip (&self->segment, GST_FORMAT_TIME,
429 start, stop, &cstart, &cstop)))
432 GST_BUFFER_TIMESTAMP (buffer) = cstart;
433 if (GST_CLOCK_TIME_IS_VALID (cstop))
434 GST_BUFFER_DURATION (buffer) = cstop - cstart;
438 GST_DEBUG_OBJECT (self,
439 "Clipped buffer to the current segment: %" GST_TIME_FORMAT " -- %"
440 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
441 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
443 GST_DEBUG_OBJECT (self, "Buffer outside the current segment -- dropping");
449 gst_deinterlace_base_init (gpointer klass)
451 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
453 gst_element_class_add_static_pad_template (element_class, &src_templ);
454 gst_element_class_add_static_pad_template (element_class, &sink_templ);
456 gst_element_class_set_details_simple (element_class,
458 "Filter/Effect/Video/Deinterlace",
459 "Deinterlace Methods ported from DScaler/TvTime",
460 "Martin Eikermann <meiker@upb.de>, "
461 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
465 gst_deinterlace_class_init (GstDeinterlaceClass * klass)
467 GObjectClass *gobject_class = (GObjectClass *) klass;
469 GstElementClass *element_class = (GstElementClass *) klass;
471 gobject_class->set_property = gst_deinterlace_set_property;
472 gobject_class->get_property = gst_deinterlace_get_property;
473 gobject_class->finalize = gst_deinterlace_finalize;
476 * GstDeinterlace:mode
478 * This selects whether the deinterlacing methods should
479 * always be applied or if they should only be applied
480 * on content that has the "interlaced" flag on the caps.
483 g_object_class_install_property (gobject_class, PROP_MODE,
484 g_param_spec_enum ("mode",
487 GST_TYPE_DEINTERLACE_MODES,
488 DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
492 * GstDeinterlace:method
494 * Selects the different deinterlacing algorithms that can be used.
495 * These provide different quality and CPU usage.
497 * Some methods provide parameters which can be set by getting
498 * the "method" child via the #GstChildProxy interface and
499 * setting the appropiate properties on it.
505 * Motion Adaptive: Motion Search
511 * Motion Adaptive: Advanced Detection
517 * Motion Adaptive: Simple Detection
529 * Linear interpolation
535 * Linear interpolation in time domain. Any motion causes significant
536 * ghosting, so this method should not be used.
548 * Weave. Bad quality, do not use.
554 * Progressive: Top Field First. Bad quality, do not use.
560 * Progressive: Bottom Field First. Bad quality, do not use.
565 g_object_class_install_property (gobject_class, PROP_METHOD,
566 g_param_spec_enum ("method",
568 "Deinterlace Method",
569 GST_TYPE_DEINTERLACE_METHODS,
570 DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
574 * GstDeinterlace:fields
576 * This selects which fields should be output. If "all" is selected
577 * the output framerate will be double.
580 g_object_class_install_property (gobject_class, PROP_FIELDS,
581 g_param_spec_enum ("fields",
583 "Fields to use for deinterlacing",
584 GST_TYPE_DEINTERLACE_FIELDS,
585 DEFAULT_FIELDS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
589 * GstDeinterlace:layout
591 * This selects which fields is the first in time.
594 g_object_class_install_property (gobject_class, PROP_FIELD_LAYOUT,
595 g_param_spec_enum ("tff",
597 "Deinterlace top field first",
598 GST_TYPE_DEINTERLACE_FIELD_LAYOUT,
599 DEFAULT_FIELD_LAYOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
603 * GstDeinterlace:locking
605 * This selects which approach to pattern locking is used which affects
606 * processing latency and accuracy of timestamp adjustment for telecine
612 g_object_class_install_property (gobject_class, PROP_LOCKING,
613 g_param_spec_enum ("locking", "locking", "Pattern locking mode",
614 GST_TYPE_DEINTERLACE_LOCKING, DEFAULT_LOCKING,
615 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
618 * GstDeinterlace:ignore-obscure
620 * This selects whether to ignore obscure/rare telecine patterns.
621 * NTSC 2:3 pulldown variants are the only really common patterns.
626 g_object_class_install_property (gobject_class, PROP_IGNORE_OBSCURE,
627 g_param_spec_boolean ("ignore-obscure", "ignore-obscure",
628 "Ignore obscure telecine patterns (only consider P, I and 2:3 "
629 "variants).", DEFAULT_IGNORE_OBSCURE,
630 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
633 * GstDeinterlace:drop-orphans
635 * This selects whether to drop orphan fields at the beginning of telecine
636 * patterns in active locking mode.
641 g_object_class_install_property (gobject_class, PROP_DROP_ORPHANS,
642 g_param_spec_boolean ("drop-orphans", "drop-orphans",
643 "Drop orphan fields at the beginning of telecine patterns in "
644 "active locking mode.", DEFAULT_DROP_ORPHANS,
645 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
647 element_class->change_state =
648 GST_DEBUG_FUNCPTR (gst_deinterlace_change_state);
652 gst_deinterlace_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
655 GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
657 g_return_val_if_fail (index == 0, NULL);
659 return gst_object_ref (self->method);
663 gst_deinterlace_child_proxy_get_children_count (GstChildProxy * child_proxy)
665 GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
667 return ((self->method) ? 1 : 0);
671 gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
674 GstChildProxyInterface *iface = g_iface;
676 iface->get_child_by_index = gst_deinterlace_child_proxy_get_child_by_index;
677 iface->get_children_count = gst_deinterlace_child_proxy_get_children_count;
681 gst_deinterlace_init (GstDeinterlace * self, GstDeinterlaceClass * klass)
683 self->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
684 gst_pad_set_chain_function (self->sinkpad,
685 GST_DEBUG_FUNCPTR (gst_deinterlace_chain));
686 gst_pad_set_event_function (self->sinkpad,
687 GST_DEBUG_FUNCPTR (gst_deinterlace_sink_event));
688 gst_pad_set_setcaps_function (self->sinkpad,
689 GST_DEBUG_FUNCPTR (gst_deinterlace_setcaps));
690 gst_pad_set_getcaps_function (self->sinkpad,
691 GST_DEBUG_FUNCPTR (gst_deinterlace_getcaps));
692 gst_pad_set_query_function (self->sinkpad,
693 GST_DEBUG_FUNCPTR (gst_deinterlace_sink_query));
694 gst_pad_set_bufferalloc_function (self->sinkpad,
695 GST_DEBUG_FUNCPTR (gst_deinterlace_alloc_buffer));
696 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
698 self->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
699 gst_pad_set_event_function (self->srcpad,
700 GST_DEBUG_FUNCPTR (gst_deinterlace_src_event));
701 gst_pad_set_query_type_function (self->srcpad,
702 GST_DEBUG_FUNCPTR (gst_deinterlace_src_query_types));
703 gst_pad_set_query_function (self->srcpad,
704 GST_DEBUG_FUNCPTR (gst_deinterlace_src_query));
705 gst_pad_set_getcaps_function (self->srcpad,
706 GST_DEBUG_FUNCPTR (gst_deinterlace_getcaps));
707 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
709 self->mode = DEFAULT_MODE;
710 self->user_set_method_id = DEFAULT_METHOD;
711 gst_deinterlace_set_method (self, self->user_set_method_id);
712 self->fields = DEFAULT_FIELDS;
713 self->field_layout = DEFAULT_FIELD_LAYOUT;
714 self->locking = DEFAULT_LOCKING;
715 self->ignore_obscure = DEFAULT_IGNORE_OBSCURE;
716 self->drop_orphans = DEFAULT_DROP_ORPHANS;
718 self->low_latency = -1;
720 self->pattern_phase = -1;
721 self->pattern_count = 0;
722 self->output_count = 0;
723 self->pattern_base_ts = GST_CLOCK_TIME_NONE;
724 self->pattern_buf_dur = GST_CLOCK_TIME_NONE;
725 self->still_frame_mode = FALSE;
727 gst_deinterlace_reset (self);
731 gst_deinterlace_reset_history (GstDeinterlace * self, gboolean drop_all)
736 GST_DEBUG_OBJECT (self, "Flushing history (count %d)", self->history_count);
737 while (self->history_count > 0) {
738 if (gst_deinterlace_output_frame (self, TRUE) != GST_FLOW_OK) {
739 /* Encountered error, or flushing -> skip and drop all remaining */
746 GST_DEBUG_OBJECT (self, "Resetting history (count %d)",
747 self->history_count);
749 for (i = 0; i < self->history_count; i++) {
750 if (self->field_history[i].buf) {
751 gst_buffer_unref (self->field_history[i].buf);
752 self->field_history[i].buf = NULL;
756 memset (self->field_history, 0,
757 GST_DEINTERLACE_MAX_FIELD_HISTORY * sizeof (GstDeinterlaceField));
758 self->history_count = 0;
759 memset (self->buf_states, 0,
760 GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY *
761 sizeof (GstDeinterlaceBufferState));
762 self->state_count = 0;
763 self->pattern_lock = FALSE;
764 self->pattern_refresh = TRUE;
765 self->cur_field_idx = -1;
767 if (!self->still_frame_mode && self->last_buffer) {
768 gst_buffer_unref (self->last_buffer);
769 self->last_buffer = NULL;
774 gst_deinterlace_update_passthrough (GstDeinterlace * self)
776 self->passthrough = (self->mode == GST_DEINTERLACE_MODE_DISABLED
777 || (!self->interlaced && self->mode != GST_DEINTERLACE_MODE_INTERLACED));
778 GST_DEBUG_OBJECT (self, "Passthrough: %d", self->passthrough);
782 gst_deinterlace_reset (GstDeinterlace * self)
784 GST_DEBUG_OBJECT (self, "Resetting internal state");
786 self->format = GST_VIDEO_FORMAT_UNKNOWN;
789 self->frame_size = 0;
790 self->fps_n = self->fps_d = 0;
791 self->passthrough = FALSE;
793 self->reconfigure = FALSE;
794 if (self->new_mode != -1)
795 self->mode = self->new_mode;
796 if (self->new_fields != -1)
797 self->fields = self->new_fields;
799 self->new_fields = -1;
801 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
803 if (self->request_caps)
804 gst_caps_unref (self->request_caps);
805 self->request_caps = NULL;
807 gst_deinterlace_reset_history (self, TRUE);
809 gst_deinterlace_reset_qos (self);
811 self->need_more = FALSE;
812 self->have_eos = FALSE;
816 gst_deinterlace_set_property (GObject * object, guint prop_id,
817 const GValue * value, GParamSpec * pspec)
819 GstDeinterlace *self;
821 g_return_if_fail (GST_IS_DEINTERLACE (object));
822 self = GST_DEINTERLACE (object);
828 GST_OBJECT_LOCK (self);
829 new_mode = g_value_get_enum (value);
830 if (self->mode != new_mode && GST_PAD_CAPS (self->srcpad)) {
831 self->reconfigure = TRUE;
832 self->new_mode = new_mode;
834 self->mode = new_mode;
835 gst_deinterlace_update_passthrough (self);
837 GST_OBJECT_UNLOCK (self);
841 self->user_set_method_id = g_value_get_enum (value);
842 gst_deinterlace_set_method (self, self->user_set_method_id);
847 GST_OBJECT_LOCK (self);
848 new_fields = g_value_get_enum (value);
849 if (self->fields != new_fields && GST_PAD_CAPS (self->srcpad)) {
850 self->reconfigure = TRUE;
851 self->new_fields = new_fields;
853 self->fields = new_fields;
855 GST_OBJECT_UNLOCK (self);
858 case PROP_FIELD_LAYOUT:
859 self->field_layout = g_value_get_enum (value);
862 self->locking = g_value_get_enum (value);
864 case PROP_IGNORE_OBSCURE:
865 self->ignore_obscure = g_value_get_boolean (value);
867 case PROP_DROP_ORPHANS:
868 self->drop_orphans = g_value_get_boolean (value);
871 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
877 gst_deinterlace_get_property (GObject * object, guint prop_id,
878 GValue * value, GParamSpec * pspec)
880 GstDeinterlace *self;
882 g_return_if_fail (GST_IS_DEINTERLACE (object));
883 self = GST_DEINTERLACE (object);
887 g_value_set_enum (value, self->mode);
890 g_value_set_enum (value, self->user_set_method_id);
893 g_value_set_enum (value, self->fields);
895 case PROP_FIELD_LAYOUT:
896 g_value_set_enum (value, self->field_layout);
899 g_value_set_enum (value, self->locking);
901 case PROP_IGNORE_OBSCURE:
902 g_value_set_boolean (value, self->ignore_obscure);
904 case PROP_DROP_ORPHANS:
905 g_value_set_boolean (value, self->drop_orphans);
908 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
913 gst_deinterlace_finalize (GObject * object)
915 GstDeinterlace *self = GST_DEINTERLACE (object);
917 gst_deinterlace_reset (self);
920 gst_object_unparent (GST_OBJECT (self->method));
924 G_OBJECT_CLASS (parent_class)->finalize (object);
928 gst_deinterlace_update_pattern_timestamps (GstDeinterlace * self)
931 if (self->low_latency) {
932 /* in low-latency mode the buffer state history contains old buffer
933 * states as well as the current one and perhaps some future ones.
934 * the current buffer's state is given by the number of field pairs
935 * rounded up, minus 1. the below is equivalent */
936 state_idx = (self->history_count - 1) >> 1;
938 /* in high-latency mode state_count - 1 is the current buffer's state */
939 state_idx = self->state_count - 1;
942 self->pattern_base_ts = self->buf_states[state_idx].timestamp;
943 self->pattern_buf_dur =
944 (self->buf_states[state_idx].duration *
945 telecine_patterns[self->pattern].ratio_d) /
946 telecine_patterns[self->pattern].ratio_n;
947 GST_DEBUG_OBJECT (self,
948 "Starting a new pattern repeat with base ts %" GST_TIME_FORMAT
949 " and dur %" GST_TIME_FORMAT, GST_TIME_ARGS (self->pattern_base_ts),
950 GST_TIME_ARGS (self->pattern_buf_dur));
954 gst_deinterlace_pop_history (GstDeinterlace * self)
958 g_return_val_if_fail (self->history_count > 0, NULL);
960 GST_DEBUG_OBJECT (self, "Pop last history buffer -- current history size %d",
961 self->history_count);
963 buffer = self->field_history[self->history_count - 1].buf;
965 self->history_count--;
966 if (self->locking != GST_DEINTERLACE_LOCKING_NONE && (!self->history_count
967 || GST_BUFFER_DATA (buffer) !=
968 GST_BUFFER_DATA (self->field_history[self->history_count - 1].buf))) {
969 if (!self->low_latency)
971 if (self->pattern_lock) {
972 self->pattern_count++;
973 if (self->pattern != -1
974 && self->pattern_count >= telecine_patterns[self->pattern].length) {
975 self->pattern_count = 0;
976 self->output_count = 0;
977 gst_deinterlace_update_pattern_timestamps (self);
982 GST_DEBUG_OBJECT (self, "Returning buffer: %p %" GST_TIME_FORMAT
983 " with duration %" GST_TIME_FORMAT " and size %u", buffer,
984 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
985 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer));
992 GST_DEINTERLACE_PROGRESSIVE,
993 GST_DEINTERLACE_INTERLACED,
994 GST_DEINTERLACE_TELECINE,
995 } GstDeinterlaceInterlacingMethod;
997 static GstDeinterlaceInterlacingMethod
998 gst_deinterlace_get_interlacing_method (const GstCaps * caps)
1000 GstDeinterlaceInterlacingMethod method = 0;
1001 gboolean interlaced;
1003 /* check interlaced cap, defaulting to FALSE */
1004 if (!gst_structure_get_boolean (gst_caps_get_structure (caps, 0),
1005 "interlaced", &interlaced))
1009 interlaced ? GST_DEINTERLACE_INTERLACED : GST_DEINTERLACE_PROGRESSIVE;
1011 if (method == GST_DEINTERLACE_INTERLACED) {
1013 gst_structure_get_string (gst_caps_get_structure (caps, 0),
1014 "interlacing-method");
1015 if (temp && g_str_equal (temp, "telecine"))
1016 method = GST_DEINTERLACE_TELECINE;
1023 gst_deinterlace_get_buffer_state (GstDeinterlace * self, GstBuffer * buffer,
1024 guint8 * state, GstDeinterlaceInterlacingMethod * i_method)
1026 GstDeinterlaceInterlacingMethod interlacing_method;
1028 if (!(i_method || state))
1031 interlacing_method =
1032 gst_deinterlace_get_interlacing_method (GST_BUFFER_CAPS (buffer));
1035 if (interlacing_method == GST_DEINTERLACE_TELECINE) {
1036 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_RFF)) {
1037 *state = GST_DEINTERLACE_BUFFER_STATE_DROP;
1038 } else if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_ONEFIELD)) {
1039 /* tc top if tff, tc bottom otherwise */
1040 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_TFF)) {
1041 *state = GST_DEINTERLACE_BUFFER_STATE_TC_T;
1043 *state = GST_DEINTERLACE_BUFFER_STATE_TC_B;
1045 } else if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_PROGRESSIVE)) {
1046 *state = GST_DEINTERLACE_BUFFER_STATE_TC_P;
1048 *state = GST_DEINTERLACE_BUFFER_STATE_TC_M;
1051 if (interlacing_method == GST_DEINTERLACE_INTERLACED) {
1052 *state = GST_DEINTERLACE_BUFFER_STATE_I;
1054 *state = GST_DEINTERLACE_BUFFER_STATE_P;
1060 *i_method = interlacing_method;
1064 gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer)
1067 GstClockTime timestamp;
1068 GstDeinterlaceFieldLayout field_layout = self->field_layout;
1069 gboolean repeated = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_RFF);
1070 gboolean tff = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_TFF);
1072 GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_ONEFIELD);
1073 GstBuffer *field1, *field2;
1074 guint fields_to_push = (onefield) ? 1 : (!repeated) ? 2 : 3;
1075 gint field1_flags, field2_flags;
1076 GstDeinterlaceInterlacingMethod interlacing_method;
1079 g_return_if_fail (self->history_count <
1080 GST_DEINTERLACE_MAX_FIELD_HISTORY - fields_to_push);
1082 gst_deinterlace_get_buffer_state (self, buffer, &buf_state,
1083 &interlacing_method);
1085 GST_DEBUG_OBJECT (self,
1086 "Pushing new buffer to the history: ptr %p at %" GST_TIME_FORMAT
1087 " with duration %" GST_TIME_FORMAT
1088 ", size %u, state %u, interlacing method %s", GST_BUFFER_DATA (buffer),
1089 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
1090 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer),
1092 interlacing_method ==
1093 GST_DEINTERLACE_TELECINE ? "TC" : interlacing_method ==
1094 GST_DEINTERLACE_INTERLACED ? "I" : "P");
1096 /* move up for new state */
1097 memmove (&self->buf_states[1], &self->buf_states[0],
1098 (GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY - 1) *
1099 sizeof (GstDeinterlaceBufferState));
1100 self->buf_states[0].state = buf_state;
1101 self->buf_states[0].timestamp = GST_BUFFER_TIMESTAMP (buffer);
1102 self->buf_states[0].duration = GST_BUFFER_DURATION (buffer);
1103 if (self->state_count < GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY)
1104 self->state_count++;
1106 if (buf_state == GST_DEINTERLACE_BUFFER_STATE_DROP) {
1107 GST_DEBUG_OBJECT (self,
1108 "Buffer contains only unneeded repeated fields, dropping and not"
1109 "adding to field history");
1110 gst_buffer_unref (buffer);
1114 /* telecine does not make use of repeated fields */
1115 if (interlacing_method == GST_DEINTERLACE_TELECINE)
1118 for (i = GST_DEINTERLACE_MAX_FIELD_HISTORY - 1; i >= fields_to_push; i--) {
1119 self->field_history[i].buf = self->field_history[i - fields_to_push].buf;
1120 self->field_history[i].flags =
1121 self->field_history[i - fields_to_push].flags;
1124 if (field_layout == GST_DEINTERLACE_LAYOUT_AUTO) {
1125 if (!self->interlaced) {
1126 GST_WARNING_OBJECT (self, "Can't detect field layout -- assuming TFF");
1127 field_layout = GST_DEINTERLACE_LAYOUT_TFF;
1129 field_layout = GST_DEINTERLACE_LAYOUT_TFF;
1131 field_layout = GST_DEINTERLACE_LAYOUT_BFF;
1135 if (field_layout == GST_DEINTERLACE_LAYOUT_TFF) {
1136 GST_DEBUG_OBJECT (self, "Top field first");
1137 field1 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
1138 field1_flags = PICTURE_INTERLACED_TOP;
1139 field2 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
1140 field2_flags = PICTURE_INTERLACED_BOTTOM;
1142 GST_DEBUG_OBJECT (self, "Bottom field first");
1143 field1 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
1144 field1_flags = PICTURE_INTERLACED_BOTTOM;
1145 field2 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
1146 field2_flags = PICTURE_INTERLACED_TOP;
1149 if (interlacing_method != GST_DEINTERLACE_TELECINE) {
1150 /* Timestamps are assigned to the field buffers under the assumption that
1151 the timestamp of the buffer equals the first fields timestamp */
1153 timestamp = GST_BUFFER_TIMESTAMP (buffer);
1154 GST_BUFFER_TIMESTAMP (field1) = timestamp;
1155 GST_BUFFER_TIMESTAMP (field2) = timestamp + self->field_duration;
1157 GST_BUFFER_TIMESTAMP (field2) += self->field_duration;
1161 self->field_history[2].buf = field1;
1162 self->field_history[2].flags = field1_flags;
1164 self->field_history[1].buf = field2;
1165 self->field_history[1].flags = field2_flags;
1167 self->field_history[0].buf =
1168 gst_buffer_make_metadata_writable (gst_buffer_ref (field1));
1169 GST_BUFFER_TIMESTAMP (self->field_history[0].buf) +=
1170 2 * self->field_duration;
1171 self->field_history[0].flags = field1_flags;
1172 } else if (!onefield) {
1173 self->field_history[1].buf = field1;
1174 self->field_history[1].flags = field1_flags;
1176 self->field_history[0].buf = field2;
1177 self->field_history[0].flags = field2_flags;
1178 } else { /* onefield */
1179 self->field_history[0].buf = field1;
1180 self->field_history[0].flags = field1_flags;
1181 gst_buffer_unref (field2);
1184 self->history_count += fields_to_push;
1185 self->cur_field_idx += fields_to_push;
1187 GST_DEBUG_OBJECT (self, "Pushed buffer -- current history size %d, index %d",
1188 self->history_count, self->cur_field_idx);
1190 if (self->last_buffer)
1191 gst_buffer_unref (self->last_buffer);
1192 self->last_buffer = buffer;
1196 gst_deinterlace_update_qos (GstDeinterlace * self, gdouble proportion,
1197 GstClockTimeDiff diff, GstClockTime timestamp)
1199 GST_DEBUG_OBJECT (self,
1200 "Updating QoS: proportion %lf, diff %s%" GST_TIME_FORMAT ", timestamp %"
1201 GST_TIME_FORMAT, proportion, (diff < 0) ? "-" : "",
1202 GST_TIME_ARGS (ABS (diff)), GST_TIME_ARGS (timestamp));
1204 GST_OBJECT_LOCK (self);
1205 self->proportion = proportion;
1206 if (G_LIKELY (timestamp != GST_CLOCK_TIME_NONE)) {
1207 if (G_UNLIKELY (diff > 0))
1208 self->earliest_time =
1209 timestamp + 2 * diff + ((self->fields ==
1210 GST_DEINTERLACE_ALL) ? self->field_duration : 2 *
1211 self->field_duration);
1213 self->earliest_time = timestamp + diff;
1215 self->earliest_time = GST_CLOCK_TIME_NONE;
1217 GST_OBJECT_UNLOCK (self);
1221 gst_deinterlace_reset_qos (GstDeinterlace * self)
1223 gst_deinterlace_update_qos (self, 0.5, 0, GST_CLOCK_TIME_NONE);
1227 gst_deinterlace_read_qos (GstDeinterlace * self, gdouble * proportion,
1228 GstClockTime * time)
1230 GST_OBJECT_LOCK (self);
1231 *proportion = self->proportion;
1232 *time = self->earliest_time;
1233 GST_OBJECT_UNLOCK (self);
1236 /* Perform qos calculations before processing the next frame. Returns TRUE if
1237 * the frame should be processed, FALSE if the frame can be dropped entirely */
1239 gst_deinterlace_do_qos (GstDeinterlace * self, GstClockTime timestamp)
1241 GstClockTime qostime, earliest_time;
1244 /* no timestamp, can't do QoS => process frame */
1245 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) {
1246 GST_LOG_OBJECT (self, "invalid timestamp, can't do QoS, process frame");
1250 /* get latest QoS observation values */
1251 gst_deinterlace_read_qos (self, &proportion, &earliest_time);
1253 /* skip qos if we have no observation (yet) => process frame */
1254 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) {
1255 GST_LOG_OBJECT (self, "no observation yet, process frame");
1259 /* qos is done on running time */
1260 qostime = gst_segment_to_running_time (&self->segment, GST_FORMAT_TIME,
1263 /* see how our next timestamp relates to the latest qos timestamp */
1264 GST_LOG_OBJECT (self, "qostime %" GST_TIME_FORMAT ", earliest %"
1265 GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
1267 if (qostime != GST_CLOCK_TIME_NONE && qostime <= earliest_time) {
1268 GST_DEBUG_OBJECT (self, "we are late, drop frame");
1272 GST_LOG_OBJECT (self, "process frame");
1277 gst_deinterlace_fix_timestamps (GstDeinterlace * self,
1278 GstDeinterlaceField * field1, GstDeinterlaceField * field2)
1280 GstDeinterlaceField *field3, *field4;
1281 GstDeinterlaceInterlacingMethod interlacing_method;
1283 if (self->pattern_lock && self->pattern > -1) {
1284 /* accurate pattern-locked timestamp adjustment */
1285 if (!self->pattern_count)
1286 gst_deinterlace_update_pattern_timestamps (self);
1288 GST_BUFFER_TIMESTAMP (field1->buf) =
1289 self->pattern_base_ts + self->output_count * self->pattern_buf_dur;
1290 GST_BUFFER_DURATION (field1->buf) = self->pattern_buf_dur;
1291 self->output_count++;
1293 /* naive (but low-latency) timestamp adjustment based on subsequent
1296 && GST_BUFFER_DATA (field1->buf) != GST_BUFFER_DATA (field2->buf)) {
1297 if (GST_BUFFER_TIMESTAMP (field1->buf) +
1298 GST_BUFFER_DURATION (field1->buf) ==
1299 GST_BUFFER_TIMESTAMP (field2->buf)) {
1300 GST_BUFFER_TIMESTAMP (field1->buf) =
1301 GST_BUFFER_TIMESTAMP (field2->buf) =
1302 (GST_BUFFER_TIMESTAMP (field1->buf) +
1303 GST_BUFFER_TIMESTAMP (field2->buf)) / 2;
1305 GST_BUFFER_TIMESTAMP (field2->buf) = GST_BUFFER_TIMESTAMP (field1->buf);
1309 if (self->history_count < 3) {
1310 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need 3)",
1311 self->history_count);
1315 field3 = &self->field_history[self->history_count - 3];
1316 interlacing_method =
1317 gst_deinterlace_get_interlacing_method (GST_BUFFER_CAPS (field3->buf));
1318 if (interlacing_method == GST_DEINTERLACE_TELECINE) {
1319 if (self->history_count < 4) {
1320 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need 4)",
1321 self->history_count);
1325 field4 = &self->field_history[self->history_count - 4];
1326 if (GST_BUFFER_DATA (field3->buf) != GST_BUFFER_DATA (field4->buf)) {
1327 /* telecine fields in separate buffers */
1328 GST_BUFFER_TIMESTAMP (field3->buf) =
1329 (GST_BUFFER_TIMESTAMP (field3->buf) +
1330 GST_BUFFER_TIMESTAMP (field4->buf)) / 2;
1334 GST_BUFFER_DURATION (field1->buf) =
1335 GST_BUFFER_TIMESTAMP (field3->buf) - GST_BUFFER_TIMESTAMP (field1->buf);
1338 GST_DEBUG_OBJECT (self,
1339 "Field 1 adjusted to ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT,
1340 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1->buf)),
1341 GST_TIME_ARGS (GST_BUFFER_DURATION (field1->buf)));
1346 gst_deinterlace_get_pattern_lock (GstDeinterlace * self, gboolean * flush_one)
1348 /* loop over all possible patterns and all possible phases
1349 * giving each a score. the highest score gets the lock */
1350 /* the score is calculated as the number of matched buffers in the
1351 * sequence starting at the phase offset with those from the history
1352 * then the longest duration pattern match is taken. if there is more than
1353 * one pattern matching all buffers, we take the longest pattern of those.
1354 * matches to complete patterns are preferred. if no non-trivial pattern is
1355 * matched, trivial patterns are tested. */
1356 gint i, j, k, score, pattern, phase;
1357 const gint state_count = self->state_count;
1358 const gint n_required = self->ignore_obscure ?
1359 GST_DEINTERLACE_OBSCURE_THRESHOLD :
1360 GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY;
1362 /* set unknown pattern as this is used in logic outside this function */
1365 /* wait for more buffers */
1366 if (!self->have_eos && state_count < n_required) {
1367 GST_DEBUG_OBJECT (self, "Need more buffers in state history - %d/%d",
1368 state_count, n_required);
1372 score = pattern = phase = -1;
1374 /* loop over all patterns */
1375 for (i = 0; i < G_N_ELEMENTS (telecine_patterns); i++) {
1376 const guint8 length = telecine_patterns[i].length;
1378 if (self->ignore_obscure && i >= GST_DEINTERLACE_OBSCURE_THRESHOLD)
1381 if (state_count < length)
1384 /* loop over all phases */
1385 for (j = 0; j < length; j++) {
1386 /* low-latency mode looks at past buffers, high latency at future buffers */
1387 const gint state_idx = (self->low_latency ? length : state_count) - 1;
1388 /* loop over history, breaking on differing buffer states */
1389 for (k = 0; k < length && k < state_count; k++) {
1390 const guint8 hist = self->buf_states[state_idx - k].state;
1391 const guint8 patt = telecine_patterns[i].states[(j + k) % length];
1396 /* make complete matches more signficant */
1398 k += GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY;
1400 /* take as new best pattern if the number of matched buffers is more than
1401 * for other patterns */
1406 if (self->low_latency) {
1407 /* state_idx + 1 is the number of buffers yet to be pushed out
1408 * so length - state_idx - 1 is the number of old buffers in the
1410 phase = (phase + length - state_idx - 1) % length;
1416 GST_DEBUG_OBJECT (self,
1417 "Final pattern match result: pa %d, ph %d, l %d, s %d", pattern, phase,
1418 telecine_patterns[pattern].length, score);
1419 self->pattern = pattern;
1420 self->pattern_phase = phase;
1421 self->pattern_count = 0;
1422 self->output_count = 0;
1423 self->pattern_lock = TRUE;
1425 /* check for the case that the first field of the pattern is an orphan */
1427 && telecine_patterns[pattern].states[phase] & (GST_ONE | GST_INT)) {
1428 gint i = phase, field_count = 0;
1429 guint8 state = telecine_patterns[pattern].states[i];
1432 if (state & GST_ONE) {
1434 } else if (!(state & GST_DRP)) {
1438 i %= telecine_patterns[pattern].length;
1439 state = telecine_patterns[pattern].states[i];
1440 } while (!(state & GST_PRG));
1442 /* if field_count is odd, we have an orphan field at the beginning of the
1444 * note - don't do this in low-latency mode as we are somewhere within the
1445 * pattern already */
1446 if (!self->low_latency && (*flush_one = field_count & 1)) {
1447 GST_DEBUG_OBJECT (self, "Orphan field detected at the beginning of the "
1448 "pattern - it will be deinterlaced.");
1453 static GstFlowReturn
1454 gst_deinterlace_output_frame (GstDeinterlace * self, gboolean flushing)
1456 GstClockTime timestamp;
1458 gint fields_required;
1459 GstBuffer *buf, *outbuf;
1460 GstDeinterlaceField *field1, *field2;
1461 GstDeinterlaceInterlacingMethod interlacing_method;
1463 gboolean hl_no_lock; /* indicates high latency timestamp adjustment but no pattern lock (could be ONEF or I) */
1464 gboolean same_buffer; /* are field1 and field2 in the same buffer? */
1465 gboolean flush_one; /* used for flushing one field when in high latency mode and not locked */
1466 TelecinePattern pattern;
1467 guint8 phase, count;
1468 const GstDeinterlaceLocking locking = self->locking;
1472 fields_required = 0;
1474 same_buffer = FALSE;
1476 self->need_more = FALSE;
1477 phase = self->pattern_phase;
1478 count = self->pattern_count;
1480 if (!self->history_count) {
1481 GST_DEBUG_OBJECT (self, "History is empty, waiting for more buffers!");
1485 field1 = &self->field_history[self->history_count - 1];
1487 if (locking != GST_DEINTERLACE_LOCKING_NONE) {
1488 if (!self->state_count) {
1489 GST_ERROR_OBJECT (self,
1490 "BROKEN! Fields in history + no states should not happen!");
1491 return GST_FLOW_ERROR;
1494 gst_deinterlace_get_buffer_state (self, field1->buf, &buf_state,
1495 &interlacing_method);
1497 if (self->pattern != -1)
1498 pattern = telecine_patterns[self->pattern];
1500 /* patterns 0 and 1 are interlaced, the rest are telecine */
1501 if (self->pattern > 1)
1502 interlacing_method = GST_DEINTERLACE_TELECINE;
1504 if (self->pattern == -1 || self->pattern_refresh
1505 || !(buf_state & pattern.states[(phase + count) % pattern.length])) {
1506 /* no pattern, pattern refresh set or unexpected buffer state */
1507 self->pattern_lock = FALSE;
1508 self->pattern_refresh = TRUE;
1510 /* refresh pattern lock */
1511 gst_deinterlace_get_pattern_lock (self, &flush_one);
1513 if (self->pattern != -1) {
1514 /* locked onto a valid pattern so refresh complete */
1515 GST_DEBUG_OBJECT (self, "Pattern locked! %s starting at %d",
1516 telecine_patterns[self->pattern].nick, self->pattern_phase);
1517 self->pattern_refresh = FALSE;
1518 } else if (!self->low_latency) {
1519 if (!self->pattern_lock) {
1526 /* setcaps on sink and src pads */
1527 gst_deinterlace_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad));
1529 if (flush_one && self->drop_orphans) {
1530 GST_DEBUG_OBJECT (self, "Dropping orphan first field");
1531 self->cur_field_idx--;
1532 gst_buffer_unref (gst_deinterlace_pop_history (self));
1537 gst_deinterlace_get_buffer_state (self, field1->buf, NULL,
1538 &interlacing_method);
1541 same_buffer = self->history_count >= 2
1542 && (GST_BUFFER_DATA (field1->buf) ==
1543 GST_BUFFER_DATA (self->field_history[self->history_count - 2].buf));
1545 if ((flushing && self->history_count == 1) || (flush_one
1546 && !self->drop_orphans) || (hl_no_lock && (self->history_count == 1
1547 || !same_buffer))) {
1548 GST_DEBUG_OBJECT (self, "Flushing one field using linear method");
1549 gst_deinterlace_set_method (self, GST_DEINTERLACE_LINEAR);
1550 fields_required = gst_deinterlace_method_get_fields_required (self->method);
1551 } else if (interlacing_method == GST_DEINTERLACE_TELECINE
1552 && (self->low_latency > 0 || self->pattern != -1 || (hl_no_lock
1554 && GST_BUFFER_FLAG_IS_SET (field1->buf,
1555 GST_VIDEO_BUFFER_PROGRESSIVE)))) {
1556 /* telecined - we reconstruct frames by weaving pairs of fields */
1557 fields_required = 2;
1558 if (!flushing && self->history_count < fields_required) {
1559 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
1560 self->history_count, self->cur_field_idx + fields_required);
1564 field2 = &self->field_history[self->history_count - 2];
1565 if (!gst_deinterlace_fix_timestamps (self, field1, field2) && !flushing)
1569 /* telecine progressive */
1570 GstBuffer *field1_buf;
1572 GST_DEBUG_OBJECT (self,
1573 "Frame type: Telecine Progressive; pushing buffer as a frame");
1575 self->cur_field_idx--;
1576 field1_buf = gst_deinterlace_pop_history (self);
1577 /* field2 is the same buffer as field1, but we need to remove it from
1578 * the history anyway */
1579 self->cur_field_idx--;
1580 gst_buffer_unref (gst_deinterlace_pop_history (self));
1581 /* set the caps from the src pad on the buffer as they should be correct */
1582 gst_buffer_set_caps (field1_buf, GST_PAD_CAPS (self->srcpad));
1583 GST_DEBUG_OBJECT (self,
1584 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1585 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf)),
1586 GST_TIME_ARGS (GST_BUFFER_DURATION (field1_buf)),
1587 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf) +
1588 GST_BUFFER_DURATION (field1_buf)));
1589 return gst_pad_push (self->srcpad, field1_buf);
1591 /* telecine fields in separate buffers */
1593 /* check field1 and field2 buffer caps and flags are corresponding */
1594 if (field1->flags == field2->flags) {
1595 /* ERROR - fields are of same parity - what should be done here?
1596 * perhaps deinterlace the tip field and start again? */
1597 GST_ERROR_OBJECT (self, "Telecine mixed with fields of same parity!");
1599 GST_DEBUG_OBJECT (self,
1600 "Frame type: Telecine Mixed; weaving tip two fields into a frame");
1601 /* set method to WEAVE */
1602 gst_deinterlace_set_method (self, GST_DEINTERLACE_WEAVE);
1604 } else if (interlacing_method == GST_DEINTERLACE_INTERLACED || (hl_no_lock
1605 && interlacing_method == GST_DEINTERLACE_TELECINE && same_buffer
1606 && !GST_BUFFER_FLAG_IS_SET (field1->buf,
1607 GST_VIDEO_BUFFER_PROGRESSIVE))) {
1608 gst_deinterlace_set_method (self, self->user_set_method_id);
1609 fields_required = gst_deinterlace_method_get_fields_required (self->method);
1610 if (flushing && self->history_count < fields_required) {
1611 /* note: we already checked for flushing with history count == 1 above
1612 * so we must have 2 or more fields in here */
1613 gst_deinterlace_set_method (self, GST_DEINTERLACE_VFIR);
1615 gst_deinterlace_method_get_fields_required (self->method);
1616 GST_DEBUG_OBJECT (self, "Flushing field(s) using %s method",
1617 methods_types[self->method_id].value_nick);
1620 /* Not enough fields in the history */
1621 if (!flushing && self->history_count < fields_required) {
1622 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
1623 self->history_count, self->cur_field_idx + fields_required);
1627 GST_DEBUG_OBJECT (self,
1628 "Frame type: Interlaced; deinterlacing using %s method",
1629 methods_types[self->method_id].value_nick);
1631 GstBuffer *field1_buf;
1634 fields_required = 2;
1636 /* Not enough fields in the history */
1637 if (!flushing && self->history_count < fields_required) {
1638 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
1639 self->history_count, self->cur_field_idx + fields_required);
1643 field2 = &self->field_history[self->history_count - 2];
1644 if (GST_BUFFER_DATA (field1->buf) != GST_BUFFER_DATA (field2->buf)) {
1645 /* ERROR - next two fields in field history are not one progressive buffer - weave? */
1646 GST_ERROR_OBJECT (self,
1647 "Progressive buffer but two fields at tip aren't in the same buffer!");
1650 GST_DEBUG_OBJECT (self,
1651 "Frame type: Progressive; pushing buffer as a frame");
1653 self->cur_field_idx--;
1654 field1_buf = gst_deinterlace_pop_history (self);
1655 /* field2 is the same buffer as field1, but we need to remove it from the
1657 self->cur_field_idx--;
1658 gst_buffer_unref (gst_deinterlace_pop_history (self));
1659 GST_DEBUG_OBJECT (self,
1660 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1661 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf)),
1662 GST_TIME_ARGS (GST_BUFFER_DURATION (field1_buf)),
1663 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf) +
1664 GST_BUFFER_DURATION (field1_buf)));
1665 return gst_pad_push (self->srcpad, field1_buf);
1668 if (!flushing && self->cur_field_idx < 1) {
1672 if (self->fields == GST_DEINTERLACE_ALL
1673 || interlacing_method == GST_DEINTERLACE_TELECINE)
1674 GST_DEBUG_OBJECT (self, "All fields");
1675 else if (self->fields == GST_DEINTERLACE_TF)
1676 GST_DEBUG_OBJECT (self, "Top fields");
1677 else if (self->fields == GST_DEINTERLACE_BF)
1678 GST_DEBUG_OBJECT (self, "Bottom fields");
1680 if ((self->field_history[self->cur_field_idx].flags == PICTURE_INTERLACED_TOP
1681 && (self->fields == GST_DEINTERLACE_TF
1682 || interlacing_method == GST_DEINTERLACE_TELECINE))
1683 || self->fields == GST_DEINTERLACE_ALL) {
1684 GST_DEBUG_OBJECT (self, "deinterlacing top field");
1686 /* create new buffer */
1688 gst_pad_alloc_buffer (self->srcpad, GST_BUFFER_OFFSET_NONE,
1689 self->frame_size, GST_PAD_CAPS (self->srcpad), &outbuf);
1690 if (ret != GST_FLOW_OK)
1693 if (GST_PAD_CAPS (self->srcpad) != GST_BUFFER_CAPS (outbuf) &&
1694 !gst_caps_is_equal (GST_PAD_CAPS (self->srcpad),
1695 GST_BUFFER_CAPS (outbuf))) {
1696 gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf));
1697 GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT,
1698 self->request_caps);
1700 gst_buffer_unref (outbuf);
1701 outbuf = gst_buffer_try_new_and_alloc (self->frame_size);
1704 return GST_FLOW_ERROR;
1706 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
1709 g_return_val_if_fail (self->history_count >=
1710 1 + gst_deinterlace_method_get_latency (self->method), GST_FLOW_ERROR);
1713 self->field_history[self->history_count - 1 -
1714 gst_deinterlace_method_get_latency (self->method)].buf;
1716 if (interlacing_method != GST_DEINTERLACE_TELECINE) {
1717 timestamp = GST_BUFFER_TIMESTAMP (buf);
1719 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1720 if (self->fields == GST_DEINTERLACE_ALL)
1721 GST_BUFFER_DURATION (outbuf) = self->field_duration;
1723 GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
1725 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1726 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1729 /* Check if we need to drop the frame because of QoS */
1730 if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
1731 self->cur_field_idx--;
1732 gst_buffer_unref (gst_deinterlace_pop_history (self));
1733 gst_buffer_unref (outbuf);
1737 if (self->cur_field_idx < 0 && flushing) {
1738 if (self->history_count == 1) {
1739 gst_buffer_unref (gst_deinterlace_pop_history (self));
1742 self->cur_field_idx++;
1744 if (self->cur_field_idx < 0) {
1747 if (!flushing && self->cur_field_idx < 1) {
1751 /* do magic calculus */
1752 gst_deinterlace_method_deinterlace_frame (self->method,
1753 self->field_history, self->history_count, outbuf,
1754 self->cur_field_idx);
1756 self->cur_field_idx--;
1757 if (self->cur_field_idx + 1 +
1758 gst_deinterlace_method_get_latency (self->method)
1759 < self->history_count || flushing) {
1760 gst_buffer_unref (gst_deinterlace_pop_history (self));
1763 if (gst_deinterlace_clip_buffer (self, outbuf)) {
1764 GST_DEBUG_OBJECT (self,
1765 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1766 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1767 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
1768 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
1769 GST_BUFFER_DURATION (outbuf)));
1770 ret = gst_pad_push (self->srcpad, outbuf);
1773 gst_buffer_unref (outbuf);
1777 if (ret != GST_FLOW_OK)
1779 if (interlacing_method == GST_DEINTERLACE_TELECINE
1780 && self->method_id == GST_DEINTERLACE_WEAVE) {
1781 /* pop off the second field */
1782 GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
1783 self->history_count);
1784 self->cur_field_idx--;
1785 gst_buffer_unref (gst_deinterlace_pop_history (self));
1786 interlacing_method = GST_DEINTERLACE_INTERLACED;
1791 if (flush_one && !self->drop_orphans) {
1792 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1796 /* no calculation done: remove excess field */
1797 else if (self->field_history[self->cur_field_idx].flags ==
1798 PICTURE_INTERLACED_TOP && (self->fields == GST_DEINTERLACE_BF
1799 && interlacing_method != GST_DEINTERLACE_TELECINE)) {
1800 GST_DEBUG_OBJECT (self, "Removing unused top field");
1801 self->cur_field_idx--;
1802 gst_buffer_unref (gst_deinterlace_pop_history (self));
1804 if (flush_one && !self->drop_orphans) {
1805 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1810 if (self->history_count < fields_required)
1813 if (self->cur_field_idx < 0)
1816 if (!flushing && self->cur_field_idx < 1) {
1820 /* deinterlace bottom_field */
1821 if ((self->field_history[self->cur_field_idx].flags ==
1822 PICTURE_INTERLACED_BOTTOM && (self->fields == GST_DEINTERLACE_BF
1823 || interlacing_method == GST_DEINTERLACE_TELECINE))
1824 || self->fields == GST_DEINTERLACE_ALL) {
1825 GST_DEBUG_OBJECT (self, "deinterlacing bottom field");
1827 /* create new buffer */
1829 gst_pad_alloc_buffer (self->srcpad, GST_BUFFER_OFFSET_NONE,
1830 self->frame_size, GST_PAD_CAPS (self->srcpad), &outbuf);
1831 if (ret != GST_FLOW_OK)
1834 if (GST_PAD_CAPS (self->srcpad) != GST_BUFFER_CAPS (outbuf) &&
1835 !gst_caps_is_equal (GST_PAD_CAPS (self->srcpad),
1836 GST_BUFFER_CAPS (outbuf))) {
1837 gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf));
1838 GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT,
1839 self->request_caps);
1841 gst_buffer_unref (outbuf);
1842 outbuf = gst_buffer_try_new_and_alloc (self->frame_size);
1845 return GST_FLOW_ERROR;
1847 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
1850 g_return_val_if_fail (self->history_count - 1 -
1851 gst_deinterlace_method_get_latency (self->method) >= 0, GST_FLOW_ERROR);
1854 self->field_history[self->history_count - 1 -
1855 gst_deinterlace_method_get_latency (self->method)].buf;
1856 if (interlacing_method != GST_DEINTERLACE_TELECINE) {
1857 timestamp = GST_BUFFER_TIMESTAMP (buf);
1859 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1860 if (self->fields == GST_DEINTERLACE_ALL)
1861 GST_BUFFER_DURATION (outbuf) = self->field_duration;
1863 GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
1865 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1866 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1869 /* Check if we need to drop the frame because of QoS */
1870 if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
1871 self->cur_field_idx--;
1872 gst_buffer_unref (gst_deinterlace_pop_history (self));
1873 gst_buffer_unref (outbuf);
1877 /* do magic calculus */
1878 gst_deinterlace_method_deinterlace_frame (self->method,
1879 self->field_history, self->history_count, outbuf,
1880 self->cur_field_idx);
1882 self->cur_field_idx--;
1883 if (self->cur_field_idx + 1 +
1884 gst_deinterlace_method_get_latency (self->method)
1885 < self->history_count) {
1886 gst_buffer_unref (gst_deinterlace_pop_history (self));
1889 if (gst_deinterlace_clip_buffer (self, outbuf)) {
1890 GST_DEBUG_OBJECT (self,
1891 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1892 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1893 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
1894 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
1895 GST_BUFFER_DURATION (outbuf)));
1896 ret = gst_pad_push (self->srcpad, outbuf);
1899 gst_buffer_unref (outbuf);
1903 if (ret != GST_FLOW_OK)
1905 if (interlacing_method == GST_DEINTERLACE_TELECINE
1906 && self->method_id == GST_DEINTERLACE_WEAVE) {
1907 /* pop off the second field */
1908 GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
1909 self->history_count);
1910 self->cur_field_idx--;
1911 gst_buffer_unref (gst_deinterlace_pop_history (self));
1912 interlacing_method = GST_DEINTERLACE_INTERLACED;
1917 if (flush_one && !self->drop_orphans) {
1918 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1922 /* no calculation done: remove excess field */
1923 else if (self->field_history[self->cur_field_idx].flags ==
1924 PICTURE_INTERLACED_BOTTOM && (self->fields == GST_DEINTERLACE_TF
1925 && interlacing_method != GST_DEINTERLACE_TELECINE)) {
1926 GST_DEBUG_OBJECT (self, "Removing unused bottom field");
1927 self->cur_field_idx--;
1928 gst_buffer_unref (gst_deinterlace_pop_history (self));
1930 if (flush_one && !self->drop_orphans) {
1931 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1939 self->need_more = TRUE;
1944 gst_deinterlace_get_latency (GstDeinterlace * self)
1946 if (self->locking == GST_DEINTERLACE_LOCKING_AUTO) {
1950 query = gst_query_new_latency ();
1951 if ((res = gst_pad_peer_query (self->sinkpad, query))) {
1953 /* if upstream is live, we use low-latency passive locking mode
1954 * else high-latency active locking mode */
1955 gst_query_parse_latency (query, &is_live, NULL, NULL);
1956 GST_DEBUG_OBJECT (self, "Latency query indicates stream is %s",
1957 is_live ? "live - using passive locking" :
1958 "not live - using active locking");
1959 gst_query_unref (query);
1962 /* conservatively use passive locking if the query fails */
1963 GST_WARNING_OBJECT (self,
1964 "Latency query failed - fall back to using passive locking");
1965 gst_query_unref (query);
1969 return self->locking - 2;
1973 static GstFlowReturn
1974 gst_deinterlace_chain (GstPad * pad, GstBuffer * buf)
1976 GstDeinterlace *self = GST_DEINTERLACE (GST_PAD_PARENT (pad));
1977 GstFlowReturn ret = GST_FLOW_OK;
1979 GST_OBJECT_LOCK (self);
1980 if (self->reconfigure) {
1981 if (self->new_fields != -1)
1982 self->fields = self->new_fields;
1983 if (self->new_mode != -1)
1984 self->mode = self->new_mode;
1985 self->new_mode = self->new_fields = -1;
1987 self->reconfigure = FALSE;
1988 GST_OBJECT_UNLOCK (self);
1989 if (GST_PAD_CAPS (self->srcpad))
1990 gst_deinterlace_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad));
1992 GST_OBJECT_UNLOCK (self);
1995 GST_DEBUG_OBJECT (self,
1996 "[IN] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1997 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1998 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
1999 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)));
2001 if (self->still_frame_mode || self->passthrough) {
2002 GST_DEBUG_OBJECT (self,
2003 "Frame type: Progressive?; pushing buffer using pass-through");
2004 GST_DEBUG_OBJECT (self,
2005 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
2006 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
2007 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
2008 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)));
2010 return gst_pad_push (self->srcpad, buf);
2013 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
2014 GST_DEBUG_OBJECT (self, "DISCONT buffer, resetting history");
2015 gst_deinterlace_reset_history (self, FALSE);
2018 gst_deinterlace_push_history (self, buf);
2022 ret = gst_deinterlace_output_frame (self, FALSE);
2023 } while (!self->need_more && self->history_count > 0 && ret == GST_FLOW_OK);
2029 gst_greatest_common_divisor (gint a, gint b)
2042 gst_fraction_double (gint * n_out, gint * d_out, gboolean half)
2052 if (n == 0 || (n == G_MAXINT && d == 1))
2055 gcd = gst_greatest_common_divisor (n, d);
2060 if (G_MAXINT / 2 >= ABS (n)) {
2062 } else if (d >= 2) {
2068 if (G_MAXINT / 2 >= ABS (d)) {
2070 } else if (n >= 2) {
2084 gst_deinterlace_getcaps (GstPad * pad)
2087 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2090 const GstCaps *ourcaps;
2093 otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad;
2095 ourcaps = gst_pad_get_pad_template_caps (pad);
2096 peercaps = gst_pad_peer_get_caps (otherpad);
2099 GST_DEBUG_OBJECT (pad, "Peer has caps %" GST_PTR_FORMAT, peercaps);
2100 ret = gst_caps_intersect (ourcaps, peercaps);
2101 gst_caps_unref (peercaps);
2103 ret = gst_caps_copy (ourcaps);
2106 for (len = gst_caps_get_size (ret); len > 0; len--) {
2107 GstStructure *s = gst_caps_get_structure (ret, len - 1);
2109 if (pad == self->sinkpad || self->passthrough)
2110 gst_structure_remove_field (s, "interlaced");
2112 gst_structure_set (s, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL);
2114 if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) {
2117 val = gst_structure_get_value (s, "framerate");
2121 if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION) {
2124 n = gst_value_get_fraction_numerator (val);
2125 d = gst_value_get_fraction_denominator (val);
2127 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
2131 gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
2132 } else if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION_RANGE) {
2133 const GValue *min, *max;
2134 GValue nrange = { 0, }, nmin = {
2139 g_value_init (&nrange, GST_TYPE_FRACTION_RANGE);
2140 g_value_init (&nmin, GST_TYPE_FRACTION);
2141 g_value_init (&nmax, GST_TYPE_FRACTION);
2143 min = gst_value_get_fraction_range_min (val);
2144 max = gst_value_get_fraction_range_max (val);
2146 n = gst_value_get_fraction_numerator (min);
2147 d = gst_value_get_fraction_denominator (min);
2149 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
2150 g_value_unset (&nrange);
2151 g_value_unset (&nmax);
2152 g_value_unset (&nmin);
2156 gst_value_set_fraction (&nmin, n, d);
2158 n = gst_value_get_fraction_numerator (max);
2159 d = gst_value_get_fraction_denominator (max);
2161 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
2162 g_value_unset (&nrange);
2163 g_value_unset (&nmax);
2164 g_value_unset (&nmin);
2168 gst_value_set_fraction (&nmax, n, d);
2169 gst_value_set_fraction_range (&nrange, &nmin, &nmax);
2171 gst_structure_set_value (s, "framerate", &nrange);
2173 g_value_unset (&nmin);
2174 g_value_unset (&nmax);
2175 g_value_unset (&nrange);
2176 } else if (G_VALUE_TYPE (val) == GST_TYPE_LIST) {
2178 GValue nlist = { 0, };
2179 GValue nval = { 0, };
2182 g_value_init (&nlist, GST_TYPE_LIST);
2183 for (i = gst_value_list_get_size (val); i > 0; i--) {
2186 lval = gst_value_list_get_value (val, i);
2188 if (G_VALUE_TYPE (lval) != GST_TYPE_FRACTION)
2191 n = gst_value_get_fraction_numerator (lval);
2192 d = gst_value_get_fraction_denominator (lval);
2194 /* Double/Half the framerate but if this fails simply
2195 * skip this value from the list */
2196 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
2200 g_value_init (&nval, GST_TYPE_FRACTION);
2202 gst_value_set_fraction (&nval, n, d);
2203 gst_value_list_append_value (&nlist, &nval);
2204 g_value_unset (&nval);
2206 gst_structure_set_value (s, "framerate", &nlist);
2207 g_value_unset (&nlist);
2212 GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret);
2214 gst_object_unref (self);
2219 GST_ERROR_OBJECT (pad, "Unable to transform peer caps");
2220 gst_caps_unref (ret);
2225 gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps)
2227 gboolean res = TRUE;
2228 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2230 GstDeinterlaceInterlacingMethod interlacing_method;
2232 if (self->locking != GST_DEINTERLACE_LOCKING_NONE) {
2233 if (self->low_latency == -1)
2234 self->low_latency = gst_deinterlace_get_latency (self);
2236 if (self->pattern_lock) {
2237 /* refresh has been successful - we have a lock now */
2238 self->pattern_refresh = FALSE;
2240 /* if we were not refreshing (!pattern_refresh) the caps have changed
2241 * so we need to refresh and we don't have a lock anymore
2242 * otherwise we have pattern_fresh and !pattern_lock anyway */
2243 self->pattern_refresh = TRUE;
2244 self->pattern_lock = FALSE;
2249 gst_video_format_parse_caps (caps, &self->format, &self->width,
2251 res &= gst_video_parse_caps_framerate (caps, &self->fps_n, &self->fps_d);
2252 if (pad == self->sinkpad)
2253 res &= gst_video_format_parse_caps_interlaced (caps, &self->interlaced);
2257 gst_deinterlace_update_passthrough (self);
2259 interlacing_method = gst_deinterlace_get_interlacing_method (caps);
2261 if (self->pattern_lock) {
2262 srccaps = gst_caps_copy (caps);
2263 if (self->pattern != -1
2264 && G_UNLIKELY (!gst_util_fraction_multiply (self->fps_n, self->fps_d,
2265 telecine_patterns[self->pattern].ratio_n,
2266 telecine_patterns[self->pattern].ratio_d, &self->fps_n,
2268 GST_ERROR_OBJECT (self,
2269 "Multiplying the framerate by the telecine pattern ratio overflowed!");
2270 gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, self->fps_n,
2272 } else if (self->low_latency > 0) {
2273 if (interlacing_method == GST_DEINTERLACE_TELECINE) {
2274 /* for initial buffers of a telecine pattern, until there is a lock we
2275 * we output naïvely adjusted timestamps */
2276 srccaps = gst_caps_copy (caps);
2277 gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
2278 } else if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) {
2279 gint fps_n = self->fps_n, fps_d = self->fps_d;
2281 if (!gst_fraction_double (&fps_n, &fps_d, FALSE))
2284 srccaps = gst_caps_copy (caps);
2286 gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, fps_n,
2289 srccaps = gst_caps_ref (caps);
2292 /* in high latency pattern locking mode if we don't have a pattern lock,
2293 * the sink pad caps are the best we know */
2294 srccaps = gst_caps_ref (caps);
2297 if (self->mode != GST_DEINTERLACE_MODE_DISABLED) {
2298 srccaps = gst_caps_make_writable (srccaps);
2299 gst_structure_remove_field (gst_caps_get_structure (srccaps, 0),
2300 "interlacing-method");
2301 gst_caps_set_simple (srccaps, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL);
2304 if (!gst_pad_set_caps (self->srcpad, srccaps))
2305 goto caps_not_accepted;
2308 gst_video_format_get_size (self->format, self->width, self->height);
2310 if (G_LIKELY (self->fps_n != 0)) {
2311 self->field_duration =
2312 gst_util_uint64_scale (GST_SECOND, self->fps_d, 2 * self->fps_n);
2314 self->field_duration = 0;
2317 gst_deinterlace_set_method (self, self->method_id);
2318 gst_deinterlace_method_setup (self->method, self->format, self->width,
2321 GST_DEBUG_OBJECT (pad, "Sink caps: %" GST_PTR_FORMAT, caps);
2322 GST_DEBUG_OBJECT (pad, "Src caps: %" GST_PTR_FORMAT, srccaps);
2324 gst_caps_unref (srccaps);
2328 gst_object_unref (self);
2333 GST_ERROR_OBJECT (pad, "Invalid caps: %" GST_PTR_FORMAT, caps);
2338 GST_ERROR_OBJECT (pad, "Caps not accepted: %" GST_PTR_FORMAT, srccaps);
2339 gst_caps_unref (srccaps);
2344 gst_deinterlace_sink_event (GstPad * pad, GstEvent * event)
2346 gboolean res = TRUE;
2347 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2349 GST_LOG_OBJECT (pad, "received %s event: %" GST_PTR_FORMAT,
2350 GST_EVENT_TYPE_NAME (event), event);
2352 switch (GST_EVENT_TYPE (event)) {
2353 case GST_EVENT_NEWSEGMENT:
2357 gint64 start, end, base;
2358 gdouble rate, applied_rate;
2360 gst_event_parse_new_segment_full (event, &is_update, &rate,
2361 &applied_rate, &fmt, &start, &end, &base);
2363 gst_deinterlace_reset_qos (self);
2364 gst_deinterlace_reset_history (self, FALSE);
2366 if (fmt == GST_FORMAT_TIME) {
2367 GST_DEBUG_OBJECT (pad,
2368 "Got NEWSEGMENT event in GST_FORMAT_TIME, passing on (%"
2369 GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")", GST_TIME_ARGS (start),
2370 GST_TIME_ARGS (end));
2371 gst_segment_set_newsegment_full (&self->segment, is_update, rate,
2372 applied_rate, fmt, start, end, base);
2374 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
2377 res = gst_pad_push_event (self->srcpad, event);
2380 case GST_EVENT_CUSTOM_DOWNSTREAM:{
2381 gboolean still_state;
2383 if (gst_video_event_parse_still_frame (event, &still_state)) {
2384 GST_DEBUG_OBJECT (self, "Received still frame event, state %d",
2390 GST_DEBUG_OBJECT (self, "Handling still frame");
2391 self->still_frame_mode = TRUE;
2392 gst_deinterlace_reset_history (self, FALSE);
2393 if (self->last_buffer) {
2395 gst_pad_push (self->srcpad, gst_buffer_ref (self->last_buffer));
2396 GST_DEBUG_OBJECT (self, "Pushed still frame, result: %s",
2397 gst_flow_get_name (ret));
2399 GST_WARNING_OBJECT (self, "No pending buffer!");
2402 GST_DEBUG_OBJECT (self, "Ending still frames");
2403 self->still_frame_mode = FALSE;
2409 self->have_eos = TRUE;
2410 gst_deinterlace_reset_history (self, FALSE);
2414 res = gst_pad_push_event (self->srcpad, event);
2417 case GST_EVENT_FLUSH_STOP:
2418 if (self->still_frame_mode) {
2419 GST_DEBUG_OBJECT (self, "Ending still frames");
2420 self->still_frame_mode = FALSE;
2422 gst_deinterlace_reset_qos (self);
2423 res = gst_pad_push_event (self->srcpad, event);
2424 gst_deinterlace_reset_history (self, TRUE);
2428 gst_object_unref (self);
2433 gst_deinterlace_sink_query (GstPad * pad, GstQuery * query)
2435 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2436 gboolean res = FALSE;
2438 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
2440 switch (GST_QUERY_TYPE (query)) {
2442 GstPad *peer = gst_pad_get_peer (self->srcpad);
2445 res = gst_pad_query (peer, query);
2446 gst_object_unref (peer);
2454 gst_object_unref (self);
2458 static GstStateChangeReturn
2459 gst_deinterlace_change_state (GstElement * element, GstStateChange transition)
2461 GstStateChangeReturn ret;
2462 GstDeinterlace *self = GST_DEINTERLACE (element);
2464 switch (transition) {
2465 case GST_STATE_CHANGE_NULL_TO_READY:
2467 case GST_STATE_CHANGE_READY_TO_PAUSED:
2469 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2475 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2476 if (ret != GST_STATE_CHANGE_SUCCESS)
2479 switch (transition) {
2480 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2482 case GST_STATE_CHANGE_PAUSED_TO_READY:
2483 gst_deinterlace_reset (self);
2485 case GST_STATE_CHANGE_READY_TO_NULL:
2494 gst_deinterlace_src_event (GstPad * pad, GstEvent * event)
2496 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2499 GST_DEBUG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
2501 switch (GST_EVENT_TYPE (event)) {
2502 case GST_EVENT_QOS:{
2503 GstClockTimeDiff diff;
2504 GstClockTime timestamp;
2507 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
2509 gst_deinterlace_update_qos (self, proportion, diff, timestamp);
2513 res = gst_pad_push_event (self->sinkpad, event);
2517 gst_object_unref (self);
2523 gst_deinterlace_src_query (GstPad * pad, GstQuery * query)
2525 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2526 gboolean res = FALSE;
2528 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
2530 switch (GST_QUERY_TYPE (query)) {
2531 case GST_QUERY_LATENCY:
2532 if (!self->passthrough) {
2533 GstClockTime min, max;
2537 if ((peer = gst_pad_get_peer (self->sinkpad))) {
2538 if ((res = gst_pad_query (peer, query))) {
2539 GstClockTime latency;
2540 gint fields_required = 0;
2541 gint method_latency = 0;
2545 gst_deinterlace_method_get_fields_required (self->method);
2547 gst_deinterlace_method_get_latency (self->method);
2550 gst_query_parse_latency (query, &live, &min, &max);
2552 GST_DEBUG_OBJECT (self, "Peer latency: min %"
2553 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
2554 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
2556 /* add our own latency */
2557 latency = (fields_required + method_latency) * self->field_duration;
2559 GST_DEBUG_OBJECT (self, "Our latency: min %" GST_TIME_FORMAT
2560 ", max %" GST_TIME_FORMAT,
2561 GST_TIME_ARGS (latency), GST_TIME_ARGS (latency));
2564 if (max != GST_CLOCK_TIME_NONE)
2567 GST_DEBUG_OBJECT (self, "Calculated total latency : min %"
2568 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
2569 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
2571 gst_query_set_latency (query, live, min, max);
2573 gst_object_unref (peer);
2580 GstPad *peer = gst_pad_get_peer (self->sinkpad);
2583 res = gst_pad_query (peer, query);
2584 gst_object_unref (peer);
2592 gst_object_unref (self);
2596 static const GstQueryType *
2597 gst_deinterlace_src_query_types (GstPad * pad)
2599 static const GstQueryType types[] = {
2606 static GstFlowReturn
2607 gst_deinterlace_alloc_buffer (GstPad * pad, guint64 offset, guint size,
2608 GstCaps * caps, GstBuffer ** buf)
2610 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2611 GstFlowReturn ret = GST_FLOW_OK;
2615 GST_DEBUG_OBJECT (pad, "alloc with caps %" GST_PTR_FORMAT ", size %u", caps,
2618 if (self->still_frame_mode || self->passthrough) {
2619 ret = gst_pad_alloc_buffer (self->srcpad, offset, size, caps, buf);
2620 } else if (G_LIKELY (!self->request_caps)) {
2621 *buf = gst_buffer_try_new_and_alloc (size);
2622 if (G_UNLIKELY (!*buf)) {
2623 ret = GST_FLOW_ERROR;
2625 gst_buffer_set_caps (*buf, caps);
2626 GST_BUFFER_OFFSET (*buf) = offset;
2631 guint new_frame_size;
2632 GstCaps *new_caps = gst_caps_copy (self->request_caps);
2634 if (self->fields == GST_DEINTERLACE_ALL) {
2636 GstStructure *s = gst_caps_get_structure (new_caps, 0);
2638 gst_structure_get_fraction (s, "framerate", &n, &d);
2640 if (!gst_fraction_double (&n, &d, TRUE)) {
2641 gst_object_unref (self);
2642 gst_caps_unref (new_caps);
2646 gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
2649 if (G_UNLIKELY (!gst_video_format_parse_caps (new_caps, &fmt, &width,
2651 gst_object_unref (self);
2652 gst_caps_unref (new_caps);
2656 new_frame_size = gst_video_format_get_size (fmt, width, height);
2658 *buf = gst_buffer_try_new_and_alloc (new_frame_size);
2659 if (G_UNLIKELY (!*buf)) {
2660 ret = GST_FLOW_ERROR;
2662 gst_buffer_set_caps (*buf, new_caps);
2663 gst_caps_unref (self->request_caps);
2664 self->request_caps = NULL;
2665 gst_caps_unref (new_caps);
2669 gst_object_unref (self);
2675 plugin_init (GstPlugin * plugin)
2677 GST_DEBUG_CATEGORY_INIT (deinterlace_debug, "deinterlace", 0, "Deinterlacer");
2683 if (!gst_element_register (plugin, "deinterlace", GST_RANK_NONE,
2684 GST_TYPE_DEINTERLACE)) {
2691 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
2694 "Deinterlacer", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
2695 GST_PACKAGE_ORIGIN);