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"
49 GST_DEBUG_CATEGORY_STATIC (deinterlace_debug);
50 #define GST_CAT_DEFAULT (deinterlace_debug)
54 #define DEFAULT_MODE GST_DEINTERLACE_MODE_AUTO
55 #define DEFAULT_METHOD GST_DEINTERLACE_LINEAR
56 #define DEFAULT_FIELDS GST_DEINTERLACE_ALL
57 #define DEFAULT_FIELD_LAYOUT GST_DEINTERLACE_LAYOUT_AUTO
69 static const GEnumValue methods_types[] = {
70 {GST_DEINTERLACE_TOMSMOCOMP, "Motion Adaptive: Motion Search",
72 {GST_DEINTERLACE_GREEDY_H, "Motion Adaptive: Advanced Detection",
74 {GST_DEINTERLACE_GREEDY_L, "Motion Adaptive: Simple Detection", "greedyl"},
75 {GST_DEINTERLACE_VFIR, "Blur Vertical", "vfir"},
76 {GST_DEINTERLACE_LINEAR, "Television: Full resolution", "linear"},
77 {GST_DEINTERLACE_LINEAR_BLEND, "Blur: Temporal (Do Not Use)",
79 {GST_DEINTERLACE_SCALER_BOB, "Double lines", "scalerbob"},
80 {GST_DEINTERLACE_WEAVE, "Weave (Do Not Use)", "weave"},
81 {GST_DEINTERLACE_WEAVE_TFF, "Progressive: Top Field First (Do Not Use)",
83 {GST_DEINTERLACE_WEAVE_BFF, "Progressive: Bottom Field First (Do Not Use)",
89 #define GST_TYPE_DEINTERLACE_METHODS (gst_deinterlace_methods_get_type ())
91 gst_deinterlace_methods_get_type (void)
93 static GType deinterlace_methods_type = 0;
95 if (!deinterlace_methods_type) {
96 deinterlace_methods_type =
97 g_enum_register_static ("GstDeinterlaceMethods", methods_types);
99 return deinterlace_methods_type;
102 #define GST_TYPE_DEINTERLACE_FIELDS (gst_deinterlace_fields_get_type ())
104 gst_deinterlace_fields_get_type (void)
106 static GType deinterlace_fields_type = 0;
108 static const GEnumValue fields_types[] = {
109 {GST_DEINTERLACE_ALL, "All fields", "all"},
110 {GST_DEINTERLACE_TF, "Top fields only", "top"},
111 {GST_DEINTERLACE_BF, "Bottom fields only", "bottom"},
115 if (!deinterlace_fields_type) {
116 deinterlace_fields_type =
117 g_enum_register_static ("GstDeinterlaceFields", fields_types);
119 return deinterlace_fields_type;
122 #define GST_TYPE_DEINTERLACE_FIELD_LAYOUT (gst_deinterlace_field_layout_get_type ())
124 gst_deinterlace_field_layout_get_type (void)
126 static GType deinterlace_field_layout_type = 0;
128 static const GEnumValue field_layout_types[] = {
129 {GST_DEINTERLACE_LAYOUT_AUTO, "Auto detection", "auto"},
130 {GST_DEINTERLACE_LAYOUT_TFF, "Top field first", "tff"},
131 {GST_DEINTERLACE_LAYOUT_BFF, "Bottom field first", "bff"},
135 if (!deinterlace_field_layout_type) {
136 deinterlace_field_layout_type =
137 g_enum_register_static ("GstDeinterlaceFieldLayout",
140 return deinterlace_field_layout_type;
143 #define GST_TYPE_DEINTERLACE_MODES (gst_deinterlace_modes_get_type ())
145 gst_deinterlace_modes_get_type (void)
147 static GType deinterlace_modes_type = 0;
149 static const GEnumValue modes_types[] = {
150 {GST_DEINTERLACE_MODE_AUTO, "Auto detection", "auto"},
151 {GST_DEINTERLACE_MODE_INTERLACED, "Force deinterlacing", "interlaced"},
152 {GST_DEINTERLACE_MODE_DISABLED, "Run in passthrough mode", "disabled"},
156 if (!deinterlace_modes_type) {
157 deinterlace_modes_type =
158 g_enum_register_static ("GstDeinterlaceModes", modes_types);
160 return deinterlace_modes_type;
163 #define DEINTERLACE_CAPS \
164 GST_VIDEO_CAPS_YUV ("{ AYUV, Y444, YUY2, YVYU, UYVY, Y42B, I420, YV12, Y41B, NV12, NV21 }") ";" \
165 GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_ABGR ";" \
166 GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_BGRA ";" \
167 GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_xBGR ";" \
168 GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx ";" \
169 GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR
171 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
174 GST_STATIC_CAPS (DEINTERLACE_CAPS)
177 static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
180 GST_STATIC_CAPS (DEINTERLACE_CAPS)
183 static void gst_deinterlace_finalize (GObject * self);
184 static void gst_deinterlace_set_property (GObject * self, guint prop_id,
185 const GValue * value, GParamSpec * pspec);
186 static void gst_deinterlace_get_property (GObject * self, guint prop_id,
187 GValue * value, GParamSpec * pspec);
189 static GstCaps *gst_deinterlace_getcaps (GstPad * pad);
190 static gboolean gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps);
191 static gboolean gst_deinterlace_sink_event (GstPad * pad, GstEvent * event);
192 static gboolean gst_deinterlace_sink_query (GstPad * pad, GstQuery * query);
193 static GstFlowReturn gst_deinterlace_chain (GstPad * pad, GstBuffer * buffer);
194 static GstFlowReturn gst_deinterlace_alloc_buffer (GstPad * pad, guint64 offset,
195 guint size, GstCaps * caps, GstBuffer ** buf);
196 static GstStateChangeReturn gst_deinterlace_change_state (GstElement * element,
197 GstStateChange transition);
199 static gboolean gst_deinterlace_src_event (GstPad * pad, GstEvent * event);
200 static gboolean gst_deinterlace_src_query (GstPad * pad, GstQuery * query);
201 static const GstQueryType *gst_deinterlace_src_query_types (GstPad * pad);
203 static GstFlowReturn gst_deinterlace_output_frame (GstDeinterlace * self,
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);
293 /* If we get here we must have invalid caps! */
294 g_assert (method_type != G_TYPE_INVALID);
297 self->method = g_object_new (method_type, NULL);
298 self->method_id = method;
300 gst_object_set_name (GST_OBJECT (self->method), "method");
301 gst_object_set_parent (GST_OBJECT (self->method), GST_OBJECT (self));
302 gst_child_proxy_child_added (GST_OBJECT (self), GST_OBJECT (self->method));
305 gst_deinterlace_method_setup (self->method, self->format, self->width,
310 gst_deinterlace_clip_buffer (GstDeinterlace * self, GstBuffer * buffer)
313 GstClockTime start, stop;
314 gint64 cstart, cstop;
316 GST_DEBUG_OBJECT (self,
317 "Clipping buffer to the current segment: %" GST_TIME_FORMAT " -- %"
318 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
319 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
320 GST_DEBUG_OBJECT (self, "Current segment: %" GST_SEGMENT_FORMAT,
323 if (G_UNLIKELY (self->segment.format != GST_FORMAT_TIME))
325 if (G_UNLIKELY (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer)))
328 start = GST_BUFFER_TIMESTAMP (buffer);
329 stop = start + GST_BUFFER_DURATION (buffer);
331 if (!(ret = gst_segment_clip (&self->segment, GST_FORMAT_TIME,
332 start, stop, &cstart, &cstop)))
335 GST_BUFFER_TIMESTAMP (buffer) = cstart;
336 if (GST_CLOCK_TIME_IS_VALID (cstop))
337 GST_BUFFER_DURATION (buffer) = cstop - cstart;
341 GST_DEBUG_OBJECT (self,
342 "Clipped buffer to the current segment: %" GST_TIME_FORMAT " -- %"
343 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
344 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
346 GST_DEBUG_OBJECT (self, "Buffer outside the current segment -- dropping");
352 gst_deinterlace_base_init (gpointer klass)
354 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
356 gst_element_class_add_pad_template (element_class,
357 gst_static_pad_template_get (&src_templ));
358 gst_element_class_add_pad_template (element_class,
359 gst_static_pad_template_get (&sink_templ));
361 gst_element_class_set_details_simple (element_class,
363 "Filter/Effect/Video/Deinterlace",
364 "Deinterlace Methods ported from DScaler/TvTime",
365 "Martin Eikermann <meiker@upb.de>, "
366 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
370 gst_deinterlace_class_init (GstDeinterlaceClass * klass)
372 GObjectClass *gobject_class = (GObjectClass *) klass;
374 GstElementClass *element_class = (GstElementClass *) klass;
376 gobject_class->set_property = gst_deinterlace_set_property;
377 gobject_class->get_property = gst_deinterlace_get_property;
378 gobject_class->finalize = gst_deinterlace_finalize;
381 * GstDeinterlace:mode
383 * This selects whether the deinterlacing methods should
384 * always be applied or if they should only be applied
385 * on content that has the "interlaced" flag on the caps.
388 g_object_class_install_property (gobject_class, PROP_MODE,
389 g_param_spec_enum ("mode",
392 GST_TYPE_DEINTERLACE_MODES,
393 DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
397 * GstDeinterlace:method
399 * Selects the different deinterlacing algorithms that can be used.
400 * These provide different quality and CPU usage.
402 * Some methods provide parameters which can be set by getting
403 * the "method" child via the #GstChildProxy interface and
404 * setting the appropiate properties on it.
410 * Motion Adaptive: Motion Search
416 * Motion Adaptive: Advanced Detection
422 * Motion Adaptive: Simple Detection
434 * Linear interpolation
440 * Linear interpolation in time domain. Any motion causes significant
441 * ghosting, so this method should not be used.
453 * Weave. Bad quality, do not use.
459 * Progressive: Top Field First. Bad quality, do not use.
465 * Progressive: Bottom Field First. Bad quality, do not use.
470 g_object_class_install_property (gobject_class, PROP_METHOD,
471 g_param_spec_enum ("method",
473 "Deinterlace Method",
474 GST_TYPE_DEINTERLACE_METHODS,
475 DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
479 * GstDeinterlace:fields
481 * This selects which fields should be output. If "all" is selected
482 * the output framerate will be double.
485 g_object_class_install_property (gobject_class, PROP_FIELDS,
486 g_param_spec_enum ("fields",
488 "Fields to use for deinterlacing",
489 GST_TYPE_DEINTERLACE_FIELDS,
490 DEFAULT_FIELDS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
494 * GstDeinterlace:layout
496 * This selects which fields is the first in time.
499 g_object_class_install_property (gobject_class, PROP_FIELD_LAYOUT,
500 g_param_spec_enum ("tff",
502 "Deinterlace top field first",
503 GST_TYPE_DEINTERLACE_FIELD_LAYOUT,
504 DEFAULT_FIELD_LAYOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
507 element_class->change_state =
508 GST_DEBUG_FUNCPTR (gst_deinterlace_change_state);
512 gst_deinterlace_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
515 GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
517 g_return_val_if_fail (index == 0, NULL);
519 return gst_object_ref (self->method);
523 gst_deinterlace_child_proxy_get_children_count (GstChildProxy * child_proxy)
525 GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
527 return ((self->method) ? 1 : 0);
531 gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
534 GstChildProxyInterface *iface = g_iface;
536 iface->get_child_by_index = gst_deinterlace_child_proxy_get_child_by_index;
537 iface->get_children_count = gst_deinterlace_child_proxy_get_children_count;
541 gst_deinterlace_init (GstDeinterlace * self, GstDeinterlaceClass * klass)
543 self->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
544 gst_pad_set_chain_function (self->sinkpad,
545 GST_DEBUG_FUNCPTR (gst_deinterlace_chain));
546 gst_pad_set_event_function (self->sinkpad,
547 GST_DEBUG_FUNCPTR (gst_deinterlace_sink_event));
548 gst_pad_set_setcaps_function (self->sinkpad,
549 GST_DEBUG_FUNCPTR (gst_deinterlace_setcaps));
550 gst_pad_set_getcaps_function (self->sinkpad,
551 GST_DEBUG_FUNCPTR (gst_deinterlace_getcaps));
552 gst_pad_set_query_function (self->sinkpad,
553 GST_DEBUG_FUNCPTR (gst_deinterlace_sink_query));
554 gst_pad_set_bufferalloc_function (self->sinkpad,
555 GST_DEBUG_FUNCPTR (gst_deinterlace_alloc_buffer));
556 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
558 self->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
559 gst_pad_set_event_function (self->srcpad,
560 GST_DEBUG_FUNCPTR (gst_deinterlace_src_event));
561 gst_pad_set_query_type_function (self->srcpad,
562 GST_DEBUG_FUNCPTR (gst_deinterlace_src_query_types));
563 gst_pad_set_query_function (self->srcpad,
564 GST_DEBUG_FUNCPTR (gst_deinterlace_src_query));
565 gst_pad_set_getcaps_function (self->srcpad,
566 GST_DEBUG_FUNCPTR (gst_deinterlace_getcaps));
567 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
569 self->mode = DEFAULT_MODE;
570 self->user_set_method_id = DEFAULT_METHOD;
571 gst_deinterlace_set_method (self, self->user_set_method_id);
572 self->fields = DEFAULT_FIELDS;
573 self->field_layout = DEFAULT_FIELD_LAYOUT;
575 self->still_frame_mode = FALSE;
577 gst_deinterlace_reset (self);
581 gst_deinterlace_reset_history (GstDeinterlace * self, gboolean drop_all)
586 GST_DEBUG_OBJECT (self, "Flushing history (count %d)", self->history_count);
587 while (self->history_count > 0) {
588 if (gst_deinterlace_output_frame (self, TRUE) != GST_FLOW_OK) {
589 /* Encountered error, or flushing -> skip and drop all remaining */
596 GST_DEBUG_OBJECT (self, "Resetting history (count %d)",
597 self->history_count);
599 for (i = 0; i < self->history_count; i++) {
600 if (self->field_history[i].buf) {
601 gst_buffer_unref (self->field_history[i].buf);
602 self->field_history[i].buf = NULL;
606 memset (self->field_history, 0,
607 GST_DEINTERLACE_MAX_FIELD_HISTORY * sizeof (GstDeinterlaceField));
608 self->history_count = 0;
610 if (!self->still_frame_mode && self->last_buffer) {
611 gst_buffer_unref (self->last_buffer);
612 self->last_buffer = NULL;
617 gst_deinterlace_update_passthrough (GstDeinterlace * self)
619 self->passthrough = (self->mode == GST_DEINTERLACE_MODE_DISABLED
620 || (!self->interlaced && self->mode != GST_DEINTERLACE_MODE_INTERLACED));
621 GST_DEBUG_OBJECT (self, "Passthrough: %d", self->passthrough);
625 gst_deinterlace_reset (GstDeinterlace * self)
627 GST_DEBUG_OBJECT (self, "Resetting internal state");
629 self->format = GST_VIDEO_FORMAT_UNKNOWN;
632 self->frame_size = 0;
633 self->fps_n = self->fps_d = 0;
634 self->passthrough = FALSE;
636 self->reconfigure = FALSE;
637 if (self->new_mode != -1)
638 self->mode = self->new_mode;
639 if (self->new_fields != -1)
640 self->fields = self->new_fields;
642 self->new_fields = -1;
644 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
646 if (self->request_caps)
647 gst_caps_unref (self->request_caps);
648 self->request_caps = NULL;
650 gst_deinterlace_reset_history (self, TRUE);
652 gst_deinterlace_reset_qos (self);
656 gst_deinterlace_set_property (GObject * object, guint prop_id,
657 const GValue * value, GParamSpec * pspec)
659 GstDeinterlace *self;
661 g_return_if_fail (GST_IS_DEINTERLACE (object));
662 self = GST_DEINTERLACE (object);
668 GST_OBJECT_LOCK (self);
669 new_mode = g_value_get_enum (value);
670 if (self->mode != new_mode && GST_PAD_CAPS (self->srcpad)) {
671 self->reconfigure = TRUE;
672 self->new_mode = new_mode;
674 self->mode = new_mode;
675 gst_deinterlace_update_passthrough (self);
677 GST_OBJECT_UNLOCK (self);
681 self->user_set_method_id = g_value_get_enum (value);
682 gst_deinterlace_set_method (self, self->user_set_method_id);
687 GST_OBJECT_LOCK (self);
688 new_fields = g_value_get_enum (value);
689 if (self->fields != new_fields && GST_PAD_CAPS (self->srcpad)) {
690 self->reconfigure = TRUE;
691 self->new_fields = new_fields;
693 self->fields = new_fields;
695 GST_OBJECT_UNLOCK (self);
698 case PROP_FIELD_LAYOUT:
699 self->field_layout = g_value_get_enum (value);
702 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
708 gst_deinterlace_get_property (GObject * object, guint prop_id,
709 GValue * value, GParamSpec * pspec)
711 GstDeinterlace *self;
713 g_return_if_fail (GST_IS_DEINTERLACE (object));
714 self = GST_DEINTERLACE (object);
718 g_value_set_enum (value, self->mode);
721 g_value_set_enum (value, self->user_set_method_id);
724 g_value_set_enum (value, self->fields);
726 case PROP_FIELD_LAYOUT:
727 g_value_set_enum (value, self->field_layout);
730 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
735 gst_deinterlace_finalize (GObject * object)
737 GstDeinterlace *self = GST_DEINTERLACE (object);
739 gst_deinterlace_reset (self);
742 gst_object_unparent (GST_OBJECT (self->method));
746 G_OBJECT_CLASS (parent_class)->finalize (object);
750 gst_deinterlace_pop_history (GstDeinterlace * self)
754 g_return_val_if_fail (self->history_count > 0, NULL);
756 GST_DEBUG_OBJECT (self, "Pop last history buffer -- current history size %d",
757 self->history_count);
759 buffer = self->field_history[self->history_count - 1].buf;
761 self->history_count--;
763 GST_DEBUG_OBJECT (self, "Returning buffer: %p %" GST_TIME_FORMAT
764 " with duration %" GST_TIME_FORMAT " and size %u", buffer,
765 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
766 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer));
772 gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer)
775 GstClockTime timestamp;
776 GstDeinterlaceFieldLayout field_layout = self->field_layout;
777 gboolean repeated = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_RFF);
778 gboolean tff = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_TFF);
780 GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_ONEFIELD);
781 GstBuffer *field1, *field2;
782 guint fields_to_push = (onefield) ? 1 : (!repeated) ? 2 : 3;
783 gint field1_flags, field2_flags;
785 g_return_if_fail (self->history_count <
786 GST_DEINTERLACE_MAX_FIELD_HISTORY - fields_to_push);
788 GST_DEBUG_OBJECT (self, "Pushing new buffer to the history: %" GST_TIME_FORMAT
789 " with duration %" GST_TIME_FORMAT " and size %u",
790 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
791 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_BUFFER_SIZE (buffer));
793 for (i = GST_DEINTERLACE_MAX_FIELD_HISTORY - 1; i >= fields_to_push; i--) {
794 self->field_history[i].buf = self->field_history[i - fields_to_push].buf;
795 self->field_history[i].flags =
796 self->field_history[i - fields_to_push].flags;
799 if (field_layout == GST_DEINTERLACE_LAYOUT_AUTO) {
800 if (!self->interlaced) {
801 GST_WARNING_OBJECT (self, "Can't detect field layout -- assuming TFF");
802 field_layout = GST_DEINTERLACE_LAYOUT_TFF;
804 field_layout = GST_DEINTERLACE_LAYOUT_TFF;
806 field_layout = GST_DEINTERLACE_LAYOUT_BFF;
810 if (field_layout == GST_DEINTERLACE_LAYOUT_TFF) {
811 GST_DEBUG_OBJECT (self, "Top field first");
812 field1 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
813 field1_flags = PICTURE_INTERLACED_TOP;
814 field2 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
815 field2_flags = PICTURE_INTERLACED_BOTTOM;
817 GST_DEBUG_OBJECT (self, "Bottom field first");
818 field1 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
819 field1_flags = PICTURE_INTERLACED_BOTTOM;
820 field2 = gst_buffer_make_metadata_writable (gst_buffer_ref (buffer));
821 field2_flags = PICTURE_INTERLACED_TOP;
824 /* Timestamps are assigned to the field buffers under the assumption that
825 the timestamp of the buffer equals the first fields timestamp */
827 timestamp = GST_BUFFER_TIMESTAMP (buffer);
828 GST_BUFFER_TIMESTAMP (field1) = timestamp;
829 GST_BUFFER_TIMESTAMP (field2) = timestamp + self->field_duration;
832 self->field_history[2].buf = field1;
833 self->field_history[2].flags = field1_flags;
835 self->field_history[1].buf = field2;
836 self->field_history[1].flags = field2_flags;
838 self->field_history[0].buf =
839 gst_buffer_make_metadata_writable (gst_buffer_ref (field1));
840 GST_BUFFER_TIMESTAMP (self->field_history[0].buf) +=
841 2 * self->field_duration;
842 self->field_history[0].flags = field1_flags;
843 } else if (!onefield) {
844 self->field_history[1].buf = field1;
845 self->field_history[1].flags = field1_flags;
847 self->field_history[0].buf = field2;
848 self->field_history[0].flags = field2_flags;
849 } else { /* onefield */
850 self->field_history[0].buf = field1;
851 self->field_history[0].flags = field1_flags;
852 gst_buffer_unref (field2);
855 self->history_count += fields_to_push;
857 GST_DEBUG_OBJECT (self, "Pushed buffer -- current history size %d",
858 self->history_count);
860 if (self->last_buffer)
861 gst_buffer_unref (self->last_buffer);
862 self->last_buffer = buffer;
866 gst_deinterlace_update_qos (GstDeinterlace * self, gdouble proportion,
867 GstClockTimeDiff diff, GstClockTime timestamp)
869 GST_DEBUG_OBJECT (self,
870 "Updating QoS: proportion %lf, diff %s%" GST_TIME_FORMAT ", timestamp %"
871 GST_TIME_FORMAT, proportion, (diff < 0) ? "-" : "",
872 GST_TIME_ARGS (ABS (diff)), GST_TIME_ARGS (timestamp));
874 GST_OBJECT_LOCK (self);
875 self->proportion = proportion;
876 if (G_LIKELY (timestamp != GST_CLOCK_TIME_NONE)) {
877 if (G_UNLIKELY (diff > 0))
878 self->earliest_time =
879 timestamp + 2 * diff + ((self->fields ==
880 GST_DEINTERLACE_ALL) ? self->field_duration : 2 *
881 self->field_duration);
883 self->earliest_time = timestamp + diff;
885 self->earliest_time = GST_CLOCK_TIME_NONE;
887 GST_OBJECT_UNLOCK (self);
891 gst_deinterlace_reset_qos (GstDeinterlace * self)
893 gst_deinterlace_update_qos (self, 0.5, 0, GST_CLOCK_TIME_NONE);
897 gst_deinterlace_read_qos (GstDeinterlace * self, gdouble * proportion,
900 GST_OBJECT_LOCK (self);
901 *proportion = self->proportion;
902 *time = self->earliest_time;
903 GST_OBJECT_UNLOCK (self);
906 /* Perform qos calculations before processing the next frame. Returns TRUE if
907 * the frame should be processed, FALSE if the frame can be dropped entirely */
909 gst_deinterlace_do_qos (GstDeinterlace * self, GstClockTime timestamp)
911 GstClockTime qostime, earliest_time;
914 /* no timestamp, can't do QoS => process frame */
915 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) {
916 GST_LOG_OBJECT (self, "invalid timestamp, can't do QoS, process frame");
920 /* get latest QoS observation values */
921 gst_deinterlace_read_qos (self, &proportion, &earliest_time);
923 /* skip qos if we have no observation (yet) => process frame */
924 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) {
925 GST_LOG_OBJECT (self, "no observation yet, process frame");
929 /* qos is done on running time */
930 qostime = gst_segment_to_running_time (&self->segment, GST_FORMAT_TIME,
933 /* see how our next timestamp relates to the latest qos timestamp */
934 GST_LOG_OBJECT (self, "qostime %" GST_TIME_FORMAT ", earliest %"
935 GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
937 if (qostime != GST_CLOCK_TIME_NONE && qostime <= earliest_time) {
938 GST_DEBUG_OBJECT (self, "we are late, drop frame");
942 GST_LOG_OBJECT (self, "process frame");
947 gst_deinterlace_output_frame (GstDeinterlace * self, gboolean flushing)
949 GstClockTime timestamp;
950 GstFlowReturn ret = GST_FLOW_OK;
951 gint fields_required = 0;
952 gint cur_field_idx = 0;
953 GstBuffer *buf, *outbuf;
955 gst_deinterlace_set_method (self, self->user_set_method_id);
956 fields_required = gst_deinterlace_method_get_fields_required (self->method);
958 if (self->history_count < fields_required) {
960 /* FIXME: if there are any methods implemented that output different
961 * dimensions (e.g. half height) that require more than one field of
962 * history, it is desirable to degrade to something that outputs
963 * half-height also */
964 gst_deinterlace_set_method (self,
965 self->history_count >= 2 ?
966 GST_DEINTERLACE_VFIR : GST_DEINTERLACE_LINEAR);
968 gst_deinterlace_method_get_fields_required (self->method);
969 GST_DEBUG_OBJECT (self, "Flushing field(s) using %s method",
970 methods_types[self->method_id].value_nick);
972 /* Not enough fields in the history */
973 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
974 self->history_count, fields_required);
979 while (self->history_count >= fields_required) {
980 if (self->fields == GST_DEINTERLACE_ALL)
981 GST_DEBUG_OBJECT (self, "All fields");
982 else if (self->fields == GST_DEINTERLACE_TF)
983 GST_DEBUG_OBJECT (self, "Top fields");
984 else if (self->fields == GST_DEINTERLACE_BF)
985 GST_DEBUG_OBJECT (self, "Bottom fields");
987 cur_field_idx = self->history_count - fields_required;
989 if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_TOP
990 && self->fields == GST_DEINTERLACE_TF) ||
991 self->fields == GST_DEINTERLACE_ALL) {
992 GST_DEBUG_OBJECT (self, "deinterlacing top field");
994 /* create new buffer */
996 gst_pad_alloc_buffer (self->srcpad, GST_BUFFER_OFFSET_NONE,
997 self->frame_size, GST_PAD_CAPS (self->srcpad), &outbuf);
998 if (ret != GST_FLOW_OK)
1001 if (GST_PAD_CAPS (self->srcpad) != GST_BUFFER_CAPS (outbuf)
1002 && !gst_caps_is_equal (GST_PAD_CAPS (self->srcpad),
1003 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, GST_PAD_CAPS (self->srcpad));
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 */
1076 gst_pad_alloc_buffer (self->srcpad, GST_BUFFER_OFFSET_NONE,
1077 self->frame_size, GST_PAD_CAPS (self->srcpad), &outbuf);
1078 if (ret != GST_FLOW_OK)
1081 if (GST_PAD_CAPS (self->srcpad) != GST_BUFFER_CAPS (outbuf)
1082 && !gst_caps_is_equal (GST_PAD_CAPS (self->srcpad),
1083 GST_BUFFER_CAPS (outbuf))) {
1084 gst_caps_replace (&self->request_caps, GST_BUFFER_CAPS (outbuf));
1085 GST_DEBUG_OBJECT (self, "Upstream wants new caps %" GST_PTR_FORMAT,
1086 self->request_caps);
1088 gst_buffer_unref (outbuf);
1089 outbuf = gst_buffer_try_new_and_alloc (self->frame_size);
1092 return GST_FLOW_ERROR;
1094 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
1097 g_return_val_if_fail (self->history_count - 1 -
1098 gst_deinterlace_method_get_latency (self->method) >= 0,
1102 self->field_history[self->history_count - 1 -
1103 gst_deinterlace_method_get_latency (self->method)].buf;
1104 timestamp = GST_BUFFER_TIMESTAMP (buf);
1106 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1107 if (self->fields == GST_DEINTERLACE_ALL)
1108 GST_BUFFER_DURATION (outbuf) = self->field_duration;
1110 GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
1112 /* Check if we need to drop the frame because of QoS */
1113 if (!gst_deinterlace_do_qos (self, GST_BUFFER_TIMESTAMP (buf))) {
1114 gst_buffer_unref (gst_deinterlace_pop_history (self));
1115 gst_buffer_unref (outbuf);
1119 /* do magic calculus */
1120 gst_deinterlace_method_deinterlace_frame (self->method,
1121 self->field_history, self->history_count, outbuf);
1123 gst_buffer_unref (gst_deinterlace_pop_history (self));
1125 if (gst_deinterlace_clip_buffer (self, outbuf)) {
1126 ret = gst_pad_push (self->srcpad, outbuf);
1129 gst_buffer_unref (outbuf);
1133 if (ret != GST_FLOW_OK)
1137 /* no calculation done: remove excess field */
1138 else if (self->field_history[cur_field_idx].flags ==
1139 PICTURE_INTERLACED_BOTTOM && self->fields == GST_DEINTERLACE_TF) {
1140 GST_DEBUG_OBJECT (self, "Removing unused bottom field");
1141 gst_buffer_unref (gst_deinterlace_pop_history (self));
1148 static GstFlowReturn
1149 gst_deinterlace_chain (GstPad * pad, GstBuffer * buf)
1151 GstDeinterlace *self = GST_DEINTERLACE (GST_PAD_PARENT (pad));
1153 GST_OBJECT_LOCK (self);
1154 if (self->reconfigure) {
1155 if (self->new_fields != -1)
1156 self->fields = self->new_fields;
1157 if (self->new_mode != -1)
1158 self->mode = self->new_mode;
1159 self->new_mode = self->new_fields = -1;
1161 self->reconfigure = FALSE;
1162 GST_OBJECT_UNLOCK (self);
1163 if (GST_PAD_CAPS (self->srcpad))
1164 gst_deinterlace_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad));
1166 GST_OBJECT_UNLOCK (self);
1169 if (self->still_frame_mode || self->passthrough)
1170 return gst_pad_push (self->srcpad, buf);
1172 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
1173 GST_DEBUG_OBJECT (self, "DISCONT buffer, resetting history");
1174 gst_deinterlace_reset_history (self, FALSE);
1177 gst_deinterlace_push_history (self, buf);
1180 return gst_deinterlace_output_frame (self, FALSE);
1184 gst_greatest_common_divisor (gint a, gint b)
1197 gst_fraction_double (gint * n_out, gint * d_out, gboolean half)
1207 if (n == 0 || (n == G_MAXINT && d == 1))
1210 gcd = gst_greatest_common_divisor (n, d);
1215 if (G_MAXINT / 2 >= ABS (n)) {
1217 } else if (d >= 2) {
1223 if (G_MAXINT / 2 >= ABS (d)) {
1225 } else if (n >= 2) {
1239 gst_deinterlace_getcaps (GstPad * pad)
1242 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1245 const GstCaps *ourcaps;
1248 GST_OBJECT_LOCK (self);
1250 otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad;
1252 ourcaps = gst_pad_get_pad_template_caps (pad);
1253 peercaps = gst_pad_peer_get_caps (otherpad);
1256 GST_DEBUG_OBJECT (pad, "Peer has caps %" GST_PTR_FORMAT, peercaps);
1257 ret = gst_caps_intersect (ourcaps, peercaps);
1258 gst_caps_unref (peercaps);
1260 ret = gst_caps_copy (ourcaps);
1263 GST_OBJECT_UNLOCK (self);
1265 for (len = gst_caps_get_size (ret); len > 0; len--) {
1266 GstStructure *s = gst_caps_get_structure (ret, len - 1);
1268 if (pad == self->sinkpad || self->passthrough)
1269 gst_structure_remove_field (s, "interlaced");
1271 gst_structure_set (s, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL);
1273 if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) {
1276 val = gst_structure_get_value (s, "framerate");
1280 if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION) {
1283 n = gst_value_get_fraction_numerator (val);
1284 d = gst_value_get_fraction_denominator (val);
1286 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
1290 gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
1291 } else if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION_RANGE) {
1292 const GValue *min, *max;
1293 GValue nrange = { 0, }, nmin = {
1298 g_value_init (&nrange, GST_TYPE_FRACTION_RANGE);
1299 g_value_init (&nmin, GST_TYPE_FRACTION);
1300 g_value_init (&nmax, GST_TYPE_FRACTION);
1302 min = gst_value_get_fraction_range_min (val);
1303 max = gst_value_get_fraction_range_max (val);
1305 n = gst_value_get_fraction_numerator (min);
1306 d = gst_value_get_fraction_denominator (min);
1308 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
1309 g_value_unset (&nrange);
1310 g_value_unset (&nmax);
1311 g_value_unset (&nmin);
1315 gst_value_set_fraction (&nmin, n, d);
1317 n = gst_value_get_fraction_numerator (max);
1318 d = gst_value_get_fraction_denominator (max);
1320 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
1321 g_value_unset (&nrange);
1322 g_value_unset (&nmax);
1323 g_value_unset (&nmin);
1327 gst_value_set_fraction (&nmax, n, d);
1328 gst_value_set_fraction_range (&nrange, &nmin, &nmax);
1330 gst_structure_set_value (s, "framerate", &nrange);
1332 g_value_unset (&nmin);
1333 g_value_unset (&nmax);
1334 g_value_unset (&nrange);
1335 } else if (G_VALUE_TYPE (val) == GST_TYPE_LIST) {
1337 GValue nlist = { 0, };
1338 GValue nval = { 0, };
1341 g_value_init (&nlist, GST_TYPE_LIST);
1342 for (i = gst_value_list_get_size (val); i > 0; i--) {
1345 lval = gst_value_list_get_value (val, i);
1347 if (G_VALUE_TYPE (lval) != GST_TYPE_FRACTION)
1350 n = gst_value_get_fraction_numerator (lval);
1351 d = gst_value_get_fraction_denominator (lval);
1353 /* Double/Half the framerate but if this fails simply
1354 * skip this value from the list */
1355 if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
1359 g_value_init (&nval, GST_TYPE_FRACTION);
1361 gst_value_set_fraction (&nval, n, d);
1362 gst_value_list_append_value (&nlist, &nval);
1363 g_value_unset (&nval);
1365 gst_structure_set_value (s, "framerate", &nlist);
1366 g_value_unset (&nlist);
1371 GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret);
1373 gst_object_unref (self);
1378 GST_ERROR_OBJECT (pad, "Unable to transform peer caps");
1379 gst_caps_unref (ret);
1384 gst_deinterlace_setcaps (GstPad * pad, GstCaps * caps)
1386 gboolean res = TRUE;
1387 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1391 gst_video_format_parse_caps (caps, &self->format, &self->width,
1393 res &= gst_video_parse_caps_framerate (caps, &self->fps_n, &self->fps_d);
1394 if (pad == self->sinkpad)
1395 res &= gst_video_format_parse_caps_interlaced (caps, &self->interlaced);
1399 gst_deinterlace_update_passthrough (self);
1401 if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) {
1402 gint fps_n = self->fps_n, fps_d = self->fps_d;
1404 if (!gst_fraction_double (&fps_n, &fps_d, FALSE))
1407 srccaps = gst_caps_copy (caps);
1409 gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, fps_n,
1412 srccaps = gst_caps_ref (caps);
1415 if (self->mode != GST_DEINTERLACE_MODE_DISABLED) {
1416 srccaps = gst_caps_make_writable (srccaps);
1417 gst_caps_set_simple (srccaps, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL);
1420 gst_deinterlace_reset_history (self, FALSE);
1422 if (!gst_pad_set_caps (self->srcpad, srccaps))
1423 goto caps_not_accepted;
1426 gst_video_format_get_size (self->format, self->width, self->height);
1428 if (G_LIKELY (self->fps_n != 0)) {
1429 self->field_duration =
1430 gst_util_uint64_scale (GST_SECOND, self->fps_d, 2 * self->fps_n);
1432 self->field_duration = 0;
1435 gst_deinterlace_set_method (self, self->method_id);
1436 gst_deinterlace_method_setup (self->method, self->format, self->width,
1439 GST_DEBUG_OBJECT (pad, "Sink caps: %" GST_PTR_FORMAT, caps);
1440 GST_DEBUG_OBJECT (pad, "Src caps: %" GST_PTR_FORMAT, srccaps);
1442 gst_caps_unref (srccaps);
1446 gst_object_unref (self);
1451 GST_ERROR_OBJECT (pad, "Invalid caps: %" GST_PTR_FORMAT, caps);
1456 GST_ERROR_OBJECT (pad, "Caps not accepted: %" GST_PTR_FORMAT, srccaps);
1457 gst_caps_unref (srccaps);
1462 gst_deinterlace_sink_event (GstPad * pad, GstEvent * event)
1464 gboolean res = TRUE;
1465 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1467 GST_LOG_OBJECT (pad, "received %s event: %" GST_PTR_FORMAT,
1468 GST_EVENT_TYPE_NAME (event), event);
1470 switch (GST_EVENT_TYPE (event)) {
1471 case GST_EVENT_NEWSEGMENT:
1475 gint64 start, end, base;
1476 gdouble rate, applied_rate;
1478 gst_event_parse_new_segment_full (event, &is_update, &rate, &applied_rate,
1479 &fmt, &start, &end, &base);
1481 gst_deinterlace_reset_qos (self);
1482 gst_deinterlace_reset_history (self, FALSE);
1484 if (fmt == GST_FORMAT_TIME) {
1485 GST_DEBUG_OBJECT (pad,
1486 "Got NEWSEGMENT event in GST_FORMAT_TIME, passing on (%"
1487 GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")", GST_TIME_ARGS (start),
1488 GST_TIME_ARGS (end));
1489 gst_segment_set_newsegment_full (&self->segment, is_update, rate,
1490 applied_rate, fmt, start, end, base);
1492 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1495 res = gst_pad_push_event (self->srcpad, event);
1498 case GST_EVENT_CUSTOM_DOWNSTREAM:{
1499 gboolean still_state;
1501 if (gst_video_event_parse_still_frame (event, &still_state)) {
1502 GST_DEBUG_OBJECT (self, "Received still frame event, state %d",
1508 GST_DEBUG_OBJECT (self, "Handling still frame");
1509 self->still_frame_mode = TRUE;
1510 gst_deinterlace_reset_history (self, FALSE);
1511 if (self->last_buffer) {
1513 gst_pad_push (self->srcpad, gst_buffer_ref (self->last_buffer));
1514 GST_DEBUG_OBJECT (self, "Pushed still frame, result: %s",
1515 gst_flow_get_name (ret));
1517 GST_WARNING_OBJECT (self, "No pending buffer!");
1520 GST_DEBUG_OBJECT (self, "Ending still frames");
1521 self->still_frame_mode = FALSE;
1527 gst_deinterlace_reset_history (self, FALSE);
1531 res = gst_pad_push_event (self->srcpad, event);
1534 case GST_EVENT_FLUSH_STOP:
1535 if (self->still_frame_mode) {
1536 GST_DEBUG_OBJECT (self, "Ending still frames");
1537 self->still_frame_mode = FALSE;
1539 gst_deinterlace_reset_qos (self);
1540 res = gst_pad_push_event (self->srcpad, event);
1541 gst_deinterlace_reset_history (self, TRUE);
1545 gst_object_unref (self);
1550 gst_deinterlace_sink_query (GstPad * pad, GstQuery * query)
1552 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1553 gboolean res = FALSE;
1555 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
1557 switch (GST_QUERY_TYPE (query)) {
1559 GstPad *peer = gst_pad_get_peer (self->srcpad);
1562 res = gst_pad_query (peer, query);
1563 gst_object_unref (peer);
1571 gst_object_unref (self);
1575 static GstStateChangeReturn
1576 gst_deinterlace_change_state (GstElement * element, GstStateChange transition)
1578 GstStateChangeReturn ret;
1579 GstDeinterlace *self = GST_DEINTERLACE (element);
1581 switch (transition) {
1582 case GST_STATE_CHANGE_NULL_TO_READY:
1584 case GST_STATE_CHANGE_READY_TO_PAUSED:
1586 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1592 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1593 if (ret != GST_STATE_CHANGE_SUCCESS)
1596 switch (transition) {
1597 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1599 case GST_STATE_CHANGE_PAUSED_TO_READY:
1600 gst_deinterlace_reset (self);
1602 case GST_STATE_CHANGE_READY_TO_NULL:
1611 gst_deinterlace_src_event (GstPad * pad, GstEvent * event)
1613 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1616 GST_DEBUG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
1618 switch (GST_EVENT_TYPE (event)) {
1619 case GST_EVENT_QOS:{
1620 GstClockTimeDiff diff;
1621 GstClockTime timestamp;
1624 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
1626 gst_deinterlace_update_qos (self, proportion, diff, timestamp);
1630 res = gst_pad_push_event (self->sinkpad, event);
1634 gst_object_unref (self);
1640 gst_deinterlace_src_query (GstPad * pad, GstQuery * query)
1642 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1643 gboolean res = FALSE;
1645 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
1647 switch (GST_QUERY_TYPE (query)) {
1648 case GST_QUERY_LATENCY:
1649 if (!self->passthrough) {
1650 GstClockTime min, max;
1654 if ((peer = gst_pad_get_peer (self->sinkpad))) {
1655 if ((res = gst_pad_query (peer, query))) {
1656 GstClockTime latency;
1657 gint fields_required = 0;
1658 gint method_latency = 0;
1662 gst_deinterlace_method_get_fields_required (self->method);
1664 gst_deinterlace_method_get_latency (self->method);
1667 gst_query_parse_latency (query, &live, &min, &max);
1669 GST_DEBUG_OBJECT (self, "Peer latency: min %"
1670 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
1671 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
1673 /* add our own latency */
1674 latency = (fields_required + method_latency) * self->field_duration;
1676 GST_DEBUG_OBJECT (self, "Our latency: min %" GST_TIME_FORMAT
1677 ", max %" GST_TIME_FORMAT,
1678 GST_TIME_ARGS (latency), GST_TIME_ARGS (latency));
1681 if (max != GST_CLOCK_TIME_NONE)
1684 GST_DEBUG_OBJECT (self, "Calculated total latency : min %"
1685 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
1686 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
1688 gst_query_set_latency (query, live, min, max);
1690 gst_object_unref (peer);
1697 GstPad *peer = gst_pad_get_peer (self->sinkpad);
1700 res = gst_pad_query (peer, query);
1701 gst_object_unref (peer);
1709 gst_object_unref (self);
1713 static const GstQueryType *
1714 gst_deinterlace_src_query_types (GstPad * pad)
1716 static const GstQueryType types[] = {
1723 static GstFlowReturn
1724 gst_deinterlace_alloc_buffer (GstPad * pad, guint64 offset, guint size,
1725 GstCaps * caps, GstBuffer ** buf)
1727 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
1728 GstFlowReturn ret = GST_FLOW_OK;
1732 GST_DEBUG_OBJECT (pad, "alloc with caps %" GST_PTR_FORMAT ", size %u", caps,
1735 if (self->still_frame_mode || self->passthrough) {
1736 ret = gst_pad_alloc_buffer (self->srcpad, offset, size, caps, buf);
1737 } else if (G_LIKELY (!self->request_caps)) {
1738 *buf = gst_buffer_try_new_and_alloc (size);
1739 if (G_UNLIKELY (!*buf)) {
1740 ret = GST_FLOW_ERROR;
1742 gst_buffer_set_caps (*buf, caps);
1743 GST_BUFFER_OFFSET (*buf) = offset;
1748 guint new_frame_size;
1749 GstCaps *new_caps = gst_caps_copy (self->request_caps);
1751 if (self->fields == GST_DEINTERLACE_ALL) {
1753 GstStructure *s = gst_caps_get_structure (new_caps, 0);
1755 gst_structure_get_fraction (s, "framerate", &n, &d);
1757 if (!gst_fraction_double (&n, &d, TRUE)) {
1758 gst_object_unref (self);
1759 gst_caps_unref (new_caps);
1763 gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
1766 if (G_UNLIKELY (!gst_video_format_parse_caps (new_caps, &fmt, &width,
1768 gst_object_unref (self);
1769 gst_caps_unref (new_caps);
1773 new_frame_size = gst_video_format_get_size (fmt, width, height);
1775 *buf = gst_buffer_try_new_and_alloc (new_frame_size);
1776 if (G_UNLIKELY (!*buf)) {
1777 ret = GST_FLOW_ERROR;
1779 gst_buffer_set_caps (*buf, new_caps);
1780 gst_caps_unref (self->request_caps);
1781 self->request_caps = NULL;
1782 gst_caps_unref (new_caps);
1786 gst_object_unref (self);
1792 plugin_init (GstPlugin * plugin)
1794 GST_DEBUG_CATEGORY_INIT (deinterlace_debug, "deinterlace", 0, "Deinterlacer");
1800 if (!gst_element_register (plugin, "deinterlace", GST_RANK_NONE,
1801 GST_TYPE_DEINTERLACE)) {
1808 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1811 "Deinterlacer", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
1812 GST_PACKAGE_ORIGIN);