2 * Copyright (C) 2021 Igalia, S.L.
3 * Author: Víctor Jáquez <vjaquez@igalia.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the0
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
22 * SECTION:element-vadeinterlace
23 * @title: vadeinterlace
24 * @short_description: A VA-API base video deinterlace filter
26 * vadeinterlace deinterlaces interlaced video frames to progressive
27 * video frames. This element and its deinterlacing methods depend on
28 * the installed and chosen [VA-API](https://01.org/linuxmedia/vaapi)
29 * driver, but it's usually avaialble with bob (linear) method.
31 * This element doesn't change the caps features, it only negotiates
32 * the same dowstream and upstream.
34 * ## Example launch line
36 * gst-launch-1.0 filesrc location=interlaced_video.mp4 ! parsebin ! vah264dec ! vadeinterlace ! vapostproc ! autovideosink
45 * + field property to select only one field and keep the same framerate
52 #include "gstvadeinterlace.h"
54 #include <gst/va/gstva.h>
55 #include <gst/video/video.h>
56 #include <va/va_drmcommon.h>
58 #include "gstvabasetransform.h"
59 #include "gstvacaps.h"
60 #include "gstvadisplay_priv.h"
61 #include "gstvafilter.h"
63 GST_DEBUG_CATEGORY_STATIC (gst_va_deinterlace_debug);
64 #define GST_CAT_DEFAULT gst_va_deinterlace_debug
66 #define GST_VA_DEINTERLACE(obj) ((GstVaDeinterlace *) obj)
67 #define GST_VA_DEINTERLACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_FROM_INSTANCE (obj), GstVaDeinterlaceClass))
68 #define GST_VA_DEINTERLACE_CLASS(klass) ((GstVaDeinterlaceClass *) klass)
70 typedef struct _GstVaDeinterlace GstVaDeinterlace;
71 typedef struct _GstVaDeinterlaceClass GstVaDeinterlaceClass;
81 struct _GstVaDeinterlaceClass
83 /* GstVideoFilter overlaps functionality */
84 GstVaBaseTransformClass parent_class;
87 struct _GstVaDeinterlace
89 GstVaBaseTransform parent;
91 gboolean rebuild_filters;
92 VAProcDeinterlacingType method;
94 guint num_backward_references;
96 GstBuffer *history[8];
100 enum CurrField curr_field;
102 /* Calculated buffer duration by using upstream framerate */
103 GstClockTime default_duration;
106 static GstElementClass *parent_class = NULL;
110 gchar *render_device_path;
115 static const gchar *caps_str =
116 GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_VA,
117 "{ NV12, I420, YV12, YUY2, RGBA, BGRA, P010_10LE, ARGB, ABGR }") " ;"
118 GST_VIDEO_CAPS_MAKE ("{ VUYA, GRAY8, NV12, NV21, YUY2, UYVY, YV12, "
119 "I420, P010_10LE, RGBA, BGRA, ARGB, ABGR }");
123 _reset_history (GstVaDeinterlace * self)
127 for (i = 0; i < self->hcount; i++)
128 gst_buffer_unref (self->history[i]);
133 gst_va_deinterlace_dispose (GObject * object)
135 GstVaDeinterlace *self = GST_VA_DEINTERLACE (object);
137 _reset_history (self);
139 G_OBJECT_CLASS (parent_class)->dispose (object);
143 gst_va_deinterlace_set_property (GObject * object, guint prop_id,
144 const GValue * value, GParamSpec * pspec)
146 GstVaDeinterlace *self = GST_VA_DEINTERLACE (object);
149 GST_OBJECT_LOCK (object);
151 case GST_VA_FILTER_PROP_DEINTERLACE_METHOD:
152 method = g_value_get_enum (value);
153 if (method != self->method) {
154 self->method = method;
155 g_atomic_int_set (&self->rebuild_filters, TRUE);
159 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
162 GST_OBJECT_UNLOCK (object);
166 gst_va_deinterlace_get_property (GObject * object, guint prop_id,
167 GValue * value, GParamSpec * pspec)
169 GstVaDeinterlace *self = GST_VA_DEINTERLACE (object);
171 GST_OBJECT_LOCK (object);
173 case GST_VA_FILTER_PROP_DEINTERLACE_METHOD:{
174 g_value_set_enum (value, self->method);
178 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
181 GST_OBJECT_UNLOCK (object);
185 gst_va_deinterlace_submit_input_buffer (GstBaseTransform * trans,
186 gboolean is_discont, GstBuffer * input)
188 GstVaBaseTransform *btrans = GST_VA_BASE_TRANSFORM (trans);
189 GstVaDeinterlace *self = GST_VA_DEINTERLACE (trans);
190 GstBuffer *buf, *inbuf;
194 /* Let baseclass handle QoS first */
195 ret = GST_BASE_TRANSFORM_CLASS (parent_class)->submit_input_buffer (trans,
197 if (ret != GST_FLOW_OK)
200 if (gst_base_transform_is_passthrough (trans))
203 /* at this moment, baseclass must hold queued_buf */
204 g_assert (trans->queued_buf != NULL);
206 /* Check if we can use this buffer directly. If not, copy this into
207 * our fallback buffer */
208 buf = trans->queued_buf;
209 trans->queued_buf = NULL;
211 ret = gst_va_base_transform_import_buffer (btrans, buf, &inbuf);
212 if (ret != GST_FLOW_OK)
215 gst_buffer_unref (buf);
217 if (self->hcount < self->hdepth) {
218 self->history[self->hcount++] = inbuf;
220 gst_clear_buffer (&self->history[0]);
221 for (i = 0; i + 1 < self->hcount; i++)
222 self->history[i] = self->history[i + 1];
223 self->history[i] = inbuf;
226 if (self->history[self->hcurr])
227 self->curr_field = FIRST_FIELD;
233 _build_filter (GstVaDeinterlace * self)
235 GstVaBaseTransform *btrans = GST_VA_BASE_TRANSFORM (self);
237 VAProcFilterCapDeinterlacing *caps;
238 guint32 num_forward_references;
240 caps = gst_va_filter_get_filter_caps (btrans->filter,
241 VAProcFilterDeinterlacing, &num_caps);
245 for (i = 0; i < num_caps; i++) {
246 if (caps[i].type != self->method)
249 if (gst_va_filter_add_deinterlace_buffer (btrans->filter, self->method,
250 &num_forward_references, &self->num_backward_references)) {
251 self->hdepth = num_forward_references + self->num_backward_references + 1;
252 if (self->hdepth > 8) {
253 GST_ELEMENT_ERROR (self, STREAM, FAILED,
254 ("Pipeline requires too many references: (%u forward, %u backward)",
255 num_forward_references, self->num_backward_references), (NULL));
257 GST_INFO_OBJECT (self, "References for method: %u forward / %u backward",
258 num_forward_references, self->num_backward_references);
259 self->hcurr = num_forward_references;
264 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS,
265 ("Invalid deinterlacing method: %d", self->method), (NULL));
269 gst_va_deinterlace_rebuild_filters (GstVaDeinterlace * self)
271 GstVaBaseTransform *btrans = GST_VA_BASE_TRANSFORM (self);
273 if (!g_atomic_int_get (&self->rebuild_filters))
276 _reset_history (self);
277 gst_va_filter_drop_filter_buffers (btrans->filter);
278 _build_filter (self);
280 /* extra number of buffers for propose_allocation */
281 if (self->hdepth > btrans->extra_min_buffers) {
282 btrans->extra_min_buffers = self->hdepth;
283 gst_base_transform_reconfigure_sink (GST_BASE_TRANSFORM (self));
286 g_atomic_int_set (&self->rebuild_filters, FALSE);
290 gst_va_deinterlace_set_info (GstVaBaseTransform * btrans, GstCaps * incaps,
291 GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
293 GstBaseTransform *trans = GST_BASE_TRANSFORM (btrans);
294 GstVaDeinterlace *self = GST_VA_DEINTERLACE (btrans);
296 switch (GST_VIDEO_INFO_INTERLACE_MODE (in_info)) {
297 case GST_VIDEO_INTERLACE_MODE_PROGRESSIVE:
299 gst_base_transform_set_passthrough (trans, TRUE);
302 case GST_VIDEO_INTERLACE_MODE_ALTERNATE:
303 case GST_VIDEO_INTERLACE_MODE_FIELDS:
304 GST_ERROR_OBJECT (self, "Unsupported interlace mode.");
311 /* Calculate expected buffer duration. We might need to reference this value
312 * when buffer duration is unknown */
313 if (GST_VIDEO_INFO_FPS_N (in_info) > 0 && GST_VIDEO_INFO_FPS_D (in_info) > 0) {
314 self->default_duration =
315 gst_util_uint64_scale_int (GST_SECOND, GST_VIDEO_INFO_FPS_D (in_info),
316 GST_VIDEO_INFO_FPS_N (in_info));
318 /* Assume 25 fps. We need this for reporting latency at least */
319 self->default_duration = gst_util_uint64_scale_int (GST_SECOND, 1, 25);
322 if (gst_va_filter_set_video_info (btrans->filter, in_info, out_info)) {
323 g_atomic_int_set (&self->rebuild_filters, TRUE);
324 gst_base_transform_set_passthrough (trans, FALSE);
325 gst_va_deinterlace_rebuild_filters (self);
334 gst_va_deinterlace_before_transform (GstBaseTransform * trans,
337 GstVaDeinterlace *self = GST_VA_DEINTERLACE (trans);
338 GstClockTime ts, stream_time;
340 ts = GST_BUFFER_TIMESTAMP (inbuf);
342 gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME, ts);
344 GST_TRACE_OBJECT (self, "sync to %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
346 if (GST_CLOCK_TIME_IS_VALID (stream_time))
347 gst_object_sync_values (GST_OBJECT (self), stream_time);
349 gst_va_deinterlace_rebuild_filters (self);
353 _set_field (GstVaDeinterlace * self, guint32 * surface_flags)
355 GstBaseTransform *trans = GST_BASE_TRANSFORM (self);
357 if (trans->segment.rate < 0) {
358 if ((self->curr_field == FIRST_FIELD
359 && (*surface_flags & VA_TOP_FIELD_FIRST))
360 || (self->curr_field == SECOND_FIELD
361 && (*surface_flags & VA_BOTTOM_FIELD_FIRST))) {
362 *surface_flags |= VA_BOTTOM_FIELD;
364 *surface_flags |= VA_TOP_FIELD;
367 if ((self->curr_field == FIRST_FIELD
368 && (*surface_flags & VA_BOTTOM_FIELD_FIRST))
369 || (self->curr_field == SECOND_FIELD
370 && (*surface_flags & VA_TOP_FIELD_FIRST))) {
371 *surface_flags |= VA_BOTTOM_FIELD;
373 *surface_flags |= VA_TOP_FIELD;
379 gst_va_deinterlace_transform (GstBaseTransform * trans, GstBuffer * inbuf,
382 GstVaDeinterlace *self = GST_VA_DEINTERLACE (trans);
383 GstVaBaseTransform *btrans = GST_VA_BASE_TRANSFORM (trans);
384 GstFlowReturn res = GST_FLOW_OK;
385 GstVaSample src, dst;
386 GstVideoInfo *info = &btrans->in_info;
387 VASurfaceID forward_references[8], backward_references[8];
388 guint i, surface_flags;
390 if (G_UNLIKELY (!btrans->negotiated))
393 g_assert (self->curr_field == FIRST_FIELD
394 || self->curr_field == SECOND_FIELD);
396 surface_flags = gst_va_buffer_get_surface_flags (inbuf, info);
397 if (surface_flags != VA_FRAME_PICTURE)
398 _set_field (self, &surface_flags);
400 GST_TRACE_OBJECT (self, "Processing %d field (flags = %u): %" GST_PTR_FORMAT,
401 self->curr_field, surface_flags, inbuf);
403 for (i = 0; i < self->hcurr; i++) {
404 forward_references[i] =
405 gst_va_buffer_get_surface (self->history[self->hcurr - i - 1]);
407 for (i = 0; i < self->num_backward_references; i++) {
408 backward_references[i] =
409 gst_va_buffer_get_surface (self->history[self->hcurr + i + 1]);
413 src = (GstVaSample) {
415 .flags = surface_flags,
416 .forward_references = forward_references,
417 .num_forward_references = self->hcurr,
418 .backward_references = backward_references,
419 .num_backward_references = self->num_backward_references,
421 dst = (GstVaSample) {
426 if (!gst_va_filter_process (btrans->filter, &src, &dst)) {
427 gst_buffer_set_flags (outbuf, GST_BUFFER_FLAG_CORRUPTED);
428 res = GST_BASE_TRANSFORM_FLOW_DROPPED;
436 GST_ELEMENT_ERROR (self, CORE, NOT_IMPLEMENTED, (NULL), ("unknown format"));
437 return GST_FLOW_NOT_NEGOTIATED;
442 gst_va_deinterlace_generate_output (GstBaseTransform * trans,
445 GstVaDeinterlace *self = GST_VA_DEINTERLACE (trans);
447 GstBuffer *inbuf, *buf = NULL;
449 if (gst_base_transform_is_passthrough (trans)) {
450 return GST_BASE_TRANSFORM_CLASS (parent_class)->generate_output (trans,
456 if (self->curr_field == FINISHED)
459 inbuf = self->history[self->hcurr];
463 if (!self->history[self->hdepth - 1])
466 ret = GST_BASE_TRANSFORM_CLASS (parent_class)->prepare_output_buffer (trans,
468 if (ret != GST_FLOW_OK || !buf) {
469 GST_WARNING_OBJECT (self, "Could not get buffer from pool: %s",
470 gst_flow_get_name (ret));
474 ret = gst_va_deinterlace_transform (trans, inbuf, buf);
475 if (ret != GST_FLOW_OK) {
476 gst_buffer_unref (buf);
480 if (!GST_BUFFER_PTS_IS_VALID (inbuf)) {
481 GST_LOG_OBJECT (self, "Input buffer timestamp is unknown");
483 GstClockTime duration;
485 if (GST_BUFFER_DURATION_IS_VALID (inbuf))
486 duration = GST_BUFFER_DURATION (inbuf) / 2;
488 duration = self->default_duration / 2;
490 GST_BUFFER_DURATION (buf) = duration;
491 if (self->curr_field == SECOND_FIELD)
492 GST_BUFFER_PTS (buf) = GST_BUFFER_PTS (buf) + duration;
497 GST_TRACE_OBJECT (self, "Pushing %" GST_PTR_FORMAT, buf);
499 if (self->curr_field == FIRST_FIELD)
500 self->curr_field = SECOND_FIELD;
501 else if (self->curr_field == SECOND_FIELD)
502 self->curr_field = FINISHED;
508 gst_va_deinterlace_remove_interlace (GstCaps * caps)
515 res = gst_caps_new_empty ();
517 n = gst_caps_get_size (caps);
518 for (i = 0; i < n; i++) {
519 st = gst_caps_get_structure (caps, i);
520 f = gst_caps_get_features (caps, i);
522 /* If this is already expressed by the existing caps
523 * skip this structure */
524 if (i > 0 && gst_caps_is_subset_structure_full (res, st, f))
527 st = gst_structure_copy (st);
528 gst_structure_remove_fields (st, "interlace-mode", "field-order",
531 gst_caps_append_structure_full (res, st, gst_caps_features_copy (f));
538 gst_va_deinterlace_transform_caps (GstBaseTransform * trans,
539 GstPadDirection direction, GstCaps * caps, GstCaps * filter)
541 GstVaDeinterlace *self = GST_VA_DEINTERLACE (trans);
542 GstVaBaseTransform *btrans = GST_VA_BASE_TRANSFORM (trans);
543 GstCaps *ret, *filter_caps;
545 GST_DEBUG_OBJECT (self,
546 "Transforming caps %" GST_PTR_FORMAT " in direction %s", caps,
547 (direction == GST_PAD_SINK) ? "sink" : "src");
549 filter_caps = gst_va_base_transform_get_filter_caps (btrans);
550 if (filter_caps && !gst_caps_can_intersect (caps, filter_caps)) {
551 ret = gst_caps_ref (caps);
555 ret = gst_va_deinterlace_remove_interlace (caps);
559 GstCaps *intersection;
562 gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
563 gst_caps_unref (ret);
567 GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, ret);
573 gst_va_deinterlace_fixate_caps (GstBaseTransform * trans,
574 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
576 GstVaDeinterlace *self = GST_VA_DEINTERLACE (trans);
577 GstCapsFeatures *out_f;
578 GstStructure *in_s, *out_s;
580 const gchar *in_interlace_mode, *out_interlace_mode;
582 GST_DEBUG_OBJECT (self,
583 "trying to fixate othercaps %" GST_PTR_FORMAT " based on caps %"
584 GST_PTR_FORMAT, othercaps, caps);
586 othercaps = gst_caps_truncate (othercaps);
587 othercaps = gst_caps_make_writable (othercaps);
589 if (direction == GST_PAD_SRC) {
590 othercaps = gst_caps_fixate (othercaps);
594 in_s = gst_caps_get_structure (caps, 0);
595 in_interlace_mode = gst_structure_get_string (in_s, "interlace-mode");
597 out_s = gst_caps_get_structure (othercaps, 0);
599 if (g_strcmp0 ("progressive", in_interlace_mode) == 0) {
600 /* Just forward interlace-mode=progressive and framerate
601 * By this way, basetransform will enable passthrough for non-interlaced
603 const GValue *framerate = gst_structure_get_value (in_s, "framerate");
604 gst_structure_set_value (out_s, "framerate", framerate);
605 gst_structure_set (out_s, "interlace-mode", G_TYPE_STRING, "progressive",
611 out_f = gst_caps_get_features (othercaps, 0);
612 out_interlace_mode = gst_structure_get_string (out_s, "interlace-mode");
614 if ((!out_interlace_mode
615 || (g_strcmp0 ("progressive", out_interlace_mode) == 0))
616 && (gst_caps_features_contains (out_f, GST_CAPS_FEATURE_MEMORY_VA)
617 || gst_caps_features_contains (out_f, GST_CAPS_FEATURE_MEMORY_DMABUF)
618 || gst_caps_features_contains (out_f,
619 GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY))) {
620 gst_structure_set (out_s, "interlace-mode", G_TYPE_STRING, "progressive",
623 if (gst_structure_get_fraction (in_s, "framerate", &fps_n, &fps_d)) {
625 gst_structure_set (out_s, "framerate", GST_TYPE_FRACTION, fps_n, fps_d,
629 /* if caps features aren't supported, just forward interlace-mode
631 const GValue *framerate = gst_structure_get_value (in_s, "framerate");
632 gst_structure_set_value (out_s, "framerate", framerate);
633 gst_structure_set (out_s, "interlace-mode", G_TYPE_STRING,
634 in_interlace_mode, NULL);
638 GST_DEBUG_OBJECT (self, "fixated othercaps to %" GST_PTR_FORMAT, othercaps);
644 gst_va_deinterlace_query (GstBaseTransform * trans, GstPadDirection direction,
647 GstVaDeinterlace *self = GST_VA_DEINTERLACE (trans);
649 if (direction == GST_PAD_SRC && GST_QUERY_TYPE (query) == GST_QUERY_LATENCY
650 && !gst_base_transform_is_passthrough (trans)) {
652 GstClockTime latency, min, max;
653 gboolean res = FALSE;
656 peer = gst_pad_get_peer (GST_BASE_TRANSFORM_SINK_PAD (trans));
660 res = gst_pad_query (peer, query);
661 gst_object_unref (peer);
665 gst_query_parse_latency (query, &live, &min, &max);
667 GST_DEBUG_OBJECT (self, "Peer latency: min %" GST_TIME_FORMAT " max %"
668 GST_TIME_FORMAT, GST_TIME_ARGS (min), GST_TIME_ARGS (max));
670 /* add our own latency: number of fields + history depth */
671 latency = (2 + self->hdepth) * self->default_duration;
673 GST_DEBUG_OBJECT (self, "Our latency: min %" GST_TIME_FORMAT ", max %"
674 GST_TIME_FORMAT, GST_TIME_ARGS (latency), GST_TIME_ARGS (latency));
677 if (max != GST_CLOCK_TIME_NONE)
680 GST_DEBUG_OBJECT (self, "Calculated total latency : min %" GST_TIME_FORMAT
681 " max %" GST_TIME_FORMAT, GST_TIME_ARGS (min), GST_TIME_ARGS (max));
683 gst_query_set_latency (query, live, min, max);
688 return GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction,
693 gst_va_deinterlace_class_init (gpointer g_class, gpointer class_data)
695 GstCaps *doc_caps, *sink_caps = NULL, *src_caps = NULL;
696 GstPadTemplate *sink_pad_templ, *src_pad_templ;
697 GObjectClass *object_class = G_OBJECT_CLASS (g_class);
698 GstBaseTransformClass *trans_class = GST_BASE_TRANSFORM_CLASS (g_class);
699 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
700 GstVaBaseTransformClass *btrans_class = GST_VA_BASE_TRANSFORM_CLASS (g_class);
701 GstVaDisplay *display;
703 struct CData *cdata = class_data;
706 parent_class = g_type_class_peek_parent (g_class);
708 btrans_class->render_device_path = g_strdup (cdata->render_device_path);
710 if (cdata->description) {
711 long_name = g_strdup_printf ("VA-API Deinterlacer in %s",
714 long_name = g_strdup ("VA-API Deinterlacer");
717 gst_element_class_set_metadata (element_class, long_name,
718 "Filter/Effect/Video/Deinterlace",
719 "VA-API based deinterlacer", "Víctor Jáquez <vjaquez@igalia.com>");
721 display = gst_va_display_drm_new_from_path (btrans_class->render_device_path);
722 filter = gst_va_filter_new (display);
724 if (gst_va_filter_open (filter)) {
725 src_caps = gst_va_filter_get_caps (filter);
726 /* adds any to enable passthrough */
728 GstCaps *any_caps = gst_caps_new_empty_simple ("video/x-raw");
729 gst_caps_set_features_simple (any_caps, gst_caps_features_new_any ());
730 src_caps = gst_caps_merge (src_caps, any_caps);
733 src_caps = gst_caps_from_string (caps_str);
736 sink_caps = gst_va_deinterlace_remove_interlace (src_caps);
738 doc_caps = gst_caps_from_string (caps_str);
740 sink_pad_templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
742 gst_element_class_add_pad_template (element_class, sink_pad_templ);
743 gst_pad_template_set_documentation_caps (sink_pad_templ,
744 gst_caps_ref (doc_caps));
746 src_pad_templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
748 gst_element_class_add_pad_template (element_class, src_pad_templ);
749 gst_pad_template_set_documentation_caps (src_pad_templ,
750 gst_caps_ref (doc_caps));
751 gst_caps_unref (doc_caps);
753 gst_caps_unref (src_caps);
754 gst_caps_unref (sink_caps);
756 object_class->dispose = gst_va_deinterlace_dispose;
757 object_class->set_property = gst_va_deinterlace_set_property;
758 object_class->get_property = gst_va_deinterlace_get_property;
760 trans_class->transform_caps =
761 GST_DEBUG_FUNCPTR (gst_va_deinterlace_transform_caps);
762 trans_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_va_deinterlace_fixate_caps);
763 trans_class->before_transform =
764 GST_DEBUG_FUNCPTR (gst_va_deinterlace_before_transform);
765 trans_class->transform = GST_DEBUG_FUNCPTR (gst_va_deinterlace_transform);
766 trans_class->submit_input_buffer =
767 GST_DEBUG_FUNCPTR (gst_va_deinterlace_submit_input_buffer);
768 trans_class->generate_output =
769 GST_DEBUG_FUNCPTR (gst_va_deinterlace_generate_output);
770 trans_class->query = GST_DEBUG_FUNCPTR (gst_va_deinterlace_query);
772 trans_class->transform_ip_on_passthrough = FALSE;
774 btrans_class->set_info = GST_DEBUG_FUNCPTR (gst_va_deinterlace_set_info);
776 gst_va_filter_install_deinterlace_properties (filter, object_class);
779 g_free (cdata->description);
780 g_free (cdata->render_device_path);
782 gst_object_unref (filter);
783 gst_object_unref (display);
787 gst_va_deinterlace_init (GTypeInstance * instance, gpointer g_class)
789 GstVaDeinterlace *self = GST_VA_DEINTERLACE (instance);
792 pspec = g_object_class_find_property (g_class, "method");
794 self->method = g_value_get_enum (g_param_spec_get_default_value (pspec));
798 _register_debug_category (gpointer data)
800 GST_DEBUG_CATEGORY_INIT (gst_va_deinterlace_debug, "vadeinterlace", 0,
801 "VA Video Deinterlace");
807 gst_va_deinterlace_register (GstPlugin * plugin, GstVaDevice * device,
810 static GOnce debug_once = G_ONCE_INIT;
812 GTypeInfo type_info = {
813 .class_size = sizeof (GstVaDeinterlaceClass),
814 .class_init = gst_va_deinterlace_class_init,
815 .instance_size = sizeof (GstVaDeinterlace),
816 .instance_init = gst_va_deinterlace_init,
820 gchar *type_name, *feature_name;
822 g_return_val_if_fail (GST_IS_PLUGIN (plugin), FALSE);
823 g_return_val_if_fail (GST_IS_VA_DEVICE (device), FALSE);
825 cdata = g_new (struct CData, 1);
826 cdata->description = NULL;
827 cdata->render_device_path = g_strdup (device->render_device_path);
829 type_info.class_data = cdata;
831 type_name = g_strdup ("GstVaDeinterlace");
832 feature_name = g_strdup ("vadeinterlace");
834 /* The first postprocessor to be registered should use a constant
835 * name, like vadeinterlace, for any additional postprocessors, we
836 * create unique names, using inserting the render device name. */
837 if (g_type_from_name (type_name)) {
838 gchar *basename = g_path_get_basename (device->render_device_path);
840 g_free (feature_name);
841 type_name = g_strdup_printf ("GstVa%sDeinterlace", basename);
842 feature_name = g_strdup_printf ("va%sdeinterlace", basename);
843 cdata->description = basename;
845 /* lower rank for non-first device */
850 g_once (&debug_once, _register_debug_category, NULL);
852 type = g_type_register_static (GST_TYPE_VA_BASE_TRANSFORM, type_name,
855 ret = gst_element_register (plugin, feature_name, rank, type);
858 g_free (feature_name);