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 the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
25 #include "gstvabasetransform.h"
27 #include "gstvaallocator.h"
28 #include "gstvacaps.h"
29 #include "gstvapool.h"
31 #define GST_CAT_DEFAULT gst_va_base_transform_debug
32 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
34 struct _GstVaBaseTransformPrivate
36 GstVideoInfo srcpad_info;
38 GstBufferPool *other_pool;
40 GstCaps *sinkpad_caps;
41 GstVideoInfo sinkpad_info;
42 GstBufferPool *sinkpad_pool;
50 * A base class implementation for VA-API filters.
54 #define gst_va_base_transform_parent_class parent_class
55 G_DEFINE_TYPE_WITH_CODE (GstVaBaseTransform, gst_va_base_transform,
56 GST_TYPE_BASE_TRANSFORM, G_ADD_PRIVATE (GstVaBaseTransform)
57 GST_DEBUG_CATEGORY_INIT (gst_va_base_transform_debug,
58 "vabasetransform", 0, "vabasetransform element");
61 extern GRecMutex GST_VA_SHARED_LOCK;
64 gst_va_base_transform_dispose (GObject * object)
66 GstVaBaseTransform *self = GST_VA_BASE_TRANSFORM (object);
68 if (self->priv->other_pool) {
69 gst_buffer_pool_set_active (self->priv->other_pool, FALSE);
70 gst_clear_object (&self->priv->other_pool);
73 gst_clear_caps (&self->out_caps);
74 gst_clear_caps (&self->in_caps);
76 gst_clear_caps (&self->priv->filter_caps);
78 gst_clear_object (&self->filter);
79 gst_clear_object (&self->display);
81 if (self->priv->sinkpad_pool) {
82 gst_buffer_pool_set_active (self->priv->sinkpad_pool, FALSE);
83 gst_clear_object (&self->priv->sinkpad_pool);
86 gst_clear_caps (&self->priv->sinkpad_caps);
88 G_OBJECT_CLASS (parent_class)->dispose (object);
92 gst_va_base_transform_init (GstVaBaseTransform * self)
94 gst_base_transform_set_qos_enabled (GST_BASE_TRANSFORM (self), TRUE);
96 self->priv = gst_va_base_transform_get_instance_private (self);
100 gst_va_base_transform_query (GstBaseTransform * trans,
101 GstPadDirection direction, GstQuery * query)
103 GstVaBaseTransform *self = GST_VA_BASE_TRANSFORM (trans);
104 gboolean ret = FALSE;
106 switch (GST_QUERY_TYPE (query)) {
107 case GST_QUERY_CONTEXT:
109 GstVaDisplay *display = NULL;
111 gst_object_replace ((GstObject **) & display,
112 (GstObject *) self->display);
113 ret = gst_va_handle_context_query (GST_ELEMENT_CAST (self), query,
115 gst_clear_object (&display);
119 ret = GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction,
128 gst_va_base_transform_set_caps (GstBaseTransform * trans, GstCaps * incaps,
131 GstVaBaseTransform *self = GST_VA_BASE_TRANSFORM (trans);
132 GstVaBaseTransformClass *fclass;
133 GstVideoInfo in_info, out_info;
137 if (!gst_video_info_from_caps (&in_info, incaps))
141 if (!gst_video_info_from_caps (&out_info, outcaps))
144 fclass = GST_VA_BASE_TRANSFORM_GET_CLASS (self);
145 if (fclass->set_info)
146 res = fclass->set_info (self, incaps, &in_info, outcaps, &out_info);
150 self->negotiated = res;
153 gst_caps_replace (&self->in_caps, incaps);
154 gst_caps_replace (&self->out_caps, outcaps);
156 self->in_info = in_info;
157 self->out_info = out_info;
160 if (self->priv->sinkpad_pool) {
161 gst_buffer_pool_set_active (self->priv->sinkpad_pool, FALSE);
162 gst_clear_object (&self->priv->sinkpad_pool);
165 if (self->priv->other_pool) {
166 gst_buffer_pool_set_active (self->priv->other_pool, FALSE);
167 gst_clear_object (&self->priv->other_pool);
175 GST_ERROR_OBJECT (self, "invalid caps");
176 self->negotiated = FALSE;
181 /* Answer upstream allocation query. */
183 gst_va_base_transform_propose_allocation (GstBaseTransform * trans,
184 GstQuery * decide_query, GstQuery * query)
186 GstVaBaseTransform *self = GST_VA_BASE_TRANSFORM (trans);
187 GstAllocator *allocator = NULL;
188 GstAllocationParams params = { 0, };
192 gboolean update_allocator = FALSE;
193 guint size, usage_hint = VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC; /* it migth be
197 gst_clear_caps (&self->priv->sinkpad_caps);
199 if (!GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (trans,
200 decide_query, query))
203 /* passthrough, we're done */
207 if (gst_query_get_n_allocation_pools (query) > 0)
210 gst_query_parse_allocation (query, &caps, NULL);
213 if (!gst_video_info_from_caps (&info, caps)) {
214 GST_ERROR_OBJECT (self, "Cannot parse caps %" GST_PTR_FORMAT, caps);
218 size = GST_VIDEO_INFO_SIZE (&info);
220 if (gst_query_get_n_allocation_params (query) > 0) {
221 gst_query_parse_nth_allocation_param (query, 0, &allocator, ¶ms);
222 if (!GST_IS_VA_DMABUF_ALLOCATOR (allocator)
223 && !GST_IS_VA_ALLOCATOR (allocator))
224 gst_clear_object (&allocator);
225 update_allocator = TRUE;
227 gst_allocation_params_init (¶ms);
231 if (!(allocator = gst_va_base_transform_allocator_from_caps (self, caps)))
235 pool = gst_va_pool_new_with_config (caps, size, 1 + self->extra_min_buffers,
236 0, usage_hint, allocator, ¶ms);
238 gst_object_unref (allocator);
242 if (update_allocator)
243 gst_query_set_nth_allocation_param (query, 0, allocator, ¶ms);
245 gst_query_add_allocation_param (query, allocator, ¶ms);
247 gst_query_add_allocation_pool (query, pool, size, 1 + self->extra_min_buffers,
250 GST_DEBUG_OBJECT (self,
251 "proposing %" GST_PTR_FORMAT " with allocator %" GST_PTR_FORMAT,
254 gst_object_unref (allocator);
255 gst_object_unref (pool);
257 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
259 self->priv->sinkpad_caps = gst_caps_ref (caps);
266 GST_ERROR_OBJECT (self, "failed to set config");
271 static GstBufferPool *
272 _create_other_pool (GstAllocator * allocator,
273 GstAllocationParams * params, GstCaps * caps, guint size)
275 GstBufferPool *pool = NULL;
276 GstStructure *config;
278 pool = gst_video_buffer_pool_new ();
279 config = gst_buffer_pool_get_config (pool);
281 gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
282 gst_buffer_pool_config_set_allocator (config, allocator, params);
283 if (!gst_buffer_pool_set_config (pool, config)) {
284 gst_clear_object (&pool);
290 /* configure the allocation query that was answered downstream, we can
291 * configure some properties on it. Only it's called when not in
292 * passthrough mode. */
294 gst_va_base_transform_decide_allocation (GstBaseTransform * trans,
297 GstVaBaseTransform *self = GST_VA_BASE_TRANSFORM (trans);
298 GstAllocator *allocator = NULL, *other_allocator = NULL;
299 GstAllocationParams params, other_params;
300 GstBufferPool *pool = NULL, *other_pool = NULL;
301 GstCaps *outcaps = NULL;
302 GstStructure *config;
304 guint min, max, size = 0, usage_hint = VA_SURFACE_ATTRIB_USAGE_HINT_VPP_WRITE;
305 gboolean update_pool, update_allocator, has_videometa, copy_frames;
307 gst_query_parse_allocation (query, &outcaps, NULL);
309 gst_allocation_params_init (&other_params);
310 gst_allocation_params_init (¶ms);
312 if (!gst_video_info_from_caps (&vinfo, outcaps)) {
313 GST_ERROR_OBJECT (self, "Cannot parse caps %" GST_PTR_FORMAT, outcaps);
317 if (gst_query_get_n_allocation_params (query) > 0) {
318 gst_query_parse_nth_allocation_param (query, 0, &allocator, &other_params);
319 if (allocator && !(GST_IS_VA_DMABUF_ALLOCATOR (allocator)
320 || GST_IS_VA_ALLOCATOR (allocator))) {
321 /* save the allocator for the other pool */
322 other_allocator = allocator;
325 update_allocator = TRUE;
327 update_allocator = FALSE;
330 if (gst_query_get_n_allocation_pools (query) > 0) {
331 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
334 if (!GST_IS_VA_POOL (pool)) {
335 GST_DEBUG_OBJECT (self,
336 "may need other pool for copy frames %" GST_PTR_FORMAT, pool);
344 size = GST_VIDEO_INFO_SIZE (&vinfo);
351 /* XXX(victor): USAGE_HINT_VPP_WRITE creates tiled dmabuf frames
353 if (gst_caps_is_dmabuf (outcaps) && GST_VIDEO_INFO_IS_RGB (&vinfo))
354 usage_hint = VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC;
356 gst_va_base_transform_allocator_from_caps (self, outcaps)))
361 pool = gst_va_pool_new ();
363 config = gst_buffer_pool_get_config (pool);
364 gst_buffer_pool_config_set_allocator (config, allocator, ¶ms);
365 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
366 gst_buffer_pool_config_set_params (config, outcaps, size, min, max);
367 gst_buffer_pool_config_set_va_allocation_params (config, usage_hint);
368 if (!gst_buffer_pool_set_config (pool, config)) {
369 gst_object_unref (allocator);
370 gst_object_unref (pool);
374 if (GST_IS_VA_DMABUF_ALLOCATOR (allocator)) {
375 gst_va_dmabuf_allocator_get_format (allocator, &self->priv->srcpad_info,
377 } else if (GST_IS_VA_ALLOCATOR (allocator)) {
378 gst_va_allocator_get_format (allocator, &self->priv->srcpad_info, NULL);
381 if (update_allocator)
382 gst_query_set_nth_allocation_param (query, 0, allocator, ¶ms);
384 gst_query_add_allocation_param (query, allocator, ¶ms);
387 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
389 gst_query_add_allocation_pool (query, pool, size, min, max);
391 has_videometa = gst_query_find_allocation_meta (query,
392 GST_VIDEO_META_API_TYPE, NULL);
394 copy_frames = (!has_videometa && gst_va_pool_requires_video_meta (pool)
395 && gst_caps_is_raw (outcaps));
398 gst_object_replace ((GstObject **) & self->priv->other_pool,
399 (GstObject *) other_pool);
401 self->priv->other_pool =
402 _create_other_pool (other_allocator, &other_params, outcaps, size);
404 GST_DEBUG_OBJECT (self, "Use the other pool for copy %" GST_PTR_FORMAT,
405 self->priv->other_pool);
407 gst_clear_object (&self->priv->other_pool);
410 GST_DEBUG_OBJECT (self,
411 "decided pool %" GST_PTR_FORMAT " with allocator %" GST_PTR_FORMAT,
414 gst_object_unref (allocator);
415 gst_object_unref (pool);
416 gst_clear_object (&other_allocator);
417 gst_clear_object (&other_pool);
419 /* removes allocation metas */
420 return GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans,
425 /* output buffers must be from our VA-based pool, they cannot be
426 * system-allocated */
428 gst_va_base_transform_transform_size (GstBaseTransform * trans,
429 GstPadDirection direction, GstCaps * caps, gsize size,
430 GstCaps * othercaps, gsize * othersize)
436 gst_va_base_transform_generate_output (GstBaseTransform * trans,
439 GstVaBaseTransform *self = GST_VA_BASE_TRANSFORM (trans);
440 GstVideoFrame src_frame;
441 GstVideoFrame dest_frame;
442 GstBuffer *buffer = NULL;
445 ret = GST_BASE_TRANSFORM_CLASS (parent_class)->generate_output (trans,
448 if (ret != GST_FLOW_OK || *outbuf == NULL)
451 if (!self->priv->other_pool)
454 /* Now need to copy the output buffer */
455 ret = GST_FLOW_ERROR;
457 if (!gst_buffer_pool_set_active (self->priv->other_pool, TRUE)) {
458 GST_WARNING_OBJECT (self, "failed to active the other pool %"
459 GST_PTR_FORMAT, self->priv->other_pool);
463 ret = gst_buffer_pool_acquire_buffer (self->priv->other_pool, &buffer, NULL);
464 if (ret != GST_FLOW_OK)
467 if (!gst_video_frame_map (&src_frame, &self->priv->srcpad_info, *outbuf,
471 if (!gst_video_frame_map (&dest_frame, &self->out_info, buffer,
473 gst_video_frame_unmap (&src_frame);
477 if (!gst_video_frame_copy (&dest_frame, &src_frame)) {
478 gst_video_frame_unmap (&src_frame);
479 gst_video_frame_unmap (&dest_frame);
483 gst_video_frame_unmap (&src_frame);
484 gst_video_frame_unmap (&dest_frame);
486 gst_buffer_replace (outbuf, buffer);
490 gst_clear_buffer (&buffer);
494 static GstStateChangeReturn
495 gst_va_base_transform_change_state (GstElement * element,
496 GstStateChange transition)
498 GstVaBaseTransform *self = GST_VA_BASE_TRANSFORM (element);
499 GstVaBaseTransformClass *klass = GST_VA_BASE_TRANSFORM_GET_CLASS (element);
500 GstStateChangeReturn ret;
502 switch (transition) {
503 case GST_STATE_CHANGE_NULL_TO_READY:
504 if (!gst_va_ensure_element_data (element, klass->render_device_path,
507 gst_clear_caps (&self->priv->filter_caps);
508 gst_clear_object (&self->filter);
509 self->filter = gst_va_filter_new (self->display);
510 if (!gst_va_filter_open (self->filter))
512 if (klass->update_properties)
513 klass->update_properties (self);
519 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
521 switch (transition) {
522 case GST_STATE_CHANGE_PAUSED_TO_READY:
523 gst_va_filter_close (self->filter);
525 case GST_STATE_CHANGE_READY_TO_NULL:
526 gst_clear_caps (&self->priv->filter_caps);
527 gst_clear_object (&self->filter);
528 gst_clear_object (&self->display);
539 GST_ELEMENT_ERROR (self, LIBRARY, INIT, (NULL), ("Failed to open VPP"));
540 return GST_STATE_CHANGE_FAILURE;
545 gst_va_base_transform_set_context (GstElement * element, GstContext * context)
547 GstVaDisplay *old_display, *new_display;
548 GstVaBaseTransform *self = GST_VA_BASE_TRANSFORM (element);
549 GstVaBaseTransformClass *klass = GST_VA_BASE_TRANSFORM_GET_CLASS (self);
552 old_display = self->display ? gst_object_ref (self->display) : NULL;
553 ret = gst_va_handle_set_context (element, context, klass->render_device_path,
555 new_display = self->display ? gst_object_ref (self->display) : NULL;
558 || (old_display && new_display && old_display != new_display
560 GST_ELEMENT_WARNING (element, RESOURCE, BUSY,
561 ("Can't replace VA display while operating"), (NULL));
564 gst_clear_object (&old_display);
565 gst_clear_object (&new_display);
567 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
571 gst_va_base_transform_class_init (GstVaBaseTransformClass * klass)
573 GObjectClass *gobject_class;
574 GstElementClass *element_class;
575 GstBaseTransformClass *trans_class;
577 gobject_class = G_OBJECT_CLASS (klass);
578 element_class = GST_ELEMENT_CLASS (klass);
579 trans_class = GST_BASE_TRANSFORM_CLASS (klass);
581 gobject_class->dispose = gst_va_base_transform_dispose;
583 trans_class->query = GST_DEBUG_FUNCPTR (gst_va_base_transform_query);
584 trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_va_base_transform_set_caps);
585 trans_class->propose_allocation =
586 GST_DEBUG_FUNCPTR (gst_va_base_transform_propose_allocation);
587 trans_class->decide_allocation =
588 GST_DEBUG_FUNCPTR (gst_va_base_transform_decide_allocation);
589 trans_class->transform_size =
590 GST_DEBUG_FUNCPTR (gst_va_base_transform_transform_size);
591 trans_class->generate_output =
592 GST_DEBUG_FUNCPTR (gst_va_base_transform_generate_output);
594 element_class->set_context =
595 GST_DEBUG_FUNCPTR (gst_va_base_transform_set_context);
596 element_class->change_state =
597 GST_DEBUG_FUNCPTR (gst_va_base_transform_change_state);
599 gst_type_mark_as_plugin_api (GST_TYPE_VA_BASE_TRANSFORM, 0);
603 gst_va_base_transform_allocator_from_caps (GstVaBaseTransform * self,
606 GstAllocator *allocator = NULL;
608 if (gst_caps_is_dmabuf (caps)) {
609 allocator = gst_va_dmabuf_allocator_new (self->display);
611 GArray *surface_formats = gst_va_filter_get_surface_formats (self->filter);
612 allocator = gst_va_allocator_new (self->display, surface_formats);
619 _get_plane_data_size (GstVideoInfo * info, guint plane)
621 gint comp[GST_VIDEO_MAX_COMPONENTS];
622 gint height, padded_height;
624 gst_video_format_info_component (info->finfo, plane, comp);
626 height = GST_VIDEO_INFO_HEIGHT (info);
628 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info->finfo, comp[0], height);
630 return GST_VIDEO_INFO_PLANE_STRIDE (info, plane) * padded_height;
634 _try_import_dmabuf_unlocked (GstVaBaseTransform * self, GstBuffer * inbuf)
636 GstVaBaseTransform *btrans = GST_VA_BASE_TRANSFORM (self);
638 GstVideoInfo in_info = btrans->in_info;
639 GstMemory *mems[GST_VIDEO_MAX_PLANES];
640 guint i, n_mem, n_planes;
641 gsize offset[GST_VIDEO_MAX_PLANES];
642 uintptr_t fd[GST_VIDEO_MAX_PLANES];
644 n_planes = GST_VIDEO_INFO_N_PLANES (&in_info);
645 n_mem = gst_buffer_n_memory (inbuf);
646 meta = gst_buffer_get_video_meta (inbuf);
648 /* This will eliminate most non-dmabuf out there */
649 if (!gst_is_dmabuf_memory (gst_buffer_peek_memory (inbuf, 0)))
652 /* We cannot have multiple dmabuf per plane */
653 if (n_mem > n_planes)
656 /* Update video info based on video meta */
658 GST_VIDEO_INFO_WIDTH (&in_info) = meta->width;
659 GST_VIDEO_INFO_HEIGHT (&in_info) = meta->height;
661 for (i = 0; i < meta->n_planes; i++) {
662 GST_VIDEO_INFO_PLANE_OFFSET (&in_info, i) = meta->offset[i];
663 GST_VIDEO_INFO_PLANE_STRIDE (&in_info, i) = meta->stride[i];
667 /* Find and validate all memories */
668 for (i = 0; i < n_planes; i++) {
674 plane_size = _get_plane_data_size (&in_info, i);
676 if (!gst_buffer_find_memory (inbuf, in_info.offset[i], plane_size,
677 &mem_idx, &length, &mem_skip))
680 /* We can't have more then one dmabuf per plane */
684 mems[i] = gst_buffer_peek_memory (inbuf, mem_idx);
686 /* And all memory found must be dmabuf */
687 if (!gst_is_dmabuf_memory (mems[i]))
690 offset[i] = mems[i]->offset + mem_skip;
691 fd[i] = gst_dmabuf_memory_get_fd (mems[i]);
694 /* Now create a VASurfaceID for the buffer */
695 return gst_va_dmabuf_memories_setup (btrans->display, &in_info, n_planes,
696 mems, fd, offset, VA_SURFACE_ATTRIB_USAGE_HINT_VPP_READ);
699 static GstBufferPool *
700 _get_sinkpad_pool (GstVaBaseTransform * self)
702 GstAllocator *allocator;
703 GstAllocationParams params = { 0, };
705 GstVideoInfo in_info;
706 guint size, usage_hint = VA_SURFACE_ATTRIB_USAGE_HINT_VPP_READ;
708 if (self->priv->sinkpad_pool)
709 return self->priv->sinkpad_pool;
711 gst_allocation_params_init (¶ms);
713 if (self->priv->sinkpad_caps) {
714 caps = self->priv->sinkpad_caps;
715 gst_video_info_from_caps (&in_info, caps);
717 caps = self->in_caps;
718 in_info = self->in_info;
721 size = GST_VIDEO_INFO_SIZE (&in_info);
723 allocator = gst_va_base_transform_allocator_from_caps (self, caps);
724 self->priv->sinkpad_pool = gst_va_pool_new_with_config (caps, size, 1, 0,
725 usage_hint, allocator, ¶ms);
726 if (!self->priv->sinkpad_pool) {
727 gst_object_unref (allocator);
731 if (GST_IS_VA_DMABUF_ALLOCATOR (allocator)) {
732 gst_va_dmabuf_allocator_get_format (allocator, &self->priv->sinkpad_info,
734 } else if (GST_IS_VA_ALLOCATOR (allocator)) {
735 gst_va_allocator_get_format (allocator, &self->priv->sinkpad_info, NULL);
738 gst_object_unref (allocator);
740 if (!gst_buffer_pool_set_active (self->priv->sinkpad_pool, TRUE)) {
741 GST_WARNING_OBJECT (self, "failed to active the sinkpad pool %"
742 GST_PTR_FORMAT, self->priv->sinkpad_pool);
746 return self->priv->sinkpad_pool;
750 _try_import_buffer (GstVaBaseTransform * self, GstBuffer * inbuf)
755 surface = gst_va_buffer_get_surface (inbuf);
756 if (surface != VA_INVALID_ID)
759 g_rec_mutex_lock (&GST_VA_SHARED_LOCK);
760 ret = _try_import_dmabuf_unlocked (self, inbuf);
761 g_rec_mutex_unlock (&GST_VA_SHARED_LOCK);
767 gst_va_base_transform_import_buffer (GstVaBaseTransform * self,
768 GstBuffer * inbuf, GstBuffer ** buf)
770 GstBuffer *buffer = NULL;
773 GstVideoFrame in_frame, out_frame;
774 gboolean imported, copied;
776 g_return_val_if_fail (GST_IS_VA_BASE_TRANSFORM (self), GST_FLOW_ERROR);
778 imported = _try_import_buffer (self, inbuf);
780 *buf = gst_buffer_ref (inbuf);
784 /* input buffer doesn't come from a vapool, thus it is required to
785 * have a pool, grab from it a new buffer and copy the input
786 * buffer to the new one */
787 if (!(pool = _get_sinkpad_pool (self)))
788 return GST_FLOW_ERROR;
790 ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL);
791 if (ret != GST_FLOW_OK)
794 GST_LOG_OBJECT (self, "copying input frame");
796 if (!gst_video_frame_map (&in_frame, &self->in_info, inbuf, GST_MAP_READ))
799 if (!gst_video_frame_map (&out_frame, &self->priv->sinkpad_info, buffer,
801 gst_video_frame_unmap (&in_frame);
805 copied = gst_video_frame_copy (&out_frame, &in_frame);
807 gst_video_frame_unmap (&out_frame);
808 gst_video_frame_unmap (&in_frame);
813 /* copy metadata, default implemenation of baseclass will copy everything
815 GST_BASE_TRANSFORM_CLASS (parent_class)->copy_metadata
816 (GST_BASE_TRANSFORM_CAST (self), inbuf, buffer);
824 GST_ELEMENT_WARNING (self, CORE, NOT_IMPLEMENTED, (NULL),
825 ("invalid video buffer received"));
827 gst_buffer_unref (buffer);
833 gst_va_base_transform_get_filter_caps (GstVaBaseTransform * self)
835 g_return_val_if_fail (GST_IS_VA_BASE_TRANSFORM (self), NULL);
837 GST_OBJECT_LOCK (self);
838 if (self->priv->filter_caps) {
839 GST_OBJECT_UNLOCK (self);
840 return self->priv->filter_caps;
842 GST_OBJECT_UNLOCK (self);
847 GST_OBJECT_LOCK (self);
848 self->priv->filter_caps = gst_va_filter_get_caps (self->filter);
849 GST_OBJECT_UNLOCK (self);
850 return self->priv->filter_caps;