plugins: fix memory leaks.
[vaapi:gstreamer-vaapi.git] / gst / vaapi / gstvaapipluginbase.c
1 /*
2  *  gstvaapipluginbase.c - Base GStreamer VA-API Plugin element
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6  *  Copyright (C) 2011-2014 Intel Corporation
7  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public License
11  *  as published by the Free Software Foundation; either version 2.1
12  *  of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this library; if not, write to the Free
21  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  *  Boston, MA 02110-1301 USA
23  */
24
25 #include "gst/vaapi/sysdeps.h"
26 #include "gstvaapipluginbase.h"
27 #include "gstvaapipluginutil.h"
28 #include "gstvaapivideocontext.h"
29 #include "gstvaapivideometa.h"
30 #if GST_CHECK_VERSION(1,0,0)
31 #include "gstvaapivideobufferpool.h"
32 #endif
33
34 /* Default debug category is from the subclass */
35 #define GST_CAT_DEFAULT (plugin->debug_category)
36
37 /* GstImplementsInterface interface */
38 #if !GST_CHECK_VERSION(1,0,0)
39 static gboolean
40 implements_interface_supported (GstImplementsInterface * iface, GType type)
41 {
42   GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (iface);
43
44   if (type == GST_TYPE_VIDEO_CONTEXT)
45     return TRUE;
46   return GST_VAAPI_PLUGIN_BASE_GET_CLASS (plugin)->has_interface (plugin, type);
47 }
48
49 static void
50 implements_interface_init (GstImplementsInterfaceClass * iface)
51 {
52   iface->supported = implements_interface_supported;
53 }
54 #endif
55
56 /* GstVideoContext interface */
57 static void
58 plugin_set_display (GstVaapiPluginBase * plugin, GstVaapiDisplay * display)
59 {
60   const gchar *const display_name =
61       gst_vaapi_display_get_display_name (display);
62
63   if (plugin->display_name && g_strcmp0 (plugin->display_name, display_name)) {
64     GST_DEBUG_OBJECT (plugin, "incompatible display name '%s', requested '%s'",
65         display_name, plugin->display_name);
66     gst_vaapi_display_replace (&plugin->display, NULL);
67   } else {
68     GST_INFO_OBJECT (plugin, "set display %p", display);
69     gst_vaapi_display_replace (&plugin->display, display);
70     plugin->display_type = gst_vaapi_display_get_display_type (display);
71     gst_vaapi_plugin_base_set_display_name (plugin, display_name);
72   }
73   gst_vaapi_display_unref (display);
74 }
75
76 #if GST_CHECK_VERSION(1,1,0)
77 static void
78 plugin_set_context (GstElement * element, GstContext * context)
79 {
80   GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element);
81   GstVaapiDisplay *display = NULL;
82
83   if (gst_vaapi_video_context_get_display (context, &display))
84     plugin_set_display (plugin, display);
85 }
86 #else
87 static void
88 plugin_set_context (GstVideoContext * context, const gchar * type,
89     const GValue * value)
90 {
91   GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (context);
92   GstVaapiDisplay *display = NULL;
93
94   gst_vaapi_set_display (type, value, &display);
95   plugin_set_display (plugin, display);
96 }
97
98 static void
99 video_context_interface_init (GstVideoContextInterface * iface)
100 {
101   iface->set_context = plugin_set_context;
102 }
103
104 #define GstVideoContextClass GstVideoContextInterface
105 #endif
106
107 void
108 gst_vaapi_plugin_base_init_interfaces (GType g_define_type_id)
109 {
110 #if !GST_CHECK_VERSION(1,0,0)
111   G_IMPLEMENT_INTERFACE (GST_TYPE_IMPLEMENTS_INTERFACE,
112       implements_interface_init);
113 #endif
114 #if !GST_CHECK_VERSION(1,1,0)
115   G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_CONTEXT, video_context_interface_init);
116 #endif
117 }
118
119 static gboolean
120 default_has_interface (GstVaapiPluginBase * plugin, GType type)
121 {
122   return FALSE;
123 }
124
125 static void
126 default_display_changed (GstVaapiPluginBase * plugin)
127 {
128 }
129
130 void
131 gst_vaapi_plugin_base_class_init (GstVaapiPluginBaseClass * klass)
132 {
133   klass->has_interface = default_has_interface;
134   klass->display_changed = default_display_changed;
135
136 #if GST_CHECK_VERSION(1,1,0)
137   GstElementClass *const element_class = GST_ELEMENT_CLASS (klass);
138   element_class->set_context = GST_DEBUG_FUNCPTR (plugin_set_context);
139 #endif
140 }
141
142 void
143 gst_vaapi_plugin_base_init (GstVaapiPluginBase * plugin,
144     GstDebugCategory * debug_category)
145 {
146   plugin->debug_category = debug_category;
147   plugin->display_type = GST_VAAPI_DISPLAY_TYPE_ANY;
148   plugin->display_type_req = GST_VAAPI_DISPLAY_TYPE_ANY;
149
150   /* sink pad */
151   plugin->sinkpad = gst_element_get_static_pad (GST_ELEMENT (plugin), "sink");
152   plugin->sinkpad_query = GST_PAD_QUERYFUNC (plugin->sinkpad);
153   gst_video_info_init (&plugin->sinkpad_info);
154
155   /* src pad */
156   if (!(GST_OBJECT_FLAGS (plugin) & GST_ELEMENT_FLAG_SINK)) {
157     plugin->srcpad = gst_element_get_static_pad (GST_ELEMENT (plugin), "src");
158     plugin->srcpad_query = GST_PAD_QUERYFUNC (plugin->srcpad);
159   }
160   gst_video_info_init (&plugin->srcpad_info);
161 }
162
163 void
164 gst_vaapi_plugin_base_finalize (GstVaapiPluginBase * plugin)
165 {
166   gst_vaapi_plugin_base_close (plugin);
167   g_free (plugin->display_name);
168   if (plugin->sinkpad)
169     gst_object_unref (plugin->sinkpad);
170   if (plugin->srcpad)
171     gst_object_unref (plugin->srcpad);
172 }
173
174 /**
175  * gst_vaapi_plugin_base_open:
176  * @plugin: a #GstVaapiPluginBase
177  *
178  * Allocates any internal resources needed for correct operation from
179  * the subclass.
180  *
181  * Returns: %TRUE if successful, %FALSE otherwise.
182  */
183 gboolean
184 gst_vaapi_plugin_base_open (GstVaapiPluginBase * plugin)
185 {
186   return TRUE;
187 }
188
189 /**
190  * gst_vaapi_plugin_base_close:
191  * @plugin: a #GstVaapiPluginBase
192  *
193  * Deallocates all internal resources that were allocated so
194  * far. i.e. put the base plugin object into a clean state.
195  */
196 void
197 gst_vaapi_plugin_base_close (GstVaapiPluginBase * plugin)
198 {
199   g_clear_object (&plugin->uploader);
200   gst_vaapi_display_replace (&plugin->display, NULL);
201
202   gst_caps_replace (&plugin->sinkpad_caps, NULL);
203   plugin->sinkpad_caps_changed = FALSE;
204   gst_video_info_init (&plugin->sinkpad_info);
205 #if GST_CHECK_VERSION(1,0,0)
206   if (plugin->sinkpad_buffer_pool) {
207     gst_object_unref (plugin->sinkpad_buffer_pool);
208     plugin->sinkpad_buffer_pool = NULL;
209   }
210   g_clear_object (&plugin->srcpad_buffer_pool);
211 #endif
212
213   gst_caps_replace (&plugin->srcpad_caps, NULL);
214   plugin->srcpad_caps_changed = FALSE;
215   gst_video_info_init (&plugin->srcpad_info);
216 }
217
218 /**
219  * gst_vaapi_plugin_base_set_display_type:
220  * @plugin: a #GstVaapiPluginBase
221  * @display_type: the new request #GstVaapiDisplayType
222  *
223  * Requests a new display type. The change is effective at the next
224  * call to gst_vaapi_plugin_base_ensure_display().
225  */
226 void
227 gst_vaapi_plugin_base_set_display_type (GstVaapiPluginBase * plugin,
228     GstVaapiDisplayType display_type)
229 {
230   plugin->display_type_req = display_type;
231 }
232
233 /**
234  * gst_vaapi_plugin_base_set_display_name:
235  * @plugin: a #GstVaapiPluginBase
236  * @display_name: the new display name to match
237  *
238  * Sets the name of the display to look for. The change is effective
239  * at the next call to gst_vaapi_plugin_base_ensure_display().
240  */
241 void
242 gst_vaapi_plugin_base_set_display_name (GstVaapiPluginBase * plugin,
243     const gchar * display_name)
244 {
245   g_free (plugin->display_name);
246   plugin->display_name = g_strdup (display_name);
247 }
248
249 /**
250  * gst_vaapi_plugin_base_ensure_display:
251  * @plugin: a #GstVaapiPluginBase
252  *
253  * Ensures the display stored in @plugin complies with the requested
254  * display type constraints.
255  *
256  * Returns: %TRUE if the display was created to match the requested
257  *   type, %FALSE otherwise.
258  */
259 gboolean
260 gst_vaapi_plugin_base_ensure_display (GstVaapiPluginBase * plugin)
261 {
262   if (plugin->display
263       && gst_vaapi_display_type_is_compatible (plugin->display_type,
264           plugin->display_type_req))
265     return TRUE;
266   gst_vaapi_display_replace (&plugin->display, NULL);
267
268   if (!gst_vaapi_ensure_display (plugin, plugin->display_type_req))
269     return FALSE;
270   plugin->display_type = gst_vaapi_display_get_display_type (plugin->display);
271
272   GST_VAAPI_PLUGIN_BASE_GET_CLASS (plugin)->display_changed (plugin);
273   return TRUE;
274 }
275
276 /**
277  * gst_vaapi_plugin_base_ensure_uploader:
278  * @plugin: a #GstVaapiPluginBase
279  *
280  * Makes sure the built-in #GstVaapiUploader object is created, or
281  * that it was successfully notified of any VA display change.
282  *
283  * Returns: %TRUE if the uploader was successfully created, %FALSE otherwise.
284  */
285 gboolean
286 gst_vaapi_plugin_base_ensure_uploader (GstVaapiPluginBase * plugin)
287 {
288   if (plugin->uploader) {
289     if (!gst_vaapi_uploader_ensure_display (plugin->uploader, plugin->display))
290       return FALSE;
291   } else {
292     plugin->uploader = gst_vaapi_uploader_new (plugin->display);
293     if (!plugin->uploader)
294       return FALSE;
295   }
296   return TRUE;
297 }
298
299 /**
300  * ensure_sinkpad_buffer_pool:
301  * @plugin: a #GstVaapiPluginBase
302  * @caps: the initial #GstCaps for the resulting buffer pool
303  *
304  * Makes sure the sink pad video buffer pool is created with the
305  * appropriate @caps.
306  *
307  * Returns: %TRUE if successful, %FALSE otherwise.
308  */
309 static gboolean
310 ensure_sinkpad_buffer_pool (GstVaapiPluginBase * plugin, GstCaps * caps)
311 {
312 #if GST_CHECK_VERSION(1,0,0)
313   GstBufferPool *pool;
314   GstCaps *pool_caps;
315   GstStructure *config;
316   GstVideoInfo vi;
317   gboolean need_pool;
318
319   if (!gst_vaapi_plugin_base_ensure_display (plugin))
320     return FALSE;
321
322   if (plugin->sinkpad_buffer_pool) {
323     config = gst_buffer_pool_get_config (plugin->sinkpad_buffer_pool);
324     gst_buffer_pool_config_get_params (config, &pool_caps, NULL, NULL, NULL);
325     need_pool = !gst_caps_is_equal (caps, pool_caps);
326     gst_structure_free (config);
327     if (!need_pool)
328       return TRUE;
329     g_clear_object (&plugin->sinkpad_buffer_pool);
330     plugin->sinkpad_buffer_size = 0;
331   }
332
333   pool = gst_vaapi_video_buffer_pool_new (plugin->display);
334   if (!pool)
335     goto error_create_pool;
336
337   gst_video_info_init (&vi);
338   gst_video_info_from_caps (&vi, caps);
339   if (GST_VIDEO_INFO_FORMAT (&vi) == GST_VIDEO_FORMAT_ENCODED) {
340     GST_DEBUG ("assume video buffer pool format is NV12");
341     gst_video_info_set_format (&vi, GST_VIDEO_FORMAT_NV12,
342         GST_VIDEO_INFO_WIDTH (&vi), GST_VIDEO_INFO_HEIGHT (&vi));
343   }
344   plugin->sinkpad_buffer_size = vi.size;
345
346   config = gst_buffer_pool_get_config (pool);
347   gst_buffer_pool_config_set_params (config, caps,
348       plugin->sinkpad_buffer_size, 0, 0);
349   gst_buffer_pool_config_add_option (config,
350       GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
351   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
352   if (!gst_buffer_pool_set_config (pool, config))
353     goto error_pool_config;
354   plugin->sinkpad_buffer_pool = pool;
355   return TRUE;
356
357   /* ERRORS */
358 error_create_pool:
359   {
360     GST_ERROR ("failed to create buffer pool");
361     return FALSE;
362   }
363 error_pool_config:
364   {
365     GST_ERROR ("failed to reset buffer pool config");
366     gst_object_unref (pool);
367     return FALSE;
368   }
369 #else
370   return TRUE;
371 #endif
372 }
373
374 /**
375  * gst_vaapi_plugin_base_set_caps:
376  * @plugin: a #GstVaapiPluginBase
377  * @incaps: the sink pad (input) caps
378  * @outcaps: the src pad (output) caps
379  *
380  * Notifies the base plugin object of the new input and output caps,
381  * obtained from the subclass.
382  *
383  * Returns: %TRUE if the update of caps was successful, %FALSE otherwise.
384  */
385 gboolean
386 gst_vaapi_plugin_base_set_caps (GstVaapiPluginBase * plugin, GstCaps * incaps,
387     GstCaps * outcaps)
388 {
389   if (incaps && incaps != plugin->sinkpad_caps) {
390     gst_caps_replace (&plugin->sinkpad_caps, incaps);
391     if (!gst_video_info_from_caps (&plugin->sinkpad_info, incaps))
392       return FALSE;
393     plugin->sinkpad_caps_changed = TRUE;
394     plugin->sinkpad_caps_is_raw = !gst_caps_has_vaapi_surface (incaps);
395   }
396
397   if (outcaps && outcaps != plugin->srcpad_caps) {
398     gst_caps_replace (&plugin->srcpad_caps, outcaps);
399     if (!gst_video_info_from_caps (&plugin->srcpad_info, outcaps))
400       return FALSE;
401     plugin->srcpad_caps_changed = TRUE;
402   }
403
404   if (plugin->uploader && plugin->sinkpad_caps_is_raw) {
405     if (!gst_vaapi_uploader_ensure_display (plugin->uploader, plugin->display))
406       return FALSE;
407     if (!gst_vaapi_uploader_ensure_caps (plugin->uploader,
408             plugin->sinkpad_caps, plugin->srcpad_caps))
409       return FALSE;
410   }
411
412   if (!ensure_sinkpad_buffer_pool (plugin, plugin->sinkpad_caps))
413     return FALSE;
414   return TRUE;
415 }
416
417 /**
418  * gst_vaapi_plugin_base_propose_allocation:
419  * @plugin: a #GstVaapiPluginBase
420  * @query: the allocation query to configure
421  *
422  * Proposes allocation parameters to the upstream elements.
423  *
424  * Returns: %TRUE if successful, %FALSE otherwise.
425  */
426 #if GST_CHECK_VERSION(1,0,0)
427 gboolean
428 gst_vaapi_plugin_base_propose_allocation (GstVaapiPluginBase * plugin,
429     GstQuery * query)
430 {
431   GstCaps *caps = NULL;
432   gboolean need_pool;
433
434   gst_query_parse_allocation (query, &caps, &need_pool);
435
436   if (need_pool) {
437     if (!caps)
438       goto error_no_caps;
439     if (!ensure_sinkpad_buffer_pool (plugin, caps))
440       return FALSE;
441     gst_query_add_allocation_pool (query, plugin->sinkpad_buffer_pool,
442         plugin->sinkpad_buffer_size, 0, 0);
443   }
444
445   gst_query_add_allocation_meta (query, GST_VAAPI_VIDEO_META_API_TYPE, NULL);
446   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
447   return TRUE;
448
449   /* ERRORS */
450 error_no_caps:
451   {
452     GST_ERROR ("no caps specified");
453     return FALSE;
454   }
455 }
456 #endif
457
458 /**
459  * gst_vaapi_plugin_base_decide_allocation:
460  * @plugin: a #GstVaapiPluginBase
461  * @query: the allocation query to parse
462  * @feature: the desired #GstVaapiCapsFeature, or zero to find the
463  *   preferred one
464  *
465  * Decides allocation parameters for the downstream elements.
466  *
467  * Returns: %TRUE if successful, %FALSE otherwise.
468  */
469 #if GST_CHECK_VERSION(1,0,0)
470 gboolean
471 gst_vaapi_plugin_base_decide_allocation (GstVaapiPluginBase * plugin,
472     GstQuery * query, guint feature)
473 {
474   GstCaps *caps = NULL;
475   GstBufferPool *pool;
476   GstStructure *config;
477   GstVideoInfo vi;
478   guint size, min, max;
479   gboolean need_pool, update_pool;
480   gboolean has_video_meta = FALSE;
481   gboolean has_video_alignment = FALSE;
482 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
483   gboolean has_texture_upload_meta = FALSE;
484 #endif
485
486   g_return_val_if_fail (plugin->display != NULL, FALSE);
487
488   gst_query_parse_allocation (query, &caps, &need_pool);
489
490   if (!caps)
491     goto error_no_caps;
492
493   if (!feature)
494     feature =
495         gst_vaapi_find_preferred_caps_feature (plugin->srcpad,
496         GST_VIDEO_FORMAT_ENCODED);
497
498   has_video_meta = gst_query_find_allocation_meta (query,
499       GST_VIDEO_META_API_TYPE, NULL);
500
501 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
502   has_texture_upload_meta = gst_query_find_allocation_meta (query,
503       GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, NULL);
504 #endif
505
506   gst_video_info_init (&vi);
507   gst_video_info_from_caps (&vi, caps);
508   if (GST_VIDEO_INFO_FORMAT (&vi) == GST_VIDEO_FORMAT_ENCODED)
509     gst_video_info_set_format (&vi, GST_VIDEO_FORMAT_I420,
510         GST_VIDEO_INFO_WIDTH (&vi), GST_VIDEO_INFO_HEIGHT (&vi));
511
512   if (gst_query_get_n_allocation_pools (query) > 0) {
513     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
514     size = MAX (size, vi.size);
515     update_pool = TRUE;
516
517     /* Check whether downstream element proposed a bufferpool but did
518        not provide a correct propose_allocation() implementation */
519     has_video_alignment = gst_buffer_pool_has_option (pool,
520         GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
521   } else {
522     pool = NULL;
523     size = vi.size;
524     min = max = 0;
525     update_pool = FALSE;
526   }
527
528   /* GstVaapiVideoMeta is mandatory, and this implies VA surface memory */
529   if (!pool || !gst_buffer_pool_has_option (pool,
530           GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) {
531     GST_INFO_OBJECT (plugin, "no pool or doesn't support GstVaapiVideoMeta, "
532         "making new pool");
533     if (pool)
534       gst_object_unref (pool);
535     pool = gst_vaapi_video_buffer_pool_new (plugin->display);
536     if (!pool)
537       goto error_create_pool;
538
539     config = gst_buffer_pool_get_config (pool);
540     gst_buffer_pool_config_set_params (config, caps, size, min, max);
541     gst_buffer_pool_config_add_option (config,
542         GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
543     gst_buffer_pool_set_config (pool, config);
544   }
545
546   /* Check whether GstVideoMeta, or GstVideoAlignment, is needed (raw video) */
547   if (has_video_meta) {
548     config = gst_buffer_pool_get_config (pool);
549     gst_buffer_pool_config_add_option (config,
550         GST_BUFFER_POOL_OPTION_VIDEO_META);
551 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
552     if (has_texture_upload_meta)
553       gst_buffer_pool_config_add_option (config,
554           GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META);
555 #endif
556     gst_buffer_pool_set_config (pool, config);
557   } else if (has_video_alignment) {
558     config = gst_buffer_pool_get_config (pool);
559     gst_buffer_pool_config_add_option (config,
560         GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
561     gst_buffer_pool_set_config (pool, config);
562   }
563
564   /* GstVideoGLTextureUploadMeta (OpenGL) */
565 #if GST_CHECK_VERSION(1,1,0) && USE_GLX
566   if (feature == GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META
567       && !has_texture_upload_meta) {
568     config = gst_buffer_pool_get_config (pool);
569     gst_buffer_pool_config_add_option (config,
570         GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META);
571     gst_buffer_pool_set_config (pool, config);
572   }
573 #endif
574
575   if (update_pool)
576     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
577   else
578     gst_query_add_allocation_pool (query, pool, size, min, max);
579
580   g_clear_object (&plugin->srcpad_buffer_pool);
581   plugin->srcpad_buffer_pool = pool;
582   return TRUE;
583
584   /* ERRORS */
585 error_no_caps:
586   {
587     GST_ERROR_OBJECT (plugin, "no caps specified");
588     return FALSE;
589   }
590 error_create_pool:
591   {
592     GST_ERROR_OBJECT (plugin, "failed to create buffer pool");
593     return FALSE;
594   }
595 }
596 #endif
597
598 /**
599  * gst_vaapi_plugin_base_allocate_input_buffer:
600  * @plugin: a #GstVaapiPluginBase
601  * @caps: the buffer caps constraints to honour
602  * @outbuf_ptr: the pointer location to the newly allocated buffer
603  *
604  * Creates a buffer that holds a VA surface memory for the sink pad to
605  * use it as the result for buffer_alloc() impementations.
606  *
607  * Return: #GST_FLOW_OK if the buffer could be created.
608  */
609 GstFlowReturn
610 gst_vaapi_plugin_base_allocate_input_buffer (GstVaapiPluginBase * plugin,
611     GstCaps * caps, GstBuffer ** outbuf_ptr)
612 {
613   GstBuffer *outbuf;
614
615   *outbuf_ptr = NULL;
616
617   if (!plugin->sinkpad_caps_changed) {
618     if (!gst_video_info_from_caps (&plugin->sinkpad_info, caps))
619       return GST_FLOW_NOT_SUPPORTED;
620     plugin->sinkpad_caps_changed = TRUE;
621   }
622
623   if (!plugin->sinkpad_caps_is_raw)
624     return GST_FLOW_OK;
625
626   if (!gst_vaapi_uploader_ensure_display (plugin->uploader, plugin->display))
627     return GST_FLOW_NOT_SUPPORTED;
628   if (!gst_vaapi_uploader_ensure_caps (plugin->uploader, caps, NULL))
629     return GST_FLOW_NOT_SUPPORTED;
630
631   outbuf = gst_vaapi_uploader_get_buffer (plugin->uploader);
632   if (!outbuf) {
633     GST_WARNING ("failed to allocate resources for raw YUV buffer");
634     return GST_FLOW_NOT_SUPPORTED;
635   }
636
637   *outbuf_ptr = outbuf;
638   return GST_FLOW_OK;
639 }
640
641 /**
642  * gst_vaapi_plugin_base_get_input_buffer:
643  * @plugin: a #GstVaapiPluginBase
644  * @incaps: the sink pad (input) buffer
645  * @outbuf_ptr: the pointer to location to the VA surface backed buffer
646  *
647  * Acquires the sink pad (input) buffer as a VA surface backed
648  * buffer. This is mostly useful for raw YUV buffers, as source
649  * buffers that are already backed as a VA surface are passed
650  * verbatim.
651  *
652  * Returns: #GST_FLOW_OK if the buffer could be acquired
653  */
654 GstFlowReturn
655 gst_vaapi_plugin_base_get_input_buffer (GstVaapiPluginBase * plugin,
656     GstBuffer * inbuf, GstBuffer ** outbuf_ptr)
657 {
658   GstVaapiVideoMeta *meta;
659   GstBuffer *outbuf;
660 #if GST_CHECK_VERSION(1,0,0)
661   GstVideoFrame src_frame, out_frame;
662   gboolean success;
663 #endif
664
665   g_return_val_if_fail (inbuf != NULL, GST_FLOW_ERROR);
666   g_return_val_if_fail (outbuf_ptr != NULL, GST_FLOW_ERROR);
667
668   meta = gst_buffer_get_vaapi_video_meta (inbuf);
669 #if GST_CHECK_VERSION(1,0,0)
670   if (meta) {
671     *outbuf_ptr = gst_buffer_ref (inbuf);
672     return GST_FLOW_OK;
673   }
674
675   if (!plugin->sinkpad_caps_is_raw)
676     goto error_invalid_buffer;
677
678   if (!plugin->sinkpad_buffer_pool)
679     goto error_no_pool;
680
681   if (!gst_buffer_pool_set_active (plugin->sinkpad_buffer_pool, TRUE))
682     goto error_active_pool;
683
684   outbuf = NULL;
685   if (gst_buffer_pool_acquire_buffer (plugin->sinkpad_buffer_pool,
686           &outbuf, NULL) != GST_FLOW_OK)
687     goto error_create_buffer;
688
689   if (!gst_video_frame_map (&src_frame, &plugin->sinkpad_info, inbuf,
690           GST_MAP_READ))
691     goto error_map_src_buffer;
692
693   if (!gst_video_frame_map (&out_frame, &plugin->sinkpad_info, outbuf,
694           GST_MAP_WRITE))
695     goto error_map_dst_buffer;
696
697   success = gst_video_frame_copy (&out_frame, &src_frame);
698   gst_video_frame_unmap (&out_frame);
699   gst_video_frame_unmap (&src_frame);
700   if (!success)
701     goto error_copy_buffer;
702
703   gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
704   *outbuf_ptr = outbuf;
705   return GST_FLOW_OK;
706
707   /* ERRORS */
708 error_no_pool:
709   {
710     GST_ERROR ("no buffer pool was negotiated");
711     return GST_FLOW_ERROR;
712   }
713 error_active_pool:
714   {
715     GST_ERROR ("failed to activate buffer pool");
716     return GST_FLOW_ERROR;
717   }
718 error_map_dst_buffer:
719   {
720     gst_video_frame_unmap (&src_frame);
721     // fall-through
722   }
723 error_map_src_buffer:
724   {
725     GST_WARNING ("failed to map buffer");
726     gst_buffer_unref (outbuf);
727     return GST_FLOW_NOT_SUPPORTED;
728   }
729 #else
730   if (meta)
731     outbuf = gst_buffer_ref (inbuf);
732   else if (plugin->sinkpad_caps_is_raw) {
733     outbuf = gst_vaapi_uploader_get_buffer (plugin->uploader);
734     if (!outbuf)
735       goto error_create_buffer;
736     gst_buffer_copy_metadata (outbuf, inbuf,
737         GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
738   } else
739     goto error_invalid_buffer;
740
741   if (plugin->sinkpad_caps_is_raw &&
742       !gst_vaapi_uploader_process (plugin->uploader, inbuf, outbuf))
743     goto error_copy_buffer;
744
745   *outbuf_ptr = outbuf;
746   return GST_FLOW_OK;
747 #endif
748
749   /* ERRORS */
750 error_invalid_buffer:
751   {
752     GST_ERROR ("failed to validate source buffer");
753     return GST_FLOW_ERROR;
754   }
755 error_create_buffer:
756   {
757     GST_ERROR ("failed to create buffer");
758     return GST_FLOW_ERROR;
759   }
760 error_copy_buffer:
761   {
762     GST_WARNING ("failed to upload buffer to VA surface");
763     gst_buffer_unref (outbuf);
764     return GST_FLOW_NOT_SUPPORTED;
765   }
766 }