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_pad_template (element_class,
454 gst_static_pad_template_get (&src_templ));
455 gst_element_class_add_pad_template (element_class,
456 gst_static_pad_template_get (&sink_templ));
458 gst_element_class_set_details_simple (element_class,
460 "Filter/Effect/Video/Deinterlace",
461 "Deinterlace Methods ported from DScaler/TvTime",
462 "Martin Eikermann <meiker@upb.de>, "
463 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
467 gst_deinterlace_class_init (GstDeinterlaceClass * klass)
469 GObjectClass *gobject_class = (GObjectClass *) klass;
471 GstElementClass *element_class = (GstElementClass *) klass;
473 gobject_class->set_property = gst_deinterlace_set_property;
474 gobject_class->get_property = gst_deinterlace_get_property;
475 gobject_class->finalize = gst_deinterlace_finalize;
478 * GstDeinterlace:mode
480 * This selects whether the deinterlacing methods should
481 * always be applied or if they should only be applied
482 * on content that has the "interlaced" flag on the caps.
485 g_object_class_install_property (gobject_class, PROP_MODE,
486 g_param_spec_enum ("mode",
489 GST_TYPE_DEINTERLACE_MODES,
490 DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
494 * GstDeinterlace:method
496 * Selects the different deinterlacing algorithms that can be used.
497 * These provide different quality and CPU usage.
499 * Some methods provide parameters which can be set by getting
500 * the "method" child via the #GstChildProxy interface and
501 * setting the appropiate properties on it.
507 * Motion Adaptive: Motion Search
513 * Motion Adaptive: Advanced Detection
519 * Motion Adaptive: Simple Detection
531 * Linear interpolation
537 * Linear interpolation in time domain. Any motion causes significant
538 * ghosting, so this method should not be used.
550 * Weave. Bad quality, do not use.
556 * Progressive: Top Field First. Bad quality, do not use.
562 * Progressive: Bottom Field First. Bad quality, do not use.
567 g_object_class_install_property (gobject_class, PROP_METHOD,
568 g_param_spec_enum ("method",
570 "Deinterlace Method",
571 GST_TYPE_DEINTERLACE_METHODS,
572 DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
576 * GstDeinterlace:fields
578 * This selects which fields should be output. If "all" is selected
579 * the output framerate will be double.
582 g_object_class_install_property (gobject_class, PROP_FIELDS,
583 g_param_spec_enum ("fields",
585 "Fields to use for deinterlacing",
586 GST_TYPE_DEINTERLACE_FIELDS,
587 DEFAULT_FIELDS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
591 * GstDeinterlace:layout
593 * This selects which fields is the first in time.
596 g_object_class_install_property (gobject_class, PROP_FIELD_LAYOUT,
597 g_param_spec_enum ("tff",
599 "Deinterlace top field first",
600 GST_TYPE_DEINTERLACE_FIELD_LAYOUT,
601 DEFAULT_FIELD_LAYOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
605 * GstDeinterlace:locking
607 * This selects which approach to pattern locking is used which affects
608 * processing latency and accuracy of timestamp adjustment for telecine
614 g_object_class_install_property (gobject_class, PROP_LOCKING,
615 g_param_spec_enum ("locking", "locking", "Pattern locking mode",
616 GST_TYPE_DEINTERLACE_LOCKING, DEFAULT_LOCKING,
617 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
620 * GstDeinterlace:ignore-obscure
622 * This selects whether to ignore obscure/rare telecine patterns.
623 * NTSC 2:3 pulldown variants are the only really common patterns.
628 g_object_class_install_property (gobject_class, PROP_IGNORE_OBSCURE,
629 g_param_spec_boolean ("ignore-obscure", "ignore-obscure",
630 "Ignore obscure telecine patterns (only consider P, I and 2:3 "
631 "variants).", DEFAULT_IGNORE_OBSCURE,
632 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
635 * GstDeinterlace:drop-orphans
637 * This selects whether to drop orphan fields at the beginning of telecine
638 * patterns in active locking mode.
643 g_object_class_install_property (gobject_class, PROP_DROP_ORPHANS,
644 g_param_spec_boolean ("drop-orphans", "drop-orphans",
645 "Drop orphan fields at the beginning of telecine patterns in "
646 "active locking mode.", DEFAULT_DROP_ORPHANS,
647 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
649 element_class->change_state =
650 GST_DEBUG_FUNCPTR (gst_deinterlace_change_state);
654 gst_deinterlace_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
657 GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
659 g_return_val_if_fail (index == 0, NULL);
661 return gst_object_ref (self->method);
665 gst_deinterlace_child_proxy_get_children_count (GstChildProxy * child_proxy)
667 GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
669 return ((self->method) ? 1 : 0);
673 gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
676 GstChildProxyInterface *iface = g_iface;
678 iface->get_child_by_index = gst_deinterlace_child_proxy_get_child_by_index;
679 iface->get_children_count = gst_deinterlace_child_proxy_get_children_count;
683 gst_deinterlace_init (GstDeinterlace * self, GstDeinterlaceClass * klass)
685 self->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
686 gst_pad_set_chain_function (self->sinkpad,
687 GST_DEBUG_FUNCPTR (gst_deinterlace_chain));
688 gst_pad_set_event_function (self->sinkpad,
689 GST_DEBUG_FUNCPTR (gst_deinterlace_sink_event));
690 gst_pad_set_setcaps_function (self->sinkpad,
691 GST_DEBUG_FUNCPTR (gst_deinterlace_setcaps));
692 gst_pad_set_getcaps_function (self->sinkpad,
693 GST_DEBUG_FUNCPTR (gst_deinterlace_getcaps));
694 gst_pad_set_query_function (self->sinkpad,
695 GST_DEBUG_FUNCPTR (gst_deinterlace_sink_query));
696 gst_pad_set_bufferalloc_function (self->sinkpad,
697 GST_DEBUG_FUNCPTR (gst_deinterlace_alloc_buffer));
698 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
700 self->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
701 gst_pad_set_event_function (self->srcpad,
702 GST_DEBUG_FUNCPTR (gst_deinterlace_src_event));
703 gst_pad_set_query_type_function (self->srcpad,
704 GST_DEBUG_FUNCPTR (gst_deinterlace_src_query_types));
705 gst_pad_set_query_function (self->srcpad,
706 GST_DEBUG_FUNCPTR (gst_deinterlace_src_query));
707 gst_pad_set_getcaps_function (self->srcpad,
708 GST_DEBUG_FUNCPTR (gst_deinterlace_getcaps));
709 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
711 self->mode = DEFAULT_MODE;
712 self->user_set_method_id = DEFAULT_METHOD;
713 gst_deinterlace_set_method (self, self->user_set_method_id);
714 self->fields = DEFAULT_FIELDS;
715 self->field_layout = DEFAULT_FIELD_LAYOUT;
716 self->locking = DEFAULT_LOCKING;
717 self->ignore_obscure = DEFAULT_IGNORE_OBSCURE;
718 self->drop_orphans = DEFAULT_DROP_ORPHANS;
720 self->low_latency = -1;
722 self->pattern_phase = -1;
723 self->pattern_count = 0;
724 self->output_count = 0;
725 self->pattern_base_ts = GST_CLOCK_TIME_NONE;
726 self->pattern_buf_dur = GST_CLOCK_TIME_NONE;
727 self->still_frame_mode = FALSE;
729 gst_deinterlace_reset (self);
733 gst_deinterlace_reset_history (GstDeinterlace * self, gboolean drop_all)
738 GST_DEBUG_OBJECT (self, "Flushing history (count %d)", self->history_count);
739 while (self->history_count > 0) {
740 if (gst_deinterlace_output_frame (self, TRUE) != GST_FLOW_OK) {
741 /* Encountered error, or flushing -> skip and drop all remaining */
748 GST_DEBUG_OBJECT (self, "Resetting history (count %d)",
749 self->history_count);
751 for (i = 0; i < self->history_count; i++) {
752 if (self->field_history[i].buf) {
753 gst_buffer_unref (self->field_history[i].buf);
754 self->field_history[i].buf = NULL;
758 memset (self->field_history, 0,
759 GST_DEINTERLACE_MAX_FIELD_HISTORY * sizeof (GstDeinterlaceField));
760 self->history_count = 0;
761 memset (self->buf_states, 0,
762 GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY *
763 sizeof (GstDeinterlaceBufferState));
764 self->state_count = 0;
765 self->pattern_lock = FALSE;
766 self->pattern_refresh = TRUE;
767 self->cur_field_idx = -1;
769 if (!self->still_frame_mode && self->last_buffer) {
770 gst_buffer_unref (self->last_buffer);
771 self->last_buffer = NULL;
776 gst_deinterlace_update_passthrough (GstDeinterlace * self)
778 self->passthrough = (self->mode == GST_DEINTERLACE_MODE_DISABLED
779 || (!self->interlaced && self->mode != GST_DEINTERLACE_MODE_INTERLACED));
780 GST_DEBUG_OBJECT (self, "Passthrough: %d", self->passthrough);
784 gst_deinterlace_reset (GstDeinterlace * self)
786 GST_DEBUG_OBJECT (self, "Resetting internal state");
788 self->format = GST_VIDEO_FORMAT_UNKNOWN;
791 self->frame_size = 0;
792 self->fps_n = self->fps_d = 0;
793 self->passthrough = FALSE;
795 self->reconfigure = FALSE;
796 if (self->new_mode != -1)
797 self->mode = self->new_mode;
798 if (self->new_fields != -1)
799 self->fields = self->new_fields;
801 self->new_fields = -1;
803 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
805 if (self->request_caps)
806 gst_caps_unref (self->request_caps);
807 self->request_caps = NULL;
809 gst_deinterlace_reset_history (self, TRUE);
811 gst_deinterlace_reset_qos (self);
813 self->need_more = FALSE;
814 self->have_eos = FALSE;
818 gst_deinterlace_set_property (GObject * object, guint prop_id,
819 const GValue * value, GParamSpec * pspec)
821 GstDeinterlace *self;
823 g_return_if_fail (GST_IS_DEINTERLACE (object));
824 self = GST_DEINTERLACE (object);
830 GST_OBJECT_LOCK (self);
831 new_mode = g_value_get_enum (value);
832 if (self->mode != new_mode && GST_PAD_CAPS (self->srcpad)) {
833 self->reconfigure = TRUE;
834 self->new_mode = new_mode;
836 self->mode = new_mode;
837 gst_deinterlace_update_passthrough (self);
839 GST_OBJECT_UNLOCK (self);
843 self->user_set_method_id = g_value_get_enum (value);
844 gst_deinterlace_set_method (self, self->user_set_method_id);
849 GST_OBJECT_LOCK (self);
850 new_fields = g_value_get_enum (value);
851 if (self->fields != new_fields && GST_PAD_CAPS (self->srcpad)) {
852 self->reconfigure = TRUE;
853 self->new_fields = new_fields;
855 self->fields = new_fields;
857 GST_OBJECT_UNLOCK (self);
860 case PROP_FIELD_LAYOUT:
861 self->field_layout = g_value_get_enum (value);
864 self->locking = g_value_get_enum (value);
866 case PROP_IGNORE_OBSCURE:
867 self->ignore_obscure = g_value_get_boolean (value);
869 case PROP_DROP_ORPHANS:
870 self->drop_orphans = g_value_get_boolean (value);
873 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
879 gst_deinterlace_get_property (GObject * object, guint prop_id,
880 GValue * value, GParamSpec * pspec)
882 GstDeinterlace *self;
884 g_return_if_fail (GST_IS_DEINTERLACE (object));
885 self = GST_DEINTERLACE (object);
889 g_value_set_enum (value, self->mode);
892 g_value_set_enum (value, self->user_set_method_id);
895 g_value_set_enum (value, self->fields);
897 case PROP_FIELD_LAYOUT:
898 g_value_set_enum (value, self->field_layout);
901 g_value_set_enum (value, self->locking);
903 case PROP_IGNORE_OBSCURE:
904 g_value_set_boolean (value, self->ignore_obscure);
906 case PROP_DROP_ORPHANS:
907 g_value_set_boolean (value, self->drop_orphans);
910 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
915 gst_deinterlace_finalize (GObject * object)
917 GstDeinterlace *self = GST_DEINTERLACE (object);
919 gst_deinterlace_reset (self);
922 gst_object_unparent (GST_OBJECT (self->method));
926 G_OBJECT_CLASS (parent_class)->finalize (object);
930 gst_deinterlace_update_pattern_timestamps (GstDeinterlace * self)
933 if (self->low_latency) {
934 /* in low-latency mode the buffer state history contains old buffer
935 * states as well as the current one and perhaps some future ones.
936 * the current buffer's state is given by the number of field pairs
937 * rounded up, minus 1. the below is equivalent */
938 state_idx = (self->history_count - 1) >> 1;
940 /* in high-latency mode state_count - 1 is the current buffer's state */
941 state_idx = self->state_count - 1;
944 self->pattern_base_ts = self->buf_states[state_idx].timestamp;
945 self->pattern_buf_dur =
946 (self->buf_states[state_idx].duration *
947 telecine_patterns[self->pattern].ratio_d) /
948 telecine_patterns[self->pattern].ratio_n;
949 GST_DEBUG_OBJECT (self,
950 "Starting a new pattern repeat with base ts %" GST_TIME_FORMAT
951 " and dur %" GST_TIME_FORMAT, GST_TIME_ARGS (self->pattern_base_ts),
952 GST_TIME_ARGS (self->pattern_buf_dur));
956 gst_deinterlace_pop_history (GstDeinterlace * self)
960 g_return_val_if_fail (self->history_count > 0, NULL);
962 GST_DEBUG_OBJECT (self, "Pop last history buffer -- current history size %d",
963 self->history_count);
965 buffer = self->field_history[self->history_count - 1].buf;
967 self->history_count--;
968 if (self->locking != GST_DEINTERLACE_LOCKING_NONE && (!self->history_count
969 || GST_BUFFER_DATA (buffer) !=
970 GST_BUFFER_DATA (self->field_history[self->history_count - 1].buf))) {
971 if (!self->low_latency)
973 if (self->pattern_lock) {
974 self->pattern_count++;
975 if (self->pattern != -1
976 && self->pattern_count >= telecine_patterns[self->pattern].length) {
977 self->pattern_count = 0;
978 self->output_count = 0;
979 gst_deinterlace_update_pattern_timestamps (self);
984 GST_DEBUG_OBJECT (self, "Returning buffer: %p %" GST_TIME_FORMAT
985 " with duration %" GST_TIME_FORMAT " and size %u", buffer,
986 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
987 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer));
994 GST_DEINTERLACE_PROGRESSIVE,
995 GST_DEINTERLACE_INTERLACED,
996 GST_DEINTERLACE_TELECINE,
997 } GstDeinterlaceInterlacingMethod;
999 static GstDeinterlaceInterlacingMethod
1000 gst_deinterlace_get_interlacing_method (const GstCaps * caps)
1002 GstDeinterlaceInterlacingMethod method = 0;
1003 gboolean interlaced;
1005 /* check interlaced cap, defaulting to FALSE */
1006 if (!gst_structure_get_boolean (gst_caps_get_structure (caps, 0),
1007 "interlaced", &interlaced))
1011 interlaced ? GST_DEINTERLACE_INTERLACED : GST_DEINTERLACE_PROGRESSIVE;
1013 if (method == GST_DEINTERLACE_INTERLACED) {
1015 gst_structure_get_string (gst_caps_get_structure (caps, 0),
1016 "interlacing-method");
1017 if (temp && g_str_equal (temp, "telecine"))
1018 method = GST_DEINTERLACE_TELECINE;
1025 gst_deinterlace_get_buffer_state (GstDeinterlace * self, GstBuffer * buffer,
1026 guint8 * state, GstDeinterlaceInterlacingMethod * i_method)
1028 GstDeinterlaceInterlacingMethod interlacing_method;
1030 if (!(i_method || state))
1033 interlacing_method =
1034 gst_deinterlace_get_interlacing_method (GST_BUFFER_CAPS (buffer));
1037 if (interlacing_method == GST_DEINTERLACE_TELECINE) {
1038 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_RFF)) {
1039 *state = GST_DEINTERLACE_BUFFER_STATE_DROP;
1040 } else if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_ONEFIELD)) {
1041 /* tc top if tff, tc bottom otherwise */
1042 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_TFF)) {
1043 *state = GST_DEINTERLACE_BUFFER_STATE_TC_T;
1045 *state = GST_DEINTERLACE_BUFFER_STATE_TC_B;
1047 } else if (GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_PROGRESSIVE)) {
1048 *state = GST_DEINTERLACE_BUFFER_STATE_TC_P;
1050 *state = GST_DEINTERLACE_BUFFER_STATE_TC_M;
1053 if (interlacing_method == GST_DEINTERLACE_INTERLACED) {
1054 *state = GST_DEINTERLACE_BUFFER_STATE_I;
1056 *state = GST_DEINTERLACE_BUFFER_STATE_P;
1062 *i_method = interlacing_method;
1066 gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer)
1069 GstClockTime timestamp;
1070 GstDeinterlaceFieldLayout field_layout = self->field_layout;
1071 gboolean repeated = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_RFF);
1072 gboolean tff = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_TFF);
1074 GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_ONEFIELD);
1075 GstBuffer *field1, *field2;
1076 guint fields_to_push = (onefield) ? 1 : (!repeated) ? 2 : 3;
1077 gint field1_flags, field2_flags;
1078 GstDeinterlaceInterlacingMethod interlacing_method;
1081 g_return_if_fail (self->history_count <
1082 GST_DEINTERLACE_MAX_FIELD_HISTORY - fields_to_push);
1084 gst_deinterlace_get_buffer_state (self, buffer, &buf_state,
1085 &interlacing_method);
1087 GST_DEBUG_OBJECT (self,
1088 "Pushing new buffer to the history: ptr %p at %" GST_TIME_FORMAT
1089 " with duration %" GST_TIME_FORMAT
1090 ", size %u, state %u, interlacing method %s", GST_BUFFER_DATA (buffer),
1091 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
1092 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer),
1094 interlacing_method ==
1095 GST_DEINTERLACE_TELECINE ? "TC" : interlacing_method ==
1096 GST_DEINTERLACE_INTERLACED ? "I" : "P");
1098 /* move up for new state */
1099 memmove (&self->buf_states[1], &self->buf_states[0],
1100 (GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY - 1) *
1101 sizeof (GstDeinterlaceBufferState));
1102 self->buf_states[0].state = buf_state;
1103 self->buf_states[0].timestamp = GST_BUFFER_TIMESTAMP (buffer);
1104 self->buf_states[0].duration = GST_BUFFER_DURATION (buffer);
1105 if (self->state_count < GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY)
1106 self->state_count++;
1108 if (buf_state == GST_DEINTERLACE_BUFFER_STATE_DROP) {
1109 GST_DEBUG_OBJECT (self,
1110 "Buffer contains only unneeded repeated fields, dropping and not"
1111 "adding to field history");
1112 gst_buffer_unref (buffer);
1116 /* telecine does not make use of repeated fields */
1117 if (interlacing_method == GST_DEINTERLACE_TELECINE)
1120 for (i = GST_DEINTERLACE_MAX_FIELD_HISTORY - 1; i >= fields_to_push; i--) {
1121 self->field_history[i].buf = self->field_history[i - fields_to_push].buf;
1122 self->field_history[i].flags =
1123 self->field_history[i - fields_to_push].flags;
1126 if (field_layout == GST_DEINTERLACE_LAYOUT_AUTO) {
1127 if (!self->interlaced) {
1128 GST_WARNING_OBJECT (self, "Can't detect field layout -- assuming TFF");
1129 field_layout = GST_DEINTERLACE_LAYOUT_TFF;
1131 field_layout = GST_DEINTERLACE_LAYOUT_TFF;
1133 field_layout = GST_DEINTERLACE_LAYOUT_BFF;
1137 if (field_layout == GST_DEINTERLACE_LAYOUT_TFF) {
1138 GST_DEBUG_OBJECT (self, "Top field first");
1139 field1 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
1140 field1_flags = PICTURE_INTERLACED_TOP;
1141 field2 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
1142 field2_flags = PICTURE_INTERLACED_BOTTOM;
1144 GST_DEBUG_OBJECT (self, "Bottom field first");
1145 field1 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
1146 field1_flags = PICTURE_INTERLACED_BOTTOM;
1147 field2 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
1148 field2_flags = PICTURE_INTERLACED_TOP;
1151 if (interlacing_method != GST_DEINTERLACE_TELECINE) {
1152 /* Timestamps are assigned to the field buffers under the assumption that
1153 the timestamp of the buffer equals the first fields timestamp */
1155 timestamp = GST_BUFFER_TIMESTAMP (buffer);
1156 GST_BUFFER_TIMESTAMP (field1) = timestamp;
1157 GST_BUFFER_TIMESTAMP (field2) = timestamp + self->field_duration;
1159 GST_BUFFER_TIMESTAMP (field2) += self->field_duration;
1163 self->field_history[2].buf = field1;
1164 self->field_history[2].flags = field1_flags;
1166 self->field_history[1].buf = field2;
1167 self->field_history[1].flags = field2_flags;
1169 self->field_history[0].buf =
1170 gst_buffer_make_metadata_writable (gst_buffer_ref (field1));
1171 GST_BUFFER_TIMESTAMP (self->field_history[0].buf) +=
1172 2 * self->field_duration;
1173 self->field_history[0].flags = field1_flags;
1174 } else if (!onefield) {
1175 self->field_history[1].buf = field1;
1176 self->field_history[1].flags = field1_flags;
1178 self->field_history[0].buf = field2;
1179 self->field_history[0].flags = field2_flags;
1180 } else { /* onefield */
1181 self->field_history[0].buf = field1;
1182 self->field_history[0].flags = field1_flags;
1183 gst_buffer_unref (field2);
1186 self->history_count += fields_to_push;
1187 self->cur_field_idx += fields_to_push;
1189 GST_DEBUG_OBJECT (self, "Pushed buffer -- current history size %d, index %d",
1190 self->history_count, self->cur_field_idx);
1192 if (self->last_buffer)
1193 gst_buffer_unref (self->last_buffer);
1194 self->last_buffer = buffer;
1198 gst_deinterlace_update_qos (GstDeinterlace * self, gdouble proportion,
1199 GstClockTimeDiff diff, GstClockTime timestamp)
1201 GST_DEBUG_OBJECT (self,
1202 "Updating QoS: proportion %lf, diff %s%" GST_TIME_FORMAT ", timestamp %"
1203 GST_TIME_FORMAT, proportion, (diff < 0) ? "-" : "",
1204 GST_TIME_ARGS (ABS (diff)), GST_TIME_ARGS (timestamp));
1206 GST_OBJECT_LOCK (self);
1207 self->proportion = proportion;
1208 if (G_LIKELY (timestamp != GST_CLOCK_TIME_NONE)) {
1209 if (G_UNLIKELY (diff > 0))
1210 self->earliest_time =
1211 timestamp + 2 * diff + ((self->fields ==
1212 GST_DEINTERLACE_ALL) ? self->field_duration : 2 *
1213 self->field_duration);
1215 self->earliest_time = timestamp + diff;
1217 self->earliest_time = GST_CLOCK_TIME_NONE;
1219 GST_OBJECT_UNLOCK (self);
1223 gst_deinterlace_reset_qos (GstDeinterlace * self)
1225 gst_deinterlace_update_qos (self, 0.5, 0, GST_CLOCK_TIME_NONE);
1229 gst_deinterlace_read_qos (GstDeinterlace * self, gdouble * proportion,
1230 GstClockTime * time)
1232 GST_OBJECT_LOCK (self);
1233 *proportion = self->proportion;
1234 *time = self->earliest_time;
1235 GST_OBJECT_UNLOCK (self);
1238 /* Perform qos calculations before processing the next frame. Returns TRUE if
1239 * the frame should be processed, FALSE if the frame can be dropped entirely */
1241 gst_deinterlace_do_qos (GstDeinterlace * self, GstClockTime timestamp)
1243 GstClockTime qostime, earliest_time;
1246 /* no timestamp, can't do QoS => process frame */
1247 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) {
1248 GST_LOG_OBJECT (self, "invalid timestamp, can't do QoS, process frame");
1252 /* get latest QoS observation values */
1253 gst_deinterlace_read_qos (self, &proportion, &earliest_time);
1255 /* skip qos if we have no observation (yet) => process frame */
1256 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) {
1257 GST_LOG_OBJECT (self, "no observation yet, process frame");
1261 /* qos is done on running time */
1262 qostime = gst_segment_to_running_time (&self->segment, GST_FORMAT_TIME,
1265 /* see how our next timestamp relates to the latest qos timestamp */
1266 GST_LOG_OBJECT (self, "qostime %" GST_TIME_FORMAT ", earliest %"
1267 GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
1269 if (qostime != GST_CLOCK_TIME_NONE && qostime <= earliest_time) {
1270 GST_DEBUG_OBJECT (self, "we are late, drop frame");
1274 GST_LOG_OBJECT (self, "process frame");
1279 gst_deinterlace_fix_timestamps (GstDeinterlace * self,
1280 GstDeinterlaceField * field1, GstDeinterlaceField * field2)
1282 GstDeinterlaceField *field3, *field4;
1283 GstDeinterlaceInterlacingMethod interlacing_method;
1285 if (self->pattern_lock && self->pattern > -1) {
1286 /* accurate pattern-locked timestamp adjustment */
1287 if (!self->pattern_count)
1288 gst_deinterlace_update_pattern_timestamps (self);
1290 GST_BUFFER_TIMESTAMP (field1->buf) =
1291 self->pattern_base_ts + self->output_count * self->pattern_buf_dur;
1292 GST_BUFFER_DURATION (field1->buf) = self->pattern_buf_dur;
1293 self->output_count++;
1295 /* naive (but low-latency) timestamp adjustment based on subsequent
1298 && GST_BUFFER_DATA (field1->buf) != GST_BUFFER_DATA (field2->buf)) {
1299 if (GST_BUFFER_TIMESTAMP (field1->buf) +
1300 GST_BUFFER_DURATION (field1->buf) ==
1301 GST_BUFFER_TIMESTAMP (field2->buf)) {
1302 GST_BUFFER_TIMESTAMP (field1->buf) =
1303 GST_BUFFER_TIMESTAMP (field2->buf) =
1304 (GST_BUFFER_TIMESTAMP (field1->buf) +
1305 GST_BUFFER_TIMESTAMP (field2->buf)) / 2;
1307 GST_BUFFER_TIMESTAMP (field2->buf) = GST_BUFFER_TIMESTAMP (field1->buf);
1311 if (self->history_count < 3) {
1312 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need 3)",
1313 self->history_count);
1317 field3 = &self->field_history[self->history_count - 3];
1318 interlacing_method =
1319 gst_deinterlace_get_interlacing_method (GST_BUFFER_CAPS (field3->buf));
1320 if (interlacing_method == GST_DEINTERLACE_TELECINE) {
1321 if (self->history_count < 4) {
1322 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need 4)",
1323 self->history_count);
1327 field4 = &self->field_history[self->history_count - 4];
1328 if (GST_BUFFER_DATA (field3->buf) != GST_BUFFER_DATA (field4->buf)) {
1329 /* telecine fields in separate buffers */
1330 GST_BUFFER_TIMESTAMP (field3->buf) =
1331 (GST_BUFFER_TIMESTAMP (field3->buf) +
1332 GST_BUFFER_TIMESTAMP (field4->buf)) / 2;
1336 GST_BUFFER_DURATION (field1->buf) =
1337 GST_BUFFER_TIMESTAMP (field3->buf) - GST_BUFFER_TIMESTAMP (field1->buf);
1340 GST_DEBUG_OBJECT (self,
1341 "Field 1 adjusted to ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT,
1342 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1->buf)),
1343 GST_TIME_ARGS (GST_BUFFER_DURATION (field1->buf)));
1348 gst_deinterlace_get_pattern_lock (GstDeinterlace * self, gboolean * flush_one)
1350 /* loop over all possible patterns and all possible phases
1351 * giving each a score. the highest score gets the lock */
1352 /* the score is calculated as the number of matched buffers in the
1353 * sequence starting at the phase offset with those from the history
1354 * then the longest duration pattern match is taken. if there is more than
1355 * one pattern matching all buffers, we take the longest pattern of those.
1356 * matches to complete patterns are preferred. if no non-trivial pattern is
1357 * matched, trivial patterns are tested. */
1358 gint i, j, k, score, pattern, phase;
1359 const gint state_count = self->state_count;
1360 const gint n_required = self->ignore_obscure ?
1361 GST_DEINTERLACE_OBSCURE_THRESHOLD :
1362 GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY;
1364 /* set unknown pattern as this is used in logic outside this function */
1367 /* wait for more buffers */
1368 if (!self->have_eos && state_count < n_required) {
1369 GST_DEBUG_OBJECT (self, "Need more buffers in state history - %d/%d",
1370 state_count, n_required);
1374 score = pattern = phase = -1;
1376 /* loop over all patterns */
1377 for (i = 0; i < G_N_ELEMENTS (telecine_patterns); i++) {
1378 const guint8 length = telecine_patterns[i].length;
1380 if (self->ignore_obscure && i >= GST_DEINTERLACE_OBSCURE_THRESHOLD)
1383 if (state_count < length)
1386 /* loop over all phases */
1387 for (j = 0; j < length; j++) {
1388 /* low-latency mode looks at past buffers, high latency at future buffers */
1389 const gint state_idx = (self->low_latency ? length : state_count) - 1;
1390 /* loop over history, breaking on differing buffer states */
1391 for (k = 0; k < length && k < state_count; k++) {
1392 const guint8 hist = self->buf_states[state_idx - k].state;
1393 const guint8 patt = telecine_patterns[i].states[(j + k) % length];
1398 /* make complete matches more signficant */
1400 k += GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY;
1402 /* take as new best pattern if the number of matched buffers is more than
1403 * for other patterns */
1408 if (self->low_latency) {
1409 /* state_idx + 1 is the number of buffers yet to be pushed out
1410 * so length - state_idx - 1 is the number of old buffers in the
1412 phase = (phase + length - state_idx - 1) % length;
1418 GST_DEBUG_OBJECT (self,
1419 "Final pattern match result: pa %d, ph %d, l %d, s %d", pattern, phase,
1420 telecine_patterns[pattern].length, score);
1421 self->pattern = pattern;
1422 self->pattern_phase = phase;
1423 self->pattern_count = 0;
1424 self->output_count = 0;
1425 self->pattern_lock = TRUE;
1427 /* check for the case that the first field of the pattern is an orphan */
1429 && telecine_patterns[pattern].states[phase] & (GST_ONE | GST_INT)) {
1430 gint i = phase, field_count = 0;
1431 guint8 state = telecine_patterns[pattern].states[i];
1434 if (state & GST_ONE) {
1436 } else if (!(state & GST_DRP)) {
1440 i %= telecine_patterns[pattern].length;
1441 state = telecine_patterns[pattern].states[i];
1442 } while (!(state & GST_PRG));
1444 /* if field_count is odd, we have an orphan field at the beginning of the
1446 * note - don't do this in low-latency mode as we are somewhere within the
1447 * pattern already */
1448 if (!self->low_latency && (*flush_one = field_count & 1)) {
1449 GST_DEBUG_OBJECT (self, "Orphan field detected at the beginning of the "
1450 "pattern - it will be deinterlaced.");
1455 static GstFlowReturn
1456 gst_deinterlace_output_frame (GstDeinterlace * self, gboolean flushing)
1458 GstClockTime timestamp;
1460 gint fields_required;
1461 GstBuffer *buf, *outbuf;
1462 GstDeinterlaceField *field1, *field2;
1463 GstDeinterlaceInterlacingMethod interlacing_method;
1465 gboolean hl_no_lock; /* indicates high latency timestamp adjustment but no pattern lock (could be ONEF or I) */
1466 gboolean same_buffer; /* are field1 and field2 in the same buffer? */
1467 gboolean flush_one; /* used for flushing one field when in high latency mode and not locked */
1468 TelecinePattern pattern;
1469 guint8 phase, count;
1470 const GstDeinterlaceLocking locking = self->locking;
1474 fields_required = 0;
1476 same_buffer = FALSE;
1478 self->need_more = FALSE;
1479 phase = self->pattern_phase;
1480 count = self->pattern_count;
1482 if (!self->history_count) {
1483 GST_DEBUG_OBJECT (self, "History is empty, waiting for more buffers!");
1487 field1 = &self->field_history[self->history_count - 1];
1489 if (locking != GST_DEINTERLACE_LOCKING_NONE) {
1490 if (!self->state_count) {
1491 GST_ERROR_OBJECT (self,
1492 "BROKEN! Fields in history + no states should not happen!");
1493 return GST_FLOW_ERROR;
1496 gst_deinterlace_get_buffer_state (self, field1->buf, &buf_state,
1497 &interlacing_method);
1499 if (self->pattern != -1)
1500 pattern = telecine_patterns[self->pattern];
1502 /* patterns 0 and 1 are interlaced, the rest are telecine */
1503 if (self->pattern > 1)
1504 interlacing_method = GST_DEINTERLACE_TELECINE;
1506 if (self->pattern == -1 || self->pattern_refresh
1507 || !(buf_state & pattern.states[(phase + count) % pattern.length])) {
1508 /* no pattern, pattern refresh set or unexpected buffer state */
1509 self->pattern_lock = FALSE;
1510 self->pattern_refresh = TRUE;
1512 /* refresh pattern lock */
1513 gst_deinterlace_get_pattern_lock (self, &flush_one);
1515 if (self->pattern != -1) {
1516 /* locked onto a valid pattern so refresh complete */
1517 GST_DEBUG_OBJECT (self, "Pattern locked! %s starting at %d",
1518 telecine_patterns[self->pattern].nick, self->pattern_phase);
1519 self->pattern_refresh = FALSE;
1520 } else if (!self->low_latency) {
1521 if (!self->pattern_lock) {
1528 /* setcaps on sink and src pads */
1529 gst_deinterlace_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad));
1531 if (flush_one && self->drop_orphans) {
1532 GST_DEBUG_OBJECT (self, "Dropping orphan first field");
1533 self->cur_field_idx--;
1534 gst_buffer_unref (gst_deinterlace_pop_history (self));
1539 gst_deinterlace_get_buffer_state (self, field1->buf, NULL,
1540 &interlacing_method);
1543 same_buffer = self->history_count >= 2
1544 && (GST_BUFFER_DATA (field1->buf) ==
1545 GST_BUFFER_DATA (self->field_history[self->history_count - 2].buf));
1547 if ((flushing && self->history_count == 1) || (flush_one
1548 && !self->drop_orphans) || (hl_no_lock && (self->history_count == 1
1549 || !same_buffer))) {
1550 GST_DEBUG_OBJECT (self, "Flushing one field using linear method");
1551 gst_deinterlace_set_method (self, GST_DEINTERLACE_LINEAR);
1552 fields_required = gst_deinterlace_method_get_fields_required (self->method);
1553 } else if (interlacing_method == GST_DEINTERLACE_TELECINE
1554 && (self->low_latency > 0 || self->pattern != -1 || (hl_no_lock
1556 && GST_BUFFER_FLAG_IS_SET (field1->buf,
1557 GST_VIDEO_BUFFER_PROGRESSIVE)))) {
1558 /* telecined - we reconstruct frames by weaving pairs of fields */
1559 fields_required = 2;
1560 if (!flushing && self->history_count < fields_required) {
1561 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
1562 self->history_count, self->cur_field_idx + fields_required);
1566 field2 = &self->field_history[self->history_count - 2];
1567 if (!gst_deinterlace_fix_timestamps (self, field1, field2) && !flushing)
1571 /* telecine progressive */
1572 GstBuffer *field1_buf;
1574 GST_DEBUG_OBJECT (self,
1575 "Frame type: Telecine Progressive; pushing buffer as a frame");
1577 self->cur_field_idx--;
1578 field1_buf = gst_deinterlace_pop_history (self);
1579 /* field2 is the same buffer as field1, but we need to remove it from
1580 * the history anyway */
1581 self->cur_field_idx--;
1582 gst_buffer_unref (gst_deinterlace_pop_history (self));
1583 /* set the caps from the src pad on the buffer as they should be correct */
1584 gst_buffer_set_caps (field1_buf, GST_PAD_CAPS (self->srcpad));
1585 GST_DEBUG_OBJECT (self,
1586 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1587 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf)),
1588 GST_TIME_ARGS (GST_BUFFER_DURATION (field1_buf)),
1589 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf) +
1590 GST_BUFFER_DURATION (field1_buf)));
1591 return gst_pad_push (self->srcpad, field1_buf);
1593 /* telecine fields in separate buffers */
1595 /* check field1 and field2 buffer caps and flags are corresponding */
1596 if (field1->flags == field2->flags) {
1597 /* ERROR - fields are of same parity - what should be done here?
1598 * perhaps deinterlace the tip field and start again? */
1599 GST_ERROR_OBJECT (self, "Telecine mixed with fields of same parity!");
1601 GST_DEBUG_OBJECT (self,
1602 "Frame type: Telecine Mixed; weaving tip two fields into a frame");
1603 /* set method to WEAVE */
1604 gst_deinterlace_set_method (self, GST_DEINTERLACE_WEAVE);
1606 } else if (interlacing_method == GST_DEINTERLACE_INTERLACED || (hl_no_lock
1607 && interlacing_method == GST_DEINTERLACE_TELECINE && same_buffer
1608 && !GST_BUFFER_FLAG_IS_SET (field1->buf,
1609 GST_VIDEO_BUFFER_PROGRESSIVE))) {
1610 gst_deinterlace_set_method (self, self->user_set_method_id);
1611 fields_required = gst_deinterlace_method_get_fields_required (self->method);
1612 if (flushing && self->history_count < fields_required) {
1613 /* note: we already checked for flushing with history count == 1 above
1614 * so we must have 2 or more fields in here */
1615 gst_deinterlace_set_method (self, GST_DEINTERLACE_VFIR);
1617 gst_deinterlace_method_get_fields_required (self->method);
1618 GST_DEBUG_OBJECT (self, "Flushing field(s) using %s method",
1619 methods_types[self->method_id].value_nick);
1622 /* Not enough fields in the history */
1623 if (!flushing && self->history_count < fields_required) {
1624 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
1625 self->history_count, self->cur_field_idx + fields_required);
1629 GST_DEBUG_OBJECT (self,
1630 "Frame type: Interlaced; deinterlacing using %s method",
1631 methods_types[self->method_id].value_nick);
1633 GstBuffer *field1_buf;
1636 fields_required = 2;
1638 /* Not enough fields in the history */
1639 if (!flushing && self->history_count < fields_required) {
1640 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
1641 self->history_count, self->cur_field_idx + fields_required);
1645 field2 = &self->field_history[self->history_count - 2];
1646 if (GST_BUFFER_DATA (field1->buf) != GST_BUFFER_DATA (field2->buf)) {
1647 /* ERROR - next two fields in field history are not one progressive buffer - weave? */
1648 GST_ERROR_OBJECT (self,
1649 "Progressive buffer but two fields at tip aren't in the same buffer!");
1652 GST_DEBUG_OBJECT (self,
1653 "Frame type: Progressive; pushing buffer as a frame");
1655 self->cur_field_idx--;
1656 field1_buf = gst_deinterlace_pop_history (self);
1657 /* field2 is the same buffer as field1, but we need to remove it from the
1659 self->cur_field_idx--;
1660 gst_buffer_unref (gst_deinterlace_pop_history (self));
1661 GST_DEBUG_OBJECT (self,
1662 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1663 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf)),
1664 GST_TIME_ARGS (GST_BUFFER_DURATION (field1_buf)),
1665 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buf) +
1666 GST_BUFFER_DURATION (field1_buf)));
1667 return gst_pad_push (self->srcpad, field1_buf);
1670 if (!flushing && self->cur_field_idx < 1) {
1674 if (self->fields == GST_DEINTERLACE_ALL
1675 || interlacing_method == GST_DEINTERLACE_TELECINE)
1676 GST_DEBUG_OBJECT (self, "All fields");
1677 else if (self->fields == GST_DEINTERLACE_TF)
1678 GST_DEBUG_OBJECT (self, "Top fields");
1679 else if (self->fields == GST_DEINTERLACE_BF)
1680 GST_DEBUG_OBJECT (self, "Bottom fields");
1682 if ((self->field_history[self->cur_field_idx].flags == PICTURE_INTERLACED_TOP
1683 && (self->fields == GST_DEINTERLACE_TF
1684 || interlacing_method == GST_DEINTERLACE_TELECINE))
1685 || self->fields == GST_DEINTERLACE_ALL) {
1686 GST_DEBUG_OBJECT (self, "deinterlacing top field");
1688 /* create new buffer */
1690 gst_pad_alloc_buffer (self->srcpad, GST_BUFFER_OFFSET_NONE,
1691 self->frame_size, GST_PAD_CAPS (self->srcpad), &outbuf);
1692 if (ret != GST_FLOW_OK)
1695 if (GST_PAD_CAPS (self->srcpad) != GST_BUFFER_CAPS (outbuf) &&
1696 !gst_caps_is_equal (GST_PAD_CAPS (self->srcpad),
1697 GST_BUFFER_CAPS (outbuf))) {
1698 gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf));
1699 GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT,
1700 self->request_caps);
1702 gst_buffer_unref (outbuf);
1703 outbuf = gst_buffer_try_new_and_alloc (self->frame_size);
1706 return GST_FLOW_ERROR;
1708 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
1711 g_return_val_if_fail (self->history_count >=
1712 1 + gst_deinterlace_method_get_latency (self->method), GST_FLOW_ERROR);
1715 self->field_history[self->history_count - 1 -
1716 gst_deinterlace_method_get_latency (self->method)].buf;
1718 if (interlacing_method != GST_DEINTERLACE_TELECINE) {
1719 timestamp = GST_BUFFER_TIMESTAMP (buf);
1721 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1722 if (self->fields == GST_DEINTERLACE_ALL)
1723 GST_BUFFER_DURATION (outbuf) = self->field_duration;
1725 GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
1727 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1728 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1731 /* Check if we need to drop the frame because of QoS */
1732 if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
1733 self->cur_field_idx--;
1734 gst_buffer_unref (gst_deinterlace_pop_history (self));
1735 gst_buffer_unref (outbuf);
1739 if (self->cur_field_idx < 0 && flushing) {
1740 if (self->history_count == 1) {
1741 gst_buffer_unref (gst_deinterlace_pop_history (self));
1744 self->cur_field_idx++;
1746 if (self->cur_field_idx < 0) {
1749 if (!flushing && self->cur_field_idx < 1) {
1753 /* do magic calculus */
1754 gst_deinterlace_method_deinterlace_frame (self->method,
1755 self->field_history, self->history_count, outbuf,
1756 self->cur_field_idx);
1758 self->cur_field_idx--;
1759 if (self->cur_field_idx + 1 +
1760 gst_deinterlace_method_get_latency (self->method)
1761 < self->history_count || flushing) {
1762 gst_buffer_unref (gst_deinterlace_pop_history (self));
1765 if (gst_deinterlace_clip_buffer (self, outbuf)) {
1766 GST_DEBUG_OBJECT (self,
1767 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1768 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1769 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
1770 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
1771 GST_BUFFER_DURATION (outbuf)));
1772 ret = gst_pad_push (self->srcpad, outbuf);
1775 gst_buffer_unref (outbuf);
1779 if (ret != GST_FLOW_OK)
1781 if (interlacing_method == GST_DEINTERLACE_TELECINE
1782 && self->method_id == GST_DEINTERLACE_WEAVE) {
1783 /* pop off the second field */
1784 GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
1785 self->history_count);
1786 self->cur_field_idx--;
1787 gst_buffer_unref (gst_deinterlace_pop_history (self));
1788 interlacing_method = GST_DEINTERLACE_INTERLACED;
1793 if (flush_one && !self->drop_orphans) {
1794 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1798 /* no calculation done: remove excess field */
1799 else if (self->field_history[self->cur_field_idx].flags ==
1800 PICTURE_INTERLACED_TOP && (self->fields == GST_DEINTERLACE_BF
1801 && interlacing_method != GST_DEINTERLACE_TELECINE)) {
1802 GST_DEBUG_OBJECT (self, "Removing unused top field");
1803 self->cur_field_idx--;
1804 gst_buffer_unref (gst_deinterlace_pop_history (self));
1806 if (flush_one && !self->drop_orphans) {
1807 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1812 if (self->history_count < fields_required)
1815 if (self->cur_field_idx < 0)
1818 if (!flushing && self->cur_field_idx < 1) {
1822 /* deinterlace bottom_field */
1823 if ((self->field_history[self->cur_field_idx].flags ==
1824 PICTURE_INTERLACED_BOTTOM && (self->fields == GST_DEINTERLACE_BF
1825 || interlacing_method == GST_DEINTERLACE_TELECINE))
1826 || self->fields == GST_DEINTERLACE_ALL) {
1827 GST_DEBUG_OBJECT (self, "deinterlacing bottom field");
1829 /* create new buffer */
1831 gst_pad_alloc_buffer (self->srcpad, GST_BUFFER_OFFSET_NONE,
1832 self->frame_size, GST_PAD_CAPS (self->srcpad), &outbuf);
1833 if (ret != GST_FLOW_OK)
1836 if (GST_PAD_CAPS (self->srcpad) != GST_BUFFER_CAPS (outbuf) &&
1837 !gst_caps_is_equal (GST_PAD_CAPS (self->srcpad),
1838 GST_BUFFER_CAPS (outbuf))) {
1839 gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf));
1840 GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT,
1841 self->request_caps);
1843 gst_buffer_unref (outbuf);
1844 outbuf = gst_buffer_try_new_and_alloc (self->frame_size);
1847 return GST_FLOW_ERROR;
1849 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
1852 g_return_val_if_fail (self->history_count - 1 -
1853 gst_deinterlace_method_get_latency (self->method) >= 0, GST_FLOW_ERROR);
1856 self->field_history[self->history_count - 1 -
1857 gst_deinterlace_method_get_latency (self->method)].buf;
1858 if (interlacing_method != GST_DEINTERLACE_TELECINE) {
1859 timestamp = GST_BUFFER_TIMESTAMP (buf);
1861 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1862 if (self->fields == GST_DEINTERLACE_ALL)
1863 GST_BUFFER_DURATION (outbuf) = self->field_duration;
1865 GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
1867 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1868 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1871 /* Check if we need to drop the frame because of QoS */
1872 if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
1873 self->cur_field_idx--;
1874 gst_buffer_unref (gst_deinterlace_pop_history (self));
1875 gst_buffer_unref (outbuf);
1879 /* do magic calculus */
1880 gst_deinterlace_method_deinterlace_frame (self->method,
1881 self->field_history, self->history_count, outbuf,
1882 self->cur_field_idx);
1884 self->cur_field_idx--;
1885 if (self->cur_field_idx + 1 +
1886 gst_deinterlace_method_get_latency (self->method)
1887 < self->history_count) {
1888 gst_buffer_unref (gst_deinterlace_pop_history (self));
1891 if (gst_deinterlace_clip_buffer (self, outbuf)) {
1892 GST_DEBUG_OBJECT (self,
1893 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1894 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1895 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
1896 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
1897 GST_BUFFER_DURATION (outbuf)));
1898 ret = gst_pad_push (self->srcpad, outbuf);
1901 gst_buffer_unref (outbuf);
1905 if (ret != GST_FLOW_OK)
1907 if (interlacing_method == GST_DEINTERLACE_TELECINE
1908 && self->method_id == GST_DEINTERLACE_WEAVE) {
1909 /* pop off the second field */
1910 GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
1911 self->history_count);
1912 self->cur_field_idx--;
1913 gst_buffer_unref (gst_deinterlace_pop_history (self));
1914 interlacing_method = GST_DEINTERLACE_INTERLACED;
1919 if (flush_one && !self->drop_orphans) {
1920 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1924 /* no calculation done: remove excess field */
1925 else if (self->field_history[self->cur_field_idx].flags ==
1926 PICTURE_INTERLACED_BOTTOM && (self->fields == GST_DEINTERLACE_TF
1927 && interlacing_method != GST_DEINTERLACE_TELECINE)) {
1928 GST_DEBUG_OBJECT (self, "Removing unused bottom field");
1929 self->cur_field_idx--;
1930 gst_buffer_unref (gst_deinterlace_pop_history (self));
1932 if (flush_one && !self->drop_orphans) {
1933 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1941 self->need_more = TRUE;
1946 gst_deinterlace_get_latency (GstDeinterlace * self)
1948 if (self->locking == GST_DEINTERLACE_LOCKING_AUTO) {
1952 query = gst_query_new_latency ();
1953 if ((res = gst_pad_peer_query (self->sinkpad, query))) {
1955 /* if upstream is live, we use low-latency passive locking mode
1956 * else high-latency active locking mode */
1957 gst_query_parse_latency (query, &is_live, NULL, NULL);
1958 GST_DEBUG_OBJECT (self, "Latency query indicates stream is %s",
1959 is_live ? "live - using passive locking" :
1960 "not live - using active locking");
1961 gst_query_unref (query);
1964 /* conservatively use passive locking if the query fails */
1965 GST_WARNING_OBJECT (self,
1966 "Latency query failed - fall back to using passive locking");
1967 gst_query_unref (query);
1971 return self->locking - 2;
1975 static GstFlowReturn
1976 gst_deinterlace_chain (GstPad * pad, GstBuffer * buf)
1978 GstDeinterlace *self = GST_DEINTERLACE (GST_PAD_PARENT (pad));
1979 GstFlowReturn ret = GST_FLOW_OK;
1981 GST_OBJECT_LOCK (self);
1982 if (self->reconfigure) {
1983 if (self->new_fields != -1)
1984 self->fields = self->new_fields;
1985 if (self->new_mode != -1)
1986 self->mode = self->new_mode;
1987 self->new_mode = -1;
1988 self->new_fields = -1;
1990 self->reconfigure = FALSE;
1991 GST_OBJECT_UNLOCK (self);
1992 if (GST_PAD_CAPS (self->srcpad))
1993 gst_deinterlace_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad));
1995 GST_OBJECT_UNLOCK (self);
1998 GST_DEBUG_OBJECT (self,
1999 "[IN] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
2000 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
2001 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
2002 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)));
2004 if (self->still_frame_mode || self->passthrough) {
2005 GST_DEBUG_OBJECT (self,
2006 "Frame type: Progressive?; pushing buffer using pass-through");
2007 GST_DEBUG_OBJECT (self,
2008 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
2009 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
2010 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
2011 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)));
2013 return gst_pad_push (self->srcpad, buf);
2016 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
2017 GST_DEBUG_OBJECT (self, "DISCONT buffer, resetting history");
2018 gst_deinterlace_reset_history (self, FALSE);
2021 gst_deinterlace_push_history (self, buf);
2025 ret = gst_deinterlace_output_frame (self, FALSE);
2026 } while (!self->need_more && self->history_count > 0 && ret == GST_FLOW_OK);
2032 gst_greatest_common_divisor (gint a, gint b)
2045 gst_fraction_double (gint * n_out, gint * d_out, gboolean half)
2055 if (n == 0 || (n == G_MAXINT && d == 1))
2058 gcd = gst_greatest_common_divisor (n, d);
2063 if (G_MAXINT / 2 >= ABS (n)) {
2065 } else if (d >= 2) {
2071 if (G_MAXINT / 2 >= ABS (d)) {
2073 } else if (n >= 2) {
2087 gst_deinterlace_getcaps (GstPad * pad)
2090 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2093 const GstCaps *ourcaps;
2096 otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad;
2098 ourcaps = gst_pad_get_pad_template_caps (pad);
2099 peercaps = gst_pad_peer_get_caps (otherpad);
2102 GST_DEBUG_OBJECT (pad, "Peer has caps %" GST_PTR_FORMAT, peercaps);
2103 ret = gst_caps_intersect (ourcaps, peercaps);
2104 gst_caps_unref (peercaps);
2106 ret = gst_caps_copy (ourcaps);
2109 for (len = gst_caps_get_size (ret); len > 0; len--) {
2110 GstStructure *s = gst_caps_get_structure (ret, len - 1);
2112 if (pad == self->sinkpad || self->passthrough)
2113 gst_structure_remove_field (s, "interlaced");
2115 gst_structure_set (s, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL);
2117 if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) {
2120 val = gst_structure_get_value (s, "framerate");
2124 if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION) {
2127 n = gst_value_get_fraction_numerator (val);
2128 d = gst_value_get_fraction_denominator (val);
2130 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
2134 gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
2135 } else if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION_RANGE) {
2136 const GValue *min, *max;
2137 GValue nrange = { 0, }, nmin = {
2142 g_value_init (&nrange, GST_TYPE_FRACTION_RANGE);
2143 g_value_init (&nmin, GST_TYPE_FRACTION);
2144 g_value_init (&nmax, GST_TYPE_FRACTION);
2146 min = gst_value_get_fraction_range_min (val);
2147 max = gst_value_get_fraction_range_max (val);
2149 n = gst_value_get_fraction_numerator (min);
2150 d = gst_value_get_fraction_denominator (min);
2152 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
2153 g_value_unset (&nrange);
2154 g_value_unset (&nmax);
2155 g_value_unset (&nmin);
2159 gst_value_set_fraction (&nmin, n, d);
2161 n = gst_value_get_fraction_numerator (max);
2162 d = gst_value_get_fraction_denominator (max);
2164 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
2165 g_value_unset (&nrange);
2166 g_value_unset (&nmax);
2167 g_value_unset (&nmin);
2171 gst_value_set_fraction (&nmax, n, d);
2172 gst_value_set_fraction_range (&nrange, &nmin, &nmax);
2174 gst_structure_set_value (s, "framerate", &nrange);
2176 g_value_unset (&nmin);
2177 g_value_unset (&nmax);
2178 g_value_unset (&nrange);
2179 } else if (G_VALUE_TYPE (val) == GST_TYPE_LIST) {
2181 GValue nlist = { 0, };
2182 GValue nval = { 0, };
2185 g_value_init (&nlist, GST_TYPE_LIST);
2186 for (i = gst_value_list_get_size (val); i > 0; i--) {
2189 lval = gst_value_list_get_value (val, i);
2191 if (G_VALUE_TYPE (lval) != GST_TYPE_FRACTION)
2194 n = gst_value_get_fraction_numerator (lval);
2195 d = gst_value_get_fraction_denominator (lval);
2197 /* Double/Half the framerate but if this fails simply
2198 * skip this value from the list */
2199 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
2203 g_value_init (&nval, GST_TYPE_FRACTION);
2205 gst_value_set_fraction (&nval, n, d);
2206 gst_value_list_append_value (&nlist, &nval);
2207 g_value_unset (&nval);
2209 gst_structure_set_value (s, "framerate", &nlist);
2210 g_value_unset (&nlist);
2215 GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret);
2217 gst_object_unref (self);
2222 GST_ERROR_OBJECT (pad, "Unable to transform peer caps");
2223 gst_caps_unref (ret);
2228 gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps)
2230 gboolean res = TRUE;
2231 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2233 GstDeinterlaceInterlacingMethod interlacing_method;
2235 if (self->locking != GST_DEINTERLACE_LOCKING_NONE) {
2236 if (self->low_latency == -1)
2237 self->low_latency = gst_deinterlace_get_latency (self);
2239 if (self->pattern_lock) {
2240 /* refresh has been successful - we have a lock now */
2241 self->pattern_refresh = FALSE;
2243 /* if we were not refreshing (!pattern_refresh) the caps have changed
2244 * so we need to refresh and we don't have a lock anymore
2245 * otherwise we have pattern_fresh and !pattern_lock anyway */
2246 self->pattern_refresh = TRUE;
2247 self->pattern_lock = FALSE;
2252 gst_video_format_parse_caps (caps, &self->format, &self->width,
2254 res &= gst_video_parse_caps_framerate (caps, &self->fps_n, &self->fps_d);
2255 if (pad == self->sinkpad)
2256 res &= gst_video_format_parse_caps_interlaced (caps, &self->interlaced);
2260 gst_deinterlace_update_passthrough (self);
2262 interlacing_method = gst_deinterlace_get_interlacing_method (caps);
2264 if (self->pattern_lock) {
2265 srccaps = gst_caps_copy (caps);
2266 if (self->pattern != -1
2267 && G_UNLIKELY (!gst_util_fraction_multiply (self->fps_n, self->fps_d,
2268 telecine_patterns[self->pattern].ratio_n,
2269 telecine_patterns[self->pattern].ratio_d, &self->fps_n,
2271 GST_ERROR_OBJECT (self,
2272 "Multiplying the framerate by the telecine pattern ratio overflowed!");
2273 gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, self->fps_n,
2275 } else if (self->low_latency > 0) {
2276 if (interlacing_method == GST_DEINTERLACE_TELECINE) {
2277 /* for initial buffers of a telecine pattern, until there is a lock we
2278 * we output naïvely adjusted timestamps */
2279 srccaps = gst_caps_copy (caps);
2280 gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
2281 } else if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) {
2282 gint fps_n = self->fps_n, fps_d = self->fps_d;
2284 if (!gst_fraction_double (&fps_n, &fps_d, FALSE))
2287 srccaps = gst_caps_copy (caps);
2289 gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, fps_n,
2292 srccaps = gst_caps_ref (caps);
2295 /* in high latency pattern locking mode if we don't have a pattern lock,
2296 * the sink pad caps are the best we know */
2297 srccaps = gst_caps_ref (caps);
2300 if (self->mode != GST_DEINTERLACE_MODE_DISABLED) {
2301 srccaps = gst_caps_make_writable (srccaps);
2302 gst_structure_remove_field (gst_caps_get_structure (srccaps, 0),
2303 "interlacing-method");
2304 gst_caps_set_simple (srccaps, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL);
2307 if (!gst_pad_set_caps (self->srcpad, srccaps))
2308 goto caps_not_accepted;
2311 gst_video_format_get_size (self->format, self->width, self->height);
2313 if (G_LIKELY (self->fps_n != 0)) {
2314 self->field_duration =
2315 gst_util_uint64_scale (GST_SECOND, self->fps_d, 2 * self->fps_n);
2317 self->field_duration = 0;
2320 gst_deinterlace_set_method (self, self->method_id);
2321 gst_deinterlace_method_setup (self->method, self->format, self->width,
2324 GST_DEBUG_OBJECT (pad, "Sink caps: %" GST_PTR_FORMAT, caps);
2325 GST_DEBUG_OBJECT (pad, "Src caps: %" GST_PTR_FORMAT, srccaps);
2327 gst_caps_unref (srccaps);
2331 gst_object_unref (self);
2336 GST_ERROR_OBJECT (pad, "Invalid caps: %" GST_PTR_FORMAT, caps);
2341 GST_ERROR_OBJECT (pad, "Caps not accepted: %" GST_PTR_FORMAT, srccaps);
2342 gst_caps_unref (srccaps);
2347 gst_deinterlace_sink_event (GstPad * pad, GstEvent * event)
2349 gboolean res = TRUE;
2350 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2352 GST_LOG_OBJECT (pad, "received %s event: %" GST_PTR_FORMAT,
2353 GST_EVENT_TYPE_NAME (event), event);
2355 switch (GST_EVENT_TYPE (event)) {
2356 case GST_EVENT_NEWSEGMENT:
2360 gint64 start, end, base;
2361 gdouble rate, applied_rate;
2363 gst_event_parse_new_segment_full (event, &is_update, &rate,
2364 &applied_rate, &fmt, &start, &end, &base);
2366 gst_deinterlace_reset_qos (self);
2367 gst_deinterlace_reset_history (self, FALSE);
2369 if (fmt == GST_FORMAT_TIME) {
2370 GST_DEBUG_OBJECT (pad,
2371 "Got NEWSEGMENT event in GST_FORMAT_TIME, passing on (%"
2372 GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")", GST_TIME_ARGS (start),
2373 GST_TIME_ARGS (end));
2374 gst_segment_set_newsegment_full (&self->segment, is_update, rate,
2375 applied_rate, fmt, start, end, base);
2377 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
2380 res = gst_pad_push_event (self->srcpad, event);
2383 case GST_EVENT_CUSTOM_DOWNSTREAM:{
2384 gboolean still_state;
2386 if (gst_video_event_parse_still_frame (event, &still_state)) {
2387 GST_DEBUG_OBJECT (self, "Received still frame event, state %d",
2393 GST_DEBUG_OBJECT (self, "Handling still frame");
2394 self->still_frame_mode = TRUE;
2395 gst_deinterlace_reset_history (self, FALSE);
2396 if (self->last_buffer) {
2398 gst_pad_push (self->srcpad, gst_buffer_ref (self->last_buffer));
2399 GST_DEBUG_OBJECT (self, "Pushed still frame, result: %s",
2400 gst_flow_get_name (ret));
2402 GST_WARNING_OBJECT (self, "No pending buffer!");
2405 GST_DEBUG_OBJECT (self, "Ending still frames");
2406 self->still_frame_mode = FALSE;
2412 self->have_eos = TRUE;
2413 gst_deinterlace_reset_history (self, FALSE);
2417 res = gst_pad_push_event (self->srcpad, event);
2420 case GST_EVENT_FLUSH_STOP:
2421 if (self->still_frame_mode) {
2422 GST_DEBUG_OBJECT (self, "Ending still frames");
2423 self->still_frame_mode = FALSE;
2425 gst_deinterlace_reset_qos (self);
2426 res = gst_pad_push_event (self->srcpad, event);
2427 gst_deinterlace_reset_history (self, TRUE);
2431 gst_object_unref (self);
2436 gst_deinterlace_sink_query (GstPad * pad, GstQuery * query)
2438 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2439 gboolean res = FALSE;
2441 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
2443 switch (GST_QUERY_TYPE (query)) {
2445 GstPad *peer = gst_pad_get_peer (self->srcpad);
2448 res = gst_pad_query (peer, query);
2449 gst_object_unref (peer);
2457 gst_object_unref (self);
2461 static GstStateChangeReturn
2462 gst_deinterlace_change_state (GstElement * element, GstStateChange transition)
2464 GstStateChangeReturn ret;
2465 GstDeinterlace *self = GST_DEINTERLACE (element);
2467 switch (transition) {
2468 case GST_STATE_CHANGE_NULL_TO_READY:
2470 case GST_STATE_CHANGE_READY_TO_PAUSED:
2472 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2478 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2479 if (ret != GST_STATE_CHANGE_SUCCESS)
2482 switch (transition) {
2483 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2485 case GST_STATE_CHANGE_PAUSED_TO_READY:
2486 gst_deinterlace_reset (self);
2488 case GST_STATE_CHANGE_READY_TO_NULL:
2497 gst_deinterlace_src_event (GstPad * pad, GstEvent * event)
2499 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2502 GST_DEBUG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
2504 switch (GST_EVENT_TYPE (event)) {
2505 case GST_EVENT_QOS:{
2506 GstClockTimeDiff diff;
2507 GstClockTime timestamp;
2510 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
2512 gst_deinterlace_update_qos (self, proportion, diff, timestamp);
2516 res = gst_pad_push_event (self->sinkpad, event);
2520 gst_object_unref (self);
2526 gst_deinterlace_src_query (GstPad * pad, GstQuery * query)
2528 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2529 gboolean res = FALSE;
2531 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
2533 switch (GST_QUERY_TYPE (query)) {
2534 case GST_QUERY_LATENCY:
2535 if (!self->passthrough) {
2536 GstClockTime min, max;
2540 if ((peer = gst_pad_get_peer (self->sinkpad))) {
2541 if ((res = gst_pad_query (peer, query))) {
2542 GstClockTime latency;
2543 gint fields_required = 0;
2544 gint method_latency = 0;
2548 gst_deinterlace_method_get_fields_required (self->method);
2550 gst_deinterlace_method_get_latency (self->method);
2553 gst_query_parse_latency (query, &live, &min, &max);
2555 GST_DEBUG_OBJECT (self, "Peer latency: min %"
2556 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
2557 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
2559 /* add our own latency */
2560 latency = (fields_required + method_latency) * self->field_duration;
2562 GST_DEBUG_OBJECT (self, "Our latency: min %" GST_TIME_FORMAT
2563 ", max %" GST_TIME_FORMAT,
2564 GST_TIME_ARGS (latency), GST_TIME_ARGS (latency));
2567 if (max != GST_CLOCK_TIME_NONE)
2570 GST_DEBUG_OBJECT (self, "Calculated total latency : min %"
2571 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
2572 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
2574 gst_query_set_latency (query, live, min, max);
2576 gst_object_unref (peer);
2583 GstPad *peer = gst_pad_get_peer (self->sinkpad);
2586 res = gst_pad_query (peer, query);
2587 gst_object_unref (peer);
2595 gst_object_unref (self);
2599 static const GstQueryType *
2600 gst_deinterlace_src_query_types (GstPad * pad)
2602 static const GstQueryType types[] = {
2609 static GstFlowReturn
2610 gst_deinterlace_alloc_buffer (GstPad * pad, guint64 offset, guint size,
2611 GstCaps * caps, GstBuffer ** buf)
2613 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2614 GstFlowReturn ret = GST_FLOW_OK;
2618 GST_DEBUG_OBJECT (pad, "alloc with caps %" GST_PTR_FORMAT ", size %u", caps,
2621 if (self->still_frame_mode || self->passthrough) {
2622 ret = gst_pad_alloc_buffer (self->srcpad, offset, size, caps, buf);
2623 } else if (G_LIKELY (!self->request_caps)) {
2624 *buf = gst_buffer_try_new_and_alloc (size);
2625 if (G_UNLIKELY (!*buf)) {
2626 ret = GST_FLOW_ERROR;
2628 gst_buffer_set_caps (*buf, caps);
2629 GST_BUFFER_OFFSET (*buf) = offset;
2634 guint new_frame_size;
2635 GstCaps *new_caps = gst_caps_copy (self->request_caps);
2637 if (self->fields == GST_DEINTERLACE_ALL) {
2639 GstStructure *s = gst_caps_get_structure (new_caps, 0);
2641 gst_structure_get_fraction (s, "framerate", &n, &d);
2643 if (!gst_fraction_double (&n, &d, TRUE)) {
2644 gst_object_unref (self);
2645 gst_caps_unref (new_caps);
2649 gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
2652 if (G_UNLIKELY (!gst_video_format_parse_caps (new_caps, &fmt, &width,
2654 gst_object_unref (self);
2655 gst_caps_unref (new_caps);
2659 new_frame_size = gst_video_format_get_size (fmt, width, height);
2661 *buf = gst_buffer_try_new_and_alloc (new_frame_size);
2662 if (G_UNLIKELY (!*buf)) {
2663 ret = GST_FLOW_ERROR;
2665 gst_buffer_set_caps (*buf, new_caps);
2666 gst_caps_unref (self->request_caps);
2667 self->request_caps = NULL;
2668 gst_caps_unref (new_caps);
2672 gst_object_unref (self);
2678 plugin_init (GstPlugin * plugin)
2680 GST_DEBUG_CATEGORY_INIT (deinterlace_debug, "deinterlace", 0, "Deinterlacer");
2686 if (!gst_element_register (plugin, "deinterlace", GST_RANK_NONE,
2687 GST_TYPE_DEINTERLACE)) {
2694 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
2697 "Deinterlacer", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
2698 GST_PACKAGE_ORIGIN);