3 * Copyright (C) 2005 Martin Eikermann <meiker@upb.de>
4 * Copyright (C) 2008-2010 Sebastian Dröge <slomo@collabora.co.uk>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
23 * SECTION:element-deinterlace
25 * deinterlace deinterlaces interlaced video frames to progressive video frames.
26 * For this different algorithms can be selected which will be described later.
29 * <title>Example launch line</title>
31 * gst-launch -v filesrc location=/path/to/file ! decodebin2 ! ffmpegcolorspace ! deinterlace ! ffmpegcolorspace ! autovideosink
32 * ]| This pipeline deinterlaces a video file with the default deinterlacing options.
40 #include "gstdeinterlace.h"
41 #include "tvtime/plugins.h"
45 GST_DEBUG_CATEGORY_STATIC (deinterlace_debug);
46 #define GST_CAT_DEFAULT (deinterlace_debug)
50 #define DEFAULT_MODE GST_DEINTERLACE_MODE_INTERLACED
51 #define DEFAULT_METHOD GST_DEINTERLACE_GREEDY_H
52 #define DEFAULT_FIELDS GST_DEINTERLACE_ALL
53 #define DEFAULT_FIELD_LAYOUT GST_DEINTERLACE_LAYOUT_AUTO
65 #define GST_TYPE_DEINTERLACE_METHODS (gst_deinterlace_methods_get_type ())
67 gst_deinterlace_methods_get_type (void)
69 static GType deinterlace_methods_type = 0;
71 static const GEnumValue methods_types[] = {
72 {GST_DEINTERLACE_TOMSMOCOMP, "Motion Adaptive: Motion Search",
74 {GST_DEINTERLACE_GREEDY_H, "Motion Adaptive: Advanced Detection",
76 {GST_DEINTERLACE_GREEDY_L, "Motion Adaptive: Simple Detection", "greedyl"},
77 {GST_DEINTERLACE_VFIR, "Blur Vertical", "vfir"},
78 {GST_DEINTERLACE_LINEAR, "Television: Full resolution", "linear"},
79 {GST_DEINTERLACE_LINEAR_BLEND, "Blur: Temporal", "linearblend"},
80 {GST_DEINTERLACE_SCALER_BOB, "Double lines", "scalerbob"},
81 {GST_DEINTERLACE_WEAVE, "Weave", "weave"},
82 {GST_DEINTERLACE_WEAVE_TFF, "Progressive: Top Field First", "weavetff"},
83 {GST_DEINTERLACE_WEAVE_BFF, "Progressive: Bottom Field First", "weavebff"},
87 if (!deinterlace_methods_type) {
88 deinterlace_methods_type =
89 g_enum_register_static ("GstDeinterlaceMethods", methods_types);
91 return deinterlace_methods_type;
94 #define GST_TYPE_DEINTERLACE_FIELDS (gst_deinterlace_fields_get_type ())
96 gst_deinterlace_fields_get_type (void)
98 static GType deinterlace_fields_type = 0;
100 static const GEnumValue fields_types[] = {
101 {GST_DEINTERLACE_ALL, "All fields", "all"},
102 {GST_DEINTERLACE_TF, "Top fields only", "top"},
103 {GST_DEINTERLACE_BF, "Bottom fields only", "bottom"},
107 if (!deinterlace_fields_type) {
108 deinterlace_fields_type =
109 g_enum_register_static ("GstDeinterlaceFields", fields_types);
111 return deinterlace_fields_type;
114 #define GST_TYPE_DEINTERLACE_FIELD_LAYOUT (gst_deinterlace_field_layout_get_type ())
116 gst_deinterlace_field_layout_get_type (void)
118 static GType deinterlace_field_layout_type = 0;
120 static const GEnumValue field_layout_types[] = {
121 {GST_DEINTERLACE_LAYOUT_AUTO, "Auto detection", "auto"},
122 {GST_DEINTERLACE_LAYOUT_TFF, "Top field first", "tff"},
123 {GST_DEINTERLACE_LAYOUT_BFF, "Bottom field first", "bff"},
127 if (!deinterlace_field_layout_type) {
128 deinterlace_field_layout_type =
129 g_enum_register_static ("GstDeinterlaceFieldLayout",
132 return deinterlace_field_layout_type;
135 #define GST_TYPE_DEINTERLACE_MODES (gst_deinterlace_modes_get_type ())
137 gst_deinterlace_modes_get_type (void)
139 static GType deinterlace_modes_type = 0;
141 static const GEnumValue modes_types[] = {
142 {GST_DEINTERLACE_MODE_AUTO, "Auto detection", "auto"},
143 {GST_DEINTERLACE_MODE_INTERLACED, "Force deinterlacing", "interlaced"},
144 {GST_DEINTERLACE_MODE_DISABLED, "Run in passthrough mode", "disabled"},
148 if (!deinterlace_modes_type) {
149 deinterlace_modes_type =
150 g_enum_register_static ("GstDeinterlaceModes", modes_types);
152 return deinterlace_modes_type;
155 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
158 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("Y444") ";"
159 GST_VIDEO_CAPS_YUV ("YUY2") ";" GST_VIDEO_CAPS_YUV ("YVYU") ";"
160 GST_VIDEO_CAPS_YUV ("Y42B") ";" GST_VIDEO_CAPS_YUV ("I420") ";"
161 GST_VIDEO_CAPS_YUV ("YV12") ";" GST_VIDEO_CAPS_YUV ("Y41B"))
164 static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
167 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("Y444") ";"
168 GST_VIDEO_CAPS_YUV ("YUY2") ";" GST_VIDEO_CAPS_YUV ("YVYU") ";"
169 GST_VIDEO_CAPS_YUV ("Y42B") ";" GST_VIDEO_CAPS_YUV ("I420") ";"
170 GST_VIDEO_CAPS_YUV ("YV12") ";" GST_VIDEO_CAPS_YUV ("Y41B"))
173 static void gst_deinterlace_finalize (GObject * self);
174 static void gst_deinterlace_set_property (GObject * self, guint prop_id,
175 const GValue * value, GParamSpec * pspec);
176 static void gst_deinterlace_get_property (GObject * self, guint prop_id,
177 GValue * value, GParamSpec * pspec);
179 static GstCaps *gst_deinterlace_getcaps (GstPad * pad);
180 static gboolean gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps);
181 static gboolean gst_deinterlace_sink_event (GstPad * pad, GstEvent * event);
182 static gboolean gst_deinterlace_sink_query (GstPad * pad, GstQuery * query);
183 static GstFlowReturn gst_deinterlace_chain (GstPad * pad, GstBuffer * buffer);
184 static GstFlowReturn gst_deinterlace_alloc_buffer (GstPad * pad, guint64 offset,
185 guint size, GstCaps * caps, GstBuffer ** buf);
186 static GstStateChangeReturn gst_deinterlace_change_state (GstElement * element,
187 GstStateChange transition);
189 static gboolean gst_deinterlace_src_event (GstPad * pad, GstEvent * event);
190 static gboolean gst_deinterlace_src_query (GstPad * pad, GstQuery * query);
191 static const GstQueryType *gst_deinterlace_src_query_types (GstPad * pad);
193 static void gst_deinterlace_reset (GstDeinterlace * self);
194 static void gst_deinterlace_update_qos (GstDeinterlace * self,
195 gdouble proportion, GstClockTimeDiff diff, GstClockTime time);
196 static void gst_deinterlace_reset_qos (GstDeinterlace * self);
197 static void gst_deinterlace_read_qos (GstDeinterlace * self,
198 gdouble * proportion, GstClockTime * time);
200 static void gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
201 gpointer iface_data);
204 _do_init (GType object_type)
206 const GInterfaceInfo child_proxy_interface_info = {
207 (GInterfaceInitFunc) gst_deinterlace_child_proxy_interface_init,
208 NULL, /* interface_finalize */
209 NULL /* interface_data */
212 g_type_add_interface_static (object_type, GST_TYPE_CHILD_PROXY,
213 &child_proxy_interface_info);
216 GST_BOILERPLATE_FULL (GstDeinterlace, gst_deinterlace, GstElement,
217 GST_TYPE_ELEMENT, _do_init);
221 GType (*get_type) (void);
222 } _method_types[] = {
224 gst_deinterlace_method_tomsmocomp_get_type}, {
225 gst_deinterlace_method_greedy_h_get_type}, {
226 gst_deinterlace_method_greedy_l_get_type}, {
227 gst_deinterlace_method_vfir_get_type}, {
228 gst_deinterlace_method_linear_get_type}, {
229 gst_deinterlace_method_linear_blend_get_type}, {
230 gst_deinterlace_method_scaler_bob_get_type}, {
231 gst_deinterlace_method_weave_get_type}, {
232 gst_deinterlace_method_weave_tff_get_type}, {
233 gst_deinterlace_method_weave_bff_get_type}
237 gst_deinterlace_set_method (GstDeinterlace * self, GstDeinterlaceMethods method)
241 GST_DEBUG_OBJECT (self, "Setting new method %d", method);
244 if (self->method_id == method &&
245 gst_deinterlace_method_supported (G_TYPE_FROM_INSTANCE (self->method),
246 self->format, self->width, self->height)) {
247 GST_DEBUG_OBJECT (self, "Reusing current method");
251 gst_child_proxy_child_removed (GST_OBJECT (self),
252 GST_OBJECT (self->method));
253 gst_object_unparent (GST_OBJECT (self->method));
258 _method_types[method].get_type !=
259 NULL ? _method_types[method].get_type () : G_TYPE_INVALID;
260 if (method_type == G_TYPE_INVALID
261 || !gst_deinterlace_method_supported (method_type, self->format,
262 self->width, self->height)) {
266 method_type = G_TYPE_INVALID;
268 GST_WARNING_OBJECT (self, "Method doesn't support requested format");
269 for (i = 0; i < G_N_ELEMENTS (_method_types); i++) {
270 if (_method_types[i].get_type == NULL)
272 tmp = _method_types[i].get_type ();
273 if (gst_deinterlace_method_supported (tmp, self->format, self->width,
275 GST_DEBUG_OBJECT (self, "Using method %d", i);
280 /* If we get here we must have invalid caps! */
281 g_assert (method_type != G_TYPE_INVALID);
284 self->method = g_object_new (method_type, NULL);
285 self->method_id = method;
287 gst_object_set_name (GST_OBJECT (self->method), "method");
288 gst_object_set_parent (GST_OBJECT (self->method), GST_OBJECT (self));
289 gst_child_proxy_child_added (GST_OBJECT (self), GST_OBJECT (self->method));
292 gst_deinterlace_method_setup (self->method, self->format, self->width,
297 gst_deinterlace_clip_buffer (GstDeinterlace * self, GstBuffer * buffer)
300 GstClockTime start, stop;
301 gint64 cstart, cstop;
303 GST_DEBUG_OBJECT (self,
304 "Clipping buffer to the current segment: %" GST_TIME_FORMAT " -- %"
305 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
306 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
307 GST_DEBUG_OBJECT (self, "Current segment: %" GST_SEGMENT_FORMAT,
310 if (G_UNLIKELY (self->segment.format != GST_FORMAT_TIME))
312 if (G_UNLIKELY (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer)))
315 start = GST_BUFFER_TIMESTAMP (buffer);
316 stop = start + GST_BUFFER_DURATION (buffer);
318 if (!(ret = gst_segment_clip (&self->segment, GST_FORMAT_TIME,
319 start, stop, &cstart, &cstop)))
322 GST_BUFFER_TIMESTAMP (buffer) = cstart;
323 if (GST_CLOCK_TIME_IS_VALID (cstop))
324 GST_BUFFER_DURATION (buffer) = cstop - cstart;
328 GST_DEBUG_OBJECT (self,
329 "Clipped buffer to the current segment: %" GST_TIME_FORMAT " -- %"
330 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
331 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
333 GST_DEBUG_OBJECT (self, "Buffer outside the current segment -- dropping");
339 gst_deinterlace_base_init (gpointer klass)
341 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
343 gst_element_class_add_pad_template (element_class,
344 gst_static_pad_template_get (&src_templ));
345 gst_element_class_add_pad_template (element_class,
346 gst_static_pad_template_get (&sink_templ));
348 gst_element_class_set_details_simple (element_class,
351 "Deinterlace Methods ported from DScaler/TvTime",
352 "Martin Eikermann <meiker@upb.de>, "
353 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
357 gst_deinterlace_class_init (GstDeinterlaceClass * klass)
359 GObjectClass *gobject_class = (GObjectClass *) klass;
361 GstElementClass *element_class = (GstElementClass *) klass;
363 gobject_class->set_property = gst_deinterlace_set_property;
364 gobject_class->get_property = gst_deinterlace_get_property;
365 gobject_class->finalize = gst_deinterlace_finalize;
368 * GstDeinterlace:mode
370 * This selects whether the deinterlacing methods should
371 * always be applied or if they should only be applied
372 * on content that has the "interlaced" flag on the caps.
375 g_object_class_install_property (gobject_class, PROP_MODE,
376 g_param_spec_enum ("mode",
379 GST_TYPE_DEINTERLACE_MODES,
380 DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
384 * GstDeinterlace:method
386 * Selects the different deinterlacing algorithms that can be used.
387 * These provide different quality and CPU usage.
389 * Some methods provide parameters which can be set by getting
390 * the "method" child via the #GstChildProxy interface and
391 * setting the appropiate properties on it.
397 * Motion Adaptive: Motion Search
403 * Motion Adaptive: Advanced Detection
409 * Motion Adaptive: Simple Detection
421 * Linear interpolation
427 * Linear interpolation in time domain
445 * Progressive: Top Field First
451 * Progressive: Bottom Field First
456 g_object_class_install_property (gobject_class, PROP_METHOD,
457 g_param_spec_enum ("method",
459 "Deinterlace Method",
460 GST_TYPE_DEINTERLACE_METHODS,
461 DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
465 * GstDeinterlace:fields
467 * This selects which fields should be output. If "all" is selected
468 * the output framerate will be double.
471 g_object_class_install_property (gobject_class, PROP_FIELDS,
472 g_param_spec_enum ("fields",
474 "Fields to use for deinterlacing",
475 GST_TYPE_DEINTERLACE_FIELDS,
476 DEFAULT_FIELDS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
480 * GstDeinterlace:layout
482 * This selects which fields is the first in time.
485 g_object_class_install_property (gobject_class, PROP_FIELD_LAYOUT,
486 g_param_spec_enum ("tff",
488 "Deinterlace top field first",
489 GST_TYPE_DEINTERLACE_FIELD_LAYOUT,
490 DEFAULT_FIELD_LAYOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
493 element_class->change_state =
494 GST_DEBUG_FUNCPTR (gst_deinterlace_change_state);
498 gst_deinterlace_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
501 GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
503 g_return_val_if_fail (index == 0, NULL);
505 return gst_object_ref (self->method);
509 gst_deinterlace_child_proxy_get_children_count (GstChildProxy * child_proxy)
511 GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
513 return ((self->method) ? 1 : 0);
517 gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
520 GstChildProxyInterface *iface = g_iface;
522 iface->get_child_by_index = gst_deinterlace_child_proxy_get_child_by_index;
523 iface->get_children_count = gst_deinterlace_child_proxy_get_children_count;
527 gst_deinterlace_init (GstDeinterlace * self, GstDeinterlaceClass * klass)
529 self->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
530 gst_pad_set_chain_function (self->sinkpad,
531 GST_DEBUG_FUNCPTR (gst_deinterlace_chain));
532 gst_pad_set_event_function (self->sinkpad,
533 GST_DEBUG_FUNCPTR (gst_deinterlace_sink_event));
534 gst_pad_set_setcaps_function (self->sinkpad,
535 GST_DEBUG_FUNCPTR (gst_deinterlace_setcaps));
536 gst_pad_set_getcaps_function (self->sinkpad,
537 GST_DEBUG_FUNCPTR (gst_deinterlace_getcaps));
538 gst_pad_set_query_function (self->sinkpad,
539 GST_DEBUG_FUNCPTR (gst_deinterlace_sink_query));
540 gst_pad_set_bufferalloc_function (self->sinkpad,
541 GST_DEBUG_FUNCPTR (gst_deinterlace_alloc_buffer));
542 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
544 self->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
545 gst_pad_set_event_function (self->srcpad,
546 GST_DEBUG_FUNCPTR (gst_deinterlace_src_event));
547 gst_pad_set_query_type_function (self->srcpad,
548 GST_DEBUG_FUNCPTR (gst_deinterlace_src_query_types));
549 gst_pad_set_query_function (self->srcpad,
550 GST_DEBUG_FUNCPTR (gst_deinterlace_src_query));
551 gst_pad_set_getcaps_function (self->srcpad,
552 GST_DEBUG_FUNCPTR (gst_deinterlace_getcaps));
553 gst_pad_set_setcaps_function (self->srcpad,
554 GST_DEBUG_FUNCPTR (gst_deinterlace_setcaps));
555 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
557 self->mode = DEFAULT_MODE;
558 gst_deinterlace_set_method (self, DEFAULT_METHOD);
559 self->fields = DEFAULT_FIELDS;
560 self->field_layout = DEFAULT_FIELD_LAYOUT;
562 self->still_frame_mode = FALSE;
564 gst_deinterlace_reset (self);
568 gst_deinterlace_reset_history (GstDeinterlace * self)
572 GST_DEBUG_OBJECT (self, "Resetting history");
574 for (i = 0; i < self->history_count; i++) {
575 if (self->field_history[i].buf) {
576 gst_buffer_unref (self->field_history[i].buf);
577 self->field_history[i].buf = NULL;
580 memset (self->field_history, 0,
581 GST_DEINTERLACE_MAX_FIELD_HISTORY * sizeof (GstDeinterlaceField));
582 self->history_count = 0;
584 if (self->last_buffer)
585 gst_buffer_unref (self->last_buffer);
586 self->last_buffer = NULL;
590 gst_deinterlace_update_passthrough (GstDeinterlace * self)
592 self->passthrough = (self->mode == GST_DEINTERLACE_MODE_DISABLED
593 || (!self->interlaced && self->mode != GST_DEINTERLACE_MODE_INTERLACED));
594 GST_DEBUG_OBJECT (self, "Passthrough: %d", self->passthrough);
598 gst_deinterlace_reset (GstDeinterlace * self)
600 GST_DEBUG_OBJECT (self, "Resetting internal state");
602 self->format = GST_VIDEO_FORMAT_UNKNOWN;
605 self->frame_size = 0;
606 self->fps_n = self->fps_d = 0;
607 self->passthrough = FALSE;
609 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
612 gst_caps_unref (self->sink_caps);
613 self->sink_caps = NULL;
616 gst_caps_unref (self->src_caps);
617 self->src_caps = NULL;
619 if (self->request_caps)
620 gst_caps_unref (self->request_caps);
621 self->request_caps = NULL;
623 gst_deinterlace_reset_history (self);
625 gst_deinterlace_reset_qos (self);
629 gst_deinterlace_set_property (GObject * object, guint prop_id,
630 const GValue * value, GParamSpec * pspec)
632 GstDeinterlace *self;
634 g_return_if_fail (GST_IS_DEINTERLACE (object));
635 self = GST_DEINTERLACE (object);
641 GST_OBJECT_LOCK (self);
642 oldmode = self->mode;
643 self->mode = g_value_get_enum (value);
644 gst_deinterlace_update_passthrough (self);
645 if (self->mode != oldmode && GST_PAD_CAPS (self->srcpad))
646 gst_deinterlace_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad));
647 GST_OBJECT_UNLOCK (self);
651 gst_deinterlace_set_method (self, g_value_get_enum (value));
656 GST_OBJECT_LOCK (self);
657 oldfields = self->fields;
658 self->fields = g_value_get_enum (value);
659 if (self->fields != oldfields && GST_PAD_CAPS (self->srcpad))
660 gst_deinterlace_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad));
661 GST_OBJECT_UNLOCK (self);
664 case PROP_FIELD_LAYOUT:
665 self->field_layout = g_value_get_enum (value);
668 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
674 gst_deinterlace_get_property (GObject * object, guint prop_id,
675 GValue * value, GParamSpec * pspec)
677 GstDeinterlace *self;
679 g_return_if_fail (GST_IS_DEINTERLACE (object));
680 self = GST_DEINTERLACE (object);
684 g_value_set_enum (value, self->mode);
687 g_value_set_enum (value, self->method_id);
690 g_value_set_enum (value, self->fields);
692 case PROP_FIELD_LAYOUT:
693 g_value_set_enum (value, self->field_layout);
696 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
701 gst_deinterlace_finalize (GObject * object)
703 GstDeinterlace *self = GST_DEINTERLACE (object);
705 gst_deinterlace_reset (self);
708 gst_object_unparent (GST_OBJECT (self->method));
712 G_OBJECT_CLASS (parent_class)->finalize (object);
716 gst_deinterlace_pop_history (GstDeinterlace * self)
720 g_return_val_if_fail (self->history_count > 0, NULL);
722 GST_DEBUG_OBJECT (self, "Pop last history buffer -- current history size %d",
723 self->history_count);
725 buffer = self->field_history[self->history_count - 1].buf;
727 self->history_count--;
729 GST_DEBUG_OBJECT (self, "Returning buffer: %" GST_TIME_FORMAT
730 " with duration %" GST_TIME_FORMAT " and size %u",
731 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
732 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer));
738 gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer)
741 GstClockTime timestamp;
742 GstDeinterlaceFieldLayout field_layout = self->field_layout;
743 gboolean repeated = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_RFF);
744 gboolean tff = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_TFF);
746 GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_ONEFIELD);
747 GstBuffer *field1, *field2;
748 guint fields_to_push = (onefield) ? 1 : (!repeated) ? 2 : 3;
749 gint field1_flags, field2_flags;
751 g_return_if_fail (self->history_count <
752 GST_DEINTERLACE_MAX_FIELD_HISTORY - fields_to_push);
754 GST_DEBUG_OBJECT (self, "Pushing new buffer to the history: %" GST_TIME_FORMAT
755 " with duration %" GST_TIME_FORMAT " and size %u",
756 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
757 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer));
759 for (i = GST_DEINTERLACE_MAX_FIELD_HISTORY - 1; i >= fields_to_push; i--) {
760 self->field_history[i].buf = self->field_history[i - fields_to_push].buf;
761 self->field_history[i].flags =
762 self->field_history[i - fields_to_push].flags;
765 if (field_layout == GST_DEINTERLACE_LAYOUT_AUTO) {
766 if (!self->interlaced) {
767 GST_WARNING_OBJECT (self, "Can't detect field layout -- assuming TFF");
768 field_layout = GST_DEINTERLACE_LAYOUT_TFF;
770 field_layout = GST_DEINTERLACE_LAYOUT_TFF;
772 field_layout = GST_DEINTERLACE_LAYOUT_BFF;
776 if (field_layout == GST_DEINTERLACE_LAYOUT_TFF) {
777 GST_DEBUG_OBJECT (self, "Top field first");
778 field1 = gst_buffer_ref (buffer);
779 field1_flags = PICTURE_INTERLACED_TOP;
780 field2 = gst_buffer_ref (buffer);
781 field2_flags = PICTURE_INTERLACED_BOTTOM;
783 GST_DEBUG_OBJECT (self, "Bottom field first");
784 field1 = gst_buffer_ref (buffer);
785 field1_flags = PICTURE_INTERLACED_BOTTOM;
786 field2 = gst_buffer_ref (buffer);
787 field2_flags = PICTURE_INTERLACED_TOP;
790 /* Timestamps are assigned to the field buffers under the assumption that
791 the timestamp of the buffer equals the first fields timestamp */
793 timestamp = GST_BUFFER_TIMESTAMP (buffer);
794 GST_BUFFER_TIMESTAMP (field1) = timestamp;
795 GST_BUFFER_TIMESTAMP (field2) = timestamp + self->field_duration;
797 GST_BUFFER_TIMESTAMP (field2) += self->field_duration;
800 self->field_history[0].buf = field2;
801 self->field_history[0].flags = field2_flags;
802 self->field_history[1].buf = gst_buffer_ref (field1);
803 GST_BUFFER_TIMESTAMP (self->field_history[1].buf) += self->field_duration;
804 self->field_history[1].flags = field1_flags;
805 self->field_history[2].buf = field1;
806 self->field_history[2].flags = field1_flags;
807 } else if (!onefield) {
808 self->field_history[0].buf = field2;
809 self->field_history[0].flags = field2_flags;
810 self->field_history[1].buf = field1;
811 self->field_history[1].flags = field1_flags;
812 } else { /* onefield */
813 self->field_history[0].buf = field1;
814 self->field_history[0].flags = field1_flags;
815 gst_buffer_unref (field2);
818 self->history_count += fields_to_push;
820 GST_DEBUG_OBJECT (self, "Pushed buffer -- current history size %d",
821 self->history_count);
823 if (self->last_buffer)
824 gst_buffer_unref (self->last_buffer);
825 self->last_buffer = buffer;
829 gst_deinterlace_update_qos (GstDeinterlace * self, gdouble proportion,
830 GstClockTimeDiff diff, GstClockTime timestamp)
832 GST_DEBUG_OBJECT (self,
833 "Updating QoS: proportion %lf, diff %s%" GST_TIME_FORMAT ", timestamp %"
834 GST_TIME_FORMAT, proportion, (diff < 0) ? "-" : "",
835 GST_TIME_ARGS (ABS (diff)), GST_TIME_ARGS (timestamp));
837 GST_OBJECT_LOCK (self);
838 self->proportion = proportion;
839 if (G_LIKELY (timestamp != GST_CLOCK_TIME_NONE)) {
840 if (G_UNLIKELY (diff > 0))
841 self->earliest_time =
842 timestamp + 2 * diff + ((self->fields ==
843 GST_DEINTERLACE_ALL) ? self->field_duration : 2 *
844 self->field_duration);
846 self->earliest_time = timestamp + diff;
848 self->earliest_time = GST_CLOCK_TIME_NONE;
850 GST_OBJECT_UNLOCK (self);
854 gst_deinterlace_reset_qos (GstDeinterlace * self)
856 gst_deinterlace_update_qos (self, 0.5, 0, GST_CLOCK_TIME_NONE);
860 gst_deinterlace_read_qos (GstDeinterlace * self, gdouble * proportion,
863 GST_OBJECT_LOCK (self);
864 *proportion = self->proportion;
865 *time = self->earliest_time;
866 GST_OBJECT_UNLOCK (self);
869 /* Perform qos calculations before processing the next frame. Returns TRUE if
870 * the frame should be processed, FALSE if the frame can be dropped entirely */
872 gst_deinterlace_do_qos (GstDeinterlace * self, GstClockTime timestamp)
874 GstClockTime qostime, earliest_time;
877 /* no timestamp, can't do QoS => process frame */
878 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) {
879 GST_LOG_OBJECT (self, "invalid timestamp, can't do QoS, process frame");
883 /* get latest QoS observation values */
884 gst_deinterlace_read_qos (self, &proportion, &earliest_time);
886 /* skip qos if we have no observation (yet) => process frame */
887 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) {
888 GST_LOG_OBJECT (self, "no observation yet, process frame");
892 /* qos is done on running time */
893 qostime = gst_segment_to_running_time (&self->segment, GST_FORMAT_TIME,
896 /* see how our next timestamp relates to the latest qos timestamp */
897 GST_LOG_OBJECT (self, "qostime %" GST_TIME_FORMAT ", earliest %"
898 GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
900 if (qostime != GST_CLOCK_TIME_NONE && qostime <= earliest_time) {
901 GST_DEBUG_OBJECT (self, "we are late, drop frame");
905 GST_LOG_OBJECT (self, "process frame");
910 gst_deinterlace_chain (GstPad * pad, GstBuffer * buf)
912 GstDeinterlace *self = GST_DEINTERLACE (GST_PAD_PARENT (pad));
913 GstClockTime timestamp;
914 GstFlowReturn ret = GST_FLOW_OK;
915 gint fields_required = 0;
916 gint cur_field_idx = 0;
919 if (self->still_frame_mode || self->passthrough)
920 return gst_pad_push (self->srcpad, buf);
922 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
923 GST_DEBUG_OBJECT (self, "DISCONT buffer, resetting history");
924 gst_deinterlace_reset_history (self);
927 gst_deinterlace_push_history (self, buf);
930 fields_required = gst_deinterlace_method_get_fields_required (self->method);
932 /* Not enough fields in the history */
933 if (self->history_count < fields_required + 1) {
934 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
935 self->history_count, fields_required + 1);
939 while (self->history_count >= fields_required) {
940 if (self->fields == GST_DEINTERLACE_ALL)
941 GST_DEBUG_OBJECT (self, "All fields");
942 else if (self->fields == GST_DEINTERLACE_TF)
943 GST_DEBUG_OBJECT (self, "Top fields");
944 else if (self->fields == GST_DEINTERLACE_BF)
945 GST_DEBUG_OBJECT (self, "Bottom fields");
947 cur_field_idx = self->history_count - fields_required;
949 if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_TOP
950 && self->fields == GST_DEINTERLACE_TF) ||
951 self->fields == GST_DEINTERLACE_ALL) {
952 GST_DEBUG_OBJECT (self, "deinterlacing top field");
954 /* create new buffer */
955 ret = gst_pad_alloc_buffer (self->srcpad,
956 GST_BUFFER_OFFSET_NONE, self->frame_size, self->src_caps, &outbuf);
957 if (ret != GST_FLOW_OK)
960 if (self->src_caps != GST_BUFFER_CAPS (outbuf) &&
961 !gst_caps_is_equal (self->src_caps, GST_BUFFER_CAPS (outbuf))) {
962 gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf));
963 GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT,
966 gst_buffer_unref (outbuf);
967 outbuf = gst_buffer_try_new_and_alloc (self->frame_size);
970 return GST_FLOW_ERROR;
972 gst_buffer_set_caps (outbuf, self->src_caps);
975 g_return_val_if_fail (self->history_count - 1 -
976 gst_deinterlace_method_get_latency (self->method) >= 0,
980 self->field_history[self->history_count - 1 -
981 gst_deinterlace_method_get_latency (self->method)].buf;
982 timestamp = GST_BUFFER_TIMESTAMP (buf);
984 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
985 if (self->fields == GST_DEINTERLACE_ALL)
986 GST_BUFFER_DURATION (outbuf) = self->field_duration;
988 GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
990 /* Check if we need to drop the frame because of QoS */
991 if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
992 gst_buffer_unref (gst_deinterlace_pop_history (self));
993 gst_buffer_unref (outbuf);
997 /* do magic calculus */
998 gst_deinterlace_method_deinterlace_frame (self->method,
999 self->field_history, self->history_count, outbuf);
1001 gst_buffer_unref (gst_deinterlace_pop_history (self));
1003 if (gst_deinterlace_clip_buffer (self, outbuf)) {
1004 ret = gst_pad_push (self->srcpad, outbuf);
1007 gst_buffer_unref (outbuf);
1011 if (ret != GST_FLOW_OK)
1015 /* no calculation done: remove excess field */
1016 else if (self->field_history[cur_field_idx].flags ==
1017 PICTURE_INTERLACED_TOP && self->fields == GST_DEINTERLACE_BF) {
1018 GST_DEBUG_OBJECT (self, "Removing unused top field");
1019 gst_buffer_unref (gst_deinterlace_pop_history (self));
1022 cur_field_idx = self->history_count - fields_required;
1023 if (self->history_count < fields_required)
1026 /* deinterlace bottom_field */
1027 if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_BOTTOM
1028 && self->fields == GST_DEINTERLACE_BF) ||
1029 self->fields == GST_DEINTERLACE_ALL) {
1030 GST_DEBUG_OBJECT (self, "deinterlacing bottom field");
1032 /* create new buffer */
1033 ret = gst_pad_alloc_buffer (self->srcpad,
1034 GST_BUFFER_OFFSET_NONE, self->frame_size, self->src_caps, &outbuf);
1035 if (ret != GST_FLOW_OK)
1038 if (self->src_caps != GST_BUFFER_CAPS (outbuf) &&
1039 !gst_caps_is_equal (self->src_caps, GST_BUFFER_CAPS (outbuf))) {
1040 gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf));
1041 GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT,
1042 self->request_caps);
1044 gst_buffer_unref (outbuf);
1045 outbuf = gst_buffer_try_new_and_alloc (self->frame_size);
1048 return GST_FLOW_ERROR;
1050 gst_buffer_set_caps (outbuf, self->src_caps);
1053 g_return_val_if_fail (self->history_count - 1 -
1054 gst_deinterlace_method_get_latency (self->method) >= 0,
1058 self->field_history[self->history_count - 1 -
1059 gst_deinterlace_method_get_latency (self->method)].buf;
1060 timestamp = GST_BUFFER_TIMESTAMP (buf);
1062 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1063 if (self->fields == GST_DEINTERLACE_ALL)
1064 GST_BUFFER_DURATION (outbuf) = self->field_duration;
1066 GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
1068 /* Check if we need to drop the frame because of QoS */
1069 if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
1070 gst_buffer_unref (gst_deinterlace_pop_history (self));
1071 gst_buffer_unref (outbuf);
1075 /* do magic calculus */
1076 gst_deinterlace_method_deinterlace_frame (self->method,
1077 self->field_history, self->history_count, outbuf);
1079 gst_buffer_unref (gst_deinterlace_pop_history (self));
1081 if (gst_deinterlace_clip_buffer (self, outbuf)) {
1082 ret = gst_pad_push (self->srcpad, outbuf);
1085 gst_buffer_unref (outbuf);
1089 if (ret != GST_FLOW_OK)
1093 /* no calculation done: remove excess field */
1094 else if (self->field_history[cur_field_idx].flags ==
1095 PICTURE_INTERLACED_BOTTOM && self->fields == GST_DEINTERLACE_TF) {
1096 GST_DEBUG_OBJECT (self, "Removing unused bottom field");
1097 gst_buffer_unref (gst_deinterlace_pop_history (self));
1105 gst_greatest_common_divisor (gint a, gint b)
1118 gst_fraction_double (gint * n_out, gint * d_out, gboolean half)
1128 if (n == 0 || (n == G_MAXINT && d == 1))
1131 gcd = gst_greatest_common_divisor (n, d);
1136 if (G_MAXINT / 2 >= ABS (n)) {
1138 } else if (d >= 2) {
1144 if (G_MAXINT / 2 >= ABS (d)) {
1146 } else if (n >= 2) {
1160 gst_deinterlace_getcaps (GstPad * pad)
1163 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1166 const GstCaps *ourcaps;
1169 GST_OBJECT_LOCK (self);
1171 otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad;
1173 ourcaps = gst_pad_get_pad_template_caps (pad);
1174 peercaps = gst_pad_peer_get_caps (otherpad);
1177 GST_DEBUG_OBJECT (pad, "Peer has caps %" GST_PTR_FORMAT, peercaps);
1178 ret = gst_caps_intersect (ourcaps, peercaps);
1179 gst_caps_unref (peercaps);
1181 ret = gst_caps_copy (ourcaps);
1184 GST_OBJECT_UNLOCK (self);
1186 for (len = gst_caps_get_size (ret); len > 0; len--) {
1187 GstStructure *s = gst_caps_get_structure (ret, len - 1);
1189 if (pad == self->sinkpad || self->passthrough)
1190 gst_structure_remove_field (s, "interlaced");
1192 gst_structure_set (s, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL);
1194 if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) {
1197 val = gst_structure_get_value (s, "framerate");
1201 if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION) {
1204 n = gst_value_get_fraction_numerator (val);
1205 d = gst_value_get_fraction_denominator (val);
1207 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
1211 gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
1212 } else if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION_RANGE) {
1213 const GValue *min, *max;
1214 GValue nrange = { 0, }, nmin = {
1219 g_value_init (&nrange, GST_TYPE_FRACTION_RANGE);
1220 g_value_init (&nmin, GST_TYPE_FRACTION);
1221 g_value_init (&nmax, GST_TYPE_FRACTION);
1223 min = gst_value_get_fraction_range_min (val);
1224 max = gst_value_get_fraction_range_max (val);
1226 n = gst_value_get_fraction_numerator (min);
1227 d = gst_value_get_fraction_denominator (min);
1229 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
1230 g_value_unset (&nrange);
1231 g_value_unset (&nmax);
1232 g_value_unset (&nmin);
1236 gst_value_set_fraction (&nmin, n, d);
1238 n = gst_value_get_fraction_numerator (max);
1239 d = gst_value_get_fraction_denominator (max);
1241 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
1242 g_value_unset (&nrange);
1243 g_value_unset (&nmax);
1244 g_value_unset (&nmin);
1248 gst_value_set_fraction (&nmax, n, d);
1249 gst_value_set_fraction_range (&nrange, &nmin, &nmax);
1251 gst_structure_set_value (s, "framerate", &nrange);
1253 g_value_unset (&nmin);
1254 g_value_unset (&nmax);
1255 g_value_unset (&nrange);
1256 } else if (G_VALUE_TYPE (val) == GST_TYPE_LIST) {
1258 GValue nlist = { 0, };
1259 GValue nval = { 0, };
1262 g_value_init (&nlist, GST_TYPE_LIST);
1263 for (i = gst_value_list_get_size (val); i > 0; i--) {
1266 lval = gst_value_list_get_value (val, i);
1268 if (G_VALUE_TYPE (lval) != GST_TYPE_FRACTION)
1271 n = gst_value_get_fraction_numerator (lval);
1272 d = gst_value_get_fraction_denominator (lval);
1274 /* Double/Half the framerate but if this fails simply
1275 * skip this value from the list */
1276 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
1280 g_value_init (&nval, GST_TYPE_FRACTION);
1282 gst_value_set_fraction (&nval, n, d);
1283 gst_value_list_append_value (&nlist, &nval);
1284 g_value_unset (&nval);
1286 gst_structure_set_value (s, "framerate", &nlist);
1287 g_value_unset (&nlist);
1292 GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret);
1297 GST_ERROR_OBJECT (pad, "Unable to transform peer caps");
1298 gst_caps_unref (ret);
1303 gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps)
1305 gboolean res = TRUE;
1306 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1310 otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad;
1313 gst_video_format_parse_caps (caps, &self->format, &self->width,
1315 res &= gst_video_parse_caps_framerate (caps, &self->fps_n, &self->fps_d);
1316 if (pad == self->sinkpad)
1317 res &= gst_video_format_parse_caps_interlaced (caps, &self->interlaced);
1321 gst_deinterlace_update_passthrough (self);
1323 if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) {
1324 gint fps_n = self->fps_n, fps_d = self->fps_d;
1326 if (!gst_fraction_double (&fps_n, &fps_d, otherpad != self->srcpad))
1329 othercaps = gst_caps_copy (caps);
1331 gst_caps_set_simple (othercaps, "framerate", GST_TYPE_FRACTION, fps_n,
1334 othercaps = gst_caps_ref (caps);
1337 if (otherpad == self->srcpad && self->mode != GST_DEINTERLACE_MODE_DISABLED) {
1338 othercaps = gst_caps_make_writable (othercaps);
1339 gst_caps_set_simple (othercaps, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL);
1342 if (!gst_pad_set_caps (otherpad, othercaps))
1343 goto caps_not_accepted;
1346 gst_video_format_get_size (self->format, self->width, self->height);
1348 if (self->fields == GST_DEINTERLACE_ALL && otherpad == self->srcpad)
1349 self->field_duration =
1350 gst_util_uint64_scale (GST_SECOND, self->fps_d, self->fps_n);
1352 self->field_duration =
1353 gst_util_uint64_scale (GST_SECOND, self->fps_d, 2 * self->fps_n);
1355 if (pad == self->sinkpad) {
1356 gst_caps_replace (&self->sink_caps, caps);
1357 gst_caps_replace (&self->src_caps, othercaps);
1359 gst_caps_replace (&self->src_caps, caps);
1360 gst_caps_replace (&self->sink_caps, othercaps);
1363 gst_deinterlace_set_method (self, self->method_id);
1364 gst_deinterlace_method_setup (self->method, self->format, self->width,
1367 GST_DEBUG_OBJECT (pad, "Set caps: %" GST_PTR_FORMAT, caps);
1368 GST_DEBUG_OBJECT (pad, "Other caps: %" GST_PTR_FORMAT, othercaps);
1370 gst_caps_unref (othercaps);
1374 gst_object_unref (self);
1379 GST_ERROR_OBJECT (pad, "Invalid caps: %" GST_PTR_FORMAT, caps);
1384 GST_ERROR_OBJECT (pad, "Caps not accepted: %" GST_PTR_FORMAT, othercaps);
1385 gst_caps_unref (othercaps);
1390 gst_deinterlace_sink_event (GstPad * pad, GstEvent * event)
1392 gboolean res = TRUE;
1393 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1395 GST_LOG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
1397 switch (GST_EVENT_TYPE (event)) {
1398 case GST_EVENT_NEWSEGMENT:
1402 gint64 start, end, base;
1403 gdouble rate, applied_rate;
1405 gst_event_parse_new_segment_full (event, &is_update, &rate, &applied_rate,
1406 &fmt, &start, &end, &base);
1407 if (fmt == GST_FORMAT_TIME) {
1408 GST_DEBUG_OBJECT (pad,
1409 "Got NEWSEGMENT event in GST_FORMAT_TIME, passing on (%"
1410 GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")", GST_TIME_ARGS (start),
1411 GST_TIME_ARGS (end));
1412 gst_segment_set_newsegment_full (&self->segment, is_update, rate,
1413 applied_rate, fmt, start, end, base);
1415 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1418 gst_deinterlace_reset_qos (self);
1419 gst_deinterlace_reset_history (self);
1420 res = gst_pad_push_event (self->srcpad, event);
1423 case GST_EVENT_CUSTOM_DOWNSTREAM:{
1424 gboolean still_state;
1426 if (gst_video_event_parse_still_frame (event, &still_state)) {
1427 GST_DEBUG_OBJECT (self, "Received still frame event, state %d",
1433 GST_DEBUG_OBJECT (self, "Handling still frame");
1434 self->still_frame_mode = TRUE;
1435 if (self->last_buffer) {
1437 gst_pad_push (self->srcpad, gst_buffer_ref (self->last_buffer));
1438 GST_DEBUG_OBJECT (self, "Pushed still frame, result: %s",
1439 gst_flow_get_name (ret));
1441 GST_WARNING_OBJECT (self, "No pending buffer!");
1444 GST_DEBUG_OBJECT (self, "Ending still frames");
1445 self->still_frame_mode = FALSE;
1451 gst_deinterlace_reset_history (self);
1455 res = gst_pad_push_event (self->srcpad, event);
1458 case GST_EVENT_FLUSH_STOP:
1459 if (self->still_frame_mode) {
1460 GST_DEBUG_OBJECT (self, "Ending still frames");
1461 self->still_frame_mode = FALSE;
1463 gst_deinterlace_reset_qos (self);
1464 res = gst_pad_push_event (self->srcpad, event);
1465 gst_deinterlace_reset_history (self);
1469 gst_object_unref (self);
1474 gst_deinterlace_sink_query (GstPad * pad, GstQuery * query)
1476 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1477 gboolean res = FALSE;
1479 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
1481 switch (GST_QUERY_TYPE (query)) {
1483 GstPad *peer = gst_pad_get_peer (self->srcpad);
1486 res = gst_pad_query (peer, query);
1487 gst_object_unref (peer);
1495 gst_object_unref (self);
1499 static GstStateChangeReturn
1500 gst_deinterlace_change_state (GstElement * element, GstStateChange transition)
1502 GstStateChangeReturn ret;
1503 GstDeinterlace *self = GST_DEINTERLACE (element);
1505 switch (transition) {
1506 case GST_STATE_CHANGE_NULL_TO_READY:
1508 case GST_STATE_CHANGE_READY_TO_PAUSED:
1510 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1516 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1517 if (ret != GST_STATE_CHANGE_SUCCESS)
1520 switch (transition) {
1521 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1523 case GST_STATE_CHANGE_PAUSED_TO_READY:
1524 gst_deinterlace_reset (self);
1526 case GST_STATE_CHANGE_READY_TO_NULL:
1535 gst_deinterlace_src_event (GstPad * pad, GstEvent * event)
1537 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1540 GST_DEBUG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
1542 switch (GST_EVENT_TYPE (event)) {
1543 case GST_EVENT_QOS:{
1544 GstClockTimeDiff diff;
1545 GstClockTime timestamp;
1548 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
1550 gst_deinterlace_update_qos (self, proportion, diff, timestamp);
1554 res = gst_pad_push_event (self->sinkpad, event);
1558 gst_object_unref (self);
1564 gst_deinterlace_src_query (GstPad * pad, GstQuery * query)
1566 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1567 gboolean res = FALSE;
1569 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
1571 switch (GST_QUERY_TYPE (query)) {
1572 case GST_QUERY_LATENCY:
1573 if (!self->passthrough) {
1574 GstClockTime min, max;
1578 if ((peer = gst_pad_get_peer (self->sinkpad))) {
1579 if ((res = gst_pad_query (peer, query))) {
1580 GstClockTime latency;
1581 gint fields_required = 0;
1582 gint method_latency = 0;
1586 gst_deinterlace_method_get_fields_required (self->method);
1588 gst_deinterlace_method_get_latency (self->method);
1591 gst_query_parse_latency (query, &live, &min, &max);
1593 GST_DEBUG_OBJECT (self, "Peer latency: min %"
1594 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
1595 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
1597 /* add our own latency */
1598 latency = (fields_required + method_latency) * self->field_duration;
1600 GST_DEBUG_OBJECT (self, "Our latency: min %" GST_TIME_FORMAT
1601 ", max %" GST_TIME_FORMAT,
1602 GST_TIME_ARGS (latency), GST_TIME_ARGS (latency));
1605 if (max != GST_CLOCK_TIME_NONE)
1608 GST_DEBUG_OBJECT (self, "Calculated total latency : min %"
1609 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
1610 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
1612 gst_query_set_latency (query, live, min, max);
1614 gst_object_unref (peer);
1621 GstPad *peer = gst_pad_get_peer (self->sinkpad);
1624 res = gst_pad_query (peer, query);
1625 gst_object_unref (peer);
1633 gst_object_unref (self);
1637 static const GstQueryType *
1638 gst_deinterlace_src_query_types (GstPad * pad)
1640 static const GstQueryType types[] = {
1647 static GstFlowReturn
1648 gst_deinterlace_alloc_buffer (GstPad * pad, guint64 offset, guint size,
1649 GstCaps * caps, GstBuffer ** buf)
1651 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1652 GstFlowReturn ret = GST_FLOW_OK;
1656 GST_DEBUG_OBJECT (pad, "alloc with caps %" GST_PTR_FORMAT ", size %u", caps,
1659 if (self->still_frame_mode || self->passthrough) {
1660 ret = gst_pad_alloc_buffer (self->srcpad, offset, size, caps, buf);
1661 } else if (G_LIKELY (!self->request_caps)) {
1662 *buf = gst_buffer_try_new_and_alloc (size);
1663 if (G_UNLIKELY (!*buf)) {
1664 ret = GST_FLOW_ERROR;
1666 gst_buffer_set_caps (*buf, caps);
1667 GST_BUFFER_OFFSET (*buf) = offset;
1672 guint new_frame_size;
1673 GstCaps *new_caps = gst_caps_copy (self->request_caps);
1675 if (self->fields == GST_DEINTERLACE_ALL) {
1677 GstStructure *s = gst_caps_get_structure (new_caps, 0);
1679 gst_structure_get_fraction (s, "framerate", &n, &d);
1681 if (!gst_fraction_double (&n, &d, TRUE)) {
1682 gst_object_unref (self);
1683 gst_caps_unref (new_caps);
1687 gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
1690 if (G_UNLIKELY (!gst_video_format_parse_caps (new_caps, &fmt, &width,
1692 gst_object_unref (self);
1693 gst_caps_unref (new_caps);
1697 new_frame_size = gst_video_format_get_size (fmt, width, height);
1699 *buf = gst_buffer_try_new_and_alloc (new_frame_size);
1700 if (G_UNLIKELY (!*buf)) {
1701 ret = GST_FLOW_ERROR;
1703 gst_buffer_set_caps (*buf, new_caps);
1704 gst_caps_unref (self->request_caps);
1705 self->request_caps = NULL;
1706 gst_caps_unref (new_caps);
1710 gst_object_unref (self);
1716 plugin_init (GstPlugin * plugin)
1718 GST_DEBUG_CATEGORY_INIT (deinterlace_debug, "deinterlace", 0, "Deinterlacer");
1722 if (!gst_element_register (plugin, "deinterlace", GST_RANK_NONE,
1723 GST_TYPE_DEINTERLACE)) {
1730 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1733 "Deinterlacer", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
1734 GST_PACKAGE_ORIGIN);