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_AUTO
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 ("AYUV") ";" GST_VIDEO_CAPS_YUV ("Y444")
159 ";" GST_VIDEO_CAPS_YUV ("YUY2") ";" GST_VIDEO_CAPS_YUV ("YVYU") ";"
160 GST_VIDEO_CAPS_YUV ("UYVY") ";"
161 GST_VIDEO_CAPS_YUV ("Y42B") ";" GST_VIDEO_CAPS_YUV ("I420") ";"
162 GST_VIDEO_CAPS_YUV ("YV12") ";" GST_VIDEO_CAPS_YUV ("Y41B") ";"
163 GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_ABGR ";"
164 GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_BGRA ";"
165 GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_xBGR ";"
166 GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx ";"
167 GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR)
170 static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
173 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";" GST_VIDEO_CAPS_YUV ("Y444")
174 ";" GST_VIDEO_CAPS_YUV ("YUY2") ";" GST_VIDEO_CAPS_YUV ("YVYU") ";"
175 GST_VIDEO_CAPS_YUV ("UYVY") ";"
176 GST_VIDEO_CAPS_YUV ("Y42B") ";" GST_VIDEO_CAPS_YUV ("I420") ";"
177 GST_VIDEO_CAPS_YUV ("YV12") ";" GST_VIDEO_CAPS_YUV ("Y41B") ";"
178 GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_ABGR ";"
179 GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_BGRA ";"
180 GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_xBGR ";"
181 GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx ";"
182 GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR)
185 static void gst_deinterlace_finalize (GObject * self);
186 static void gst_deinterlace_set_property (GObject * self, guint prop_id,
187 const GValue * value, GParamSpec * pspec);
188 static void gst_deinterlace_get_property (GObject * self, guint prop_id,
189 GValue * value, GParamSpec * pspec);
191 static GstCaps *gst_deinterlace_getcaps (GstPad * pad);
192 static gboolean gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps);
193 static gboolean gst_deinterlace_sink_event (GstPad * pad, GstEvent * event);
194 static gboolean gst_deinterlace_sink_query (GstPad * pad, GstQuery * query);
195 static GstFlowReturn gst_deinterlace_chain (GstPad * pad, GstBuffer * buffer);
196 static GstFlowReturn gst_deinterlace_alloc_buffer (GstPad * pad, guint64 offset,
197 guint size, GstCaps * caps, GstBuffer ** buf);
198 static GstStateChangeReturn gst_deinterlace_change_state (GstElement * element,
199 GstStateChange transition);
201 static gboolean gst_deinterlace_src_event (GstPad * pad, GstEvent * event);
202 static gboolean gst_deinterlace_src_query (GstPad * pad, GstQuery * query);
203 static const GstQueryType *gst_deinterlace_src_query_types (GstPad * pad);
205 static void gst_deinterlace_reset (GstDeinterlace * self);
206 static void gst_deinterlace_update_qos (GstDeinterlace * self,
207 gdouble proportion, GstClockTimeDiff diff, GstClockTime time);
208 static void gst_deinterlace_reset_qos (GstDeinterlace * self);
209 static void gst_deinterlace_read_qos (GstDeinterlace * self,
210 gdouble * proportion, GstClockTime * time);
212 static void gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
213 gpointer iface_data);
216 _do_init (GType object_type)
218 const GInterfaceInfo child_proxy_interface_info = {
219 (GInterfaceInitFunc) gst_deinterlace_child_proxy_interface_init,
220 NULL, /* interface_finalize */
221 NULL /* interface_data */
224 g_type_add_interface_static (object_type, GST_TYPE_CHILD_PROXY,
225 &child_proxy_interface_info);
228 GST_BOILERPLATE_FULL (GstDeinterlace, gst_deinterlace, GstElement,
229 GST_TYPE_ELEMENT, _do_init);
233 GType (*get_type) (void);
234 } _method_types[] = {
236 gst_deinterlace_method_tomsmocomp_get_type}, {
237 gst_deinterlace_method_greedy_h_get_type}, {
238 gst_deinterlace_method_greedy_l_get_type}, {
239 gst_deinterlace_method_vfir_get_type}, {
240 gst_deinterlace_method_linear_get_type}, {
241 gst_deinterlace_method_linear_blend_get_type}, {
242 gst_deinterlace_method_scaler_bob_get_type}, {
243 gst_deinterlace_method_weave_get_type}, {
244 gst_deinterlace_method_weave_tff_get_type}, {
245 gst_deinterlace_method_weave_bff_get_type}
249 gst_deinterlace_set_method (GstDeinterlace * self, GstDeinterlaceMethods method)
253 GST_DEBUG_OBJECT (self, "Setting new method %d", method);
256 if (self->method_id == method &&
257 gst_deinterlace_method_supported (G_TYPE_FROM_INSTANCE (self->method),
258 self->format, self->width, self->height)) {
259 GST_DEBUG_OBJECT (self, "Reusing current method");
263 gst_child_proxy_child_removed (GST_OBJECT (self),
264 GST_OBJECT (self->method));
265 gst_object_unparent (GST_OBJECT (self->method));
270 _method_types[method].get_type !=
271 NULL ? _method_types[method].get_type () : G_TYPE_INVALID;
272 if (method_type == G_TYPE_INVALID
273 || !gst_deinterlace_method_supported (method_type, self->format,
274 self->width, self->height)) {
278 method_type = G_TYPE_INVALID;
280 GST_WARNING_OBJECT (self, "Method doesn't support requested format");
281 for (i = 0; i < G_N_ELEMENTS (_method_types); i++) {
282 if (_method_types[i].get_type == NULL)
284 tmp = _method_types[i].get_type ();
285 if (gst_deinterlace_method_supported (tmp, self->format, self->width,
287 GST_DEBUG_OBJECT (self, "Using method %d", i);
292 /* If we get here we must have invalid caps! */
293 g_assert (method_type != G_TYPE_INVALID);
296 self->method = g_object_new (method_type, NULL);
297 self->method_id = method;
299 gst_object_set_name (GST_OBJECT (self->method), "method");
300 gst_object_set_parent (GST_OBJECT (self->method), GST_OBJECT (self));
301 gst_child_proxy_child_added (GST_OBJECT (self), GST_OBJECT (self->method));
304 gst_deinterlace_method_setup (self->method, self->format, self->width,
309 gst_deinterlace_clip_buffer (GstDeinterlace * self, GstBuffer * buffer)
312 GstClockTime start, stop;
313 gint64 cstart, cstop;
315 GST_DEBUG_OBJECT (self,
316 "Clipping buffer to the current segment: %" GST_TIME_FORMAT " -- %"
317 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
318 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
319 GST_DEBUG_OBJECT (self, "Current segment: %" GST_SEGMENT_FORMAT,
322 if (G_UNLIKELY (self->segment.format != GST_FORMAT_TIME))
324 if (G_UNLIKELY (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer)))
327 start = GST_BUFFER_TIMESTAMP (buffer);
328 stop = start + GST_BUFFER_DURATION (buffer);
330 if (!(ret = gst_segment_clip (&self->segment, GST_FORMAT_TIME,
331 start, stop, &cstart, &cstop)))
334 GST_BUFFER_TIMESTAMP (buffer) = cstart;
335 if (GST_CLOCK_TIME_IS_VALID (cstop))
336 GST_BUFFER_DURATION (buffer) = cstop - cstart;
340 GST_DEBUG_OBJECT (self,
341 "Clipped buffer to the current segment: %" GST_TIME_FORMAT " -- %"
342 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
343 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
345 GST_DEBUG_OBJECT (self, "Buffer outside the current segment -- dropping");
351 gst_deinterlace_base_init (gpointer klass)
353 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
355 gst_element_class_add_pad_template (element_class,
356 gst_static_pad_template_get (&src_templ));
357 gst_element_class_add_pad_template (element_class,
358 gst_static_pad_template_get (&sink_templ));
360 gst_element_class_set_details_simple (element_class,
363 "Deinterlace Methods ported from DScaler/TvTime",
364 "Martin Eikermann <meiker@upb.de>, "
365 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
369 gst_deinterlace_class_init (GstDeinterlaceClass * klass)
371 GObjectClass *gobject_class = (GObjectClass *) klass;
373 GstElementClass *element_class = (GstElementClass *) klass;
375 gobject_class->set_property = gst_deinterlace_set_property;
376 gobject_class->get_property = gst_deinterlace_get_property;
377 gobject_class->finalize = gst_deinterlace_finalize;
380 * GstDeinterlace:mode
382 * This selects whether the deinterlacing methods should
383 * always be applied or if they should only be applied
384 * on content that has the "interlaced" flag on the caps.
387 g_object_class_install_property (gobject_class, PROP_MODE,
388 g_param_spec_enum ("mode",
391 GST_TYPE_DEINTERLACE_MODES,
392 DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
396 * GstDeinterlace:method
398 * Selects the different deinterlacing algorithms that can be used.
399 * These provide different quality and CPU usage.
401 * Some methods provide parameters which can be set by getting
402 * the "method" child via the #GstChildProxy interface and
403 * setting the appropiate properties on it.
409 * Motion Adaptive: Motion Search
415 * Motion Adaptive: Advanced Detection
421 * Motion Adaptive: Simple Detection
433 * Linear interpolation
439 * Linear interpolation in time domain
457 * Progressive: Top Field First
463 * Progressive: Bottom Field First
468 g_object_class_install_property (gobject_class, PROP_METHOD,
469 g_param_spec_enum ("method",
471 "Deinterlace Method",
472 GST_TYPE_DEINTERLACE_METHODS,
473 DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
477 * GstDeinterlace:fields
479 * This selects which fields should be output. If "all" is selected
480 * the output framerate will be double.
483 g_object_class_install_property (gobject_class, PROP_FIELDS,
484 g_param_spec_enum ("fields",
486 "Fields to use for deinterlacing",
487 GST_TYPE_DEINTERLACE_FIELDS,
488 DEFAULT_FIELDS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
492 * GstDeinterlace:layout
494 * This selects which fields is the first in time.
497 g_object_class_install_property (gobject_class, PROP_FIELD_LAYOUT,
498 g_param_spec_enum ("tff",
500 "Deinterlace top field first",
501 GST_TYPE_DEINTERLACE_FIELD_LAYOUT,
502 DEFAULT_FIELD_LAYOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
505 element_class->change_state =
506 GST_DEBUG_FUNCPTR (gst_deinterlace_change_state);
510 gst_deinterlace_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
513 GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
515 g_return_val_if_fail (index == 0, NULL);
517 return gst_object_ref (self->method);
521 gst_deinterlace_child_proxy_get_children_count (GstChildProxy * child_proxy)
523 GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
525 return ((self->method) ? 1 : 0);
529 gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
532 GstChildProxyInterface *iface = g_iface;
534 iface->get_child_by_index = gst_deinterlace_child_proxy_get_child_by_index;
535 iface->get_children_count = gst_deinterlace_child_proxy_get_children_count;
539 gst_deinterlace_init (GstDeinterlace * self, GstDeinterlaceClass * klass)
541 self->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
542 gst_pad_set_chain_function (self->sinkpad,
543 GST_DEBUG_FUNCPTR (gst_deinterlace_chain));
544 gst_pad_set_event_function (self->sinkpad,
545 GST_DEBUG_FUNCPTR (gst_deinterlace_sink_event));
546 gst_pad_set_setcaps_function (self->sinkpad,
547 GST_DEBUG_FUNCPTR (gst_deinterlace_setcaps));
548 gst_pad_set_getcaps_function (self->sinkpad,
549 GST_DEBUG_FUNCPTR (gst_deinterlace_getcaps));
550 gst_pad_set_query_function (self->sinkpad,
551 GST_DEBUG_FUNCPTR (gst_deinterlace_sink_query));
552 gst_pad_set_bufferalloc_function (self->sinkpad,
553 GST_DEBUG_FUNCPTR (gst_deinterlace_alloc_buffer));
554 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
556 self->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
557 gst_pad_set_event_function (self->srcpad,
558 GST_DEBUG_FUNCPTR (gst_deinterlace_src_event));
559 gst_pad_set_query_type_function (self->srcpad,
560 GST_DEBUG_FUNCPTR (gst_deinterlace_src_query_types));
561 gst_pad_set_query_function (self->srcpad,
562 GST_DEBUG_FUNCPTR (gst_deinterlace_src_query));
563 gst_pad_set_getcaps_function (self->srcpad,
564 GST_DEBUG_FUNCPTR (gst_deinterlace_getcaps));
565 gst_pad_set_setcaps_function (self->srcpad,
566 GST_DEBUG_FUNCPTR (gst_deinterlace_setcaps));
567 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
569 self->mode = DEFAULT_MODE;
570 gst_deinterlace_set_method (self, DEFAULT_METHOD);
571 self->fields = DEFAULT_FIELDS;
572 self->field_layout = DEFAULT_FIELD_LAYOUT;
574 self->still_frame_mode = FALSE;
576 gst_deinterlace_reset (self);
580 gst_deinterlace_reset_history (GstDeinterlace * self)
584 GST_DEBUG_OBJECT (self, "Resetting history");
586 for (i = 0; i < self->history_count; i++) {
587 if (self->field_history[i].buf) {
588 gst_buffer_unref (self->field_history[i].buf);
589 self->field_history[i].buf = NULL;
592 memset (self->field_history, 0,
593 GST_DEINTERLACE_MAX_FIELD_HISTORY * sizeof (GstDeinterlaceField));
594 self->history_count = 0;
596 if (self->last_buffer)
597 gst_buffer_unref (self->last_buffer);
598 self->last_buffer = NULL;
602 gst_deinterlace_update_passthrough (GstDeinterlace * self)
604 self->passthrough = (self->mode == GST_DEINTERLACE_MODE_DISABLED
605 || (!self->interlaced && self->mode != GST_DEINTERLACE_MODE_INTERLACED));
606 GST_DEBUG_OBJECT (self, "Passthrough: %d", self->passthrough);
610 gst_deinterlace_reset (GstDeinterlace * self)
612 GST_DEBUG_OBJECT (self, "Resetting internal state");
614 self->format = GST_VIDEO_FORMAT_UNKNOWN;
617 self->frame_size = 0;
618 self->fps_n = self->fps_d = 0;
619 self->passthrough = FALSE;
621 self->reconfigure = FALSE;
622 if (self->new_mode != -1)
623 self->mode = self->new_mode;
624 if (self->new_fields != -1)
625 self->fields = self->new_fields;
627 self->new_fields = -1;
629 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
632 gst_caps_unref (self->sink_caps);
633 self->sink_caps = NULL;
636 gst_caps_unref (self->src_caps);
637 self->src_caps = NULL;
639 if (self->request_caps)
640 gst_caps_unref (self->request_caps);
641 self->request_caps = NULL;
643 gst_deinterlace_reset_history (self);
645 gst_deinterlace_reset_qos (self);
649 gst_deinterlace_set_property (GObject * object, guint prop_id,
650 const GValue * value, GParamSpec * pspec)
652 GstDeinterlace *self;
654 g_return_if_fail (GST_IS_DEINTERLACE (object));
655 self = GST_DEINTERLACE (object);
661 GST_OBJECT_LOCK (self);
662 new_mode = g_value_get_enum (value);
663 if (self->mode != new_mode && GST_PAD_CAPS (self->srcpad)) {
664 self->reconfigure = TRUE;
665 self->new_mode = new_mode;
667 self->mode = new_mode;
668 gst_deinterlace_update_passthrough (self);
670 GST_OBJECT_UNLOCK (self);
674 gst_deinterlace_set_method (self, g_value_get_enum (value));
679 GST_OBJECT_LOCK (self);
680 new_fields = g_value_get_enum (value);
681 if (self->fields != new_fields && GST_PAD_CAPS (self->srcpad)) {
682 self->reconfigure = TRUE;
683 self->new_fields = new_fields;
685 self->fields = new_fields;
687 GST_OBJECT_UNLOCK (self);
690 case PROP_FIELD_LAYOUT:
691 self->field_layout = g_value_get_enum (value);
694 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
700 gst_deinterlace_get_property (GObject * object, guint prop_id,
701 GValue * value, GParamSpec * pspec)
703 GstDeinterlace *self;
705 g_return_if_fail (GST_IS_DEINTERLACE (object));
706 self = GST_DEINTERLACE (object);
710 g_value_set_enum (value, self->mode);
713 g_value_set_enum (value, self->method_id);
716 g_value_set_enum (value, self->fields);
718 case PROP_FIELD_LAYOUT:
719 g_value_set_enum (value, self->field_layout);
722 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
727 gst_deinterlace_finalize (GObject * object)
729 GstDeinterlace *self = GST_DEINTERLACE (object);
731 gst_deinterlace_reset (self);
734 gst_object_unparent (GST_OBJECT (self->method));
738 G_OBJECT_CLASS (parent_class)->finalize (object);
742 gst_deinterlace_pop_history (GstDeinterlace * self)
746 g_return_val_if_fail (self->history_count > 0, NULL);
748 GST_DEBUG_OBJECT (self, "Pop last history buffer -- current history size %d",
749 self->history_count);
751 buffer = self->field_history[self->history_count - 1].buf;
753 self->history_count--;
755 GST_DEBUG_OBJECT (self, "Returning buffer: %" GST_TIME_FORMAT
756 " with duration %" GST_TIME_FORMAT " and size %u",
757 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
758 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer));
764 gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer)
767 GstClockTime timestamp;
768 GstDeinterlaceFieldLayout field_layout = self->field_layout;
769 gboolean repeated = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_RFF);
770 gboolean tff = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_TFF);
772 GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_ONEFIELD);
773 GstBuffer *field1, *field2;
774 guint fields_to_push = (onefield) ? 1 : (!repeated) ? 2 : 3;
775 gint field1_flags, field2_flags;
777 g_return_if_fail (self->history_count <
778 GST_DEINTERLACE_MAX_FIELD_HISTORY - fields_to_push);
780 GST_DEBUG_OBJECT (self, "Pushing new buffer to the history: %" GST_TIME_FORMAT
781 " with duration %" GST_TIME_FORMAT " and size %u",
782 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
783 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer));
785 for (i = GST_DEINTERLACE_MAX_FIELD_HISTORY - 1; i >= fields_to_push; i--) {
786 self->field_history[i].buf = self->field_history[i - fields_to_push].buf;
787 self->field_history[i].flags =
788 self->field_history[i - fields_to_push].flags;
791 if (field_layout == GST_DEINTERLACE_LAYOUT_AUTO) {
792 if (!self->interlaced) {
793 GST_WARNING_OBJECT (self, "Can't detect field layout -- assuming TFF");
794 field_layout = GST_DEINTERLACE_LAYOUT_TFF;
796 field_layout = GST_DEINTERLACE_LAYOUT_TFF;
798 field_layout = GST_DEINTERLACE_LAYOUT_BFF;
802 if (field_layout == GST_DEINTERLACE_LAYOUT_TFF) {
803 GST_DEBUG_OBJECT (self, "Top field first");
804 field1 = gst_buffer_ref (buffer);
805 field1_flags = PICTURE_INTERLACED_TOP;
806 field2 = gst_buffer_ref (buffer);
807 field2_flags = PICTURE_INTERLACED_BOTTOM;
809 GST_DEBUG_OBJECT (self, "Bottom field first");
810 field1 = gst_buffer_ref (buffer);
811 field1_flags = PICTURE_INTERLACED_BOTTOM;
812 field2 = gst_buffer_ref (buffer);
813 field2_flags = PICTURE_INTERLACED_TOP;
816 /* Timestamps are assigned to the field buffers under the assumption that
817 the timestamp of the buffer equals the first fields timestamp */
819 timestamp = GST_BUFFER_TIMESTAMP (buffer);
820 GST_BUFFER_TIMESTAMP (field1) = timestamp;
821 GST_BUFFER_TIMESTAMP (field2) = timestamp + self->field_duration;
823 GST_BUFFER_TIMESTAMP (field2) += self->field_duration;
826 self->field_history[0].buf = field2;
827 self->field_history[0].flags = field2_flags;
828 self->field_history[1].buf = gst_buffer_ref (field1);
829 GST_BUFFER_TIMESTAMP (self->field_history[1].buf) += self->field_duration;
830 self->field_history[1].flags = field1_flags;
831 self->field_history[2].buf = field1;
832 self->field_history[2].flags = field1_flags;
833 } else if (!onefield) {
834 self->field_history[0].buf = field2;
835 self->field_history[0].flags = field2_flags;
836 self->field_history[1].buf = field1;
837 self->field_history[1].flags = field1_flags;
838 } else { /* onefield */
839 self->field_history[0].buf = field1;
840 self->field_history[0].flags = field1_flags;
841 gst_buffer_unref (field2);
844 self->history_count += fields_to_push;
846 GST_DEBUG_OBJECT (self, "Pushed buffer -- current history size %d",
847 self->history_count);
849 if (self->last_buffer)
850 gst_buffer_unref (self->last_buffer);
851 self->last_buffer = buffer;
855 gst_deinterlace_update_qos (GstDeinterlace * self, gdouble proportion,
856 GstClockTimeDiff diff, GstClockTime timestamp)
858 GST_DEBUG_OBJECT (self,
859 "Updating QoS: proportion %lf, diff %s%" GST_TIME_FORMAT ", timestamp %"
860 GST_TIME_FORMAT, proportion, (diff < 0) ? "-" : "",
861 GST_TIME_ARGS (ABS (diff)), GST_TIME_ARGS (timestamp));
863 GST_OBJECT_LOCK (self);
864 self->proportion = proportion;
865 if (G_LIKELY (timestamp != GST_CLOCK_TIME_NONE)) {
866 if (G_UNLIKELY (diff > 0))
867 self->earliest_time =
868 timestamp + 2 * diff + ((self->fields ==
869 GST_DEINTERLACE_ALL) ? self->field_duration : 2 *
870 self->field_duration);
872 self->earliest_time = timestamp + diff;
874 self->earliest_time = GST_CLOCK_TIME_NONE;
876 GST_OBJECT_UNLOCK (self);
880 gst_deinterlace_reset_qos (GstDeinterlace * self)
882 gst_deinterlace_update_qos (self, 0.5, 0, GST_CLOCK_TIME_NONE);
886 gst_deinterlace_read_qos (GstDeinterlace * self, gdouble * proportion,
889 GST_OBJECT_LOCK (self);
890 *proportion = self->proportion;
891 *time = self->earliest_time;
892 GST_OBJECT_UNLOCK (self);
895 /* Perform qos calculations before processing the next frame. Returns TRUE if
896 * the frame should be processed, FALSE if the frame can be dropped entirely */
898 gst_deinterlace_do_qos (GstDeinterlace * self, GstClockTime timestamp)
900 GstClockTime qostime, earliest_time;
903 /* no timestamp, can't do QoS => process frame */
904 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) {
905 GST_LOG_OBJECT (self, "invalid timestamp, can't do QoS, process frame");
909 /* get latest QoS observation values */
910 gst_deinterlace_read_qos (self, &proportion, &earliest_time);
912 /* skip qos if we have no observation (yet) => process frame */
913 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) {
914 GST_LOG_OBJECT (self, "no observation yet, process frame");
918 /* qos is done on running time */
919 qostime = gst_segment_to_running_time (&self->segment, GST_FORMAT_TIME,
922 /* see how our next timestamp relates to the latest qos timestamp */
923 GST_LOG_OBJECT (self, "qostime %" GST_TIME_FORMAT ", earliest %"
924 GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
926 if (qostime != GST_CLOCK_TIME_NONE && qostime <= earliest_time) {
927 GST_DEBUG_OBJECT (self, "we are late, drop frame");
931 GST_LOG_OBJECT (self, "process frame");
936 gst_deinterlace_chain (GstPad * pad, GstBuffer * buf)
938 GstDeinterlace *self = GST_DEINTERLACE (GST_PAD_PARENT (pad));
939 GstClockTime timestamp;
940 GstFlowReturn ret = GST_FLOW_OK;
941 gint fields_required = 0;
942 gint cur_field_idx = 0;
945 GST_OBJECT_LOCK (self);
946 if (self->reconfigure) {
947 if (self->new_fields != -1)
948 self->fields = self->new_fields;
949 if (self->new_mode != -1)
950 self->mode = self->new_mode;
951 self->new_mode = self->new_fields = -1;
953 self->reconfigure = FALSE;
954 GST_OBJECT_UNLOCK (self);
955 if (GST_PAD_CAPS (self->srcpad))
956 gst_deinterlace_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad));
958 GST_OBJECT_UNLOCK (self);
961 if (self->still_frame_mode || self->passthrough)
962 return gst_pad_push (self->srcpad, buf);
964 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
965 GST_DEBUG_OBJECT (self, "DISCONT buffer, resetting history");
966 gst_deinterlace_reset_history (self);
969 gst_deinterlace_push_history (self, buf);
972 fields_required = gst_deinterlace_method_get_fields_required (self->method);
974 /* Not enough fields in the history */
975 if (self->history_count < fields_required + 1) {
976 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
977 self->history_count, fields_required + 1);
981 while (self->history_count >= fields_required) {
982 if (self->fields == GST_DEINTERLACE_ALL)
983 GST_DEBUG_OBJECT (self, "All fields");
984 else if (self->fields == GST_DEINTERLACE_TF)
985 GST_DEBUG_OBJECT (self, "Top fields");
986 else if (self->fields == GST_DEINTERLACE_BF)
987 GST_DEBUG_OBJECT (self, "Bottom fields");
989 cur_field_idx = self->history_count - fields_required;
991 if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_TOP
992 && self->fields == GST_DEINTERLACE_TF) ||
993 self->fields == GST_DEINTERLACE_ALL) {
994 GST_DEBUG_OBJECT (self, "deinterlacing top field");
996 /* create new buffer */
997 ret = gst_pad_alloc_buffer (self->srcpad,
998 GST_BUFFER_OFFSET_NONE, self->frame_size, self->src_caps, &outbuf);
999 if (ret != GST_FLOW_OK)
1002 if (self->src_caps != GST_BUFFER_CAPS (outbuf) &&
1003 !gst_caps_is_equal (self->src_caps, GST_BUFFER_CAPS (outbuf))) {
1004 gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf));
1005 GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT,
1006 self->request_caps);
1008 gst_buffer_unref (outbuf);
1009 outbuf = gst_buffer_try_new_and_alloc (self->frame_size);
1012 return GST_FLOW_ERROR;
1014 gst_buffer_set_caps (outbuf, self->src_caps);
1017 g_return_val_if_fail (self->history_count - 1 -
1018 gst_deinterlace_method_get_latency (self->method) >= 0,
1022 self->field_history[self->history_count - 1 -
1023 gst_deinterlace_method_get_latency (self->method)].buf;
1024 timestamp = GST_BUFFER_TIMESTAMP (buf);
1026 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1027 if (self->fields == GST_DEINTERLACE_ALL)
1028 GST_BUFFER_DURATION (outbuf) = self->field_duration;
1030 GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
1032 /* Check if we need to drop the frame because of QoS */
1033 if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
1034 gst_buffer_unref (gst_deinterlace_pop_history (self));
1035 gst_buffer_unref (outbuf);
1039 /* do magic calculus */
1040 gst_deinterlace_method_deinterlace_frame (self->method,
1041 self->field_history, self->history_count, outbuf);
1043 gst_buffer_unref (gst_deinterlace_pop_history (self));
1045 if (gst_deinterlace_clip_buffer (self, outbuf)) {
1046 ret = gst_pad_push (self->srcpad, outbuf);
1049 gst_buffer_unref (outbuf);
1053 if (ret != GST_FLOW_OK)
1057 /* no calculation done: remove excess field */
1058 else if (self->field_history[cur_field_idx].flags ==
1059 PICTURE_INTERLACED_TOP && self->fields == GST_DEINTERLACE_BF) {
1060 GST_DEBUG_OBJECT (self, "Removing unused top field");
1061 gst_buffer_unref (gst_deinterlace_pop_history (self));
1064 cur_field_idx = self->history_count - fields_required;
1065 if (self->history_count < fields_required)
1068 /* deinterlace bottom_field */
1069 if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_BOTTOM
1070 && self->fields == GST_DEINTERLACE_BF) ||
1071 self->fields == GST_DEINTERLACE_ALL) {
1072 GST_DEBUG_OBJECT (self, "deinterlacing bottom field");
1074 /* create new buffer */
1075 ret = gst_pad_alloc_buffer (self->srcpad,
1076 GST_BUFFER_OFFSET_NONE, self->frame_size, self->src_caps, &outbuf);
1077 if (ret != GST_FLOW_OK)
1080 if (self->src_caps != GST_BUFFER_CAPS (outbuf) &&
1081 !gst_caps_is_equal (self->src_caps, GST_BUFFER_CAPS (outbuf))) {
1082 gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf));
1083 GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT,
1084 self->request_caps);
1086 gst_buffer_unref (outbuf);
1087 outbuf = gst_buffer_try_new_and_alloc (self->frame_size);
1090 return GST_FLOW_ERROR;
1092 gst_buffer_set_caps (outbuf, self->src_caps);
1095 g_return_val_if_fail (self->history_count - 1 -
1096 gst_deinterlace_method_get_latency (self->method) >= 0,
1100 self->field_history[self->history_count - 1 -
1101 gst_deinterlace_method_get_latency (self->method)].buf;
1102 timestamp = GST_BUFFER_TIMESTAMP (buf);
1104 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1105 if (self->fields == GST_DEINTERLACE_ALL)
1106 GST_BUFFER_DURATION (outbuf) = self->field_duration;
1108 GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
1110 /* Check if we need to drop the frame because of QoS */
1111 if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
1112 gst_buffer_unref (gst_deinterlace_pop_history (self));
1113 gst_buffer_unref (outbuf);
1117 /* do magic calculus */
1118 gst_deinterlace_method_deinterlace_frame (self->method,
1119 self->field_history, self->history_count, outbuf);
1121 gst_buffer_unref (gst_deinterlace_pop_history (self));
1123 if (gst_deinterlace_clip_buffer (self, outbuf)) {
1124 ret = gst_pad_push (self->srcpad, outbuf);
1127 gst_buffer_unref (outbuf);
1131 if (ret != GST_FLOW_OK)
1135 /* no calculation done: remove excess field */
1136 else if (self->field_history[cur_field_idx].flags ==
1137 PICTURE_INTERLACED_BOTTOM && self->fields == GST_DEINTERLACE_TF) {
1138 GST_DEBUG_OBJECT (self, "Removing unused bottom field");
1139 gst_buffer_unref (gst_deinterlace_pop_history (self));
1147 gst_greatest_common_divisor (gint a, gint b)
1160 gst_fraction_double (gint * n_out, gint * d_out, gboolean half)
1170 if (n == 0 || (n == G_MAXINT && d == 1))
1173 gcd = gst_greatest_common_divisor (n, d);
1178 if (G_MAXINT / 2 >= ABS (n)) {
1180 } else if (d >= 2) {
1186 if (G_MAXINT / 2 >= ABS (d)) {
1188 } else if (n >= 2) {
1202 gst_deinterlace_getcaps (GstPad * pad)
1205 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1208 const GstCaps *ourcaps;
1211 GST_OBJECT_LOCK (self);
1213 otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad;
1215 ourcaps = gst_pad_get_pad_template_caps (pad);
1216 peercaps = gst_pad_peer_get_caps (otherpad);
1219 GST_DEBUG_OBJECT (pad, "Peer has caps %" GST_PTR_FORMAT, peercaps);
1220 ret = gst_caps_intersect (ourcaps, peercaps);
1221 gst_caps_unref (peercaps);
1223 ret = gst_caps_copy (ourcaps);
1226 GST_OBJECT_UNLOCK (self);
1228 for (len = gst_caps_get_size (ret); len > 0; len--) {
1229 GstStructure *s = gst_caps_get_structure (ret, len - 1);
1231 if (pad == self->sinkpad || self->passthrough)
1232 gst_structure_remove_field (s, "interlaced");
1234 gst_structure_set (s, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL);
1236 if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) {
1239 val = gst_structure_get_value (s, "framerate");
1243 if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION) {
1246 n = gst_value_get_fraction_numerator (val);
1247 d = gst_value_get_fraction_denominator (val);
1249 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
1253 gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
1254 } else if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION_RANGE) {
1255 const GValue *min, *max;
1256 GValue nrange = { 0, }, nmin = {
1261 g_value_init (&nrange, GST_TYPE_FRACTION_RANGE);
1262 g_value_init (&nmin, GST_TYPE_FRACTION);
1263 g_value_init (&nmax, GST_TYPE_FRACTION);
1265 min = gst_value_get_fraction_range_min (val);
1266 max = gst_value_get_fraction_range_max (val);
1268 n = gst_value_get_fraction_numerator (min);
1269 d = gst_value_get_fraction_denominator (min);
1271 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
1272 g_value_unset (&nrange);
1273 g_value_unset (&nmax);
1274 g_value_unset (&nmin);
1278 gst_value_set_fraction (&nmin, n, d);
1280 n = gst_value_get_fraction_numerator (max);
1281 d = gst_value_get_fraction_denominator (max);
1283 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
1284 g_value_unset (&nrange);
1285 g_value_unset (&nmax);
1286 g_value_unset (&nmin);
1290 gst_value_set_fraction (&nmax, n, d);
1291 gst_value_set_fraction_range (&nrange, &nmin, &nmax);
1293 gst_structure_set_value (s, "framerate", &nrange);
1295 g_value_unset (&nmin);
1296 g_value_unset (&nmax);
1297 g_value_unset (&nrange);
1298 } else if (G_VALUE_TYPE (val) == GST_TYPE_LIST) {
1300 GValue nlist = { 0, };
1301 GValue nval = { 0, };
1304 g_value_init (&nlist, GST_TYPE_LIST);
1305 for (i = gst_value_list_get_size (val); i > 0; i--) {
1308 lval = gst_value_list_get_value (val, i);
1310 if (G_VALUE_TYPE (lval) != GST_TYPE_FRACTION)
1313 n = gst_value_get_fraction_numerator (lval);
1314 d = gst_value_get_fraction_denominator (lval);
1316 /* Double/Half the framerate but if this fails simply
1317 * skip this value from the list */
1318 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
1322 g_value_init (&nval, GST_TYPE_FRACTION);
1324 gst_value_set_fraction (&nval, n, d);
1325 gst_value_list_append_value (&nlist, &nval);
1326 g_value_unset (&nval);
1328 gst_structure_set_value (s, "framerate", &nlist);
1329 g_value_unset (&nlist);
1334 GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret);
1339 GST_ERROR_OBJECT (pad, "Unable to transform peer caps");
1340 gst_caps_unref (ret);
1345 gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps)
1347 gboolean res = TRUE;
1348 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1352 otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad;
1355 gst_video_format_parse_caps (caps, &self->format, &self->width,
1357 res &= gst_video_parse_caps_framerate (caps, &self->fps_n, &self->fps_d);
1358 if (pad == self->sinkpad)
1359 res &= gst_video_format_parse_caps_interlaced (caps, &self->interlaced);
1363 gst_deinterlace_update_passthrough (self);
1365 if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) {
1366 gint fps_n = self->fps_n, fps_d = self->fps_d;
1368 if (!gst_fraction_double (&fps_n, &fps_d, otherpad != self->srcpad))
1371 othercaps = gst_caps_copy (caps);
1373 gst_caps_set_simple (othercaps, "framerate", GST_TYPE_FRACTION, fps_n,
1376 othercaps = gst_caps_ref (caps);
1379 if (otherpad == self->srcpad && self->mode != GST_DEINTERLACE_MODE_DISABLED) {
1380 othercaps = gst_caps_make_writable (othercaps);
1381 gst_caps_set_simple (othercaps, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL);
1384 if (!gst_pad_set_caps (otherpad, othercaps))
1385 goto caps_not_accepted;
1388 gst_video_format_get_size (self->format, self->width, self->height);
1390 if (self->fields == GST_DEINTERLACE_ALL && otherpad == self->srcpad)
1391 self->field_duration =
1392 gst_util_uint64_scale (GST_SECOND, self->fps_d, self->fps_n);
1394 self->field_duration =
1395 gst_util_uint64_scale (GST_SECOND, self->fps_d, 2 * self->fps_n);
1397 if (pad == self->sinkpad) {
1398 gst_caps_replace (&self->sink_caps, caps);
1399 gst_caps_replace (&self->src_caps, othercaps);
1401 gst_caps_replace (&self->src_caps, caps);
1402 gst_caps_replace (&self->sink_caps, othercaps);
1405 gst_deinterlace_set_method (self, self->method_id);
1406 gst_deinterlace_method_setup (self->method, self->format, self->width,
1409 GST_DEBUG_OBJECT (pad, "Set caps: %" GST_PTR_FORMAT, caps);
1410 GST_DEBUG_OBJECT (pad, "Other caps: %" GST_PTR_FORMAT, othercaps);
1412 gst_caps_unref (othercaps);
1416 gst_object_unref (self);
1421 GST_ERROR_OBJECT (pad, "Invalid caps: %" GST_PTR_FORMAT, caps);
1426 GST_ERROR_OBJECT (pad, "Caps not accepted: %" GST_PTR_FORMAT, othercaps);
1427 gst_caps_unref (othercaps);
1432 gst_deinterlace_sink_event (GstPad * pad, GstEvent * event)
1434 gboolean res = TRUE;
1435 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1437 GST_LOG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
1439 switch (GST_EVENT_TYPE (event)) {
1440 case GST_EVENT_NEWSEGMENT:
1444 gint64 start, end, base;
1445 gdouble rate, applied_rate;
1447 gst_event_parse_new_segment_full (event, &is_update, &rate, &applied_rate,
1448 &fmt, &start, &end, &base);
1449 if (fmt == GST_FORMAT_TIME) {
1450 GST_DEBUG_OBJECT (pad,
1451 "Got NEWSEGMENT event in GST_FORMAT_TIME, passing on (%"
1452 GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")", GST_TIME_ARGS (start),
1453 GST_TIME_ARGS (end));
1454 gst_segment_set_newsegment_full (&self->segment, is_update, rate,
1455 applied_rate, fmt, start, end, base);
1457 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1460 gst_deinterlace_reset_qos (self);
1461 gst_deinterlace_reset_history (self);
1462 res = gst_pad_push_event (self->srcpad, event);
1465 case GST_EVENT_CUSTOM_DOWNSTREAM:{
1466 gboolean still_state;
1468 if (gst_video_event_parse_still_frame (event, &still_state)) {
1469 GST_DEBUG_OBJECT (self, "Received still frame event, state %d",
1475 GST_DEBUG_OBJECT (self, "Handling still frame");
1476 self->still_frame_mode = TRUE;
1477 if (self->last_buffer) {
1479 gst_pad_push (self->srcpad, gst_buffer_ref (self->last_buffer));
1480 GST_DEBUG_OBJECT (self, "Pushed still frame, result: %s",
1481 gst_flow_get_name (ret));
1483 GST_WARNING_OBJECT (self, "No pending buffer!");
1486 GST_DEBUG_OBJECT (self, "Ending still frames");
1487 self->still_frame_mode = FALSE;
1493 gst_deinterlace_reset_history (self);
1497 res = gst_pad_push_event (self->srcpad, event);
1500 case GST_EVENT_FLUSH_STOP:
1501 if (self->still_frame_mode) {
1502 GST_DEBUG_OBJECT (self, "Ending still frames");
1503 self->still_frame_mode = FALSE;
1505 gst_deinterlace_reset_qos (self);
1506 res = gst_pad_push_event (self->srcpad, event);
1507 gst_deinterlace_reset_history (self);
1511 gst_object_unref (self);
1516 gst_deinterlace_sink_query (GstPad * pad, GstQuery * query)
1518 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1519 gboolean res = FALSE;
1521 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
1523 switch (GST_QUERY_TYPE (query)) {
1525 GstPad *peer = gst_pad_get_peer (self->srcpad);
1528 res = gst_pad_query (peer, query);
1529 gst_object_unref (peer);
1537 gst_object_unref (self);
1541 static GstStateChangeReturn
1542 gst_deinterlace_change_state (GstElement * element, GstStateChange transition)
1544 GstStateChangeReturn ret;
1545 GstDeinterlace *self = GST_DEINTERLACE (element);
1547 switch (transition) {
1548 case GST_STATE_CHANGE_NULL_TO_READY:
1550 case GST_STATE_CHANGE_READY_TO_PAUSED:
1552 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1558 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1559 if (ret != GST_STATE_CHANGE_SUCCESS)
1562 switch (transition) {
1563 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1565 case GST_STATE_CHANGE_PAUSED_TO_READY:
1566 gst_deinterlace_reset (self);
1568 case GST_STATE_CHANGE_READY_TO_NULL:
1577 gst_deinterlace_src_event (GstPad * pad, GstEvent * event)
1579 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1582 GST_DEBUG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
1584 switch (GST_EVENT_TYPE (event)) {
1585 case GST_EVENT_QOS:{
1586 GstClockTimeDiff diff;
1587 GstClockTime timestamp;
1590 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
1592 gst_deinterlace_update_qos (self, proportion, diff, timestamp);
1596 res = gst_pad_push_event (self->sinkpad, event);
1600 gst_object_unref (self);
1606 gst_deinterlace_src_query (GstPad * pad, GstQuery * query)
1608 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1609 gboolean res = FALSE;
1611 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
1613 switch (GST_QUERY_TYPE (query)) {
1614 case GST_QUERY_LATENCY:
1615 if (!self->passthrough) {
1616 GstClockTime min, max;
1620 if ((peer = gst_pad_get_peer (self->sinkpad))) {
1621 if ((res = gst_pad_query (peer, query))) {
1622 GstClockTime latency;
1623 gint fields_required = 0;
1624 gint method_latency = 0;
1628 gst_deinterlace_method_get_fields_required (self->method);
1630 gst_deinterlace_method_get_latency (self->method);
1633 gst_query_parse_latency (query, &live, &min, &max);
1635 GST_DEBUG_OBJECT (self, "Peer latency: min %"
1636 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
1637 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
1639 /* add our own latency */
1640 latency = (fields_required + method_latency) * self->field_duration;
1642 GST_DEBUG_OBJECT (self, "Our latency: min %" GST_TIME_FORMAT
1643 ", max %" GST_TIME_FORMAT,
1644 GST_TIME_ARGS (latency), GST_TIME_ARGS (latency));
1647 if (max != GST_CLOCK_TIME_NONE)
1650 GST_DEBUG_OBJECT (self, "Calculated total latency : min %"
1651 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
1652 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
1654 gst_query_set_latency (query, live, min, max);
1656 gst_object_unref (peer);
1663 GstPad *peer = gst_pad_get_peer (self->sinkpad);
1666 res = gst_pad_query (peer, query);
1667 gst_object_unref (peer);
1675 gst_object_unref (self);
1679 static const GstQueryType *
1680 gst_deinterlace_src_query_types (GstPad * pad)
1682 static const GstQueryType types[] = {
1689 static GstFlowReturn
1690 gst_deinterlace_alloc_buffer (GstPad * pad, guint64 offset, guint size,
1691 GstCaps * caps, GstBuffer ** buf)
1693 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1694 GstFlowReturn ret = GST_FLOW_OK;
1698 GST_DEBUG_OBJECT (pad, "alloc with caps %" GST_PTR_FORMAT ", size %u", caps,
1701 if (self->still_frame_mode || self->passthrough) {
1702 ret = gst_pad_alloc_buffer (self->srcpad, offset, size, caps, buf);
1703 } else if (G_LIKELY (!self->request_caps)) {
1704 *buf = gst_buffer_try_new_and_alloc (size);
1705 if (G_UNLIKELY (!*buf)) {
1706 ret = GST_FLOW_ERROR;
1708 gst_buffer_set_caps (*buf, caps);
1709 GST_BUFFER_OFFSET (*buf) = offset;
1714 guint new_frame_size;
1715 GstCaps *new_caps = gst_caps_copy (self->request_caps);
1717 if (self->fields == GST_DEINTERLACE_ALL) {
1719 GstStructure *s = gst_caps_get_structure (new_caps, 0);
1721 gst_structure_get_fraction (s, "framerate", &n, &d);
1723 if (!gst_fraction_double (&n, &d, TRUE)) {
1724 gst_object_unref (self);
1725 gst_caps_unref (new_caps);
1729 gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
1732 if (G_UNLIKELY (!gst_video_format_parse_caps (new_caps, &fmt, &width,
1734 gst_object_unref (self);
1735 gst_caps_unref (new_caps);
1739 new_frame_size = gst_video_format_get_size (fmt, width, height);
1741 *buf = gst_buffer_try_new_and_alloc (new_frame_size);
1742 if (G_UNLIKELY (!*buf)) {
1743 ret = GST_FLOW_ERROR;
1745 gst_buffer_set_caps (*buf, new_caps);
1746 gst_caps_unref (self->request_caps);
1747 self->request_caps = NULL;
1748 gst_caps_unref (new_caps);
1752 gst_object_unref (self);
1758 plugin_init (GstPlugin * plugin)
1760 GST_DEBUG_CATEGORY_INIT (deinterlace_debug, "deinterlace", 0, "Deinterlacer");
1764 if (!gst_element_register (plugin, "deinterlace", GST_RANK_NONE,
1765 GST_TYPE_DEINTERLACE)) {
1772 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1775 "Deinterlacer", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
1776 GST_PACKAGE_ORIGIN);