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 */
1004 gst_structure_get_boolean (gst_caps_get_structure (caps, 0), "interlaced",
1008 interlaced ? GST_DEINTERLACE_INTERLACED : GST_DEINTERLACE_PROGRESSIVE;
1010 if (method == GST_DEINTERLACE_INTERLACED) {
1012 gst_structure_get_string (gst_caps_get_structure (caps, 0),
1013 "interlacing-method");
1014 if (temp && g_str_equal (temp, "telecine"))
1015 method = GST_DEINTERLACE_TELECINE;
1022 gst_deinterlace_get_buffer_state (GstDeinterlace * self, GstBuffer * buffer,
1023 guint8 * state, GstDeinterlaceInterlacingMethod * i_method)
1025 GstDeinterlaceInterlacingMethod interlacing_method;
1027 if (!(i_method || state))
1030 interlacing_method =
1031 gst_deinterlace_get_interlacing_method (GST_BUFFER_CAPS (buffer));
1034 if (interlacing_method == GST_DEINTERLACE_TELECINE) {
1035 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_RFF)) {
1036 *state = GST_DEINTERLACE_BUFFER_STATE_DROP;
1037 } else if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_ONEFIELD)) {
1038 /* tc top if tff, tc bottom otherwise */
1039 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_TFF)) {
1040 *state = GST_DEINTERLACE_BUFFER_STATE_TC_T;
1042 *state = GST_DEINTERLACE_BUFFER_STATE_TC_B;
1044 } else if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_PROGRESSIVE)) {
1045 *state = GST_DEINTERLACE_BUFFER_STATE_TC_P;
1047 *state = GST_DEINTERLACE_BUFFER_STATE_TC_M;
1050 if (interlacing_method == GST_DEINTERLACE_INTERLACED) {
1051 *state = GST_DEINTERLACE_BUFFER_STATE_I;
1053 *state = GST_DEINTERLACE_BUFFER_STATE_P;
1059 *i_method = interlacing_method;
1063 gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer)
1066 GstClockTime timestamp;
1067 GstDeinterlaceFieldLayout field_layout = self->field_layout;
1068 gboolean repeated = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_RFF);
1069 gboolean tff = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_TFF);
1071 GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_ONEFIELD);
1072 GstBuffer *field1, *field2;
1073 guint fields_to_push = (onefield) ? 1 : (!repeated) ? 2 : 3;
1074 gint field1_flags, field2_flags;
1075 GstDeinterlaceInterlacingMethod interlacing_method;
1078 g_return_if_fail (self->history_count <
1079 GST_DEINTERLACE_MAX_FIELD_HISTORY - fields_to_push);
1081 gst_deinterlace_get_buffer_state (self, buffer, &buf_state,
1082 &interlacing_method);
1084 GST_DEBUG_OBJECT (self,
1085 "Pushing new buffer to the history: ptr %p at %" GST_TIME_FORMAT
1086 " with duration %" GST_TIME_FORMAT
1087 ", size %u, state %u, interlacing method %s", GST_BUFFER_DATA (buffer),
1088 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
1089 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer),
1091 interlacing_method ==
1092 GST_DEINTERLACE_TELECINE ? "TC" : interlacing_method ==
1093 GST_DEINTERLACE_INTERLACED ? "I" : "P");
1095 /* move up for new state */
1096 memmove (&self->buf_states[1], &self->buf_states[0],
1097 (GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY - 1) *
1098 sizeof (GstDeinterlaceBufferState));
1099 self->buf_states[0].state = buf_state;
1100 self->buf_states[0].timestamp = GST_BUFFER_TIMESTAMP (buffer);
1101 self->buf_states[0].duration = GST_BUFFER_DURATION (buffer);
1102 if (self->state_count < GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY)
1103 self->state_count++;
1105 if (buf_state == GST_DEINTERLACE_BUFFER_STATE_DROP) {
1106 GST_DEBUG_OBJECT (self,
1107 "Buffer contains only unneeded repeated fields, dropping and not"
1108 "adding to field history");
1109 gst_buffer_unref (buffer);
1113 /* telecine does not make use of repeated fields */
1114 if (interlacing_method == GST_DEINTERLACE_TELECINE)
1117 for (i = GST_DEINTERLACE_MAX_FIELD_HISTORY - 1; i >= fields_to_push; i--) {
1118 self->field_history[i].buf = self->field_history[i - fields_to_push].buf;
1119 self->field_history[i].flags =
1120 self->field_history[i - fields_to_push].flags;
1123 if (field_layout == GST_DEINTERLACE_LAYOUT_AUTO) {
1124 if (!self->interlaced) {
1125 GST_WARNING_OBJECT (self, "Can't detect field layout -- assuming TFF");
1126 field_layout = GST_DEINTERLACE_LAYOUT_TFF;
1128 field_layout = GST_DEINTERLACE_LAYOUT_TFF;
1130 field_layout = GST_DEINTERLACE_LAYOUT_BFF;
1134 if (field_layout == GST_DEINTERLACE_LAYOUT_TFF) {
1135 GST_DEBUG_OBJECT (self, "Top field first");
1136 field1 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
1137 field1_flags = PICTURE_INTERLACED_TOP;
1138 field2 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
1139 field2_flags = PICTURE_INTERLACED_BOTTOM;
1141 GST_DEBUG_OBJECT (self, "Bottom field first");
1142 field1 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
1143 field1_flags = PICTURE_INTERLACED_BOTTOM;
1144 field2 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
1145 field2_flags = PICTURE_INTERLACED_TOP;
1148 if (interlacing_method != GST_DEINTERLACE_TELECINE) {
1149 /* Timestamps are assigned to the field buffers under the assumption that
1150 the timestamp of the buffer equals the first fields timestamp */
1152 timestamp = GST_BUFFER_TIMESTAMP (buffer);
1153 GST_BUFFER_TIMESTAMP (field1) = timestamp;
1154 GST_BUFFER_TIMESTAMP (field2) = timestamp + self->field_duration;
1156 GST_BUFFER_TIMESTAMP (field2) += self->field_duration;
1160 self->field_history[2].buf = field1;
1161 self->field_history[2].flags = field1_flags;
1163 self->field_history[1].buf = field2;
1164 self->field_history[1].flags = field2_flags;
1166 self->field_history[0].buf =
1167 gst_buffer_make_metadata_writable (gst_buffer_ref (field1));
1168 GST_BUFFER_TIMESTAMP (self->field_history[0].buf) +=
1169 2 * self->field_duration;
1170 self->field_history[0].flags = field1_flags;
1171 } else if (!onefield) {
1172 self->field_history[1].buf = field1;
1173 self->field_history[1].flags = field1_flags;
1175 self->field_history[0].buf = field2;
1176 self->field_history[0].flags = field2_flags;
1177 } else { /* onefield */
1178 self->field_history[0].buf = field1;
1179 self->field_history[0].flags = field1_flags;
1180 gst_buffer_unref (field2);
1183 self->history_count += fields_to_push;
1184 self->cur_field_idx += fields_to_push;
1186 GST_DEBUG_OBJECT (self, "Pushed buffer -- current history size %d, index %d",
1187 self->history_count, self->cur_field_idx);
1189 if (self->last_buffer)
1190 gst_buffer_unref (self->last_buffer);
1191 self->last_buffer = buffer;
1195 gst_deinterlace_update_qos (GstDeinterlace * self, gdouble proportion,
1196 GstClockTimeDiff diff, GstClockTime timestamp)
1198 GST_DEBUG_OBJECT (self,
1199 "Updating QoS: proportion %lf, diff %s%" GST_TIME_FORMAT ", timestamp %"
1200 GST_TIME_FORMAT, proportion, (diff < 0) ? "-" : "",
1201 GST_TIME_ARGS (ABS (diff)), GST_TIME_ARGS (timestamp));
1203 GST_OBJECT_LOCK (self);
1204 self->proportion = proportion;
1205 if (G_LIKELY (timestamp != GST_CLOCK_TIME_NONE)) {
1206 if (G_UNLIKELY (diff > 0))
1207 self->earliest_time =
1208 timestamp + 2 * diff + ((self->fields ==
1209 GST_DEINTERLACE_ALL) ? self->field_duration : 2 *
1210 self->field_duration);
1212 self->earliest_time = timestamp + diff;
1214 self->earliest_time = GST_CLOCK_TIME_NONE;
1216 GST_OBJECT_UNLOCK (self);
1220 gst_deinterlace_reset_qos (GstDeinterlace * self)
1222 gst_deinterlace_update_qos (self, 0.5, 0, GST_CLOCK_TIME_NONE);
1226 gst_deinterlace_read_qos (GstDeinterlace * self, gdouble * proportion,
1227 GstClockTime * time)
1229 GST_OBJECT_LOCK (self);
1230 *proportion = self->proportion;
1231 *time = self->earliest_time;
1232 GST_OBJECT_UNLOCK (self);
1235 /* Perform qos calculations before processing the next frame. Returns TRUE if
1236 * the frame should be processed, FALSE if the frame can be dropped entirely */
1238 gst_deinterlace_do_qos (GstDeinterlace * self, GstClockTime timestamp)
1240 GstClockTime qostime, earliest_time;
1243 /* no timestamp, can't do QoS => process frame */
1244 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) {
1245 GST_LOG_OBJECT (self, "invalid timestamp, can't do QoS, process frame");
1249 /* get latest QoS observation values */
1250 gst_deinterlace_read_qos (self, &proportion, &earliest_time);
1252 /* skip qos if we have no observation (yet) => process frame */
1253 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) {
1254 GST_LOG_OBJECT (self, "no observation yet, process frame");
1258 /* qos is done on running time */
1259 qostime = gst_segment_to_running_time (&self->segment, GST_FORMAT_TIME,
1262 /* see how our next timestamp relates to the latest qos timestamp */
1263 GST_LOG_OBJECT (self, "qostime %" GST_TIME_FORMAT ", earliest %"
1264 GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
1266 if (qostime != GST_CLOCK_TIME_NONE && qostime <= earliest_time) {
1267 GST_DEBUG_OBJECT (self, "we are late, drop frame");
1271 GST_LOG_OBJECT (self, "process frame");
1276 gst_deinterlace_fix_timestamps (GstDeinterlace * self,
1277 GstDeinterlaceField * field1, GstDeinterlaceField * field2)
1279 GstDeinterlaceField *field3, *field4;
1280 GstDeinterlaceInterlacingMethod interlacing_method;
1282 if (self->pattern_lock && self->pattern > -1) {
1283 /* accurate pattern-locked timestamp adjustment */
1284 if (!self->pattern_count)
1285 gst_deinterlace_update_pattern_timestamps (self);
1287 GST_BUFFER_TIMESTAMP (field1->buf) =
1288 self->pattern_base_ts + self->output_count * self->pattern_buf_dur;
1289 GST_BUFFER_DURATION (field1->buf) = self->pattern_buf_dur;
1290 self->output_count++;
1292 /* naive (but low-latency) timestamp adjustment based on subsequent
1295 && GST_BUFFER_DATA (field1->buf) != GST_BUFFER_DATA (field2->buf)) {
1296 if (GST_BUFFER_TIMESTAMP (field1->buf) +
1297 GST_BUFFER_DURATION (field1->buf) ==
1298 GST_BUFFER_TIMESTAMP (field2->buf)) {
1299 GST_BUFFER_TIMESTAMP (field1->buf) =
1300 GST_BUFFER_TIMESTAMP (field2->buf) =
1301 (GST_BUFFER_TIMESTAMP (field1->buf) +
1302 GST_BUFFER_TIMESTAMP (field2->buf)) / 2;
1304 GST_BUFFER_TIMESTAMP (field2->buf) = GST_BUFFER_TIMESTAMP (field1->buf);
1308 if (self->history_count < 3) {
1309 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need 3)",
1310 self->history_count);
1314 field3 = &self->field_history[self->history_count - 3];
1315 interlacing_method =
1316 gst_deinterlace_get_interlacing_method (GST_BUFFER_CAPS (field3->buf));
1317 if (interlacing_method == GST_DEINTERLACE_TELECINE) {
1318 if (self->history_count < 4) {
1319 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need 4)",
1320 self->history_count);
1324 field4 = &self->field_history[self->history_count - 4];
1325 if (GST_BUFFER_DATA (field3->buf) != GST_BUFFER_DATA (field4->buf)) {
1326 /* telecine fields in separate buffers */
1327 GST_BUFFER_TIMESTAMP (field3->buf) =
1328 (GST_BUFFER_TIMESTAMP (field3->buf) +
1329 GST_BUFFER_TIMESTAMP (field4->buf)) / 2;
1333 GST_BUFFER_DURATION (field1->buf) =
1334 GST_BUFFER_TIMESTAMP (field3->buf) - GST_BUFFER_TIMESTAMP (field1->buf);
1337 GST_DEBUG_OBJECT (self,
1338 "Field 1 adjusted to ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT,
1339 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1->buf)),
1340 GST_TIME_ARGS (GST_BUFFER_DURATION (field1->buf)));
1345 gst_deinterlace_get_pattern_lock (GstDeinterlace * self, gboolean * flush_one)
1347 /* loop over all possible patterns and all possible phases
1348 * giving each a score. the highest score gets the lock */
1349 /* the score is calculated as the number of matched buffers in the
1350 * sequence starting at the phase offset with those from the history
1351 * then the longest duration pattern match is taken. if there is more than
1352 * one pattern matching all buffers, we take the longest pattern of those.
1353 * matches to complete patterns are preferred. if no non-trivial pattern is
1354 * matched, trivial patterns are tested. */
1355 gint i, j, k, score, pattern, phase;
1356 const gint state_count = self->state_count;
1357 const gint n_required = self->ignore_obscure ?
1358 GST_DEINTERLACE_OBSCURE_THRESHOLD :
1359 GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY;
1361 /* set unknown pattern as this is used in logic outside this function */
1364 /* wait for more buffers */
1365 if (!self->have_eos && state_count < n_required) {
1366 GST_DEBUG_OBJECT (self, "Need more buffers in state history - %d/%d",
1367 state_count, n_required);
1371 score = pattern = phase = -1;
1373 /* loop over all patterns */
1374 for (i = 0; i < G_N_ELEMENTS (telecine_patterns); i++) {
1375 const guint8 length = telecine_patterns[i].length;
1377 if (self->ignore_obscure && i >= GST_DEINTERLACE_OBSCURE_THRESHOLD)
1380 if (state_count < length)
1383 /* loop over all phases */
1384 for (j = 0; j < length; j++) {
1385 /* low-latency mode looks at past buffers, high latency at future buffers */
1386 const gint state_idx = (self->low_latency ? length : state_count) - 1;
1387 /* loop over history, breaking on differing buffer states */
1388 for (k = 0; k < length && k < state_count; k++) {
1389 const guint8 hist = self->buf_states[state_idx - k].state;
1390 const guint8 patt = telecine_patterns[i].states[(j + k) % length];
1395 /* make complete matches more signficant */
1397 k += GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY;
1399 /* take as new best pattern if the number of matched buffers is more than
1400 * for other patterns */
1405 if (self->low_latency) {
1406 /* state_idx + 1 is the number of buffers yet to be pushed out
1407 * so length - state_idx - 1 is the number of old buffers in the
1409 phase = (phase + length - state_idx - 1) % length;
1415 GST_DEBUG_OBJECT (self,
1416 "Final pattern match result: pa %d, ph %d, l %d, s %d", pattern, phase,
1417 telecine_patterns[pattern].length, score);
1418 self->pattern = pattern;
1419 self->pattern_phase = phase;
1420 self->pattern_count = 0;
1421 self->output_count = 0;
1422 self->pattern_lock = TRUE;
1424 /* check for the case that the first field of the pattern is an orphan */
1426 && telecine_patterns[pattern].states[phase] & (GST_ONE | GST_INT)) {
1427 gint i = phase, field_count = 0;
1428 guint8 state = telecine_patterns[pattern].states[i];
1431 if (state & GST_ONE) {
1433 } else if (!(state & GST_DRP)) {
1437 i %= telecine_patterns[pattern].length;
1438 state = telecine_patterns[pattern].states[i];
1439 } while (!(state & GST_PRG));
1441 /* if field_count is odd, we have an orphan field at the beginning of the
1443 * note - don't do this in low-latency mode as we are somewhere within the
1444 * pattern already */
1445 if (!self->low_latency && (*flush_one = field_count & 1)) {
1446 GST_DEBUG_OBJECT (self, "Orphan field detected at the beginning of the "
1447 "pattern - it will be deinterlaced.");
1452 static GstFlowReturn
1453 gst_deinterlace_output_frame (GstDeinterlace * self, gboolean flushing)
1455 GstClockTime timestamp;
1457 gint fields_required;
1458 GstBuffer *buf, *outbuf;
1459 GstDeinterlaceField *field1, *field2;
1460 GstDeinterlaceInterlacingMethod interlacing_method;
1462 gboolean hl_no_lock; /* indicates high latency timestamp adjustment but no pattern lock (could be ONEF or I) */
1463 gboolean same_buffer; /* are field1 and field2 in the same buffer? */
1464 gboolean flush_one; /* used for flushing one field when in high latency mode and not locked */
1465 TelecinePattern pattern;
1466 guint8 phase, count;
1467 const GstDeinterlaceLocking locking = self->locking;
1471 fields_required = 0;
1473 same_buffer = FALSE;
1475 self->need_more = FALSE;
1476 phase = self->pattern_phase;
1477 count = self->pattern_count;
1479 if (!self->history_count) {
1480 GST_DEBUG_OBJECT (self, "History is empty, waiting for more buffers!");
1484 field1 = &self->field_history[self->history_count - 1];
1486 if (locking != GST_DEINTERLACE_LOCKING_NONE) {
1487 if (!self->state_count) {
1488 GST_ERROR_OBJECT (self,
1489 "BROKEN! Fields in history + no states should not happen!");
1490 return GST_FLOW_ERROR;
1493 gst_deinterlace_get_buffer_state (self, field1->buf, &buf_state,
1494 &interlacing_method);
1496 if (self->pattern != -1)
1497 pattern = telecine_patterns[self->pattern];
1499 /* patterns 0 and 1 are interlaced, the rest are telecine */
1500 if (self->pattern > 1)
1501 interlacing_method = GST_DEINTERLACE_TELECINE;
1503 if (self->pattern == -1 || self->pattern_refresh
1504 || !(buf_state & pattern.states[(phase + count) % pattern.length])) {
1505 /* no pattern, pattern refresh set or unexpected buffer state */
1506 self->pattern_lock = FALSE;
1507 self->pattern_refresh = TRUE;
1509 /* refresh pattern lock */
1510 gst_deinterlace_get_pattern_lock (self, &flush_one);
1512 if (self->pattern != -1) {
1513 /* locked onto a valid pattern so refresh complete */
1514 GST_DEBUG_OBJECT (self, "Pattern locked! %s starting at %d",
1515 telecine_patterns[self->pattern].nick, self->pattern_phase);
1516 self->pattern_refresh = FALSE;
1517 } else if (!self->low_latency) {
1518 if (!self->pattern_lock) {
1525 /* setcaps on sink and src pads */
1526 gst_deinterlace_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad));
1528 if (flush_one && self->drop_orphans) {
1529 GST_DEBUG_OBJECT (self, "Dropping orphan first field");
1530 self->cur_field_idx--;
1531 gst_buffer_unref (gst_deinterlace_pop_history (self));
1536 gst_deinterlace_get_buffer_state (self, field1->buf, NULL,
1537 &interlacing_method);
1540 same_buffer = self->history_count >= 2
1541 && (GST_BUFFER_DATA (field1->buf) ==
1542 GST_BUFFER_DATA (self->field_history[self->history_count - 2].buf));
1544 if ((flushing && self->history_count == 1) || (flush_one
1545 && !self->drop_orphans) || (hl_no_lock && (self->history_count == 1
1546 || !same_buffer))) {
1547 GST_DEBUG_OBJECT (self, "Flushing one field using linear method");
1548 gst_deinterlace_set_method (self, GST_DEINTERLACE_LINEAR);
1549 fields_required = gst_deinterlace_method_get_fields_required (self->method);
1550 } else if (interlacing_method == GST_DEINTERLACE_TELECINE
1551 && (self->low_latency > 0 || self->pattern != -1 || (hl_no_lock
1553 && GST_BUFFER_FLAG_IS_SET (field1->buf,
1554 GST_VIDEO_BUFFER_PROGRESSIVE)))) {
1555 /* telecined - we reconstruct frames by weaving pairs of fields */
1556 fields_required = 2;
1557 if (!flushing && self->history_count < fields_required) {
1558 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
1559 self->history_count, self->cur_field_idx + fields_required);
1563 field2 = &self->field_history[self->history_count - 2];
1564 if (!gst_deinterlace_fix_timestamps (self, field1, field2) && !flushing)
1568 /* telecine progressive */
1569 GstBuffer *field1_buf;
1571 GST_DEBUG_OBJECT (self,
1572 "Frame type: Telecine Progressive; pushing buffer as a frame");
1574 self->cur_field_idx--;
1575 field1_buf = gst_deinterlace_pop_history (self);
1576 /* field2 is the same buffer as field1, but we need to remove it from
1577 * the history anyway */
1578 self->cur_field_idx--;
1579 gst_buffer_unref (gst_deinterlace_pop_history (self));
1580 /* set the caps from the src pad on the buffer as they should be correct */
1581 gst_buffer_set_caps (field1_buf, GST_PAD_CAPS (self->srcpad));
1582 GST_DEBUG_OBJECT (self,
1583 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1584 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf)),
1585 GST_TIME_ARGS (GST_BUFFER_DURATION (field1_buf)),
1586 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf) +
1587 GST_BUFFER_DURATION (field1_buf)));
1588 return gst_pad_push (self->srcpad, field1_buf);
1590 /* telecine fields in separate buffers */
1592 /* check field1 and field2 buffer caps and flags are corresponding */
1593 if (field1->flags == field2->flags) {
1594 /* ERROR - fields are of same parity - what should be done here?
1595 * perhaps deinterlace the tip field and start again? */
1596 GST_ERROR_OBJECT (self, "Telecine mixed with fields of same parity!");
1598 GST_DEBUG_OBJECT (self,
1599 "Frame type: Telecine Mixed; weaving tip two fields into a frame");
1600 /* set method to WEAVE */
1601 gst_deinterlace_set_method (self, GST_DEINTERLACE_WEAVE);
1603 } else if (interlacing_method == GST_DEINTERLACE_INTERLACED || (hl_no_lock
1604 && interlacing_method == GST_DEINTERLACE_TELECINE && same_buffer
1605 && !GST_BUFFER_FLAG_IS_SET (field1->buf,
1606 GST_VIDEO_BUFFER_PROGRESSIVE))) {
1607 gst_deinterlace_set_method (self, self->user_set_method_id);
1608 fields_required = gst_deinterlace_method_get_fields_required (self->method);
1609 if (flushing && self->history_count < fields_required) {
1610 /* note: we already checked for flushing with history count == 1 above
1611 * so we must have 2 or more fields in here */
1612 gst_deinterlace_set_method (self, GST_DEINTERLACE_VFIR);
1614 gst_deinterlace_method_get_fields_required (self->method);
1615 GST_DEBUG_OBJECT (self, "Flushing field(s) using %s method",
1616 methods_types[self->method_id].value_nick);
1619 /* Not enough fields in the history */
1620 if (!flushing && self->history_count < fields_required) {
1621 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
1622 self->history_count, self->cur_field_idx + fields_required);
1626 GST_DEBUG_OBJECT (self,
1627 "Frame type: Interlaced; deinterlacing using %s method",
1628 methods_types[self->method_id].value_nick);
1630 GstBuffer *field1_buf;
1633 fields_required = 2;
1635 /* Not enough fields in the history */
1636 if (!flushing && self->history_count < fields_required) {
1637 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
1638 self->history_count, self->cur_field_idx + fields_required);
1642 field2 = &self->field_history[self->history_count - 2];
1643 if (GST_BUFFER_DATA (field1->buf) != GST_BUFFER_DATA (field2->buf)) {
1644 /* ERROR - next two fields in field history are not one progressive buffer - weave? */
1645 GST_ERROR_OBJECT (self,
1646 "Progressive buffer but two fields at tip aren't in the same buffer!");
1649 GST_DEBUG_OBJECT (self,
1650 "Frame type: Progressive; pushing buffer as a frame");
1652 self->cur_field_idx--;
1653 field1_buf = gst_deinterlace_pop_history (self);
1654 /* field2 is the same buffer as field1, but we need to remove it from the
1656 self->cur_field_idx--;
1657 gst_buffer_unref (gst_deinterlace_pop_history (self));
1658 GST_DEBUG_OBJECT (self,
1659 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1660 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf)),
1661 GST_TIME_ARGS (GST_BUFFER_DURATION (field1_buf)),
1662 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf) +
1663 GST_BUFFER_DURATION (field1_buf)));
1664 return gst_pad_push (self->srcpad, field1_buf);
1667 if (!flushing && self->cur_field_idx < 1) {
1671 if (self->fields == GST_DEINTERLACE_ALL
1672 || interlacing_method == GST_DEINTERLACE_TELECINE)
1673 GST_DEBUG_OBJECT (self, "All fields");
1674 else if (self->fields == GST_DEINTERLACE_TF)
1675 GST_DEBUG_OBJECT (self, "Top fields");
1676 else if (self->fields == GST_DEINTERLACE_BF)
1677 GST_DEBUG_OBJECT (self, "Bottom fields");
1679 if ((self->field_history[self->cur_field_idx].flags == PICTURE_INTERLACED_TOP
1680 && (self->fields == GST_DEINTERLACE_TF
1681 || interlacing_method == GST_DEINTERLACE_TELECINE))
1682 || self->fields == GST_DEINTERLACE_ALL) {
1683 GST_DEBUG_OBJECT (self, "deinterlacing top field");
1685 /* create new buffer */
1687 gst_pad_alloc_buffer (self->srcpad, GST_BUFFER_OFFSET_NONE,
1688 self->frame_size, GST_PAD_CAPS (self->srcpad), &outbuf);
1689 if (ret != GST_FLOW_OK)
1692 if (GST_PAD_CAPS (self->srcpad) != GST_BUFFER_CAPS (outbuf) &&
1693 !gst_caps_is_equal (GST_PAD_CAPS (self->srcpad),
1694 GST_BUFFER_CAPS (outbuf))) {
1695 gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf));
1696 GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT,
1697 self->request_caps);
1699 gst_buffer_unref (outbuf);
1700 outbuf = gst_buffer_try_new_and_alloc (self->frame_size);
1703 return GST_FLOW_ERROR;
1705 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
1708 g_return_val_if_fail (self->history_count - 1 -
1709 gst_deinterlace_method_get_latency (self->method) >= 0, GST_FLOW_ERROR);
1712 self->field_history[self->history_count - 1 -
1713 gst_deinterlace_method_get_latency (self->method)].buf;
1715 if (interlacing_method != GST_DEINTERLACE_TELECINE) {
1716 timestamp = GST_BUFFER_TIMESTAMP (buf);
1718 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1719 if (self->fields == GST_DEINTERLACE_ALL)
1720 GST_BUFFER_DURATION (outbuf) = self->field_duration;
1722 GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
1724 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1725 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1728 /* Check if we need to drop the frame because of QoS */
1729 if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
1730 self->cur_field_idx--;
1731 gst_buffer_unref (gst_deinterlace_pop_history (self));
1732 gst_buffer_unref (outbuf);
1736 if (self->cur_field_idx < 0 && flushing) {
1737 if (self->history_count == 1) {
1738 gst_buffer_unref (gst_deinterlace_pop_history (self));
1741 self->cur_field_idx++;
1743 if (self->cur_field_idx < 0) {
1746 if (!flushing && self->cur_field_idx < 1) {
1750 /* do magic calculus */
1751 gst_deinterlace_method_deinterlace_frame (self->method,
1752 self->field_history, self->history_count, outbuf,
1753 self->cur_field_idx);
1755 self->cur_field_idx--;
1756 if (self->cur_field_idx + 1 +
1757 gst_deinterlace_method_get_latency (self->method)
1758 < self->history_count || flushing) {
1759 gst_buffer_unref (gst_deinterlace_pop_history (self));
1762 if (gst_deinterlace_clip_buffer (self, outbuf)) {
1763 GST_DEBUG_OBJECT (self,
1764 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1765 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1766 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
1767 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
1768 GST_BUFFER_DURATION (outbuf)));
1769 ret = gst_pad_push (self->srcpad, outbuf);
1772 gst_buffer_unref (outbuf);
1776 if (ret != GST_FLOW_OK)
1778 if (interlacing_method == GST_DEINTERLACE_TELECINE
1779 && self->method_id == GST_DEINTERLACE_WEAVE) {
1780 /* pop off the second field */
1781 GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
1782 self->history_count);
1783 self->cur_field_idx--;
1784 gst_buffer_unref (gst_deinterlace_pop_history (self));
1785 interlacing_method = GST_DEINTERLACE_INTERLACED;
1790 if (flush_one && !self->drop_orphans) {
1791 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1795 /* no calculation done: remove excess field */
1796 else if (self->field_history[self->cur_field_idx].flags ==
1797 PICTURE_INTERLACED_TOP && (self->fields == GST_DEINTERLACE_BF
1798 && interlacing_method != GST_DEINTERLACE_TELECINE)) {
1799 GST_DEBUG_OBJECT (self, "Removing unused top field");
1800 self->cur_field_idx--;
1801 gst_buffer_unref (gst_deinterlace_pop_history (self));
1803 if (flush_one && !self->drop_orphans) {
1804 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1809 if (self->history_count < fields_required)
1812 if (self->cur_field_idx < 0)
1815 if (!flushing && self->cur_field_idx < 1) {
1819 /* deinterlace bottom_field */
1820 if ((self->field_history[self->cur_field_idx].flags ==
1821 PICTURE_INTERLACED_BOTTOM && (self->fields == GST_DEINTERLACE_BF
1822 || interlacing_method == GST_DEINTERLACE_TELECINE))
1823 || self->fields == GST_DEINTERLACE_ALL) {
1824 GST_DEBUG_OBJECT (self, "deinterlacing bottom field");
1826 /* create new buffer */
1828 gst_pad_alloc_buffer (self->srcpad, GST_BUFFER_OFFSET_NONE,
1829 self->frame_size, GST_PAD_CAPS (self->srcpad), &outbuf);
1830 if (ret != GST_FLOW_OK)
1833 if (GST_PAD_CAPS (self->srcpad) != GST_BUFFER_CAPS (outbuf) &&
1834 !gst_caps_is_equal (GST_PAD_CAPS (self->srcpad),
1835 GST_BUFFER_CAPS (outbuf))) {
1836 gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf));
1837 GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT,
1838 self->request_caps);
1840 gst_buffer_unref (outbuf);
1841 outbuf = gst_buffer_try_new_and_alloc (self->frame_size);
1844 return GST_FLOW_ERROR;
1846 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
1849 g_return_val_if_fail (self->history_count - 1 -
1850 gst_deinterlace_method_get_latency (self->method) >= 0, GST_FLOW_ERROR);
1853 self->field_history[self->history_count - 1 -
1854 gst_deinterlace_method_get_latency (self->method)].buf;
1855 if (interlacing_method != GST_DEINTERLACE_TELECINE) {
1856 timestamp = GST_BUFFER_TIMESTAMP (buf);
1858 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1859 if (self->fields == GST_DEINTERLACE_ALL)
1860 GST_BUFFER_DURATION (outbuf) = self->field_duration;
1862 GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
1864 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1865 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1868 /* Check if we need to drop the frame because of QoS */
1869 if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
1870 self->cur_field_idx--;
1871 gst_buffer_unref (gst_deinterlace_pop_history (self));
1872 gst_buffer_unref (outbuf);
1876 /* do magic calculus */
1877 gst_deinterlace_method_deinterlace_frame (self->method,
1878 self->field_history, self->history_count, outbuf,
1879 self->cur_field_idx);
1881 self->cur_field_idx--;
1882 if (self->cur_field_idx + 1 +
1883 gst_deinterlace_method_get_latency (self->method)
1884 < self->history_count) {
1885 gst_buffer_unref (gst_deinterlace_pop_history (self));
1888 if (gst_deinterlace_clip_buffer (self, outbuf)) {
1889 GST_DEBUG_OBJECT (self,
1890 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1891 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1892 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
1893 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
1894 GST_BUFFER_DURATION (outbuf)));
1895 ret = gst_pad_push (self->srcpad, outbuf);
1898 gst_buffer_unref (outbuf);
1902 if (ret != GST_FLOW_OK)
1904 if (interlacing_method == GST_DEINTERLACE_TELECINE
1905 && self->method_id == GST_DEINTERLACE_WEAVE) {
1906 /* pop off the second field */
1907 GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
1908 self->history_count);
1909 self->cur_field_idx--;
1910 gst_buffer_unref (gst_deinterlace_pop_history (self));
1911 interlacing_method = GST_DEINTERLACE_INTERLACED;
1916 if (flush_one && !self->drop_orphans) {
1917 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1921 /* no calculation done: remove excess field */
1922 else if (self->field_history[self->cur_field_idx].flags ==
1923 PICTURE_INTERLACED_BOTTOM && (self->fields == GST_DEINTERLACE_TF
1924 && interlacing_method != GST_DEINTERLACE_TELECINE)) {
1925 GST_DEBUG_OBJECT (self, "Removing unused bottom field");
1926 self->cur_field_idx--;
1927 gst_buffer_unref (gst_deinterlace_pop_history (self));
1929 if (flush_one && !self->drop_orphans) {
1930 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1938 self->need_more = TRUE;
1943 gst_deinterlace_get_latency (GstDeinterlace * self)
1945 if (self->locking == GST_DEINTERLACE_LOCKING_AUTO) {
1949 query = gst_query_new_latency ();
1950 if ((res = gst_pad_peer_query (self->sinkpad, query))) {
1952 /* if upstream is live, we use low-latency passive locking mode
1953 * else high-latency active locking mode */
1954 gst_query_parse_latency (query, &is_live, NULL, NULL);
1955 GST_DEBUG_OBJECT (self, "Latency query indicates stream is %s",
1956 is_live ? "live - using passive locking" :
1957 "not live - using active locking");
1958 gst_query_unref (query);
1961 /* conservatively use passive locking if the query fails */
1962 GST_WARNING_OBJECT (self,
1963 "Latency query failed - fall back to using passive locking");
1964 gst_query_unref (query);
1968 return self->locking - 2;
1972 static GstFlowReturn
1973 gst_deinterlace_chain (GstPad * pad, GstBuffer * buf)
1975 GstDeinterlace *self = GST_DEINTERLACE (GST_PAD_PARENT (pad));
1976 GstFlowReturn ret = GST_FLOW_OK;
1978 GST_OBJECT_LOCK (self);
1979 if (self->reconfigure) {
1980 if (self->new_fields != -1)
1981 self->fields = self->new_fields;
1982 if (self->new_mode != -1)
1983 self->mode = self->new_mode;
1984 self->new_mode = self->new_fields = -1;
1986 self->reconfigure = FALSE;
1987 GST_OBJECT_UNLOCK (self);
1988 if (GST_PAD_CAPS (self->srcpad))
1989 gst_deinterlace_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad));
1991 GST_OBJECT_UNLOCK (self);
1994 GST_DEBUG_OBJECT (self,
1995 "[IN] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1996 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1997 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
1998 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)));
2000 if (self->still_frame_mode || self->passthrough) {
2001 GST_DEBUG_OBJECT (self,
2002 "Frame type: Progressive?; pushing buffer using pass-through");
2003 GST_DEBUG_OBJECT (self,
2004 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
2005 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
2006 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
2007 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)));
2009 return gst_pad_push (self->srcpad, buf);
2012 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
2013 GST_DEBUG_OBJECT (self, "DISCONT buffer, resetting history");
2014 gst_deinterlace_reset_history (self, FALSE);
2017 gst_deinterlace_push_history (self, buf);
2021 ret = gst_deinterlace_output_frame (self, FALSE);
2022 } while (!self->need_more && self->history_count > 0 && ret == GST_FLOW_OK);
2028 gst_greatest_common_divisor (gint a, gint b)
2041 gst_fraction_double (gint * n_out, gint * d_out, gboolean half)
2051 if (n == 0 || (n == G_MAXINT && d == 1))
2054 gcd = gst_greatest_common_divisor (n, d);
2059 if (G_MAXINT / 2 >= ABS (n)) {
2061 } else if (d >= 2) {
2067 if (G_MAXINT / 2 >= ABS (d)) {
2069 } else if (n >= 2) {
2083 gst_deinterlace_getcaps (GstPad * pad)
2086 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2089 const GstCaps *ourcaps;
2092 otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad;
2094 ourcaps = gst_pad_get_pad_template_caps (pad);
2095 peercaps = gst_pad_peer_get_caps (otherpad);
2098 GST_DEBUG_OBJECT (pad, "Peer has caps %" GST_PTR_FORMAT, peercaps);
2099 ret = gst_caps_intersect (ourcaps, peercaps);
2100 gst_caps_unref (peercaps);
2102 ret = gst_caps_copy (ourcaps);
2105 for (len = gst_caps_get_size (ret); len > 0; len--) {
2106 GstStructure *s = gst_caps_get_structure (ret, len - 1);
2108 if (pad == self->sinkpad || self->passthrough)
2109 gst_structure_remove_field (s, "interlaced");
2111 gst_structure_set (s, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL);
2113 if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) {
2116 val = gst_structure_get_value (s, "framerate");
2120 if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION) {
2123 n = gst_value_get_fraction_numerator (val);
2124 d = gst_value_get_fraction_denominator (val);
2126 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
2130 gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
2131 } else if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION_RANGE) {
2132 const GValue *min, *max;
2133 GValue nrange = { 0, }, nmin = {
2138 g_value_init (&nrange, GST_TYPE_FRACTION_RANGE);
2139 g_value_init (&nmin, GST_TYPE_FRACTION);
2140 g_value_init (&nmax, GST_TYPE_FRACTION);
2142 min = gst_value_get_fraction_range_min (val);
2143 max = gst_value_get_fraction_range_max (val);
2145 n = gst_value_get_fraction_numerator (min);
2146 d = gst_value_get_fraction_denominator (min);
2148 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
2149 g_value_unset (&nrange);
2150 g_value_unset (&nmax);
2151 g_value_unset (&nmin);
2155 gst_value_set_fraction (&nmin, n, d);
2157 n = gst_value_get_fraction_numerator (max);
2158 d = gst_value_get_fraction_denominator (max);
2160 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
2161 g_value_unset (&nrange);
2162 g_value_unset (&nmax);
2163 g_value_unset (&nmin);
2167 gst_value_set_fraction (&nmax, n, d);
2168 gst_value_set_fraction_range (&nrange, &nmin, &nmax);
2170 gst_structure_set_value (s, "framerate", &nrange);
2172 g_value_unset (&nmin);
2173 g_value_unset (&nmax);
2174 g_value_unset (&nrange);
2175 } else if (G_VALUE_TYPE (val) == GST_TYPE_LIST) {
2177 GValue nlist = { 0, };
2178 GValue nval = { 0, };
2181 g_value_init (&nlist, GST_TYPE_LIST);
2182 for (i = gst_value_list_get_size (val); i > 0; i--) {
2185 lval = gst_value_list_get_value (val, i);
2187 if (G_VALUE_TYPE (lval) != GST_TYPE_FRACTION)
2190 n = gst_value_get_fraction_numerator (lval);
2191 d = gst_value_get_fraction_denominator (lval);
2193 /* Double/Half the framerate but if this fails simply
2194 * skip this value from the list */
2195 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
2199 g_value_init (&nval, GST_TYPE_FRACTION);
2201 gst_value_set_fraction (&nval, n, d);
2202 gst_value_list_append_value (&nlist, &nval);
2203 g_value_unset (&nval);
2205 gst_structure_set_value (s, "framerate", &nlist);
2206 g_value_unset (&nlist);
2211 GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret);
2213 gst_object_unref (self);
2218 GST_ERROR_OBJECT (pad, "Unable to transform peer caps");
2219 gst_caps_unref (ret);
2224 gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps)
2226 gboolean res = TRUE;
2227 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2229 GstDeinterlaceInterlacingMethod interlacing_method;
2231 if (self->locking != GST_DEINTERLACE_LOCKING_NONE) {
2232 if (self->low_latency == -1)
2233 self->low_latency = gst_deinterlace_get_latency (self);
2235 if (self->pattern_lock) {
2236 /* refresh has been successful - we have a lock now */
2237 self->pattern_refresh = FALSE;
2239 /* if we were not refreshing (!pattern_refresh) the caps have changed
2240 * so we need to refresh and we don't have a lock anymore
2241 * otherwise we have pattern_fresh and !pattern_lock anyway */
2242 self->pattern_refresh = TRUE;
2243 self->pattern_lock = FALSE;
2248 gst_video_format_parse_caps (caps, &self->format, &self->width,
2250 res &= gst_video_parse_caps_framerate (caps, &self->fps_n, &self->fps_d);
2251 if (pad == self->sinkpad)
2252 res &= gst_video_format_parse_caps_interlaced (caps, &self->interlaced);
2256 gst_deinterlace_update_passthrough (self);
2258 interlacing_method = gst_deinterlace_get_interlacing_method (caps);
2260 if (self->pattern_lock) {
2261 srccaps = gst_caps_copy (caps);
2262 if (self->pattern != -1
2263 && G_UNLIKELY (!gst_util_fraction_multiply (self->fps_n, self->fps_d,
2264 telecine_patterns[self->pattern].ratio_n,
2265 telecine_patterns[self->pattern].ratio_d, &self->fps_n,
2267 GST_ERROR_OBJECT (self,
2268 "Multiplying the framerate by the telecine pattern ratio overflowed!");
2269 gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, self->fps_n,
2271 } else if (self->low_latency > 0) {
2272 if (interlacing_method == GST_DEINTERLACE_TELECINE) {
2273 /* for initial buffers of a telecine pattern, until there is a lock we
2274 * we output naïvely adjusted timestamps */
2275 srccaps = gst_caps_copy (caps);
2276 gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
2277 } else if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) {
2278 gint fps_n = self->fps_n, fps_d = self->fps_d;
2280 if (!gst_fraction_double (&fps_n, &fps_d, FALSE))
2283 srccaps = gst_caps_copy (caps);
2285 gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, fps_n,
2288 srccaps = gst_caps_ref (caps);
2291 /* in high latency pattern locking mode if we don't have a pattern lock,
2292 * the sink pad caps are the best we know */
2293 srccaps = gst_caps_ref (caps);
2296 if (self->mode != GST_DEINTERLACE_MODE_DISABLED) {
2297 srccaps = gst_caps_make_writable (srccaps);
2298 gst_structure_remove_field (gst_caps_get_structure (srccaps, 0),
2299 "interlacing-method");
2300 gst_caps_set_simple (srccaps, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL);
2303 if (!gst_pad_set_caps (self->srcpad, srccaps))
2304 goto caps_not_accepted;
2307 gst_video_format_get_size (self->format, self->width, self->height);
2309 if (G_LIKELY (self->fps_n != 0)) {
2310 self->field_duration =
2311 gst_util_uint64_scale (GST_SECOND, self->fps_d, 2 * self->fps_n);
2313 self->field_duration = 0;
2316 gst_deinterlace_set_method (self, self->method_id);
2317 gst_deinterlace_method_setup (self->method, self->format, self->width,
2320 GST_DEBUG_OBJECT (pad, "Sink caps: %" GST_PTR_FORMAT, caps);
2321 GST_DEBUG_OBJECT (pad, "Src caps: %" GST_PTR_FORMAT, srccaps);
2323 gst_caps_unref (srccaps);
2327 gst_object_unref (self);
2332 GST_ERROR_OBJECT (pad, "Invalid caps: %" GST_PTR_FORMAT, caps);
2337 GST_ERROR_OBJECT (pad, "Caps not accepted: %" GST_PTR_FORMAT, srccaps);
2338 gst_caps_unref (srccaps);
2343 gst_deinterlace_sink_event (GstPad * pad, GstEvent * event)
2345 gboolean res = TRUE;
2346 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2348 GST_LOG_OBJECT (pad, "received %s event: %" GST_PTR_FORMAT,
2349 GST_EVENT_TYPE_NAME (event), event);
2351 switch (GST_EVENT_TYPE (event)) {
2352 case GST_EVENT_NEWSEGMENT:
2356 gint64 start, end, base;
2357 gdouble rate, applied_rate;
2359 gst_event_parse_new_segment_full (event, &is_update, &rate,
2360 &applied_rate, &fmt, &start, &end, &base);
2362 gst_deinterlace_reset_qos (self);
2363 gst_deinterlace_reset_history (self, FALSE);
2365 if (fmt == GST_FORMAT_TIME) {
2366 GST_DEBUG_OBJECT (pad,
2367 "Got NEWSEGMENT event in GST_FORMAT_TIME, passing on (%"
2368 GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")", GST_TIME_ARGS (start),
2369 GST_TIME_ARGS (end));
2370 gst_segment_set_newsegment_full (&self->segment, is_update, rate,
2371 applied_rate, fmt, start, end, base);
2373 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
2376 res = gst_pad_push_event (self->srcpad, event);
2379 case GST_EVENT_CUSTOM_DOWNSTREAM:{
2380 gboolean still_state;
2382 if (gst_video_event_parse_still_frame (event, &still_state)) {
2383 GST_DEBUG_OBJECT (self, "Received still frame event, state %d",
2389 GST_DEBUG_OBJECT (self, "Handling still frame");
2390 self->still_frame_mode = TRUE;
2391 gst_deinterlace_reset_history (self, FALSE);
2392 if (self->last_buffer) {
2394 gst_pad_push (self->srcpad, gst_buffer_ref (self->last_buffer));
2395 GST_DEBUG_OBJECT (self, "Pushed still frame, result: %s",
2396 gst_flow_get_name (ret));
2398 GST_WARNING_OBJECT (self, "No pending buffer!");
2401 GST_DEBUG_OBJECT (self, "Ending still frames");
2402 self->still_frame_mode = FALSE;
2408 self->have_eos = TRUE;
2409 gst_deinterlace_reset_history (self, FALSE);
2413 res = gst_pad_push_event (self->srcpad, event);
2416 case GST_EVENT_FLUSH_STOP:
2417 if (self->still_frame_mode) {
2418 GST_DEBUG_OBJECT (self, "Ending still frames");
2419 self->still_frame_mode = FALSE;
2421 gst_deinterlace_reset_qos (self);
2422 res = gst_pad_push_event (self->srcpad, event);
2423 gst_deinterlace_reset_history (self, TRUE);
2427 gst_object_unref (self);
2432 gst_deinterlace_sink_query (GstPad * pad, GstQuery * query)
2434 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2435 gboolean res = FALSE;
2437 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
2439 switch (GST_QUERY_TYPE (query)) {
2441 GstPad *peer = gst_pad_get_peer (self->srcpad);
2444 res = gst_pad_query (peer, query);
2445 gst_object_unref (peer);
2453 gst_object_unref (self);
2457 static GstStateChangeReturn
2458 gst_deinterlace_change_state (GstElement * element, GstStateChange transition)
2460 GstStateChangeReturn ret;
2461 GstDeinterlace *self = GST_DEINTERLACE (element);
2463 switch (transition) {
2464 case GST_STATE_CHANGE_NULL_TO_READY:
2466 case GST_STATE_CHANGE_READY_TO_PAUSED:
2468 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2474 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2475 if (ret != GST_STATE_CHANGE_SUCCESS)
2478 switch (transition) {
2479 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2481 case GST_STATE_CHANGE_PAUSED_TO_READY:
2482 gst_deinterlace_reset (self);
2484 case GST_STATE_CHANGE_READY_TO_NULL:
2493 gst_deinterlace_src_event (GstPad * pad, GstEvent * event)
2495 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2498 GST_DEBUG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
2500 switch (GST_EVENT_TYPE (event)) {
2501 case GST_EVENT_QOS:{
2502 GstClockTimeDiff diff;
2503 GstClockTime timestamp;
2506 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
2508 gst_deinterlace_update_qos (self, proportion, diff, timestamp);
2512 res = gst_pad_push_event (self->sinkpad, event);
2516 gst_object_unref (self);
2522 gst_deinterlace_src_query (GstPad * pad, GstQuery * query)
2524 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2525 gboolean res = FALSE;
2527 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
2529 switch (GST_QUERY_TYPE (query)) {
2530 case GST_QUERY_LATENCY:
2531 if (!self->passthrough) {
2532 GstClockTime min, max;
2536 if ((peer = gst_pad_get_peer (self->sinkpad))) {
2537 if ((res = gst_pad_query (peer, query))) {
2538 GstClockTime latency;
2539 gint fields_required = 0;
2540 gint method_latency = 0;
2544 gst_deinterlace_method_get_fields_required (self->method);
2546 gst_deinterlace_method_get_latency (self->method);
2549 gst_query_parse_latency (query, &live, &min, &max);
2551 GST_DEBUG_OBJECT (self, "Peer latency: min %"
2552 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
2553 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
2555 /* add our own latency */
2556 latency = (fields_required + method_latency) * self->field_duration;
2558 GST_DEBUG_OBJECT (self, "Our latency: min %" GST_TIME_FORMAT
2559 ", max %" GST_TIME_FORMAT,
2560 GST_TIME_ARGS (latency), GST_TIME_ARGS (latency));
2563 if (max != GST_CLOCK_TIME_NONE)
2566 GST_DEBUG_OBJECT (self, "Calculated total latency : min %"
2567 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
2568 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
2570 gst_query_set_latency (query, live, min, max);
2572 gst_object_unref (peer);
2579 GstPad *peer = gst_pad_get_peer (self->sinkpad);
2582 res = gst_pad_query (peer, query);
2583 gst_object_unref (peer);
2591 gst_object_unref (self);
2595 static const GstQueryType *
2596 gst_deinterlace_src_query_types (GstPad * pad)
2598 static const GstQueryType types[] = {
2605 static GstFlowReturn
2606 gst_deinterlace_alloc_buffer (GstPad * pad, guint64 offset, guint size,
2607 GstCaps * caps, GstBuffer ** buf)
2609 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2610 GstFlowReturn ret = GST_FLOW_OK;
2614 GST_DEBUG_OBJECT (pad, "alloc with caps %" GST_PTR_FORMAT ", size %u", caps,
2617 if (self->still_frame_mode || self->passthrough) {
2618 ret = gst_pad_alloc_buffer (self->srcpad, offset, size, caps, buf);
2619 } else if (G_LIKELY (!self->request_caps)) {
2620 *buf = gst_buffer_try_new_and_alloc (size);
2621 if (G_UNLIKELY (!*buf)) {
2622 ret = GST_FLOW_ERROR;
2624 gst_buffer_set_caps (*buf, caps);
2625 GST_BUFFER_OFFSET (*buf) = offset;
2630 guint new_frame_size;
2631 GstCaps *new_caps = gst_caps_copy (self->request_caps);
2633 if (self->fields == GST_DEINTERLACE_ALL) {
2635 GstStructure *s = gst_caps_get_structure (new_caps, 0);
2637 gst_structure_get_fraction (s, "framerate", &n, &d);
2639 if (!gst_fraction_double (&n, &d, TRUE)) {
2640 gst_object_unref (self);
2641 gst_caps_unref (new_caps);
2645 gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
2648 if (G_UNLIKELY (!gst_video_format_parse_caps (new_caps, &fmt, &width,
2650 gst_object_unref (self);
2651 gst_caps_unref (new_caps);
2655 new_frame_size = gst_video_format_get_size (fmt, width, height);
2657 *buf = gst_buffer_try_new_and_alloc (new_frame_size);
2658 if (G_UNLIKELY (!*buf)) {
2659 ret = GST_FLOW_ERROR;
2661 gst_buffer_set_caps (*buf, new_caps);
2662 gst_caps_unref (self->request_caps);
2663 self->request_caps = NULL;
2664 gst_caps_unref (new_caps);
2668 gst_object_unref (self);
2674 plugin_init (GstPlugin * plugin)
2676 GST_DEBUG_CATEGORY_INIT (deinterlace_debug, "deinterlace", 0, "Deinterlacer");
2682 if (!gst_element_register (plugin, "deinterlace", GST_RANK_NONE,
2683 GST_TYPE_DEINTERLACE)) {
2690 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
2693 "Deinterlacer", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
2694 GST_PACKAGE_ORIGIN);