0842fcf27b060ffca35116a06f7afa8f57fd4a7b
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / va / gstvabasetransform.c
1 /* GStreamer
2  * Copyright (C) 2021 Igalia, S.L.
3  *     Author: Víctor Jáquez <vjaquez@igalia.com>
4  *
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.
9  *
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.
14  *
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.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "gstvabasetransform.h"
26
27 #include "gstvaallocator.h"
28 #include "gstvacaps.h"
29 #include "gstvapool.h"
30
31 #define GST_CAT_DEFAULT gst_va_base_transform_debug
32 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
33
34 struct _GstVaBaseTransformPrivate
35 {
36   GstVideoInfo srcpad_info;
37
38   GstBufferPool *other_pool;
39
40   GstCaps *sinkpad_caps;
41   GstVideoInfo sinkpad_info;
42   GstBufferPool *sinkpad_pool;
43
44   GstCaps *filter_caps;
45 };
46
47 /**
48  * GstVaBaseTransform:
49  *
50  * A base class implementation for VA-API filters.
51  *
52  * Since: 1.20
53  */
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");
59     );
60
61 extern GRecMutex GST_VA_SHARED_LOCK;
62
63 static void
64 gst_va_base_transform_dispose (GObject * object)
65 {
66   GstVaBaseTransform *self = GST_VA_BASE_TRANSFORM (object);
67
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);
71   }
72
73   gst_clear_caps (&self->out_caps);
74   gst_clear_caps (&self->in_caps);
75
76   gst_clear_caps (&self->priv->filter_caps);
77
78   gst_clear_object (&self->filter);
79   gst_clear_object (&self->display);
80
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);
84   }
85
86   gst_clear_caps (&self->priv->sinkpad_caps);
87
88   G_OBJECT_CLASS (parent_class)->dispose (object);
89 }
90
91 static void
92 gst_va_base_transform_init (GstVaBaseTransform * self)
93 {
94   gst_base_transform_set_qos_enabled (GST_BASE_TRANSFORM (self), TRUE);
95
96   self->priv = gst_va_base_transform_get_instance_private (self);
97 }
98
99 static gboolean
100 gst_va_base_transform_query (GstBaseTransform * trans,
101     GstPadDirection direction, GstQuery * query)
102 {
103   GstVaBaseTransform *self = GST_VA_BASE_TRANSFORM (trans);
104   gboolean ret = FALSE;
105
106   switch (GST_QUERY_TYPE (query)) {
107     case GST_QUERY_CONTEXT:
108     {
109       GstVaDisplay *display = NULL;
110
111       gst_object_replace ((GstObject **) & display,
112           (GstObject *) self->display);
113       ret = gst_va_handle_context_query (GST_ELEMENT_CAST (self), query,
114           display);
115       gst_clear_object (&display);
116       break;
117     }
118     default:
119       ret = GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction,
120           query);
121       break;
122   }
123
124   return ret;
125 }
126
127 static gboolean
128 gst_va_base_transform_set_caps (GstBaseTransform * trans, GstCaps * incaps,
129     GstCaps * outcaps)
130 {
131   GstVaBaseTransform *self = GST_VA_BASE_TRANSFORM (trans);
132   GstVaBaseTransformClass *fclass;
133   GstVideoInfo in_info, out_info;
134   gboolean res;
135
136   /* input caps */
137   if (!gst_video_info_from_caps (&in_info, incaps))
138     goto invalid_caps;
139
140   /* output caps */
141   if (!gst_video_info_from_caps (&out_info, outcaps))
142     goto invalid_caps;
143
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);
147   else
148     res = TRUE;
149
150   self->negotiated = res;
151
152   if (res) {
153     gst_caps_replace (&self->in_caps, incaps);
154     gst_caps_replace (&self->out_caps, outcaps);
155
156     self->in_info = in_info;
157     self->out_info = out_info;
158   }
159
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);
163   }
164
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);
168   }
169
170   return res;
171
172   /* ERRORS */
173 invalid_caps:
174   {
175     GST_ERROR_OBJECT (self, "invalid caps");
176     self->negotiated = FALSE;
177     return FALSE;
178   }
179 }
180
181 /* Answer upstream allocation query. */
182 static gboolean
183 gst_va_base_transform_propose_allocation (GstBaseTransform * trans,
184     GstQuery * decide_query, GstQuery * query)
185 {
186   GstVaBaseTransform *self = GST_VA_BASE_TRANSFORM (trans);
187   GstAllocator *allocator = NULL;
188   GstAllocationParams params = { 0, };
189   GstBufferPool *pool;
190   GstCaps *caps;
191   GstVideoInfo info;
192   gboolean update_allocator = FALSE;
193   guint size, usage_hint = VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC;        /* it migth be
194                                                                          * used by a va
195                                                                          * decoder */
196
197   gst_clear_caps (&self->priv->sinkpad_caps);
198
199   if (!GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (trans,
200           decide_query, query))
201     return FALSE;
202
203   /* passthrough, we're done */
204   if (!decide_query)
205     return TRUE;
206
207   if (gst_query_get_n_allocation_pools (query) > 0)
208     return TRUE;
209
210   gst_query_parse_allocation (query, &caps, NULL);
211   if (!caps)
212     return FALSE;
213   if (!gst_video_info_from_caps (&info, caps)) {
214     GST_ERROR_OBJECT (self, "Cannot parse caps %" GST_PTR_FORMAT, caps);
215     return FALSE;
216   }
217
218   size = GST_VIDEO_INFO_SIZE (&info);
219
220   if (gst_query_get_n_allocation_params (query) > 0) {
221     gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);
222     if (!GST_IS_VA_DMABUF_ALLOCATOR (allocator)
223         && !GST_IS_VA_ALLOCATOR (allocator))
224       gst_clear_object (&allocator);
225     update_allocator = TRUE;
226   } else {
227     gst_allocation_params_init (&params);
228   }
229
230   if (!allocator) {
231     if (!(allocator = gst_va_base_transform_allocator_from_caps (self, caps)))
232       return FALSE;
233   }
234
235   pool = gst_va_pool_new_with_config (caps, size, 1 + self->extra_min_buffers,
236       0, usage_hint, allocator, &params);
237   if (!pool) {
238     gst_object_unref (allocator);
239     goto config_failed;
240   }
241
242   if (update_allocator)
243     gst_query_set_nth_allocation_param (query, 0, allocator, &params);
244   else
245     gst_query_add_allocation_param (query, allocator, &params);
246
247   gst_query_add_allocation_pool (query, pool, size, 1 + self->extra_min_buffers,
248       0);
249
250   GST_DEBUG_OBJECT (self,
251       "proposing %" GST_PTR_FORMAT " with allocator %" GST_PTR_FORMAT,
252       pool, allocator);
253
254   gst_object_unref (allocator);
255   gst_object_unref (pool);
256
257   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
258
259   self->priv->sinkpad_caps = gst_caps_ref (caps);
260
261   return TRUE;
262
263   /* ERRORS */
264 config_failed:
265   {
266     GST_ERROR_OBJECT (self, "failed to set config");
267     return FALSE;
268   }
269 }
270
271 static GstBufferPool *
272 _create_other_pool (GstAllocator * allocator,
273     GstAllocationParams * params, GstCaps * caps, guint size)
274 {
275   GstBufferPool *pool = NULL;
276   GstStructure *config;
277
278   pool = gst_video_buffer_pool_new ();
279   config = gst_buffer_pool_get_config (pool);
280
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);
285   }
286
287   return pool;
288 }
289
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. */
293 static gboolean
294 gst_va_base_transform_decide_allocation (GstBaseTransform * trans,
295     GstQuery * query)
296 {
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;
303   GstVideoInfo vinfo;
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;
306
307   gst_query_parse_allocation (query, &outcaps, NULL);
308
309   gst_allocation_params_init (&other_params);
310   gst_allocation_params_init (&params);
311
312   if (!gst_video_info_from_caps (&vinfo, outcaps)) {
313     GST_ERROR_OBJECT (self, "Cannot parse caps %" GST_PTR_FORMAT, outcaps);
314     return FALSE;
315   }
316
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;
323       allocator = NULL;
324     }
325     update_allocator = TRUE;
326   } else {
327     update_allocator = FALSE;
328   }
329
330   if (gst_query_get_n_allocation_pools (query) > 0) {
331     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
332
333     if (pool) {
334       if (!GST_IS_VA_POOL (pool)) {
335         GST_DEBUG_OBJECT (self,
336             "may need other pool for copy frames %" GST_PTR_FORMAT, pool);
337         other_pool = pool;
338         pool = NULL;
339       }
340     }
341
342     update_pool = TRUE;
343   } else {
344     size = GST_VIDEO_INFO_SIZE (&vinfo);
345     min = 1;
346     max = 0;
347     update_pool = FALSE;
348   }
349
350   if (!allocator) {
351     /* XXX(victor): USAGE_HINT_VPP_WRITE creates tiled dmabuf frames
352      * in iHD */
353     if (gst_caps_is_dmabuf (outcaps) && GST_VIDEO_INFO_IS_RGB (&vinfo))
354       usage_hint = VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC;
355     if (!(allocator =
356             gst_va_base_transform_allocator_from_caps (self, outcaps)))
357       return FALSE;
358   }
359
360   if (!pool)
361     pool = gst_va_pool_new ();
362
363   config = gst_buffer_pool_get_config (pool);
364   gst_buffer_pool_config_set_allocator (config, allocator, &params);
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);
371     return FALSE;
372   }
373
374   if (GST_IS_VA_DMABUF_ALLOCATOR (allocator)) {
375     gst_va_dmabuf_allocator_get_format (allocator, &self->priv->srcpad_info,
376         NULL);
377   } else if (GST_IS_VA_ALLOCATOR (allocator)) {
378     gst_va_allocator_get_format (allocator, &self->priv->srcpad_info, NULL);
379   }
380
381   if (update_allocator)
382     gst_query_set_nth_allocation_param (query, 0, allocator, &params);
383   else
384     gst_query_add_allocation_param (query, allocator, &params);
385
386   if (update_pool)
387     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
388   else
389     gst_query_add_allocation_pool (query, pool, size, min, max);
390
391   has_videometa = gst_query_find_allocation_meta (query,
392       GST_VIDEO_META_API_TYPE, NULL);
393
394   copy_frames = (!has_videometa && gst_va_pool_requires_video_meta (pool)
395       && gst_caps_is_raw (outcaps));
396   if (copy_frames) {
397     if (other_pool) {
398       gst_object_replace ((GstObject **) & self->priv->other_pool,
399           (GstObject *) other_pool);
400     } else {
401       self->priv->other_pool =
402           _create_other_pool (other_allocator, &other_params, outcaps, size);
403     }
404     GST_DEBUG_OBJECT (self, "Use the other pool for copy %" GST_PTR_FORMAT,
405         self->priv->other_pool);
406   } else {
407     gst_clear_object (&self->priv->other_pool);
408   }
409
410   GST_DEBUG_OBJECT (self,
411       "decided pool %" GST_PTR_FORMAT " with allocator %" GST_PTR_FORMAT,
412       pool, allocator);
413
414   gst_object_unref (allocator);
415   gst_object_unref (pool);
416   gst_clear_object (&other_allocator);
417   gst_clear_object (&other_pool);
418
419   /* removes allocation metas */
420   return GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans,
421       query);
422
423 }
424
425 /* output buffers must be from our VA-based pool, they cannot be
426  * system-allocated */
427 static gboolean
428 gst_va_base_transform_transform_size (GstBaseTransform * trans,
429     GstPadDirection direction, GstCaps * caps, gsize size,
430     GstCaps * othercaps, gsize * othersize)
431 {
432   return FALSE;
433 }
434
435 static GstFlowReturn
436 gst_va_base_transform_generate_output (GstBaseTransform * trans,
437     GstBuffer ** outbuf)
438 {
439   GstVaBaseTransform *self = GST_VA_BASE_TRANSFORM (trans);
440   GstVideoFrame src_frame;
441   GstVideoFrame dest_frame;
442   GstBuffer *buffer = NULL;
443   GstFlowReturn ret;
444
445   ret = GST_BASE_TRANSFORM_CLASS (parent_class)->generate_output (trans,
446       outbuf);
447
448   if (ret != GST_FLOW_OK || *outbuf == NULL)
449     return ret;
450
451   if (!self->priv->other_pool)
452     return GST_FLOW_OK;
453
454   /* Now need to copy the output buffer */
455   ret = GST_FLOW_ERROR;
456
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);
460     goto out;
461   }
462
463   ret = gst_buffer_pool_acquire_buffer (self->priv->other_pool, &buffer, NULL);
464   if (ret != GST_FLOW_OK)
465     goto out;
466
467   if (!gst_video_frame_map (&src_frame, &self->priv->srcpad_info, *outbuf,
468           GST_MAP_READ))
469     goto out;
470
471   if (!gst_video_frame_map (&dest_frame, &self->out_info, buffer,
472           GST_MAP_WRITE)) {
473     gst_video_frame_unmap (&src_frame);
474     goto out;
475   }
476
477   if (!gst_video_frame_copy (&dest_frame, &src_frame)) {
478     gst_video_frame_unmap (&src_frame);
479     gst_video_frame_unmap (&dest_frame);
480     goto out;
481   }
482
483   gst_video_frame_unmap (&src_frame);
484   gst_video_frame_unmap (&dest_frame);
485
486   gst_buffer_replace (outbuf, buffer);
487   ret = GST_FLOW_OK;
488
489 out:
490   gst_clear_buffer (&buffer);
491   return ret;
492 }
493
494 static GstStateChangeReturn
495 gst_va_base_transform_change_state (GstElement * element,
496     GstStateChange transition)
497 {
498   GstVaBaseTransform *self = GST_VA_BASE_TRANSFORM (element);
499   GstVaBaseTransformClass *klass = GST_VA_BASE_TRANSFORM_GET_CLASS (element);
500   GstStateChangeReturn ret;
501
502   switch (transition) {
503     case GST_STATE_CHANGE_NULL_TO_READY:
504       if (!gst_va_ensure_element_data (element, klass->render_device_path,
505               &self->display))
506         goto open_failed;
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))
511         goto open_failed;
512       if (klass->update_properties)
513         klass->update_properties (self);
514       break;
515     default:
516       break;
517   }
518
519   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
520
521   switch (transition) {
522     case GST_STATE_CHANGE_PAUSED_TO_READY:
523       gst_va_filter_close (self->filter);
524       break;
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);
529       break;
530     default:
531       break;
532   }
533
534   return ret;
535
536   /* Errors */
537 open_failed:
538   {
539     GST_ELEMENT_ERROR (self, LIBRARY, INIT, (NULL), ("Failed to open VPP"));
540     return GST_STATE_CHANGE_FAILURE;
541   }
542 }
543
544 static void
545 gst_va_base_transform_set_context (GstElement * element, GstContext * context)
546 {
547   GstVaDisplay *old_display, *new_display;
548   GstVaBaseTransform *self = GST_VA_BASE_TRANSFORM (element);
549   GstVaBaseTransformClass *klass = GST_VA_BASE_TRANSFORM_GET_CLASS (self);
550   gboolean ret;
551
552   old_display = self->display ? gst_object_ref (self->display) : NULL;
553   ret = gst_va_handle_set_context (element, context, klass->render_device_path,
554       &self->display);
555   new_display = self->display ? gst_object_ref (self->display) : NULL;
556
557   if (!ret
558       || (old_display && new_display && old_display != new_display
559           && self->filter)) {
560     GST_ELEMENT_WARNING (element, RESOURCE, BUSY,
561         ("Can't replace VA display while operating"), (NULL));
562   }
563
564   gst_clear_object (&old_display);
565   gst_clear_object (&new_display);
566
567   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
568 }
569
570 static void
571 gst_va_base_transform_class_init (GstVaBaseTransformClass * klass)
572 {
573   GObjectClass *gobject_class;
574   GstElementClass *element_class;
575   GstBaseTransformClass *trans_class;
576
577   gobject_class = G_OBJECT_CLASS (klass);
578   element_class = GST_ELEMENT_CLASS (klass);
579   trans_class = GST_BASE_TRANSFORM_CLASS (klass);
580
581   gobject_class->dispose = gst_va_base_transform_dispose;
582
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);
593
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);
598
599   gst_type_mark_as_plugin_api (GST_TYPE_VA_BASE_TRANSFORM, 0);
600 }
601
602 GstAllocator *
603 gst_va_base_transform_allocator_from_caps (GstVaBaseTransform * self,
604     GstCaps * caps)
605 {
606   GstAllocator *allocator = NULL;
607
608   if (gst_caps_is_dmabuf (caps)) {
609     allocator = gst_va_dmabuf_allocator_new (self->display);
610   } else {
611     GArray *surface_formats = gst_va_filter_get_surface_formats (self->filter);
612     allocator = gst_va_allocator_new (self->display, surface_formats);
613   }
614
615   return allocator;
616 }
617
618 static inline gsize
619 _get_plane_data_size (GstVideoInfo * info, guint plane)
620 {
621   gint comp[GST_VIDEO_MAX_COMPONENTS];
622   gint height, padded_height;
623
624   gst_video_format_info_component (info->finfo, plane, comp);
625
626   height = GST_VIDEO_INFO_HEIGHT (info);
627   padded_height =
628       GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info->finfo, comp[0], height);
629
630   return GST_VIDEO_INFO_PLANE_STRIDE (info, plane) * padded_height;
631 }
632
633 static gboolean
634 _try_import_dmabuf_unlocked (GstVaBaseTransform * self, GstBuffer * inbuf)
635 {
636   GstVaBaseTransform *btrans = GST_VA_BASE_TRANSFORM (self);
637   GstVideoMeta *meta;
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];
643
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);
647
648   /* This will eliminate most non-dmabuf out there */
649   if (!gst_is_dmabuf_memory (gst_buffer_peek_memory (inbuf, 0)))
650     return FALSE;
651
652   /* We cannot have multiple dmabuf per plane */
653   if (n_mem > n_planes)
654     return FALSE;
655
656   /* Update video info based on video meta */
657   if (meta) {
658     GST_VIDEO_INFO_WIDTH (&in_info) = meta->width;
659     GST_VIDEO_INFO_HEIGHT (&in_info) = meta->height;
660
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];
664     }
665   }
666
667   /* Find and validate all memories */
668   for (i = 0; i < n_planes; i++) {
669     guint plane_size;
670     guint length;
671     guint mem_idx;
672     gsize mem_skip;
673
674     plane_size = _get_plane_data_size (&in_info, i);
675
676     if (!gst_buffer_find_memory (inbuf, in_info.offset[i], plane_size,
677             &mem_idx, &length, &mem_skip))
678       return FALSE;
679
680     /* We can't have more then one dmabuf per plane */
681     if (length != 1)
682       return FALSE;
683
684     mems[i] = gst_buffer_peek_memory (inbuf, mem_idx);
685
686     /* And all memory found must be dmabuf */
687     if (!gst_is_dmabuf_memory (mems[i]))
688       return FALSE;
689
690     offset[i] = mems[i]->offset + mem_skip;
691     fd[i] = gst_dmabuf_memory_get_fd (mems[i]);
692   }
693
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);
697 }
698
699 static GstBufferPool *
700 _get_sinkpad_pool (GstVaBaseTransform * self)
701 {
702   GstAllocator *allocator;
703   GstAllocationParams params = { 0, };
704   GstCaps *caps;
705   GstVideoInfo in_info;
706   guint size, usage_hint = VA_SURFACE_ATTRIB_USAGE_HINT_VPP_READ;
707
708   if (self->priv->sinkpad_pool)
709     return self->priv->sinkpad_pool;
710
711   gst_allocation_params_init (&params);
712
713   if (self->priv->sinkpad_caps) {
714     caps = self->priv->sinkpad_caps;
715     gst_video_info_from_caps (&in_info, caps);
716   } else {
717     caps = self->in_caps;
718     in_info = self->in_info;
719   }
720
721   size = GST_VIDEO_INFO_SIZE (&in_info);
722
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, &params);
726   if (!self->priv->sinkpad_pool) {
727     gst_object_unref (allocator);
728     return NULL;
729   }
730
731   if (GST_IS_VA_DMABUF_ALLOCATOR (allocator)) {
732     gst_va_dmabuf_allocator_get_format (allocator, &self->priv->sinkpad_info,
733         NULL);
734   } else if (GST_IS_VA_ALLOCATOR (allocator)) {
735     gst_va_allocator_get_format (allocator, &self->priv->sinkpad_info, NULL);
736   }
737
738   gst_object_unref (allocator);
739
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);
743     return NULL;
744   }
745
746   return self->priv->sinkpad_pool;
747 }
748
749 static gboolean
750 _try_import_buffer (GstVaBaseTransform * self, GstBuffer * inbuf)
751 {
752   VASurfaceID surface;
753   gboolean ret;
754
755   surface = gst_va_buffer_get_surface (inbuf);
756   if (surface != VA_INVALID_ID)
757     return TRUE;
758
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);
762
763   return ret;
764 }
765
766 GstFlowReturn
767 gst_va_base_transform_import_buffer (GstVaBaseTransform * self,
768     GstBuffer * inbuf, GstBuffer ** buf)
769 {
770   GstBuffer *buffer = NULL;
771   GstBufferPool *pool;
772   GstFlowReturn ret;
773   GstVideoFrame in_frame, out_frame;
774   gboolean imported, copied;
775
776   g_return_val_if_fail (GST_IS_VA_BASE_TRANSFORM (self), GST_FLOW_ERROR);
777
778   imported = _try_import_buffer (self, inbuf);
779   if (imported) {
780     *buf = gst_buffer_ref (inbuf);
781     return GST_FLOW_OK;
782   }
783
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;
789
790   ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL);
791   if (ret != GST_FLOW_OK)
792     return ret;
793
794   GST_LOG_OBJECT (self, "copying input frame");
795
796   if (!gst_video_frame_map (&in_frame, &self->in_info, inbuf, GST_MAP_READ))
797     goto invalid_buffer;
798
799   if (!gst_video_frame_map (&out_frame, &self->priv->sinkpad_info, buffer,
800           GST_MAP_WRITE)) {
801     gst_video_frame_unmap (&in_frame);
802     goto invalid_buffer;
803   }
804
805   copied = gst_video_frame_copy (&out_frame, &in_frame);
806
807   gst_video_frame_unmap (&out_frame);
808   gst_video_frame_unmap (&in_frame);
809
810   if (!copied)
811     goto invalid_buffer;
812
813   /* copy metadata, default implemenation of baseclass will copy everything
814    * what we need */
815   GST_BASE_TRANSFORM_CLASS (parent_class)->copy_metadata
816       (GST_BASE_TRANSFORM_CAST (self), inbuf, buffer);
817
818   *buf = buffer;
819
820   return GST_FLOW_OK;
821
822 invalid_buffer:
823   {
824     GST_ELEMENT_WARNING (self, CORE, NOT_IMPLEMENTED, (NULL),
825         ("invalid video buffer received"));
826     if (buffer)
827       gst_buffer_unref (buffer);
828     return GST_FLOW_OK;
829   }
830 }
831
832 GstCaps *
833 gst_va_base_transform_get_filter_caps (GstVaBaseTransform * self)
834 {
835   g_return_val_if_fail (GST_IS_VA_BASE_TRANSFORM (self), NULL);
836
837   GST_OBJECT_LOCK (self);
838   if (self->priv->filter_caps) {
839     GST_OBJECT_UNLOCK (self);
840     return self->priv->filter_caps;
841   }
842   GST_OBJECT_UNLOCK (self);
843
844   if (!self->filter)
845     return NULL;
846
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;
851 }