3 * Copyright (C) 2005 Martin Eikermann <meiker@upb.de>
4 * Copyright (C) 2008-2010 Sebastian Dröge <slomo@collabora.co.uk>
5 * Copyright (C) 2011 Robert Swain <robert.swain@collabora.co.uk>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
24 * SECTION:element-deinterlace
26 * deinterlace deinterlaces interlaced video frames to progressive video frames.
27 * For this different algorithms can be selected which will be described later.
30 * <title>Example launch line</title>
32 * gst-launch-1.0 -v filesrc location=/path/to/file ! decodebin2 ! videoconvert ! deinterlace ! videoconvert ! autovideosink
33 * ]| This pipeline deinterlaces a video file with the default deinterlacing options.
37 /* FIXME PORTING 0.11:
38 * - getcaps/setcaps stuff needs revisiting
39 * - reconfiguration needs to be done differently
40 * - bufferalloc -> buffer pool/alloc query
47 #include "gstdeinterlace.h"
48 #include "tvtime/plugins.h"
56 GST_DEBUG_CATEGORY_STATIC (deinterlace_debug);
57 #define GST_CAT_DEFAULT (deinterlace_debug)
61 #define DEFAULT_MODE GST_DEINTERLACE_MODE_AUTO
62 #define DEFAULT_METHOD GST_DEINTERLACE_LINEAR
63 #define DEFAULT_FIELDS GST_DEINTERLACE_ALL
64 #define DEFAULT_FIELD_LAYOUT GST_DEINTERLACE_LAYOUT_AUTO
65 #define DEFAULT_LOCKING GST_DEINTERLACE_LOCKING_NONE
66 #define DEFAULT_IGNORE_OBSCURE TRUE
67 #define DEFAULT_DROP_ORPHANS TRUE
82 #define GST_DEINTERLACE_BUFFER_STATE_P (1<<0)
83 #define GST_DEINTERLACE_BUFFER_STATE_I (1<<1)
84 #define GST_DEINTERLACE_BUFFER_STATE_TC_B (1<<2)
85 #define GST_DEINTERLACE_BUFFER_STATE_TC_T (1<<3)
86 #define GST_DEINTERLACE_BUFFER_STATE_TC_P (1<<4)
87 #define GST_DEINTERLACE_BUFFER_STATE_TC_M (1<<5)
88 #define GST_DEINTERLACE_BUFFER_STATE_RFF (1<<6)
91 (GST_DEINTERLACE_BUFFER_STATE_TC_T | GST_DEINTERLACE_BUFFER_STATE_TC_B)
93 (GST_DEINTERLACE_BUFFER_STATE_P | GST_DEINTERLACE_BUFFER_STATE_TC_P)
95 (GST_DEINTERLACE_BUFFER_STATE_I | GST_DEINTERLACE_BUFFER_STATE_TC_M)
96 #define GST_RFF (GST_DEINTERLACE_BUFFER_STATE_RFF)
98 #define GST_DEINTERLACE_OBSCURE_THRESHOLD 5
100 static const TelecinePattern telecine_patterns[] = {
101 /* 60i -> 60p or 50i -> 50p (NOTE THE WEIRD RATIOS) */
102 {"1:1", 1, 2, 1, {GST_ONE,}},
103 /* 60i -> 30p or 50i -> 25p */
104 {"2:2", 1, 1, 1, {GST_INT,}},
105 /* 60i telecine -> 24p */
106 {"2:3-RFF", 4, 4, 5, {GST_PRG, GST_RFF, GST_PRG, GST_RFF,}},
107 {"2:3", 5, 4, 5, {GST_PRG, GST_PRG, GST_ONE, GST_ONE, GST_PRG,}},
108 {"3:2:2:3-RFF", 4, 4, 5, {GST_RFF, GST_PRG, GST_PRG, GST_RFF,}},
109 {"3:2:2:3", 5, 4, 5, {GST_PRG, GST_ONE, GST_INT, GST_ONE, GST_PRG,}},
110 /* fieldanalysis should indicate this using RFF on the second and fourth
111 * buffers and not send the third buffer at all. it will be identified as
113 /* {"2:3:3:2", 5, 4, 5, {GST_PRG, GST_PRG, GST_DRP, GST_PRG, GST_PRG,}}, */
115 /* The following patterns are obscure and are ignored if ignore-obscure is
116 * set to true. If any patterns are added above this line, check and edit
117 * GST_DEINTERLACE_OBSCURE_THRESHOLD */
119 /* 50i Euro pulldown -> 24p */
120 {"2-11:3", 25, 24, 25, {GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_PRG,
121 GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_PRG,
122 GST_PRG, GST_PRG, GST_ONE, GST_INT, GST_INT,
123 GST_INT, GST_INT, GST_INT, GST_INT, GST_INT,
124 GST_INT, GST_INT, GST_INT, GST_ONE, GST_PRG,}},
126 /* haven't figured out how fieldanalysis should handle these yet */
127 /* 60i (NTSC 30000/1001) -> 16p (16000/1001) */
128 {"3:4-3", 15, 8, 15, {GST_PRG, GST_DRP, GST_PRG, GST_DRP, GST_PRG,
129 GST_DRP, GST_PRG, GST_DRP, GST_PRG, GST_DRP,
130 GST_PRG, GST_DRP, GST_PRG, GST_DRP, GST_PRG,}},
131 /* 50i (PAL) -> 16p */
132 {"3-7:4", 25, 16, 25, {GST_PRG, GST_DRP, GST_PRG, GST_PRG, GST_DRP,
133 GST_PRG, GST_PRG, GST_DRP, GST_PRG, GST_PRG,
134 GST_DRP, GST_PRG, GST_DRP, GST_PRG, GST_PRG,
135 GST_DRP, GST_PRG, GST_PRG, GST_DRP, GST_PRG,
136 GST_PRG, GST_DRP, GST_PRG, GST_PRG, GST_DRP,}},
137 /* NTSC 60i -> 18p */
138 {"3:3:4", 5, 3, 5, {GST_PRG, GST_DRP, GST_PRG, GST_DRP, GST_PRG,}},
139 /* NTSC 60i -> 20p */
140 {"3:3", 3, 2, 3, {GST_PRG, GST_DRP, GST_PRG,}},
142 /* NTSC 60i -> 27.5 */
143 {"3:2-4", 11, 10, 11, {GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_PRG,
144 GST_PRG, GST_ONE, GST_INT, GST_INT, GST_INT,
146 /* PAL 50i -> 27.5 */
147 {"1:2-4", 9, 9, 10, {GST_PRG, GST_PRG, GST_PRG, GST_PRG, GST_INT,
148 GST_INT, GST_INT, GST_INT, GST_INT,}},
151 static const GEnumValue methods_types[] = {
152 {GST_DEINTERLACE_TOMSMOCOMP, "Motion Adaptive: Motion Search",
154 {GST_DEINTERLACE_GREEDY_H, "Motion Adaptive: Advanced Detection",
156 {GST_DEINTERLACE_GREEDY_L, "Motion Adaptive: Simple Detection", "greedyl"},
157 {GST_DEINTERLACE_VFIR, "Blur Vertical", "vfir"},
158 {GST_DEINTERLACE_LINEAR, "Television: Full resolution", "linear"},
159 {GST_DEINTERLACE_LINEAR_BLEND, "Blur: Temporal (Do Not Use)",
161 {GST_DEINTERLACE_SCALER_BOB, "Double lines", "scalerbob"},
162 {GST_DEINTERLACE_WEAVE, "Weave (Do Not Use)", "weave"},
163 {GST_DEINTERLACE_WEAVE_TFF, "Progressive: Top Field First (Do Not Use)",
165 {GST_DEINTERLACE_WEAVE_BFF, "Progressive: Bottom Field First (Do Not Use)",
170 static const GEnumValue locking_types[] = {
171 {GST_DEINTERLACE_LOCKING_NONE,
172 "No pattern locking", "none"},
173 {GST_DEINTERLACE_LOCKING_AUTO,
174 "Choose passive/active locking depending on whether upstream is live",
176 {GST_DEINTERLACE_LOCKING_ACTIVE,
177 "Block until pattern-locked. Use accurate timestamp interpolation within a pattern repeat.",
179 {GST_DEINTERLACE_LOCKING_PASSIVE,
180 "Do not block. Use naïve timestamp adjustment until pattern-locked based on state history.",
186 #define GST_TYPE_DEINTERLACE_METHODS (gst_deinterlace_methods_get_type ())
188 gst_deinterlace_methods_get_type (void)
190 static GType deinterlace_methods_type = 0;
192 if (!deinterlace_methods_type) {
193 deinterlace_methods_type =
194 g_enum_register_static ("GstDeinterlaceMethods", methods_types);
196 return deinterlace_methods_type;
199 #define GST_TYPE_DEINTERLACE_FIELDS (gst_deinterlace_fields_get_type ())
201 gst_deinterlace_fields_get_type (void)
203 static GType deinterlace_fields_type = 0;
205 static const GEnumValue fields_types[] = {
206 {GST_DEINTERLACE_ALL, "All fields", "all"},
207 {GST_DEINTERLACE_TF, "Top fields only", "top"},
208 {GST_DEINTERLACE_BF, "Bottom fields only", "bottom"},
212 if (!deinterlace_fields_type) {
213 deinterlace_fields_type =
214 g_enum_register_static ("GstDeinterlaceFields", fields_types);
216 return deinterlace_fields_type;
219 #define GST_TYPE_DEINTERLACE_FIELD_LAYOUT (gst_deinterlace_field_layout_get_type ())
221 gst_deinterlace_field_layout_get_type (void)
223 static GType deinterlace_field_layout_type = 0;
225 static const GEnumValue field_layout_types[] = {
226 {GST_DEINTERLACE_LAYOUT_AUTO, "Auto detection", "auto"},
227 {GST_DEINTERLACE_LAYOUT_TFF, "Top field first", "tff"},
228 {GST_DEINTERLACE_LAYOUT_BFF, "Bottom field first", "bff"},
232 if (!deinterlace_field_layout_type) {
233 deinterlace_field_layout_type =
234 g_enum_register_static ("GstDeinterlaceFieldLayout",
237 return deinterlace_field_layout_type;
240 #define GST_TYPE_DEINTERLACE_MODES (gst_deinterlace_modes_get_type ())
242 gst_deinterlace_modes_get_type (void)
244 static GType deinterlace_modes_type = 0;
246 static const GEnumValue modes_types[] = {
247 {GST_DEINTERLACE_MODE_AUTO, "Auto detection", "auto"},
248 {GST_DEINTERLACE_MODE_INTERLACED, "Force deinterlacing", "interlaced"},
249 {GST_DEINTERLACE_MODE_DISABLED, "Run in passthrough mode", "disabled"},
253 if (!deinterlace_modes_type) {
254 deinterlace_modes_type =
255 g_enum_register_static ("GstDeinterlaceModes", modes_types);
257 return deinterlace_modes_type;
260 #define GST_TYPE_DEINTERLACE_LOCKING (gst_deinterlace_locking_get_type ())
262 gst_deinterlace_locking_get_type (void)
264 static GType deinterlace_locking_type = 0;
266 if (!deinterlace_locking_type) {
267 deinterlace_locking_type =
268 g_enum_register_static ("GstDeinterlaceLocking", locking_types);
271 return deinterlace_locking_type;
274 #define DEINTERLACE_VIDEO_FORMATS \
275 "{ AYUV, ARGB, ABGR, RGBA, BGRA, Y444, xRGB, xBGR, RGBx, BGRx, RGB, " \
276 "BGR, YUY2, YVYU, UYVY, Y42B, I420, YV12, Y41B, NV12, NV21 }"
278 #define DEINTERLACE_CAPS GST_VIDEO_CAPS_MAKE(DEINTERLACE_VIDEO_FORMATS)
280 #define DEINTERLACE_ALL_CAPS DEINTERLACE_CAPS ";" \
281 GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY", GST_VIDEO_FORMATS_ALL)
283 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
286 GST_STATIC_CAPS (DEINTERLACE_ALL_CAPS)
289 static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
292 GST_STATIC_CAPS (DEINTERLACE_ALL_CAPS)
295 static void gst_deinterlace_finalize (GObject * self);
296 static void gst_deinterlace_set_property (GObject * self, guint prop_id,
297 const GValue * value, GParamSpec * pspec);
298 static void gst_deinterlace_get_property (GObject * self, guint prop_id,
299 GValue * value, GParamSpec * pspec);
301 static GstCaps *gst_deinterlace_getcaps (GstDeinterlace * self, GstPad * pad,
303 static gboolean gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad,
305 static gboolean gst_deinterlace_sink_event (GstPad * pad, GstObject * parent,
307 static gboolean gst_deinterlace_sink_query (GstPad * pad, GstObject * parent,
309 static GstFlowReturn gst_deinterlace_chain (GstPad * pad, GstObject * parent,
311 static GstStateChangeReturn gst_deinterlace_change_state (GstElement * element,
312 GstStateChange transition);
313 static gboolean gst_deinterlace_set_allocation (GstDeinterlace * self,
314 GstBufferPool * pool, GstAllocator * allocator,
315 GstAllocationParams * params);
317 static gboolean gst_deinterlace_src_event (GstPad * pad, GstObject * parent,
319 static gboolean gst_deinterlace_src_query (GstPad * pad, GstObject * parent,
322 static GstFlowReturn gst_deinterlace_output_frame (GstDeinterlace * self,
324 static void gst_deinterlace_reset (GstDeinterlace * self);
325 static void gst_deinterlace_update_qos (GstDeinterlace * self,
326 gdouble proportion, GstClockTimeDiff diff, GstClockTime time);
327 static void gst_deinterlace_reset_qos (GstDeinterlace * self);
328 static void gst_deinterlace_read_qos (GstDeinterlace * self,
329 gdouble * proportion, GstClockTime * time);
331 #define IS_TELECINE(m) ((m) == GST_VIDEO_INTERLACE_MODE_MIXED && self->pattern > 1)
333 /* FIXME: what's the point of the childproxy interface here? What can you
334 * actually do with it? The method objects seem to have no properties */
336 static void gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
337 gpointer iface_data);
340 _do_init (GType object_type)
342 const GInterfaceInfo child_proxy_interface_info = {
343 (GInterfaceInitFunc) gst_deinterlace_child_proxy_interface_init,
344 NULL, /* interface_finalize */
345 NULL /* interface_data */
348 g_type_add_interface_static (object_type, GST_TYPE_CHILD_PROXY,
349 &child_proxy_interface_info);
353 G_DEFINE_TYPE (GstDeinterlace, gst_deinterlace, GST_TYPE_ELEMENT);
355 #define parent_class gst_deinterlace_parent_class
359 GType (*get_type) (void);
360 } _method_types[] = {
362 gst_deinterlace_method_tomsmocomp_get_type}, {
363 gst_deinterlace_method_greedy_h_get_type}, {
364 gst_deinterlace_method_greedy_l_get_type}, {
365 gst_deinterlace_method_vfir_get_type}, {
366 gst_deinterlace_method_linear_get_type}, {
367 gst_deinterlace_method_linear_blend_get_type}, {
368 gst_deinterlace_method_scaler_bob_get_type}, {
369 gst_deinterlace_method_weave_get_type}, {
370 gst_deinterlace_method_weave_tff_get_type}, {
371 gst_deinterlace_method_weave_bff_get_type}
375 gst_deinterlace_set_method (GstDeinterlace * self, GstDeinterlaceMethods method)
379 GstVideoFormat format;
381 GST_DEBUG_OBJECT (self, "Setting new method %d", method);
383 width = GST_VIDEO_INFO_WIDTH (&self->vinfo);
384 height = GST_VIDEO_INFO_HEIGHT (&self->vinfo);
385 format = GST_VIDEO_INFO_FORMAT (&self->vinfo);
388 if (self->method_id == method &&
389 gst_deinterlace_method_supported (G_TYPE_FROM_INSTANCE (self->method),
390 format, width, height)) {
391 GST_DEBUG_OBJECT (self, "Reusing current method");
395 gst_child_proxy_child_removed (GST_OBJECT (self),
396 GST_OBJECT (self->method));
397 gst_object_unparent (GST_OBJECT (self->method));
403 _method_types[method].get_type !=
404 NULL ? _method_types[method].get_type () : G_TYPE_INVALID;
405 if (method_type == G_TYPE_INVALID
406 || !gst_deinterlace_method_supported (method_type, format,
411 method_type = G_TYPE_INVALID;
413 GST_WARNING_OBJECT (self, "Method doesn't support requested format");
414 for (i = 0; i < G_N_ELEMENTS (_method_types); i++) {
415 if (_method_types[i].get_type == NULL)
417 tmp = _method_types[i].get_type ();
418 if (gst_deinterlace_method_supported (tmp, format, width, height)) {
419 GST_DEBUG_OBJECT (self, "Using method %d", i);
425 /* If we get here we must have invalid caps! */
426 g_assert (method_type != G_TYPE_INVALID);
429 self->method = g_object_new (method_type, "name", "method", NULL);
430 self->method_id = method;
432 gst_object_set_parent (GST_OBJECT (self->method), GST_OBJECT (self));
434 gst_child_proxy_child_added (GST_OBJECT (self), GST_OBJECT (self->method));
438 gst_deinterlace_method_setup (self->method, &self->vinfo);
442 gst_deinterlace_clip_buffer (GstDeinterlace * self, GstBuffer * buffer)
445 GstClockTime start, stop;
446 guint64 cstart, cstop;
448 GST_DEBUG_OBJECT (self,
449 "Clipping buffer to the current segment: %" GST_TIME_FORMAT " -- %"
450 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
451 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
452 GST_DEBUG_OBJECT (self, "Current segment: %" GST_SEGMENT_FORMAT,
455 if (G_UNLIKELY (self->segment.format != GST_FORMAT_TIME))
457 if (G_UNLIKELY (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer)))
460 start = GST_BUFFER_TIMESTAMP (buffer);
461 stop = start + GST_BUFFER_DURATION (buffer);
463 if (!(ret = gst_segment_clip (&self->segment, GST_FORMAT_TIME,
464 start, stop, &cstart, &cstop)))
467 GST_BUFFER_TIMESTAMP (buffer) = cstart;
468 if (GST_CLOCK_TIME_IS_VALID (cstop))
469 GST_BUFFER_DURATION (buffer) = cstop - cstart;
473 GST_DEBUG_OBJECT (self,
474 "Clipped buffer to the current segment: %" GST_TIME_FORMAT " -- %"
475 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
476 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
478 GST_DEBUG_OBJECT (self, "Buffer outside the current segment -- dropping");
484 gst_deinterlace_class_init (GstDeinterlaceClass * klass)
486 GObjectClass *gobject_class = (GObjectClass *) klass;
488 GstElementClass *element_class = (GstElementClass *) klass;
490 gst_element_class_add_pad_template (element_class,
491 gst_static_pad_template_get (&src_templ));
492 gst_element_class_add_pad_template (element_class,
493 gst_static_pad_template_get (&sink_templ));
495 gst_element_class_set_static_metadata (element_class,
497 "Filter/Effect/Video/Deinterlace",
498 "Deinterlace Methods ported from DScaler/TvTime",
499 "Martin Eikermann <meiker@upb.de>, "
500 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
502 gobject_class->set_property = gst_deinterlace_set_property;
503 gobject_class->get_property = gst_deinterlace_get_property;
504 gobject_class->finalize = gst_deinterlace_finalize;
507 * GstDeinterlace:mode:
509 * This selects whether the deinterlacing methods should
510 * always be applied or if they should only be applied
511 * on content that has the "interlaced" flag on the caps.
513 g_object_class_install_property (gobject_class, PROP_MODE,
514 g_param_spec_enum ("mode",
517 GST_TYPE_DEINTERLACE_MODES,
518 DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
522 * GstDeinterlace:method:
524 * Selects the different deinterlacing algorithms that can be used.
525 * These provide different quality and CPU usage.
527 * Some methods provide parameters which can be set by getting
528 * the "method" child via the #GstChildProxy interface and
529 * setting the appropiate properties on it.
535 * Motion Adaptive: Motion Search
541 * Motion Adaptive: Advanced Detection
547 * Motion Adaptive: Simple Detection
559 * Linear interpolation
565 * Linear interpolation in time domain. Any motion causes significant
566 * ghosting, so this method should not be used.
578 * Weave. Bad quality, do not use.
584 * Progressive: Top Field First. Bad quality, do not use.
590 * Progressive: Bottom Field First. Bad quality, do not use.
595 g_object_class_install_property (gobject_class, PROP_METHOD,
596 g_param_spec_enum ("method",
598 "Deinterlace Method",
599 GST_TYPE_DEINTERLACE_METHODS,
600 DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
604 * GstDeinterlace:fields:
606 * This selects which fields should be output. If "all" is selected
607 * the output framerate will be double.
609 g_object_class_install_property (gobject_class, PROP_FIELDS,
610 g_param_spec_enum ("fields",
612 "Fields to use for deinterlacing",
613 GST_TYPE_DEINTERLACE_FIELDS,
614 DEFAULT_FIELDS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
618 * GstDeinterlace:layout:
620 * This selects which fields is the first in time.
623 g_object_class_install_property (gobject_class, PROP_FIELD_LAYOUT,
624 g_param_spec_enum ("tff",
626 "Deinterlace top field first",
627 GST_TYPE_DEINTERLACE_FIELD_LAYOUT,
628 DEFAULT_FIELD_LAYOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
632 * GstDeinterlace:locking:
634 * This selects which approach to pattern locking is used which affects
635 * processing latency and accuracy of timestamp adjustment for telecine
638 g_object_class_install_property (gobject_class, PROP_LOCKING,
639 g_param_spec_enum ("locking", "locking", "Pattern locking mode",
640 GST_TYPE_DEINTERLACE_LOCKING, DEFAULT_LOCKING,
641 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
644 * GstDeinterlace:ignore-obscure:
646 * This selects whether to ignore obscure/rare telecine patterns.
647 * NTSC 2:3 pulldown variants are the only really common patterns.
649 g_object_class_install_property (gobject_class, PROP_IGNORE_OBSCURE,
650 g_param_spec_boolean ("ignore-obscure", "ignore-obscure",
651 "Ignore obscure telecine patterns (only consider P, I and 2:3 "
652 "variants).", DEFAULT_IGNORE_OBSCURE,
653 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
656 * GstDeinterlace:drop-orphans:
658 * This selects whether to drop orphan fields at the beginning of telecine
659 * patterns in active locking mode.
661 g_object_class_install_property (gobject_class, PROP_DROP_ORPHANS,
662 g_param_spec_boolean ("drop-orphans", "drop-orphans",
663 "Drop orphan fields at the beginning of telecine patterns in "
664 "active locking mode.", DEFAULT_DROP_ORPHANS,
665 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
667 element_class->change_state =
668 GST_DEBUG_FUNCPTR (gst_deinterlace_change_state);
673 gst_deinterlace_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
676 GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
678 g_return_val_if_fail (index == 0, NULL);
680 return gst_object_ref (self->method);
684 gst_deinterlace_child_proxy_get_children_count (GstChildProxy * child_proxy)
686 GstDeinterlace *self = GST_DEINTERLACE (child_proxy);
688 return ((self->method) ? 1 : 0);
692 gst_deinterlace_child_proxy_interface_init (gpointer g_iface,
695 GstChildProxyInterface *iface = g_iface;
697 iface->get_child_by_index = gst_deinterlace_child_proxy_get_child_by_index;
698 iface->get_children_count = gst_deinterlace_child_proxy_get_children_count;
703 gst_deinterlace_init (GstDeinterlace * self)
705 self->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
706 gst_pad_set_chain_function (self->sinkpad,
707 GST_DEBUG_FUNCPTR (gst_deinterlace_chain));
708 gst_pad_set_event_function (self->sinkpad,
709 GST_DEBUG_FUNCPTR (gst_deinterlace_sink_event));
710 gst_pad_set_query_function (self->sinkpad,
711 GST_DEBUG_FUNCPTR (gst_deinterlace_sink_query));
712 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
714 self->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
715 gst_pad_set_event_function (self->srcpad,
716 GST_DEBUG_FUNCPTR (gst_deinterlace_src_event));
717 gst_pad_set_query_function (self->srcpad,
718 GST_DEBUG_FUNCPTR (gst_deinterlace_src_query));
719 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
721 self->mode = DEFAULT_MODE;
722 self->user_set_method_id = DEFAULT_METHOD;
723 gst_video_info_init (&self->vinfo);
724 gst_deinterlace_set_method (self, self->user_set_method_id);
725 self->fields = DEFAULT_FIELDS;
726 self->field_layout = DEFAULT_FIELD_LAYOUT;
727 self->locking = DEFAULT_LOCKING;
728 self->ignore_obscure = DEFAULT_IGNORE_OBSCURE;
729 self->drop_orphans = DEFAULT_DROP_ORPHANS;
731 self->low_latency = -1;
733 self->pattern_phase = -1;
734 self->pattern_count = 0;
735 self->output_count = 0;
736 self->pattern_base_ts = GST_CLOCK_TIME_NONE;
737 self->pattern_buf_dur = GST_CLOCK_TIME_NONE;
738 self->still_frame_mode = FALSE;
740 gst_deinterlace_reset (self);
743 static GstVideoFrame *
744 gst_video_frame_new_and_map (GstVideoInfo * vinfo, GstBuffer * buffer,
747 GstVideoFrame *frame = g_malloc0 (sizeof (GstVideoFrame));
748 gst_video_frame_map (frame, vinfo, buffer, flags);
753 gst_video_frame_unmap_and_free (GstVideoFrame * frame)
755 gst_video_frame_unmap (frame);
760 gst_deinterlace_reset_history (GstDeinterlace * self, gboolean drop_all)
765 GST_DEBUG_OBJECT (self, "Flushing history (count %d)", self->history_count);
766 while (self->history_count > 0) {
767 if (gst_deinterlace_output_frame (self, TRUE) != GST_FLOW_OK) {
768 /* Encountered error, or flushing -> skip and drop all remaining */
775 GST_DEBUG_OBJECT (self, "Resetting history (count %d)",
776 self->history_count);
778 for (i = 0; i < self->history_count; i++) {
779 if (self->field_history[i].frame) {
780 gst_video_frame_unmap_and_free (self->field_history[i].frame);
781 self->field_history[i].frame = NULL;
785 memset (self->field_history, 0,
786 GST_DEINTERLACE_MAX_FIELD_HISTORY * sizeof (GstDeinterlaceField));
787 self->history_count = 0;
788 memset (self->buf_states, 0,
789 GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY *
790 sizeof (GstDeinterlaceBufferState));
791 self->state_count = 0;
792 self->pattern_lock = FALSE;
793 self->pattern_refresh = TRUE;
794 self->cur_field_idx = -1;
796 if (!self->still_frame_mode && self->last_buffer) {
797 gst_buffer_unref (self->last_buffer);
798 self->last_buffer = NULL;
803 gst_deinterlace_update_passthrough (GstDeinterlace * self)
805 if (self->mode == GST_DEINTERLACE_MODE_DISABLED)
806 self->passthrough = TRUE;
807 else if (!GST_VIDEO_INFO_IS_INTERLACED (&self->vinfo)
808 && self->mode != GST_DEINTERLACE_MODE_INTERLACED)
809 self->passthrough = TRUE;
811 self->passthrough = FALSE;
813 GST_DEBUG_OBJECT (self, "Passthrough: %d", self->passthrough);
817 gst_deinterlace_reset (GstDeinterlace * self)
819 GST_DEBUG_OBJECT (self, "Resetting internal state");
821 gst_video_info_init (&self->vinfo);
823 self->passthrough = FALSE;
825 self->reconfigure = FALSE;
826 if ((gint) self->new_mode != -1)
827 self->mode = self->new_mode;
828 if ((gint) self->new_fields != -1)
829 self->fields = self->new_fields;
831 self->new_fields = -1;
833 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
835 if (self->request_caps)
836 gst_caps_unref (self->request_caps);
837 self->request_caps = NULL;
839 gst_deinterlace_reset_history (self, TRUE);
841 gst_deinterlace_reset_qos (self);
843 self->need_more = FALSE;
844 self->have_eos = FALSE;
846 gst_deinterlace_set_allocation (self, NULL, NULL, NULL);
850 gst_deinterlace_set_property (GObject * object, guint prop_id,
851 const GValue * value, GParamSpec * pspec)
853 GstDeinterlace *self;
855 self = GST_DEINTERLACE (object);
861 GST_OBJECT_LOCK (self);
862 new_mode = g_value_get_enum (value);
863 /* FIXME: reconfiguration should probably be done differently */
864 if (self->mode != new_mode && gst_pad_has_current_caps (self->srcpad)) {
865 self->reconfigure = TRUE;
866 self->new_mode = new_mode;
868 self->mode = new_mode;
869 gst_deinterlace_update_passthrough (self);
871 GST_OBJECT_UNLOCK (self);
875 self->user_set_method_id = g_value_get_enum (value);
876 gst_deinterlace_set_method (self, self->user_set_method_id);
881 GST_OBJECT_LOCK (self);
882 new_fields = g_value_get_enum (value);
883 /* FIXME: reconfiguration should probably be done differently */
884 if (self->fields != new_fields && gst_pad_has_current_caps (self->srcpad)) {
885 self->reconfigure = TRUE;
886 self->new_fields = new_fields;
888 self->fields = new_fields;
890 GST_OBJECT_UNLOCK (self);
893 case PROP_FIELD_LAYOUT:
894 self->field_layout = g_value_get_enum (value);
897 self->locking = g_value_get_enum (value);
899 case PROP_IGNORE_OBSCURE:
900 self->ignore_obscure = g_value_get_boolean (value);
902 case PROP_DROP_ORPHANS:
903 self->drop_orphans = g_value_get_boolean (value);
906 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
912 gst_deinterlace_get_property (GObject * object, guint prop_id,
913 GValue * value, GParamSpec * pspec)
915 GstDeinterlace *self;
917 self = GST_DEINTERLACE (object);
921 g_value_set_enum (value, self->mode);
924 g_value_set_enum (value, self->user_set_method_id);
927 g_value_set_enum (value, self->fields);
929 case PROP_FIELD_LAYOUT:
930 g_value_set_enum (value, self->field_layout);
933 g_value_set_enum (value, self->locking);
935 case PROP_IGNORE_OBSCURE:
936 g_value_set_boolean (value, self->ignore_obscure);
938 case PROP_DROP_ORPHANS:
939 g_value_set_boolean (value, self->drop_orphans);
942 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
947 gst_deinterlace_finalize (GObject * object)
949 GstDeinterlace *self = GST_DEINTERLACE (object);
951 gst_deinterlace_reset (self);
954 gst_object_unparent (GST_OBJECT (self->method));
958 G_OBJECT_CLASS (parent_class)->finalize (object);
962 gst_deinterlace_update_pattern_timestamps (GstDeinterlace * self)
965 if (self->low_latency) {
966 /* in low-latency mode the buffer state history contains old buffer
967 * states as well as the current one and perhaps some future ones.
968 * the current buffer's state is given by the number of field pairs
969 * rounded up, minus 1. the below is equivalent */
970 state_idx = (self->history_count - 1) >> 1;
972 /* in high-latency mode state_count - 1 is the current buffer's state */
973 state_idx = self->state_count - 1;
976 self->pattern_base_ts = self->buf_states[state_idx].timestamp;
977 if (self->buf_states[state_idx].state != GST_RFF) {
978 self->pattern_buf_dur =
979 (self->buf_states[state_idx].duration *
980 telecine_patterns[self->pattern].ratio_d) /
981 telecine_patterns[self->pattern].ratio_n;
983 self->pattern_buf_dur =
984 (self->buf_states[state_idx].duration *
985 telecine_patterns[self->pattern].ratio_d * 2) /
986 (telecine_patterns[self->pattern].ratio_n * 3);
988 GST_DEBUG_OBJECT (self,
989 "Starting a new pattern repeat with base ts %" GST_TIME_FORMAT
990 " and dur %" GST_TIME_FORMAT, GST_TIME_ARGS (self->pattern_base_ts),
991 GST_TIME_ARGS (self->pattern_buf_dur));
994 static GstVideoFrame *
995 gst_deinterlace_pop_history (GstDeinterlace * self)
997 GstVideoFrame *frame;
999 g_return_val_if_fail (self->history_count > 0, NULL);
1001 GST_DEBUG_OBJECT (self, "Pop last history frame -- current history size %d",
1002 self->history_count);
1004 frame = self->field_history[self->history_count - 1].frame;
1006 self->history_count--;
1007 if (self->locking != GST_DEINTERLACE_LOCKING_NONE && (!self->history_count
1008 || GST_VIDEO_FRAME_PLANE_DATA (frame, 0) !=
1009 GST_VIDEO_FRAME_PLANE_DATA (self->field_history[self->history_count -
1011 if (!self->low_latency)
1012 self->state_count--;
1013 if (self->pattern_lock) {
1014 self->pattern_count++;
1015 if (self->pattern != -1
1016 && self->pattern_count >= telecine_patterns[self->pattern].length) {
1017 self->pattern_count = 0;
1018 self->output_count = 0;
1023 GST_DEBUG_OBJECT (self, "Returning frame: %p %" GST_TIME_FORMAT
1024 " with duration %" GST_TIME_FORMAT " and size %" G_GSIZE_FORMAT, frame,
1025 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (frame->buffer)),
1026 GST_TIME_ARGS (GST_BUFFER_DURATION (frame->buffer)),
1027 GST_VIDEO_FRAME_SIZE (frame));
1033 gst_deinterlace_get_buffer_state (GstDeinterlace * self, GstVideoFrame * frame,
1034 guint8 * state, GstVideoInterlaceMode * i_mode)
1036 GstVideoInterlaceMode interlacing_mode;
1038 if (!(i_mode || state))
1041 interlacing_mode = GST_VIDEO_INFO_INTERLACE_MODE (&frame->info);
1042 if (self->mode == GST_DEINTERLACE_MODE_INTERLACED)
1043 interlacing_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
1046 if (interlacing_mode == GST_VIDEO_INTERLACE_MODE_MIXED) {
1047 if (GST_VIDEO_FRAME_IS_RFF (frame)) {
1048 *state = GST_DEINTERLACE_BUFFER_STATE_RFF;
1049 } else if (GST_VIDEO_FRAME_IS_ONEFIELD (frame)) {
1050 /* tc top if tff, tc bottom otherwise */
1051 if (GST_VIDEO_FRAME_IS_TFF (frame)) {
1052 *state = GST_DEINTERLACE_BUFFER_STATE_TC_T;
1054 *state = GST_DEINTERLACE_BUFFER_STATE_TC_B;
1056 } else if (GST_VIDEO_FRAME_IS_INTERLACED (frame)) {
1057 *state = GST_DEINTERLACE_BUFFER_STATE_TC_M;
1059 *state = GST_DEINTERLACE_BUFFER_STATE_TC_P;
1062 if (interlacing_mode == GST_VIDEO_INTERLACE_MODE_INTERLEAVED) {
1063 *state = GST_DEINTERLACE_BUFFER_STATE_I;
1065 *state = GST_DEINTERLACE_BUFFER_STATE_P;
1071 *i_mode = interlacing_mode;
1074 #define STATE_TO_STRING(s) ((s) == GST_DEINTERLACE_BUFFER_STATE_P ? "P" : \
1075 (s) == GST_DEINTERLACE_BUFFER_STATE_I ? "I" : \
1076 (s) == GST_DEINTERLACE_BUFFER_STATE_TC_B ? "B" : \
1077 (s) == GST_DEINTERLACE_BUFFER_STATE_TC_T ? "T" : \
1078 (s) == GST_DEINTERLACE_BUFFER_STATE_TC_P ? "TCP" : \
1079 (s) == GST_DEINTERLACE_BUFFER_STATE_TC_M ? "TCM" : "RFF")
1081 #define MODE_TO_STRING(m) ((m) == GST_VIDEO_INTERLACE_MODE_MIXED ? "MIXED" : \
1082 (m) == GST_VIDEO_INTERLACE_MODE_INTERLEAVED ? "I" : \
1083 (m) == GST_VIDEO_INTERLACE_MODE_FIELDS ? "FIELDS" : "P")
1086 gst_deinterlace_push_history (GstDeinterlace * self, GstBuffer * buffer)
1089 GstDeinterlaceFieldLayout field_layout = self->field_layout;
1092 GstVideoFrame *frame = NULL;
1093 GstVideoFrame *field1, *field2 = NULL;
1094 guint fields_to_push;
1095 gint field1_flags, field2_flags;
1096 GstVideoInterlaceMode interlacing_mode;
1099 /* we will only read from this buffer and write into fresh output buffers
1100 * if this is not the case, change the map flags as appropriate
1102 frame = gst_video_frame_new_and_map (&self->vinfo, buffer, GST_MAP_READ);
1103 /* we can manage the buffer ref count using the maps from here on */
1104 gst_buffer_unref (buffer);
1106 tff = GST_VIDEO_FRAME_IS_TFF (frame);
1107 onefield = GST_VIDEO_FRAME_IS_ONEFIELD (frame);
1108 fields_to_push = (onefield) ? 1 : 2;
1110 g_return_if_fail (self->history_count <
1111 GST_DEINTERLACE_MAX_FIELD_HISTORY - fields_to_push);
1113 gst_deinterlace_get_buffer_state (self, frame, &buf_state, &interlacing_mode);
1115 GST_DEBUG_OBJECT (self,
1116 "Pushing new frame as %d fields to the history (count before %d): ptr %p at %"
1117 GST_TIME_FORMAT " with duration %" GST_TIME_FORMAT
1118 ", size %" G_GSIZE_FORMAT ", state %s, interlacing mode %s",
1119 fields_to_push, self->history_count, frame,
1120 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
1121 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
1122 gst_buffer_get_size (buffer),
1123 STATE_TO_STRING (buf_state), MODE_TO_STRING (interlacing_mode));
1125 /* move up for new state */
1126 memmove (&self->buf_states[1], &self->buf_states[0],
1127 (GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY - 1) *
1128 sizeof (GstDeinterlaceBufferState));
1129 self->buf_states[0].state = buf_state;
1130 self->buf_states[0].timestamp = GST_BUFFER_TIMESTAMP (buffer);
1131 self->buf_states[0].duration = GST_BUFFER_DURATION (buffer);
1132 if (self->state_count < GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY)
1133 self->state_count++;
1135 for (i = GST_DEINTERLACE_MAX_FIELD_HISTORY - 1; i >= fields_to_push; i--) {
1136 self->field_history[i].frame =
1137 self->field_history[i - fields_to_push].frame;
1138 self->field_history[i].flags =
1139 self->field_history[i - fields_to_push].flags;
1142 if (field_layout == GST_DEINTERLACE_LAYOUT_AUTO) {
1143 if (!GST_VIDEO_INFO_IS_INTERLACED (&self->vinfo)) {
1144 GST_WARNING_OBJECT (self, "Can't detect field layout -- assuming TFF");
1145 field_layout = GST_DEINTERLACE_LAYOUT_TFF;
1147 field_layout = GST_DEINTERLACE_LAYOUT_TFF;
1149 field_layout = GST_DEINTERLACE_LAYOUT_BFF;
1154 field2 = gst_video_frame_new_and_map (&self->vinfo, buffer, GST_MAP_READ);
1155 if (field_layout == GST_DEINTERLACE_LAYOUT_TFF) {
1156 GST_DEBUG_OBJECT (self, "Top field first");
1157 field1_flags = PICTURE_INTERLACED_TOP;
1158 field2_flags = PICTURE_INTERLACED_BOTTOM;
1160 GST_DEBUG_OBJECT (self, "Bottom field first");
1161 field1_flags = PICTURE_INTERLACED_BOTTOM;
1162 field2_flags = PICTURE_INTERLACED_TOP;
1166 GST_DEBUG_OBJECT (self, "Two fields");
1167 self->field_history[1].frame = field1;
1168 self->field_history[1].flags = field1_flags;
1170 self->field_history[0].frame = field2;
1171 self->field_history[0].flags = field2_flags;
1172 } else { /* onefield */
1173 GST_DEBUG_OBJECT (self, "One field");
1174 self->field_history[0].frame = field1;
1175 self->field_history[0].flags = field1_flags;
1176 gst_video_frame_unmap_and_free (field2);
1179 self->history_count += fields_to_push;
1180 self->cur_field_idx += fields_to_push;
1182 GST_DEBUG_OBJECT (self, "Pushed buffer -- current history size %d, index %d",
1183 self->history_count, self->cur_field_idx);
1185 if (self->last_buffer)
1186 gst_buffer_unref (self->last_buffer);
1187 self->last_buffer = gst_buffer_ref (buffer);
1191 gst_deinterlace_update_qos (GstDeinterlace * self, gdouble proportion,
1192 GstClockTimeDiff diff, GstClockTime timestamp)
1194 GST_DEBUG_OBJECT (self,
1195 "Updating QoS: proportion %lf, diff %s%" GST_TIME_FORMAT ", timestamp %"
1196 GST_TIME_FORMAT, proportion, (diff < 0) ? "-" : "",
1197 GST_TIME_ARGS (ABS (diff)), GST_TIME_ARGS (timestamp));
1199 GST_OBJECT_LOCK (self);
1200 self->proportion = proportion;
1201 if (G_LIKELY (timestamp != GST_CLOCK_TIME_NONE)) {
1202 if (G_UNLIKELY (diff > 0))
1203 self->earliest_time =
1204 timestamp + 2 * diff + ((self->fields ==
1205 GST_DEINTERLACE_ALL) ? self->field_duration : 2 *
1206 self->field_duration);
1208 self->earliest_time = timestamp + diff;
1210 self->earliest_time = GST_CLOCK_TIME_NONE;
1212 GST_OBJECT_UNLOCK (self);
1216 gst_deinterlace_reset_qos (GstDeinterlace * self)
1218 gst_deinterlace_update_qos (self, 0.5, 0, GST_CLOCK_TIME_NONE);
1219 self->processed = 0;
1224 gst_deinterlace_read_qos (GstDeinterlace * self, gdouble * proportion,
1225 GstClockTime * time)
1227 GST_OBJECT_LOCK (self);
1228 *proportion = self->proportion;
1229 *time = self->earliest_time;
1230 GST_OBJECT_UNLOCK (self);
1233 /* Perform qos calculations before processing the next frame. Returns TRUE if
1234 * the frame should be processed, FALSE if the frame can be dropped entirely */
1236 gst_deinterlace_do_qos (GstDeinterlace * self, const GstBuffer * buffer)
1238 GstClockTime qostime, earliest_time;
1239 GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
1242 /* no timestamp, can't do QoS => process frame */
1243 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) {
1244 GST_LOG_OBJECT (self, "invalid timestamp, can't do QoS, process frame");
1248 /* get latest QoS observation values */
1249 gst_deinterlace_read_qos (self, &proportion, &earliest_time);
1251 /* skip qos if we have no observation (yet) => process frame */
1252 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) {
1253 GST_LOG_OBJECT (self, "no observation yet, process frame");
1257 /* qos is done on running time */
1258 qostime = gst_segment_to_running_time (&self->segment, GST_FORMAT_TIME,
1261 /* see how our next timestamp relates to the latest qos timestamp */
1262 GST_LOG_OBJECT (self, "qostime %" GST_TIME_FORMAT ", earliest %"
1263 GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
1265 if (qostime != GST_CLOCK_TIME_NONE && qostime <= earliest_time) {
1266 GstClockTime stream_time, jitter;
1267 GstMessage *qos_msg;
1269 GST_DEBUG_OBJECT (self, "we are late, drop frame");
1272 gst_segment_to_stream_time (&self->segment, GST_FORMAT_TIME, timestamp);
1273 jitter = GST_CLOCK_DIFF (qostime, earliest_time);
1275 gst_message_new_qos (GST_OBJECT (self), FALSE, qostime, stream_time,
1276 timestamp, GST_BUFFER_DURATION (buffer));
1277 gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000);
1278 gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS,
1279 self->processed, self->dropped);
1280 gst_element_post_message (GST_ELEMENT (self), qos_msg);
1284 GST_LOG_OBJECT (self, "process frame");
1291 gst_deinterlace_fix_timestamps (GstDeinterlace * self,
1292 GstVideoFrame * field1, GstVideoFrame * field2)
1294 GstVideoFrame *field3, *field4;
1295 GstVideoInterlaceMode interlacing_mode;
1297 if (self->pattern_lock && self->pattern > -1) {
1298 /* accurate pattern-locked timestamp adjustment */
1299 if (!self->pattern_count)
1300 gst_deinterlace_update_pattern_timestamps (self);
1302 GST_BUFFER_TIMESTAMP (field1->buffer) =
1303 self->pattern_base_ts + self->output_count * self->pattern_buf_dur;
1304 GST_BUFFER_DURATION (field1->buffer) = self->pattern_buf_dur;
1305 self->output_count++;
1307 /* naive (but low-latency) timestamp adjustment based on subsequent
1310 && GST_VIDEO_FRAME_PLANE_DATA (field1,
1311 0) != GST_VIDEO_FRAME_PLANE_DATA (field2, 0)) {
1312 if (GST_BUFFER_TIMESTAMP (field1->buffer) +
1313 GST_BUFFER_DURATION (field1->buffer) ==
1314 GST_BUFFER_TIMESTAMP (field2->buffer)) {
1315 GST_BUFFER_TIMESTAMP (field1->buffer) =
1316 GST_BUFFER_TIMESTAMP (field2->buffer) =
1317 (GST_BUFFER_TIMESTAMP (field1->buffer) +
1318 GST_BUFFER_TIMESTAMP (field2->buffer)) / 2;
1320 GST_BUFFER_TIMESTAMP (field2->buffer) =
1321 GST_BUFFER_TIMESTAMP (field1->buffer);
1325 if (self->history_count < 3) {
1326 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need 3)",
1327 self->history_count);
1331 field3 = self->field_history[self->history_count - 3].frame;
1332 interlacing_mode = GST_VIDEO_INFO_INTERLACE_MODE (&field3->info);
1333 if (IS_TELECINE (interlacing_mode)) {
1334 if (self->history_count < 4) {
1335 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need 4)",
1336 self->history_count);
1340 field4 = self->field_history[self->history_count - 4].frame;
1341 if (GST_VIDEO_FRAME_PLANE_DATA (field3,
1342 0) != GST_VIDEO_FRAME_PLANE_DATA (field4, 0)) {
1343 /* telecine fields in separate buffers */
1344 GST_BUFFER_TIMESTAMP (field3->buffer) =
1345 (GST_BUFFER_TIMESTAMP (field3->buffer) +
1346 GST_BUFFER_TIMESTAMP (field4->buffer)) / 2;
1350 GST_BUFFER_DURATION (field1->buffer) =
1351 GST_BUFFER_TIMESTAMP (field3->buffer) -
1352 GST_BUFFER_TIMESTAMP (field1->buffer);
1355 GST_DEBUG_OBJECT (self,
1356 "Field 1 adjusted to ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT,
1357 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1->buffer)),
1358 GST_TIME_ARGS (GST_BUFFER_DURATION (field1->buffer)));
1363 gst_deinterlace_get_pattern_lock (GstDeinterlace * self, gboolean * flush_one)
1365 /* loop over all possible patterns and all possible phases
1366 * giving each a score. the highest score gets the lock */
1367 /* the score is calculated as the number of matched buffers in the
1368 * sequence starting at the phase offset with those from the history
1369 * then the longest duration pattern match is taken. if there is more than
1370 * one pattern matching all buffers, we take the longest pattern of those.
1371 * matches to complete patterns are preferred. if no non-trivial pattern is
1372 * matched, trivial patterns are tested. */
1373 gint i, j, k, score, pattern, phase;
1374 const gint state_count = self->state_count;
1375 const gint n_required = self->ignore_obscure ?
1376 GST_DEINTERLACE_OBSCURE_THRESHOLD :
1377 GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY;
1379 /* set unknown pattern as this is used in logic outside this function */
1382 /* wait for more buffers */
1383 if (!self->have_eos && state_count < n_required) {
1384 GST_DEBUG_OBJECT (self, "Need more buffers in state history - %d/%d",
1385 state_count, n_required);
1389 score = pattern = phase = -1;
1391 /* loop over all patterns */
1392 for (i = 0; i < G_N_ELEMENTS (telecine_patterns); i++) {
1393 const guint8 length = telecine_patterns[i].length;
1395 if (self->ignore_obscure && i >= GST_DEINTERLACE_OBSCURE_THRESHOLD)
1398 if (state_count < length)
1401 /* loop over all phases */
1402 for (j = 0; j < length; j++) {
1403 /* low-latency mode looks at past buffers, high latency at future buffers */
1404 const gint state_idx =
1405 self->low_latency ? (self->history_count - 1) >> 1 : state_count - 1;
1406 /* loop over history, breaking on differing buffer states */
1407 for (k = 0; k < length && k < state_count; k++) {
1408 const guint8 hist = self->buf_states[state_idx - k].state;
1409 const guint8 patt = telecine_patterns[i].states[(j + k) % length];
1414 /* make complete matches more signficant */
1416 k += GST_DEINTERLACE_MAX_BUFFER_STATE_HISTORY;
1418 /* take as new best pattern if the number of matched buffers is more than
1419 * for other patterns */
1429 GST_WARNING_OBJECT (self, "Failed to select a pattern");
1433 GST_DEBUG_OBJECT (self,
1434 "Final pattern match result: pa %d, ph %d, l %d, s %d", pattern, phase,
1435 telecine_patterns[pattern].length, score);
1436 self->pattern = pattern;
1437 self->pattern_phase = phase;
1438 self->pattern_count = 0;
1439 self->output_count = 0;
1440 self->pattern_lock = TRUE;
1442 for (i = 0; i < telecine_patterns[pattern].length; i++) {
1444 self->low_latency ? (self->history_count - 1) >> 1 : self->state_count -
1447 GST_LOG_OBJECT (self, "buf[%d] %s", i,
1448 STATE_TO_STRING (self->buf_states[state_idx].state));
1451 /* check for the case that the first field of the pattern is an orphan */
1453 && telecine_patterns[pattern].states[phase] & (GST_ONE | GST_INT)) {
1454 gint i = phase, field_count = 0;
1455 guint8 state = telecine_patterns[pattern].states[i];
1458 if (state & GST_ONE) {
1461 } else if (!(state & GST_DRP)) {
1467 i %= telecine_patterns[pattern].length;
1468 state = telecine_patterns[pattern].states[i];
1469 } while (!(state & GST_PRG));
1471 /* if field_count is odd, we have an orphan field at the beginning of the
1473 * note - don't do this in low-latency mode as we are somewhere within the
1474 * pattern already */
1475 if (!self->low_latency && (*flush_one = field_count & 1)) {
1476 GST_DEBUG_OBJECT (self, "Orphan field detected at the beginning of the "
1477 "pattern - it will be deinterlaced.");
1482 static GstFlowReturn
1483 gst_deinterlace_output_frame (GstDeinterlace * self, gboolean flushing)
1485 GstClockTime timestamp;
1487 gint fields_required;
1488 GstBuffer *buf, *outbuf;
1489 GstVideoFrame *outframe = NULL;
1490 GstDeinterlaceField *field1, *field2;
1491 GstVideoInterlaceMode interlacing_mode;
1493 gboolean hl_no_lock; /* indicates high latency timestamp adjustment but no pattern lock (could be ONEF or I) */
1494 gboolean same_buffer; /* are field1 and field2 in the same buffer? */
1495 gboolean flush_one; /* used for flushing one field when in high latency mode and not locked */
1496 TelecinePattern pattern;
1497 guint8 phase, count;
1498 const GstDeinterlaceLocking locking = self->locking;
1502 fields_required = 0;
1504 same_buffer = FALSE;
1506 self->need_more = FALSE;
1507 phase = self->pattern_phase;
1508 count = self->pattern_count;
1510 if (!self->history_count) {
1511 GST_DEBUG_OBJECT (self, "History is empty, waiting for more buffers!");
1515 field1 = &self->field_history[self->history_count - 1];
1517 if (locking != GST_DEINTERLACE_LOCKING_NONE) {
1520 if (!self->state_count) {
1521 GST_ERROR_OBJECT (self,
1522 "BROKEN! Fields in history + no states should not happen!");
1523 return GST_FLOW_ERROR;
1526 gst_deinterlace_get_buffer_state (self, field1->frame, &buf_state,
1529 if (self->pattern != -1)
1530 pattern = telecine_patterns[self->pattern];
1532 /* patterns 0 and 1 are interlaced, the rest are telecine */
1533 if (self->pattern > 1)
1534 interlacing_mode = GST_VIDEO_INTERLACE_MODE_MIXED;
1536 if (self->pattern == -1 || self->pattern_refresh
1537 || !(buf_state & pattern.states[(phase + count) % pattern.length])) {
1538 if (self->pattern == -1) {
1539 GST_DEBUG_OBJECT (self, "No pattern lock - refresh lock");
1540 } else if (self->pattern_refresh) {
1541 GST_DEBUG_OBJECT (self, "Pattern refresh - refresh lock");
1543 GST_DEBUG_OBJECT (self, "Unexpected buffer state - refresh lock");
1545 /* no pattern, pattern refresh set or unexpected buffer state */
1546 self->pattern_lock = FALSE;
1547 self->pattern_refresh = TRUE;
1549 /* refresh pattern lock */
1550 gst_deinterlace_get_pattern_lock (self, &flush_one);
1552 if (self->pattern != -1) {
1553 /* locked onto a valid pattern so refresh complete */
1554 GST_DEBUG_OBJECT (self, "Pattern locked! %s starting at %d",
1555 telecine_patterns[self->pattern].nick, self->pattern_phase);
1556 self->pattern_refresh = FALSE;
1557 } else if (!self->low_latency) {
1558 if (!self->pattern_lock) {
1565 /* setcaps on sink and src pads */
1566 sinkcaps = gst_pad_get_current_caps (self->sinkpad);
1567 gst_deinterlace_setcaps (self, self->sinkpad, sinkcaps); // FIXME
1568 gst_caps_unref (sinkcaps);
1570 if (flush_one && self->drop_orphans) {
1571 GST_DEBUG_OBJECT (self, "Dropping orphan first field");
1572 self->cur_field_idx--;
1573 gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1578 gst_deinterlace_get_buffer_state (self, field1->frame, NULL,
1582 same_buffer = self->history_count >= 2
1583 && (GST_VIDEO_FRAME_PLANE_DATA (field1->frame, 0) ==
1584 GST_VIDEO_FRAME_PLANE_DATA (self->field_history[self->history_count -
1587 if ((flushing && self->history_count == 1) || (flush_one
1588 && !self->drop_orphans) || (hl_no_lock && (self->history_count == 1
1589 || !same_buffer))) {
1590 /* This case is for flushing a single field:
1591 * - flushing and 1 field in the history
1592 * - flush one (due to orphans in the pattern) and do not drop orphans
1593 * - high-latency pattern locking with no possible lock given the current
1594 * state and either only one field in the history or the tip two fields
1595 * are in separate buffers */
1596 GST_DEBUG_OBJECT (self, "Flushing one field using linear method");
1597 gst_deinterlace_set_method (self, GST_DEINTERLACE_LINEAR);
1598 fields_required = gst_deinterlace_method_get_fields_required (self->method);
1599 } else if (interlacing_mode == GST_VIDEO_INTERLACE_MODE_PROGRESSIVE ||
1600 (interlacing_mode == GST_VIDEO_INTERLACE_MODE_MIXED &&
1601 !GST_VIDEO_FRAME_IS_INTERLACED (field1->frame))) {
1602 /* This case is for processing progressive buffers, telecine or plain
1604 GstVideoFrame *field1_frame;
1605 GstBuffer *field1_buffer;
1608 fields_required = 2;
1610 /* Not enough fields in the history */
1611 if (!flushing && self->history_count < fields_required) {
1612 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
1613 self->history_count, self->cur_field_idx + fields_required);
1617 field2 = &self->field_history[self->history_count - 2];
1618 if (GST_VIDEO_FRAME_PLANE_DATA (field1->frame,
1619 0) != GST_VIDEO_FRAME_PLANE_DATA (field2->frame, 0)) {
1620 /* ERROR - next two fields in field history are not one progressive buffer - weave? */
1621 GST_ERROR_OBJECT (self,
1622 "Progressive buffer but two fields at tip aren't in the same buffer!");
1625 if (IS_TELECINE (interlacing_mode)
1626 && !gst_deinterlace_fix_timestamps (self, field1->frame, field2->frame)
1630 GST_DEBUG_OBJECT (self,
1631 "Frame type: Progressive; pushing buffer as a frame");
1633 self->cur_field_idx--;
1634 field1_frame = gst_deinterlace_pop_history (self);
1635 field1_buffer = field1_frame->buffer;
1636 gst_buffer_ref (field1_buffer);
1637 gst_video_frame_unmap_and_free (field1_frame);
1638 /* field2 is the same buffer as field1, but we need to remove it from the
1640 self->cur_field_idx--;
1641 gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1642 GST_DEBUG_OBJECT (self,
1643 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1645 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buffer)),
1646 GST_TIME_ARGS (GST_BUFFER_DURATION (field1_buffer)),
1647 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (field1_buffer) +
1648 GST_BUFFER_DURATION (field1_buffer)));
1649 return gst_pad_push (self->srcpad, field1_buffer);
1650 } else if (IS_TELECINE (interlacing_mode)
1651 && GST_VIDEO_FRAME_IS_INTERLACED (field1->frame) && !same_buffer) {
1652 /* This case needs to identify telecine mixed buffers that require weaving
1653 * of two fields in different buffers.
1654 * - interlacing mode is mixed
1655 * - locked on to a telecine pattern
1656 * - frame is interlaced
1657 * - fields are in separate buffers
1658 * If we don't yet have a pattern lock, we will have to deinterlace as we
1659 * don't explicitly know we have a telecine sequence and so we drop through
1660 * to the plain deinterlace case */
1661 fields_required = 2;
1662 if (!flushing && self->history_count < fields_required) {
1663 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
1664 self->history_count, self->cur_field_idx + fields_required);
1668 field2 = &self->field_history[self->history_count - 2];
1669 if (!gst_deinterlace_fix_timestamps (self, field1->frame, field2->frame)
1673 /* check field1 and field2 buffer caps and flags are corresponding */
1674 if (field1->flags == field2->flags) {
1675 /* ERROR - fields are of same parity - what should be done here?
1676 * perhaps deinterlace the tip field and start again? */
1677 GST_ERROR_OBJECT (self, "Telecine mixed with fields of same parity!");
1679 GST_DEBUG_OBJECT (self,
1680 "Frame type: Telecine Mixed; weaving tip two fields into a frame");
1681 /* set method to WEAVE */
1682 gst_deinterlace_set_method (self, GST_DEINTERLACE_WEAVE);
1684 /* This is the final catch-all case that applies the selected deinterlacing
1685 * method. At this point the fields to be processed are either definitely
1686 * interlaced or we do not yet know that we have a telecine pattern lock
1687 * and so the best we can do is to deinterlace the fields. */
1688 gst_deinterlace_set_method (self, self->user_set_method_id);
1689 fields_required = gst_deinterlace_method_get_fields_required (self->method);
1690 if (flushing && self->history_count < fields_required) {
1691 /* note: we already checked for flushing with history count == 1 above
1692 * so we must have 2 or more fields in here */
1693 gst_deinterlace_set_method (self, GST_DEINTERLACE_VFIR);
1695 gst_deinterlace_method_get_fields_required (self->method);
1696 GST_DEBUG_OBJECT (self, "Flushing field(s) using %s method",
1697 methods_types[self->method_id].value_nick);
1700 /* Not enough fields in the history */
1701 if (!flushing && self->history_count < fields_required) {
1702 GST_DEBUG_OBJECT (self, "Need more fields (have %d, need %d)",
1703 self->history_count, self->cur_field_idx + fields_required);
1707 GST_DEBUG_OBJECT (self,
1708 "Frame type: Interlaced; deinterlacing using %s method",
1709 methods_types[self->method_id].value_nick);
1712 if (!flushing && self->cur_field_idx < 1) {
1714 } else if (self->cur_field_idx < 0 && flushing) {
1715 self->cur_field_idx++;
1718 if (self->fields == GST_DEINTERLACE_ALL || IS_TELECINE (interlacing_mode))
1719 GST_DEBUG_OBJECT (self, "All fields");
1720 else if (self->fields == GST_DEINTERLACE_TF)
1721 GST_DEBUG_OBJECT (self, "Top fields");
1722 else if (self->fields == GST_DEINTERLACE_BF)
1723 GST_DEBUG_OBJECT (self, "Bottom fields");
1725 if ((self->field_history[self->cur_field_idx].flags == PICTURE_INTERLACED_TOP
1726 && (self->fields == GST_DEINTERLACE_TF
1727 || IS_TELECINE (interlacing_mode)))
1728 || (self->fields == GST_DEINTERLACE_ALL
1729 && !IS_TELECINE (interlacing_mode))) {
1730 GST_DEBUG_OBJECT (self, "deinterlacing top field");
1732 /* create new buffer */
1733 ret = gst_buffer_pool_acquire_buffer (self->pool, &outbuf, NULL);
1734 if (ret != GST_FLOW_OK)
1737 g_return_val_if_fail (self->history_count >=
1738 1 + gst_deinterlace_method_get_latency (self->method), GST_FLOW_ERROR);
1741 self->field_history[self->history_count - 1 -
1742 gst_deinterlace_method_get_latency (self->method)].frame->buffer;
1744 if (!IS_TELECINE (interlacing_mode)) {
1745 timestamp = GST_BUFFER_TIMESTAMP (buf);
1747 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1748 if (self->fields == GST_DEINTERLACE_ALL)
1749 GST_BUFFER_DURATION (outbuf) = self->field_duration;
1751 GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
1752 GST_DEBUG_OBJECT (self,
1753 "[ADJUST] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1754 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1755 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
1756 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
1757 GST_BUFFER_DURATION (outbuf)));
1759 GST_BUFFER_TIMESTAMP (outbuf) =
1760 GST_BUFFER_TIMESTAMP (field1->frame->buffer);
1761 GST_BUFFER_DURATION (outbuf) =
1762 GST_BUFFER_DURATION (field1->frame->buffer);
1765 /* Check if we need to drop the frame because of QoS */
1766 if (!gst_deinterlace_do_qos (self, buf)) {
1767 self->cur_field_idx--;
1768 gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1769 gst_buffer_unref (outbuf);
1773 if (self->cur_field_idx < 0 && flushing) {
1774 if (self->history_count == 1) {
1775 gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1778 self->cur_field_idx++;
1780 if (self->cur_field_idx < 0) {
1783 if (!flushing && self->cur_field_idx < 1) {
1787 /* map the frame so the deinterlace methods can write the data to the
1788 * correct memory locations */
1790 gst_video_frame_new_and_map (&self->vinfo, outbuf, GST_MAP_WRITE);
1792 /* do magic calculus */
1793 gst_deinterlace_method_deinterlace_frame (self->method,
1794 self->field_history, self->history_count, outframe,
1795 self->cur_field_idx);
1797 gst_video_frame_unmap_and_free (outframe);
1799 self->cur_field_idx--;
1800 /* need to remove the field in the telecine weaving case */
1801 if ((IS_TELECINE (interlacing_mode)
1802 && self->method_id == GST_DEINTERLACE_WEAVE)
1803 || self->cur_field_idx + 1 +
1804 gst_deinterlace_method_get_latency (self->method) <
1805 self->history_count || flushing) {
1806 gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1809 if (gst_deinterlace_clip_buffer (self, outbuf)) {
1810 GST_DEBUG_OBJECT (self,
1811 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1812 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1813 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
1814 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
1815 GST_BUFFER_DURATION (outbuf)));
1816 ret = gst_pad_push (self->srcpad, outbuf);
1819 gst_buffer_unref (outbuf);
1823 if (ret != GST_FLOW_OK)
1825 if (IS_TELECINE (interlacing_mode)
1826 && self->method_id == GST_DEINTERLACE_WEAVE) {
1827 /* pop off the second field */
1828 GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
1829 self->history_count);
1830 self->cur_field_idx--;
1831 gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1832 interlacing_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
1837 if (flush_one && !self->drop_orphans) {
1838 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1842 /* no calculation done: remove excess field */
1843 else if (self->field_history[self->cur_field_idx].flags ==
1844 PICTURE_INTERLACED_TOP && (self->fields == GST_DEINTERLACE_BF
1845 && !IS_TELECINE (interlacing_mode))) {
1846 GST_DEBUG_OBJECT (self, "Removing unused top field");
1847 self->cur_field_idx--;
1848 gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1850 if (flush_one && !self->drop_orphans) {
1851 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1856 if (self->history_count < fields_required)
1859 if (self->cur_field_idx < 0)
1862 /* deinterlace bottom_field */
1863 if ((self->field_history[self->cur_field_idx].flags ==
1864 PICTURE_INTERLACED_BOTTOM && (self->fields == GST_DEINTERLACE_BF
1865 || IS_TELECINE (interlacing_mode)))
1866 || (self->fields == GST_DEINTERLACE_ALL
1867 && !IS_TELECINE (interlacing_mode))) {
1868 GST_DEBUG_OBJECT (self, "deinterlacing bottom field");
1870 /* create new buffer */
1871 ret = gst_buffer_pool_acquire_buffer (self->pool, &outbuf, NULL);
1872 if (ret != GST_FLOW_OK)
1875 g_return_val_if_fail (self->history_count - 1 -
1876 gst_deinterlace_method_get_latency (self->method) >= 0, GST_FLOW_ERROR);
1879 self->field_history[self->history_count - 1 -
1880 gst_deinterlace_method_get_latency (self->method)].frame->buffer;
1881 if (!IS_TELECINE (interlacing_mode)) {
1882 timestamp = GST_BUFFER_TIMESTAMP (buf);
1884 if (self->fields == GST_DEINTERLACE_ALL) {
1885 GST_BUFFER_TIMESTAMP (outbuf) = timestamp + self->field_duration;
1886 GST_BUFFER_DURATION (outbuf) = self->field_duration;
1888 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1889 GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
1891 GST_DEBUG_OBJECT (self,
1892 "[ADJUST] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1893 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1894 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
1895 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
1896 GST_BUFFER_DURATION (outbuf)));
1898 GST_BUFFER_TIMESTAMP (outbuf) =
1899 GST_BUFFER_TIMESTAMP (field1->frame->buffer);
1900 GST_BUFFER_DURATION (outbuf) =
1901 GST_BUFFER_DURATION (field1->frame->buffer);
1904 /* Check if we need to drop the frame because of QoS */
1905 if (!gst_deinterlace_do_qos (self, buf)) {
1906 self->cur_field_idx--;
1907 gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1908 gst_buffer_unref (outbuf);
1912 /* map the frame so the deinterlace methods can write the data to the
1913 * correct memory locations */
1915 gst_video_frame_new_and_map (&self->vinfo, outbuf, GST_MAP_WRITE);
1917 /* do magic calculus */
1918 gst_deinterlace_method_deinterlace_frame (self->method,
1919 self->field_history, self->history_count, outframe,
1920 self->cur_field_idx);
1922 gst_video_frame_unmap_and_free (outframe);
1924 self->cur_field_idx--;
1925 /* need to remove the field in the telecine weaving case */
1926 if ((IS_TELECINE (interlacing_mode)
1927 && self->method_id == GST_DEINTERLACE_WEAVE)
1928 || self->cur_field_idx + 1 +
1929 gst_deinterlace_method_get_latency (self->method) <
1930 self->history_count) {
1931 gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1934 if (gst_deinterlace_clip_buffer (self, outbuf)) {
1935 GST_DEBUG_OBJECT (self,
1936 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
1937 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1938 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
1939 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf) +
1940 GST_BUFFER_DURATION (outbuf)));
1941 ret = gst_pad_push (self->srcpad, outbuf);
1944 gst_buffer_unref (outbuf);
1948 if (ret != GST_FLOW_OK)
1950 if (IS_TELECINE (interlacing_mode)
1951 && self->method_id == GST_DEINTERLACE_WEAVE) {
1952 /* pop off the second field */
1953 GST_DEBUG_OBJECT (self, "Removing unused field (count: %d)",
1954 self->history_count);
1955 self->cur_field_idx--;
1956 gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1957 interlacing_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
1962 if (flush_one && !self->drop_orphans) {
1963 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1967 /* no calculation done: remove excess field */
1968 else if (self->field_history[self->cur_field_idx].flags ==
1969 PICTURE_INTERLACED_BOTTOM && (self->fields == GST_DEINTERLACE_TF
1970 && !IS_TELECINE (interlacing_mode))) {
1971 GST_DEBUG_OBJECT (self, "Removing unused bottom field");
1972 self->cur_field_idx--;
1973 gst_video_frame_unmap_and_free (gst_deinterlace_pop_history (self));
1975 if (flush_one && !self->drop_orphans) {
1976 GST_DEBUG_OBJECT (self, "Orphan field deinterlaced - reconfiguring");
1985 self->need_more = TRUE;
1990 GST_DEBUG_OBJECT (self, "could not allocate buffer");
1996 gst_deinterlace_get_latency (GstDeinterlace * self)
1998 if (self->locking == GST_DEINTERLACE_LOCKING_AUTO) {
2002 query = gst_query_new_latency ();
2003 if ((res = gst_pad_peer_query (self->sinkpad, query))) {
2005 /* if upstream is live, we use low-latency passive locking mode
2006 * else high-latency active locking mode */
2007 gst_query_parse_latency (query, &is_live, NULL, NULL);
2008 GST_DEBUG_OBJECT (self, "Latency query indicates stream is %s",
2009 is_live ? "live - using passive locking" :
2010 "not live - using active locking");
2011 gst_query_unref (query);
2014 /* conservatively use passive locking if the query fails */
2015 GST_WARNING_OBJECT (self,
2016 "Latency query failed - fall back to using passive locking");
2017 gst_query_unref (query);
2021 return self->locking - 2;
2025 static GstFlowReturn
2026 gst_deinterlace_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2028 GstDeinterlace *self = GST_DEINTERLACE (parent);
2029 GstFlowReturn ret = GST_FLOW_OK;
2031 GST_OBJECT_LOCK (self);
2032 if (self->reconfigure) { /* FIXME: reconfigure should probably work differently */
2035 if ((gint) self->new_fields != -1)
2036 self->fields = self->new_fields;
2037 if ((gint) self->new_mode != -1)
2038 self->mode = self->new_mode;
2039 self->new_mode = -1;
2040 self->new_fields = -1;
2042 self->reconfigure = FALSE;
2043 GST_OBJECT_UNLOCK (self);
2044 caps = gst_pad_get_current_caps (self->sinkpad);
2046 gst_deinterlace_setcaps (self, self->sinkpad, caps); // FIXME
2047 gst_caps_unref (caps);
2050 GST_OBJECT_UNLOCK (self);
2053 GST_DEBUG_OBJECT (self,
2054 "[IN] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
2055 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
2056 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
2057 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)));
2059 if (self->still_frame_mode || self->passthrough) {
2060 GST_DEBUG_OBJECT (self,
2061 "Frame type: Progressive?; pushing buffer using pass-through");
2062 GST_DEBUG_OBJECT (self,
2063 "[OUT] ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", end %"
2064 GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
2065 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
2066 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)));
2068 return gst_pad_push (self->srcpad, buf);
2071 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
2072 GST_DEBUG_OBJECT (self, "DISCONT buffer, resetting history");
2073 gst_deinterlace_reset_history (self, FALSE);
2076 gst_deinterlace_push_history (self, buf);
2080 ret = gst_deinterlace_output_frame (self, FALSE);
2081 } while (!self->need_more && self->history_count > 0 && ret == GST_FLOW_OK);
2087 gst_fraction_double (gint * n_out, gint * d_out, gboolean half)
2100 gcd = gst_util_greatest_common_divisor (n, d);
2105 if (G_MAXINT / 2 >= ABS (d)) {
2107 } else if (n >= 2 && n != G_MAXINT) {
2113 if (G_MAXINT / 2 >= ABS (n)) {
2115 } else if (d >= 2 && d != G_MAXINT) {
2129 gst_deinterlace_getcaps (GstDeinterlace * self, GstPad * pad, GstCaps * filter)
2137 GstVideoInterlaceMode interlacing_mode;
2139 otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad;
2140 half = pad != self->srcpad;
2142 ourcaps = gst_pad_get_pad_template_caps (pad);
2143 peercaps = gst_pad_peer_query_caps (otherpad, NULL);
2145 interlacing_mode = GST_VIDEO_INFO_INTERLACE_MODE (&self->vinfo);
2146 if (self->mode == GST_DEINTERLACE_MODE_INTERLACED ||
2147 (self->mode == GST_DEINTERLACE_MODE_AUTO &&
2148 interlacing_mode != GST_VIDEO_INTERLACE_MODE_PROGRESSIVE)) {
2149 gst_caps_unref (ourcaps);
2150 ourcaps = gst_caps_from_string (DEINTERLACE_CAPS);
2154 GST_DEBUG_OBJECT (pad, "Peer has caps %" GST_PTR_FORMAT, peercaps);
2155 ret = gst_caps_make_writable (gst_caps_intersect (ourcaps, peercaps));
2156 gst_caps_unref (peercaps);
2157 gst_caps_unref (ourcaps);
2159 ret = gst_caps_make_writable (ourcaps);
2162 for (len = gst_caps_get_size (ret); len > 0; len--) {
2163 GstStructure *s = gst_caps_get_structure (ret, len - 1);
2165 if (pad == self->sinkpad || self->passthrough)
2166 gst_structure_remove_field (s, "interlace-mode");
2168 gst_structure_set (s, "interlace-mode", G_TYPE_STRING, "progressive",
2171 if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) {
2174 val = gst_structure_get_value (s, "framerate");
2178 if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION) {
2181 n = gst_value_get_fraction_numerator (val);
2182 d = gst_value_get_fraction_denominator (val);
2184 if (!gst_fraction_double (&n, &d, half)) {
2188 gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
2189 } else if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION_RANGE) {
2190 const GValue *min, *max;
2191 GValue nrange = { 0, }, nmin = {
2196 g_value_init (&nrange, GST_TYPE_FRACTION_RANGE);
2197 g_value_init (&nmin, GST_TYPE_FRACTION);
2198 g_value_init (&nmax, GST_TYPE_FRACTION);
2200 min = gst_value_get_fraction_range_min (val);
2201 max = gst_value_get_fraction_range_max (val);
2203 n = gst_value_get_fraction_numerator (min);
2204 d = gst_value_get_fraction_denominator (min);
2206 if (!gst_fraction_double (&n, &d, half)) {
2207 g_value_unset (&nrange);
2208 g_value_unset (&nmax);
2209 g_value_unset (&nmin);
2213 gst_value_set_fraction (&nmin, n, d);
2215 n = gst_value_get_fraction_numerator (max);
2216 d = gst_value_get_fraction_denominator (max);
2218 if (!gst_fraction_double (&n, &d, half)) {
2219 g_value_unset (&nrange);
2220 g_value_unset (&nmax);
2221 g_value_unset (&nmin);
2225 gst_value_set_fraction (&nmax, n, d);
2226 gst_value_set_fraction_range (&nrange, &nmin, &nmax);
2228 gst_structure_take_value (s, "framerate", &nrange);
2230 g_value_unset (&nmin);
2231 g_value_unset (&nmax);
2232 } else if (G_VALUE_TYPE (val) == GST_TYPE_LIST) {
2234 GValue nlist = { 0, };
2235 GValue nval = { 0, };
2238 g_value_init (&nlist, GST_TYPE_LIST);
2239 for (i = gst_value_list_get_size (val); i > 0; i--) {
2242 lval = gst_value_list_get_value (val, i - 1);
2244 if (G_VALUE_TYPE (lval) != GST_TYPE_FRACTION)
2247 n = gst_value_get_fraction_numerator (lval);
2248 d = gst_value_get_fraction_denominator (lval);
2250 /* Double/Half the framerate but if this fails simply
2251 * skip this value from the list */
2252 if (!gst_fraction_double (&n, &d, half)) {
2256 g_value_init (&nval, GST_TYPE_FRACTION);
2258 gst_value_set_fraction (&nval, n, d);
2259 gst_value_list_append_and_take_value (&nlist, &nval);
2261 gst_structure_take_value (s, "framerate", &nlist);
2267 GstCaps *filter_caps;
2269 GST_LOG_OBJECT (pad, "intersecting with %" GST_PTR_FORMAT, filter);
2270 filter_caps = gst_caps_intersect_full (filter, ret,
2271 GST_CAPS_INTERSECT_FIRST);
2272 gst_caps_unref (ret);
2276 GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret);
2281 GST_ERROR_OBJECT (pad, "Unable to transform peer caps");
2282 gst_caps_unref (ret);
2286 /* takes ownership of the pool, allocator and query */
2288 gst_deinterlace_set_allocation (GstDeinterlace * self,
2289 GstBufferPool * pool, GstAllocator * allocator,
2290 GstAllocationParams * params)
2292 GstAllocator *oldalloc;
2293 GstBufferPool *oldpool;
2295 GST_OBJECT_LOCK (self);
2296 oldpool = self->pool;
2299 oldalloc = self->allocator;
2300 self->allocator = allocator;
2303 self->params = *params;
2305 gst_allocation_params_init (&self->params);
2306 GST_OBJECT_UNLOCK (self);
2309 GST_DEBUG_OBJECT (self, "deactivating old pool %p", oldpool);
2310 gst_buffer_pool_set_active (oldpool, FALSE);
2311 gst_object_unref (oldpool);
2314 gst_object_unref (oldalloc);
2317 GST_DEBUG_OBJECT (self, "activating new pool %p", pool);
2318 gst_buffer_pool_set_active (pool, TRUE);
2324 gst_deinterlace_do_bufferpool (GstDeinterlace * self, GstCaps * outcaps)
2327 gboolean result = TRUE;
2328 GstBufferPool *pool;
2329 GstAllocator *allocator;
2330 GstAllocationParams params;
2331 GstStructure *config;
2332 guint size, min, max;
2334 if (self->passthrough) {
2335 /* we are in passthrough, the input buffer is never copied and always passed
2336 * along. We never allocate an output buffer on the srcpad. What we do is
2337 * let the upstream element decide if it wants to use a bufferpool and
2338 * then we will proxy the downstream pool */
2339 GST_DEBUG_OBJECT (self, "we're passthough, delay bufferpool");
2340 gst_deinterlace_set_allocation (self, NULL, NULL, NULL);
2344 /* not passthrough, we need to allocate */
2345 /* find a pool for the negotiated caps now */
2346 GST_DEBUG_OBJECT (self, "doing allocation query");
2347 query = gst_query_new_allocation (outcaps, TRUE);
2348 if (!gst_pad_peer_query (self->srcpad, query)) {
2349 /* not a problem, just debug a little */
2350 GST_DEBUG_OBJECT (self, "peer ALLOCATION query failed");
2353 GST_DEBUG_OBJECT (self, "ALLOCATION (%d) params: %" GST_PTR_FORMAT, result,
2356 /* we got configuration from our peer or the decide_allocation method,
2358 if (gst_query_get_n_allocation_params (query) > 0) {
2359 gst_query_parse_nth_allocation_param (query, 0, &allocator, ¶ms);
2362 gst_allocation_params_init (¶ms);
2365 if (gst_query_get_n_allocation_pools (query) > 0)
2366 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
2369 size = GST_VIDEO_INFO_SIZE (&self->vinfo);
2371 MAX ((gst_deinterlace_method_get_fields_required (self->method) +
2377 /* no pool, we can make our own */
2378 GST_DEBUG_OBJECT (self, "no pool, making new pool");
2379 pool = gst_video_buffer_pool_new ();
2383 config = gst_buffer_pool_get_config (pool);
2384 gst_buffer_pool_config_set_params (config, outcaps, size, min, max);
2385 gst_buffer_pool_config_set_allocator (config, allocator, ¶ms);
2386 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
2387 gst_buffer_pool_set_config (pool, config);
2390 result = gst_deinterlace_set_allocation (self, pool, allocator, ¶ms);
2392 gst_query_unref (query);
2399 gst_deinterlace_setcaps (GstDeinterlace * self, GstPad * pad, GstCaps * caps)
2402 GstVideoInterlaceMode interlacing_mode;
2405 if (self->locking != GST_DEINTERLACE_LOCKING_NONE) {
2406 if (self->low_latency == -1)
2407 self->low_latency = gst_deinterlace_get_latency (self);
2409 if (self->pattern_lock) {
2410 /* refresh has been successful - we have a lock now */
2411 self->pattern_refresh = FALSE;
2413 /* if we were not refreshing (!pattern_refresh) the caps have changed
2414 * so we need to refresh and we don't have a lock anymore
2415 * otherwise we have pattern_fresh and !pattern_lock anyway */
2416 self->pattern_refresh = TRUE;
2417 self->pattern_lock = FALSE;
2421 if (!gst_video_info_from_caps (&self->vinfo, caps))
2424 fps_n = GST_VIDEO_INFO_FPS_N (&self->vinfo);
2425 fps_d = GST_VIDEO_INFO_FPS_D (&self->vinfo);
2427 gst_deinterlace_update_passthrough (self);
2429 interlacing_mode = GST_VIDEO_INFO_INTERLACE_MODE (&self->vinfo);
2431 if (self->pattern_lock) {
2432 srccaps = gst_caps_copy (caps);
2433 if (self->pattern != -1
2434 && G_UNLIKELY (!gst_util_fraction_multiply (fps_n, fps_d,
2435 telecine_patterns[self->pattern].ratio_n,
2436 telecine_patterns[self->pattern].ratio_d, &fps_n, &fps_d)))
2437 GST_ERROR_OBJECT (self,
2438 "Multiplying the framerate by the telecine pattern ratio overflowed!");
2439 gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, fps_n,
2441 } else if (self->locking == GST_DEINTERLACE_LOCKING_ACTIVE
2442 || self->low_latency == 0) {
2443 /* in high latency pattern locking mode if we don't have a pattern lock,
2444 * the sink pad caps are the best we know */
2445 srccaps = gst_caps_ref (caps);
2446 } else if (self->low_latency > 0
2447 && interlacing_mode == GST_VIDEO_INTERLACE_MODE_MIXED
2448 && self->pattern == -1) {
2449 /* for initial buffers of a telecine pattern, until there is a lock we
2450 * we output naïvely adjusted timestamps in low-latency pattern locking
2452 srccaps = gst_caps_copy (caps);
2453 gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
2454 } else if (!self->passthrough && self->fields == GST_DEINTERLACE_ALL) {
2455 if (!gst_fraction_double (&fps_n, &fps_d, FALSE))
2458 srccaps = gst_caps_copy (caps);
2460 gst_caps_set_simple (srccaps, "framerate", GST_TYPE_FRACTION, fps_n,
2463 srccaps = gst_caps_ref (caps);
2466 if (self->mode != GST_DEINTERLACE_MODE_DISABLED) {
2467 srccaps = gst_caps_make_writable (srccaps);
2468 gst_caps_set_simple (srccaps, "interlace-mode", G_TYPE_STRING,
2469 "progressive", NULL);
2472 gst_pad_set_caps (self->srcpad, srccaps);
2475 self->field_duration = gst_util_uint64_scale (GST_SECOND, fps_d, fps_n);
2477 self->field_duration = 0;
2480 if (!self->passthrough) {
2481 gst_deinterlace_set_method (self, self->method_id);
2482 gst_deinterlace_method_setup (self->method, &self->vinfo);
2485 GST_DEBUG_OBJECT (pad, "Sink caps: %" GST_PTR_FORMAT, caps);
2486 GST_DEBUG_OBJECT (pad, "Src caps: %" GST_PTR_FORMAT, srccaps);
2488 if (!gst_deinterlace_do_bufferpool (self, srccaps))
2491 gst_caps_unref (srccaps);
2497 GST_ERROR_OBJECT (pad, "Invalid caps: %" GST_PTR_FORMAT, caps);
2502 GST_ERROR_OBJECT (pad, "could not negotiate bufferpool");
2503 gst_caps_unref (srccaps);
2509 gst_deinterlace_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
2511 gboolean res = TRUE;
2512 GstDeinterlace *self = GST_DEINTERLACE (parent);
2514 GST_LOG_OBJECT (pad, "received %s event: %" GST_PTR_FORMAT,
2515 GST_EVENT_TYPE_NAME (event), event);
2517 switch (GST_EVENT_TYPE (event)) {
2518 case GST_EVENT_CAPS:
2520 GstCaps *caps = NULL;
2522 gst_event_parse_caps (event, &caps);
2523 res = gst_deinterlace_setcaps (self, pad, caps);
2524 gst_event_unref (event);
2527 case GST_EVENT_SEGMENT:
2529 const GstSegment *segment;
2531 gst_event_parse_segment (event, &segment);
2533 gst_deinterlace_reset_qos (self);
2534 gst_deinterlace_reset_history (self, FALSE);
2536 if (segment->format == GST_FORMAT_TIME) {
2537 GST_DEBUG_OBJECT (pad,
2538 "Got SEGMENT event in TIME format, passing on (%"
2539 GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")",
2540 GST_TIME_ARGS (segment->start), GST_TIME_ARGS (segment->stop));
2541 gst_segment_copy_into (segment, &self->segment);
2543 GST_WARNING_OBJECT (pad, "Got SEGMENT event in %s format",
2544 gst_format_get_name (segment->format));
2545 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
2548 res = gst_pad_push_event (self->srcpad, event);
2551 case GST_EVENT_CUSTOM_DOWNSTREAM:{
2552 gboolean still_state;
2554 if (gst_video_event_parse_still_frame (event, &still_state)) {
2555 GST_DEBUG_OBJECT (self, "Received still frame event, state %d",
2561 GST_DEBUG_OBJECT (self, "Handling still frame");
2562 self->still_frame_mode = TRUE;
2563 gst_deinterlace_reset_history (self, FALSE);
2564 if (self->last_buffer) {
2566 gst_pad_push (self->srcpad, gst_buffer_ref (self->last_buffer));
2567 GST_DEBUG_OBJECT (self, "Pushed still frame, result: %s",
2568 gst_flow_get_name (ret));
2570 GST_WARNING_OBJECT (self, "No pending buffer!");
2573 GST_DEBUG_OBJECT (self, "Ending still frames");
2574 self->still_frame_mode = FALSE;
2578 res = gst_pad_push_event (self->srcpad, event);
2582 self->have_eos = TRUE;
2583 gst_deinterlace_reset_history (self, FALSE);
2584 res = gst_pad_push_event (self->srcpad, event);
2587 case GST_EVENT_FLUSH_STOP:
2588 if (self->still_frame_mode) {
2589 GST_DEBUG_OBJECT (self, "Ending still frames");
2590 self->still_frame_mode = FALSE;
2592 gst_deinterlace_reset_qos (self);
2593 res = gst_pad_push_event (self->srcpad, event);
2594 gst_deinterlace_reset_history (self, TRUE);
2598 res = gst_pad_event_default (pad, parent, event);
2606 gst_deinterlace_propose_allocation (GstDeinterlace * self, GstQuery * query)
2608 GstBufferPool *pool;
2612 GstStructure *config;
2614 gst_query_parse_allocation (query, &caps, NULL);
2619 if (!gst_video_info_from_caps (&info, caps))
2622 size = GST_VIDEO_INFO_SIZE (&info);
2624 pool = gst_video_buffer_pool_new ();
2626 gst_query_add_allocation_pool (query, pool, size, 0, 0);
2628 config = gst_buffer_pool_get_config (pool);
2629 gst_buffer_pool_config_set_params (config, caps, size,
2630 (gst_deinterlace_method_get_fields_required (self->method) + 1) / 2 + 1,
2632 gst_buffer_pool_set_config (pool, config);
2634 gst_object_unref (pool);
2635 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
2641 gst_deinterlace_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
2643 GstDeinterlace *self = GST_DEINTERLACE (parent);
2644 gboolean res = FALSE;
2646 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
2648 switch (GST_QUERY_TYPE (query)) {
2649 case GST_QUERY_CAPS:
2651 GstCaps *filter, *caps;
2653 gst_query_parse_caps (query, &filter);
2654 caps = gst_deinterlace_getcaps (self, pad, filter);
2655 gst_query_set_caps_result (query, caps);
2656 gst_caps_unref (caps);
2660 case GST_QUERY_ALLOCATION:
2661 if (self->passthrough)
2662 res = gst_pad_peer_query (self->srcpad, query);
2664 res = gst_deinterlace_propose_allocation (self, query);
2667 res = gst_pad_query_default (pad, parent, query);
2673 static GstStateChangeReturn
2674 gst_deinterlace_change_state (GstElement * element, GstStateChange transition)
2676 GstStateChangeReturn ret;
2677 GstDeinterlace *self = GST_DEINTERLACE (element);
2679 switch (transition) {
2680 case GST_STATE_CHANGE_NULL_TO_READY:
2682 case GST_STATE_CHANGE_READY_TO_PAUSED:
2684 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2690 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2691 if (ret != GST_STATE_CHANGE_SUCCESS)
2694 switch (transition) {
2695 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2697 case GST_STATE_CHANGE_PAUSED_TO_READY:
2698 gst_deinterlace_reset (self);
2700 case GST_STATE_CHANGE_READY_TO_NULL:
2709 gst_deinterlace_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
2711 GstDeinterlace *self = GST_DEINTERLACE (parent);
2714 GST_DEBUG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
2716 switch (GST_EVENT_TYPE (event)) {
2717 case GST_EVENT_QOS:{
2718 GstClockTimeDiff diff;
2719 GstClockTime timestamp;
2723 gst_event_parse_qos (event, &type, &proportion, &diff, ×tamp);
2725 gst_deinterlace_update_qos (self, proportion, diff, timestamp);
2729 res = gst_pad_event_default (pad, parent, event);
2737 gst_deinterlace_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
2739 GstDeinterlace *self = GST_DEINTERLACE (parent);
2740 gboolean res = FALSE;
2742 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
2744 switch (GST_QUERY_TYPE (query)) {
2745 case GST_QUERY_LATENCY:
2746 if (!self->passthrough) {
2747 GstClockTime min, max;
2751 if ((peer = gst_pad_get_peer (self->sinkpad))) {
2752 if ((res = gst_pad_query (peer, query))) {
2753 GstClockTime latency;
2754 gint fields_required = 0;
2755 gint method_latency = 0;
2759 gst_deinterlace_method_get_fields_required (self->method);
2761 gst_deinterlace_method_get_latency (self->method);
2764 gst_query_parse_latency (query, &live, &min, &max);
2766 GST_DEBUG_OBJECT (self, "Peer latency: min %"
2767 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
2768 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
2770 /* add our own latency */
2771 latency = (fields_required + method_latency) * self->field_duration;
2773 GST_DEBUG_OBJECT (self, "Our latency: min %" GST_TIME_FORMAT
2774 ", max %" GST_TIME_FORMAT,
2775 GST_TIME_ARGS (latency), GST_TIME_ARGS (latency));
2778 if (max != GST_CLOCK_TIME_NONE)
2781 GST_DEBUG_OBJECT (self, "Calculated total latency : min %"
2782 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
2783 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
2785 gst_query_set_latency (query, live, min, max);
2787 gst_object_unref (peer);
2794 res = gst_pad_query_default (pad, parent, query);
2801 /* FIXME: buffer alloc */
2803 static GstFlowReturn
2804 gst_deinterlace_alloc_buffer (GstPad * pad, guint64 offset, guint size,
2805 GstCaps * caps, GstBuffer ** buf)
2807 GstDeinterlace *self = GST_DEINTERLACE (gst_pad_get_parent (pad));
2808 GstFlowReturn ret = GST_FLOW_OK;
2812 GST_DEBUG_OBJECT (pad, "alloc with caps %" GST_PTR_FORMAT ", size %u", caps,
2815 if (self->still_frame_mode || self->passthrough) {
2816 ret = gst_pad_alloc_buffer (self->srcpad, offset, size, caps, buf);
2817 } else if (G_LIKELY (!self->request_caps)) {
2818 *buf = gst_buffer_try_new_and_alloc (size);
2819 if (G_UNLIKELY (!*buf)) {
2820 ret = GST_FLOW_ERROR;
2822 gst_buffer_set_caps (*buf, caps);
2823 GST_BUFFER_OFFSET (*buf) = offset;
2828 guint new_frame_size;
2829 GstCaps *new_caps = gst_caps_copy (self->request_caps);
2831 if (self->fields == GST_DEINTERLACE_ALL) {
2833 GstStructure *s = gst_caps_get_structure (new_caps, 0);
2835 gst_structure_get_fraction (s, "framerate", &n, &d);
2837 if (!gst_fraction_double (&n, &d, TRUE)) {
2838 gst_object_unref (self);
2839 gst_caps_unref (new_caps);
2843 gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
2846 if (G_UNLIKELY (!gst_video_format_parse_caps (new_caps, &fmt, &width,
2848 gst_object_unref (self);
2849 gst_caps_unref (new_caps);
2853 new_frame_size = gst_video_format_get_size (fmt, width, height);
2855 *buf = gst_buffer_try_new_and_alloc (new_frame_size);
2856 if (G_UNLIKELY (!*buf)) {
2857 ret = GST_FLOW_ERROR;
2859 gst_buffer_set_caps (*buf, new_caps);
2860 gst_caps_unref (self->request_caps);
2861 self->request_caps = NULL;
2862 gst_caps_unref (new_caps);
2866 gst_object_unref (self);
2873 plugin_init (GstPlugin * plugin)
2875 GST_DEBUG_CATEGORY_INIT (deinterlace_debug, "deinterlace", 0, "Deinterlacer");
2881 if (!gst_element_register (plugin, "deinterlace", GST_RANK_NONE,
2882 GST_TYPE_DEINTERLACE)) {
2889 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
2892 "Deinterlacer", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
2893 GST_PACKAGE_ORIGIN);