2013-12-13 09:24:26 +00:00
|
|
|
/*
|
|
|
|
* gstvaapipluginbase.c - Base GStreamer VA-API Plugin element
|
|
|
|
*
|
|
|
|
* Copyright (C) 2010-2011 Splitted-Desktop Systems
|
|
|
|
* Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
|
2014-01-22 17:54:14 +00:00
|
|
|
* Copyright (C) 2011-2014 Intel Corporation
|
2013-12-13 09:24:26 +00:00
|
|
|
* Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2.1
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free
|
|
|
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
* Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
2015-04-03 14:08:30 +00:00
|
|
|
#include "gstcompat.h"
|
2014-01-23 10:00:09 +00:00
|
|
|
#include <gst/vaapi/gstvaapisurface_drm.h>
|
2015-01-26 17:30:47 +00:00
|
|
|
#include <gst/base/gstpushsrc.h>
|
2013-12-13 09:24:26 +00:00
|
|
|
#include "gstvaapipluginbase.h"
|
2013-12-13 10:52:47 +00:00
|
|
|
#include "gstvaapipluginutil.h"
|
2013-12-13 15:03:08 +00:00
|
|
|
#include "gstvaapivideocontext.h"
|
2013-12-17 17:52:23 +00:00
|
|
|
#include "gstvaapivideometa.h"
|
|
|
|
#include "gstvaapivideobufferpool.h"
|
2014-01-23 10:00:09 +00:00
|
|
|
#include <gst/allocators/allocators.h>
|
2013-12-13 09:24:26 +00:00
|
|
|
|
2013-12-13 10:52:47 +00:00
|
|
|
/* Default debug category is from the subclass */
|
2013-12-13 09:24:26 +00:00
|
|
|
#define GST_CAT_DEFAULT (plugin->debug_category)
|
|
|
|
|
2013-12-13 15:03:08 +00:00
|
|
|
/* GstVideoContext interface */
|
2014-07-25 09:13:29 +00:00
|
|
|
static void
|
|
|
|
plugin_set_display (GstVaapiPluginBase * plugin, GstVaapiDisplay * display)
|
|
|
|
{
|
|
|
|
const gchar *const display_name =
|
|
|
|
gst_vaapi_display_get_display_name (display);
|
|
|
|
|
|
|
|
if (plugin->display_name && g_strcmp0 (plugin->display_name, display_name)) {
|
|
|
|
GST_DEBUG_OBJECT (plugin, "incompatible display name '%s', requested '%s'",
|
|
|
|
display_name, plugin->display_name);
|
|
|
|
gst_vaapi_display_replace (&plugin->display, NULL);
|
|
|
|
} else {
|
|
|
|
GST_INFO_OBJECT (plugin, "set display %p", display);
|
|
|
|
gst_vaapi_display_replace (&plugin->display, display);
|
|
|
|
plugin->display_type = gst_vaapi_display_get_display_type (display);
|
|
|
|
gst_vaapi_plugin_base_set_display_name (plugin, display_name);
|
|
|
|
}
|
|
|
|
gst_vaapi_display_unref (display);
|
|
|
|
}
|
|
|
|
|
2013-12-13 15:03:08 +00:00
|
|
|
static void
|
|
|
|
plugin_set_context (GstElement * element, GstContext * context)
|
|
|
|
{
|
|
|
|
GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element);
|
|
|
|
GstVaapiDisplay *display = NULL;
|
|
|
|
|
2014-07-25 09:13:29 +00:00
|
|
|
if (gst_vaapi_video_context_get_display (context, &display))
|
|
|
|
plugin_set_display (plugin, display);
|
2013-12-13 15:03:08 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 12:24:24 +00:00
|
|
|
void
|
|
|
|
gst_vaapi_plugin_base_init_interfaces (GType g_define_type_id)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
default_has_interface (GstVaapiPluginBase * plugin, GType type)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2013-12-13 10:52:47 +00:00
|
|
|
static void
|
|
|
|
default_display_changed (GstVaapiPluginBase * plugin)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-01-23 10:00:09 +00:00
|
|
|
static gboolean
|
|
|
|
plugin_update_sinkpad_info_from_buffer (GstVaapiPluginBase * plugin,
|
|
|
|
GstBuffer * buf)
|
|
|
|
{
|
|
|
|
GstVideoInfo *const vip = &plugin->sinkpad_info;
|
|
|
|
GstVideoMeta *vmeta;
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
vmeta = gst_buffer_get_video_meta (buf);
|
|
|
|
if (!vmeta)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
if (GST_VIDEO_INFO_FORMAT (vip) != vmeta->format ||
|
|
|
|
GST_VIDEO_INFO_WIDTH (vip) != vmeta->width ||
|
|
|
|
GST_VIDEO_INFO_HEIGHT (vip) != vmeta->height ||
|
|
|
|
GST_VIDEO_INFO_N_PLANES (vip) != vmeta->n_planes)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (vip); ++i) {
|
|
|
|
GST_VIDEO_INFO_PLANE_OFFSET (vip, i) = vmeta->offset[i];
|
|
|
|
GST_VIDEO_INFO_PLANE_STRIDE (vip, i) = vmeta->stride[i];
|
|
|
|
}
|
|
|
|
GST_VIDEO_INFO_SIZE (vip) = gst_buffer_get_size (buf);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
is_dma_buffer (GstBuffer * buf)
|
|
|
|
{
|
|
|
|
GstMemory *mem;
|
|
|
|
|
|
|
|
if (gst_buffer_n_memory (buf) < 1)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
mem = gst_buffer_peek_memory (buf, 0);
|
|
|
|
if (!mem || !gst_is_dmabuf_memory (mem))
|
|
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
plugin_bind_dma_to_vaapi_buffer (GstVaapiPluginBase * plugin,
|
|
|
|
GstBuffer * inbuf, GstBuffer * outbuf)
|
|
|
|
{
|
|
|
|
GstVideoInfo *const vip = &plugin->sinkpad_info;
|
|
|
|
GstVaapiVideoMeta *meta;
|
|
|
|
GstVaapiSurface *surface;
|
|
|
|
GstVaapiSurfaceProxy *proxy;
|
|
|
|
gint fd;
|
|
|
|
|
|
|
|
fd = gst_dmabuf_memory_get_fd (gst_buffer_peek_memory (inbuf, 0));
|
|
|
|
if (fd < 0)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (!plugin_update_sinkpad_info_from_buffer (plugin, inbuf))
|
|
|
|
goto error_update_sinkpad_info;
|
|
|
|
|
|
|
|
meta = gst_buffer_get_vaapi_video_meta (outbuf);
|
|
|
|
g_return_val_if_fail (meta != NULL, FALSE);
|
|
|
|
|
|
|
|
surface = gst_vaapi_surface_new_with_dma_buf_handle (plugin->display, fd,
|
|
|
|
GST_VIDEO_INFO_SIZE (vip), GST_VIDEO_INFO_FORMAT (vip),
|
|
|
|
GST_VIDEO_INFO_WIDTH (vip), GST_VIDEO_INFO_HEIGHT (vip),
|
|
|
|
vip->offset, vip->stride);
|
|
|
|
if (!surface)
|
|
|
|
goto error_create_surface;
|
|
|
|
|
|
|
|
proxy = gst_vaapi_surface_proxy_new (surface);
|
|
|
|
gst_vaapi_object_unref (surface);
|
|
|
|
if (!proxy)
|
|
|
|
goto error_create_proxy;
|
|
|
|
|
|
|
|
gst_vaapi_surface_proxy_set_destroy_notify (proxy,
|
|
|
|
(GDestroyNotify) gst_buffer_unref, (gpointer) gst_buffer_ref (inbuf));
|
|
|
|
gst_vaapi_video_meta_set_surface_proxy (meta, proxy);
|
|
|
|
gst_vaapi_surface_proxy_unref (proxy);
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
/* ERRORS */
|
|
|
|
error_update_sinkpad_info:
|
|
|
|
GST_ERROR ("failed to update sink pad video info from video meta");
|
|
|
|
return FALSE;
|
|
|
|
error_create_surface:
|
|
|
|
GST_ERROR ("failed to create VA surface from dma_buf handle");
|
|
|
|
return FALSE;
|
|
|
|
error_create_proxy:
|
|
|
|
GST_ERROR ("failed to create VA surface proxy from wrapped VA surface");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2013-12-13 09:24:26 +00:00
|
|
|
void
|
|
|
|
gst_vaapi_plugin_base_class_init (GstVaapiPluginBaseClass * klass)
|
|
|
|
{
|
2013-12-13 12:24:24 +00:00
|
|
|
klass->has_interface = default_has_interface;
|
2013-12-13 10:52:47 +00:00
|
|
|
klass->display_changed = default_display_changed;
|
2013-12-13 15:03:08 +00:00
|
|
|
|
|
|
|
GstElementClass *const element_class = GST_ELEMENT_CLASS (klass);
|
|
|
|
element_class->set_context = GST_DEBUG_FUNCPTR (plugin_set_context);
|
2013-12-13 09:24:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gst_vaapi_plugin_base_init (GstVaapiPluginBase * plugin,
|
|
|
|
GstDebugCategory * debug_category)
|
|
|
|
{
|
|
|
|
plugin->debug_category = debug_category;
|
2013-12-13 10:52:47 +00:00
|
|
|
plugin->display_type = GST_VAAPI_DISPLAY_TYPE_ANY;
|
|
|
|
plugin->display_type_req = GST_VAAPI_DISPLAY_TYPE_ANY;
|
2013-12-17 17:46:07 +00:00
|
|
|
|
|
|
|
/* sink pad */
|
|
|
|
plugin->sinkpad = gst_element_get_static_pad (GST_ELEMENT (plugin), "sink");
|
|
|
|
plugin->sinkpad_query = GST_PAD_QUERYFUNC (plugin->sinkpad);
|
|
|
|
gst_video_info_init (&plugin->sinkpad_info);
|
|
|
|
|
|
|
|
/* src pad */
|
|
|
|
if (!(GST_OBJECT_FLAGS (plugin) & GST_ELEMENT_FLAG_SINK)) {
|
|
|
|
plugin->srcpad = gst_element_get_static_pad (GST_ELEMENT (plugin), "src");
|
|
|
|
plugin->srcpad_query = GST_PAD_QUERYFUNC (plugin->srcpad);
|
|
|
|
}
|
|
|
|
gst_video_info_init (&plugin->srcpad_info);
|
2013-12-13 09:24:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gst_vaapi_plugin_base_finalize (GstVaapiPluginBase * plugin)
|
|
|
|
{
|
|
|
|
gst_vaapi_plugin_base_close (plugin);
|
2014-08-22 11:25:03 +00:00
|
|
|
g_free (plugin->display_name);
|
2013-12-17 17:46:07 +00:00
|
|
|
if (plugin->sinkpad)
|
|
|
|
gst_object_unref (plugin->sinkpad);
|
|
|
|
if (plugin->srcpad)
|
|
|
|
gst_object_unref (plugin->srcpad);
|
2013-12-13 09:24:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_vaapi_plugin_base_open:
|
|
|
|
* @plugin: a #GstVaapiPluginBase
|
|
|
|
*
|
|
|
|
* Allocates any internal resources needed for correct operation from
|
|
|
|
* the subclass.
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if successful, %FALSE otherwise.
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_vaapi_plugin_base_open (GstVaapiPluginBase * plugin)
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_vaapi_plugin_base_close:
|
|
|
|
* @plugin: a #GstVaapiPluginBase
|
|
|
|
*
|
|
|
|
* Deallocates all internal resources that were allocated so
|
|
|
|
* far. i.e. put the base plugin object into a clean state.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_vaapi_plugin_base_close (GstVaapiPluginBase * plugin)
|
|
|
|
{
|
|
|
|
gst_vaapi_display_replace (&plugin->display, NULL);
|
2014-12-03 13:14:30 +00:00
|
|
|
gst_object_replace (&plugin->gl_context, NULL);
|
2013-12-17 17:46:07 +00:00
|
|
|
|
|
|
|
gst_caps_replace (&plugin->sinkpad_caps, NULL);
|
|
|
|
plugin->sinkpad_caps_changed = FALSE;
|
|
|
|
gst_video_info_init (&plugin->sinkpad_info);
|
2013-12-17 17:52:23 +00:00
|
|
|
if (plugin->sinkpad_buffer_pool) {
|
|
|
|
gst_object_unref (plugin->sinkpad_buffer_pool);
|
|
|
|
plugin->sinkpad_buffer_pool = NULL;
|
|
|
|
}
|
2014-08-21 12:10:36 +00:00
|
|
|
g_clear_object (&plugin->srcpad_buffer_pool);
|
2013-12-17 17:46:07 +00:00
|
|
|
|
|
|
|
gst_caps_replace (&plugin->srcpad_caps, NULL);
|
|
|
|
plugin->srcpad_caps_changed = FALSE;
|
|
|
|
gst_video_info_init (&plugin->srcpad_info);
|
2015-07-23 11:11:40 +00:00
|
|
|
gst_caps_replace (&plugin->allowed_raw_caps, NULL);
|
2013-12-13 09:24:26 +00:00
|
|
|
}
|
2013-12-13 10:52:47 +00:00
|
|
|
|
2014-12-03 14:45:52 +00:00
|
|
|
/**
|
|
|
|
* gst_vaapi_plugin_base_has_display_type:
|
|
|
|
* @plugin: a #GstVaapiPluginBase
|
|
|
|
* @display_type_req: the desired #GstVaapiDisplayType
|
|
|
|
*
|
|
|
|
* Checks whether the @plugin elements already has a #GstVaapiDisplay
|
|
|
|
* instance compatible with type @display_type_req.
|
|
|
|
*
|
|
|
|
* Return value: %TRUE if @plugin has a compatible display, %FALSE otherwise
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_vaapi_plugin_base_has_display_type (GstVaapiPluginBase * plugin,
|
|
|
|
GstVaapiDisplayType display_type_req)
|
|
|
|
{
|
|
|
|
GstVaapiDisplayType display_type;
|
|
|
|
|
|
|
|
if (!plugin->display)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
display_type = plugin->display_type;
|
|
|
|
if (gst_vaapi_display_type_is_compatible (display_type, display_type_req))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
display_type = gst_vaapi_display_get_class_type (plugin->display);
|
|
|
|
if (gst_vaapi_display_type_is_compatible (display_type, display_type_req))
|
|
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2013-12-13 10:52:47 +00:00
|
|
|
/**
|
|
|
|
* gst_vaapi_plugin_base_set_display_type:
|
|
|
|
* @plugin: a #GstVaapiPluginBase
|
|
|
|
* @display_type: the new request #GstVaapiDisplayType
|
|
|
|
*
|
|
|
|
* Requests a new display type. The change is effective at the next
|
|
|
|
* call to gst_vaapi_plugin_base_ensure_display().
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_vaapi_plugin_base_set_display_type (GstVaapiPluginBase * plugin,
|
|
|
|
GstVaapiDisplayType display_type)
|
|
|
|
{
|
|
|
|
plugin->display_type_req = display_type;
|
|
|
|
}
|
|
|
|
|
2014-07-25 09:13:29 +00:00
|
|
|
/**
|
|
|
|
* gst_vaapi_plugin_base_set_display_name:
|
|
|
|
* @plugin: a #GstVaapiPluginBase
|
|
|
|
* @display_name: the new display name to match
|
|
|
|
*
|
|
|
|
* Sets the name of the display to look for. The change is effective
|
|
|
|
* at the next call to gst_vaapi_plugin_base_ensure_display().
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_vaapi_plugin_base_set_display_name (GstVaapiPluginBase * plugin,
|
|
|
|
const gchar * display_name)
|
|
|
|
{
|
|
|
|
g_free (plugin->display_name);
|
|
|
|
plugin->display_name = g_strdup (display_name);
|
|
|
|
}
|
|
|
|
|
2013-12-13 10:52:47 +00:00
|
|
|
/**
|
|
|
|
* gst_vaapi_plugin_base_ensure_display:
|
|
|
|
* @plugin: a #GstVaapiPluginBase
|
|
|
|
*
|
|
|
|
* Ensures the display stored in @plugin complies with the requested
|
|
|
|
* display type constraints.
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if the display was created to match the requested
|
|
|
|
* type, %FALSE otherwise.
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_vaapi_plugin_base_ensure_display (GstVaapiPluginBase * plugin)
|
|
|
|
{
|
2014-12-03 14:45:52 +00:00
|
|
|
if (gst_vaapi_plugin_base_has_display_type (plugin, plugin->display_type_req))
|
2013-12-13 10:52:47 +00:00
|
|
|
return TRUE;
|
|
|
|
gst_vaapi_display_replace (&plugin->display, NULL);
|
|
|
|
|
2015-05-08 13:54:09 +00:00
|
|
|
if (!gst_vaapi_ensure_display (GST_ELEMENT (plugin),
|
|
|
|
plugin->display_type_req))
|
2013-12-13 10:52:47 +00:00
|
|
|
return FALSE;
|
|
|
|
plugin->display_type = gst_vaapi_display_get_display_type (plugin->display);
|
|
|
|
|
|
|
|
GST_VAAPI_PLUGIN_BASE_GET_CLASS (plugin)->display_changed (plugin);
|
|
|
|
return TRUE;
|
|
|
|
}
|
2013-12-17 17:46:07 +00:00
|
|
|
|
2015-01-26 17:30:47 +00:00
|
|
|
/* Checks whether the supplied pad peer element supports DMABUF sharing */
|
|
|
|
/* XXX: this is a workaround to the absence of any proposer way to
|
|
|
|
specify DMABUF memory capsfeatures or bufferpool option to downstream */
|
|
|
|
static gboolean
|
|
|
|
has_dmabuf_capable_peer (GstVaapiPluginBase * plugin, GstPad * pad)
|
|
|
|
{
|
|
|
|
GstPad *other_pad = NULL;
|
|
|
|
GstElement *element = NULL;
|
|
|
|
gchar *element_name = NULL;
|
|
|
|
gboolean is_dmabuf_capable = FALSE;
|
|
|
|
gint v;
|
|
|
|
|
2015-03-02 12:28:41 +00:00
|
|
|
gst_object_ref (pad);
|
|
|
|
|
|
|
|
for (;;) {
|
2015-01-26 17:30:47 +00:00
|
|
|
other_pad = gst_pad_get_peer (pad);
|
2015-03-02 12:28:41 +00:00
|
|
|
gst_object_unref (pad);
|
2015-01-26 17:30:47 +00:00
|
|
|
if (!other_pad)
|
|
|
|
break;
|
|
|
|
|
|
|
|
element = gst_pad_get_parent_element (other_pad);
|
2015-03-02 12:28:41 +00:00
|
|
|
gst_object_unref (other_pad);
|
|
|
|
if (!element)
|
2015-01-26 17:30:47 +00:00
|
|
|
break;
|
|
|
|
|
2015-03-02 12:28:41 +00:00
|
|
|
if (GST_IS_PUSH_SRC (element)) {
|
|
|
|
element_name = gst_element_get_name (element);
|
|
|
|
if (!element_name || sscanf (element_name, "v4l2src%d", &v) != 1)
|
|
|
|
break;
|
|
|
|
|
|
|
|
v = 0;
|
|
|
|
g_object_get (element, "io-mode", &v, NULL);
|
2015-06-30 06:44:18 +00:00
|
|
|
is_dmabuf_capable = v == 5; /* "dmabuf-import" enum value */
|
2015-03-02 12:28:41 +00:00
|
|
|
break;
|
|
|
|
} else if (GST_IS_BASE_TRANSFORM (element)) {
|
|
|
|
element_name = gst_element_get_name (element);
|
|
|
|
if (!element_name || sscanf (element_name, "capsfilter%d", &v) != 1)
|
|
|
|
break;
|
|
|
|
|
|
|
|
pad = gst_element_get_static_pad (element, "sink");
|
|
|
|
if (!pad)
|
|
|
|
break;
|
|
|
|
} else
|
2015-01-26 17:30:47 +00:00
|
|
|
break;
|
|
|
|
|
2015-03-02 12:28:41 +00:00
|
|
|
g_free (element_name);
|
|
|
|
element_name = NULL;
|
|
|
|
g_clear_object (&element);
|
|
|
|
}
|
2015-01-26 17:30:47 +00:00
|
|
|
|
|
|
|
g_free (element_name);
|
|
|
|
g_clear_object (&element);
|
|
|
|
return is_dmabuf_capable;
|
|
|
|
}
|
|
|
|
|
2013-12-17 17:52:23 +00:00
|
|
|
/**
|
|
|
|
* ensure_sinkpad_buffer_pool:
|
|
|
|
* @plugin: a #GstVaapiPluginBase
|
|
|
|
* @caps: the initial #GstCaps for the resulting buffer pool
|
|
|
|
*
|
|
|
|
* Makes sure the sink pad video buffer pool is created with the
|
|
|
|
* appropriate @caps.
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if successful, %FALSE otherwise.
|
|
|
|
*/
|
|
|
|
static gboolean
|
|
|
|
ensure_sinkpad_buffer_pool (GstVaapiPluginBase * plugin, GstCaps * caps)
|
|
|
|
{
|
|
|
|
GstBufferPool *pool;
|
|
|
|
GstCaps *pool_caps;
|
|
|
|
GstStructure *config;
|
|
|
|
GstVideoInfo vi;
|
|
|
|
gboolean need_pool;
|
|
|
|
|
|
|
|
if (!gst_vaapi_plugin_base_ensure_display (plugin))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (plugin->sinkpad_buffer_pool) {
|
|
|
|
config = gst_buffer_pool_get_config (plugin->sinkpad_buffer_pool);
|
|
|
|
gst_buffer_pool_config_get_params (config, &pool_caps, NULL, NULL, NULL);
|
|
|
|
need_pool = !gst_caps_is_equal (caps, pool_caps);
|
|
|
|
gst_structure_free (config);
|
|
|
|
if (!need_pool)
|
|
|
|
return TRUE;
|
|
|
|
g_clear_object (&plugin->sinkpad_buffer_pool);
|
|
|
|
plugin->sinkpad_buffer_size = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
pool = gst_vaapi_video_buffer_pool_new (plugin->display);
|
|
|
|
if (!pool)
|
|
|
|
goto error_create_pool;
|
|
|
|
|
|
|
|
gst_video_info_init (&vi);
|
|
|
|
gst_video_info_from_caps (&vi, caps);
|
|
|
|
if (GST_VIDEO_INFO_FORMAT (&vi) == GST_VIDEO_FORMAT_ENCODED) {
|
|
|
|
GST_DEBUG ("assume video buffer pool format is NV12");
|
|
|
|
gst_video_info_set_format (&vi, GST_VIDEO_FORMAT_NV12,
|
|
|
|
GST_VIDEO_INFO_WIDTH (&vi), GST_VIDEO_INFO_HEIGHT (&vi));
|
|
|
|
}
|
|
|
|
plugin->sinkpad_buffer_size = vi.size;
|
|
|
|
|
|
|
|
config = gst_buffer_pool_get_config (pool);
|
|
|
|
gst_buffer_pool_config_set_params (config, caps,
|
|
|
|
plugin->sinkpad_buffer_size, 0, 0);
|
|
|
|
gst_buffer_pool_config_add_option (config,
|
|
|
|
GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
|
|
|
|
gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
|
|
|
|
if (!gst_buffer_pool_set_config (pool, config))
|
|
|
|
goto error_pool_config;
|
|
|
|
plugin->sinkpad_buffer_pool = pool;
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
/* ERRORS */
|
|
|
|
error_create_pool:
|
|
|
|
{
|
|
|
|
GST_ERROR ("failed to create buffer pool");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
error_pool_config:
|
|
|
|
{
|
|
|
|
GST_ERROR ("failed to reset buffer pool config");
|
|
|
|
gst_object_unref (pool);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-17 17:46:07 +00:00
|
|
|
/**
|
|
|
|
* gst_vaapi_plugin_base_set_caps:
|
|
|
|
* @plugin: a #GstVaapiPluginBase
|
|
|
|
* @incaps: the sink pad (input) caps
|
|
|
|
* @outcaps: the src pad (output) caps
|
|
|
|
*
|
|
|
|
* Notifies the base plugin object of the new input and output caps,
|
|
|
|
* obtained from the subclass.
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if the update of caps was successful, %FALSE otherwise.
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_vaapi_plugin_base_set_caps (GstVaapiPluginBase * plugin, GstCaps * incaps,
|
|
|
|
GstCaps * outcaps)
|
|
|
|
{
|
|
|
|
if (incaps && incaps != plugin->sinkpad_caps) {
|
|
|
|
gst_caps_replace (&plugin->sinkpad_caps, incaps);
|
|
|
|
if (!gst_video_info_from_caps (&plugin->sinkpad_info, incaps))
|
|
|
|
return FALSE;
|
|
|
|
plugin->sinkpad_caps_changed = TRUE;
|
2014-08-20 09:43:08 +00:00
|
|
|
plugin->sinkpad_caps_is_raw = !gst_caps_has_vaapi_surface (incaps);
|
2013-12-17 17:46:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (outcaps && outcaps != plugin->srcpad_caps) {
|
|
|
|
gst_caps_replace (&plugin->srcpad_caps, outcaps);
|
|
|
|
if (!gst_video_info_from_caps (&plugin->srcpad_info, outcaps))
|
|
|
|
return FALSE;
|
|
|
|
plugin->srcpad_caps_changed = TRUE;
|
|
|
|
}
|
2013-12-17 17:52:23 +00:00
|
|
|
|
|
|
|
if (!ensure_sinkpad_buffer_pool (plugin, plugin->sinkpad_caps))
|
|
|
|
return FALSE;
|
2013-12-17 17:46:07 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
2013-12-17 17:52:23 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_vaapi_plugin_base_propose_allocation:
|
|
|
|
* @plugin: a #GstVaapiPluginBase
|
|
|
|
* @query: the allocation query to configure
|
|
|
|
*
|
|
|
|
* Proposes allocation parameters to the upstream elements.
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if successful, %FALSE otherwise.
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_vaapi_plugin_base_propose_allocation (GstVaapiPluginBase * plugin,
|
|
|
|
GstQuery * query)
|
|
|
|
{
|
|
|
|
GstCaps *caps = NULL;
|
|
|
|
gboolean need_pool;
|
|
|
|
|
|
|
|
gst_query_parse_allocation (query, &caps, &need_pool);
|
|
|
|
|
|
|
|
if (need_pool) {
|
|
|
|
if (!caps)
|
|
|
|
goto error_no_caps;
|
|
|
|
if (!ensure_sinkpad_buffer_pool (plugin, caps))
|
|
|
|
return FALSE;
|
|
|
|
gst_query_add_allocation_pool (query, plugin->sinkpad_buffer_pool,
|
|
|
|
plugin->sinkpad_buffer_size, 0, 0);
|
2015-01-26 17:30:47 +00:00
|
|
|
|
|
|
|
if (has_dmabuf_capable_peer (plugin, plugin->sinkpad)) {
|
|
|
|
GstStructure *const config =
|
|
|
|
gst_buffer_pool_get_config (plugin->sinkpad_buffer_pool);
|
|
|
|
|
|
|
|
gst_buffer_pool_config_add_option (config,
|
|
|
|
GST_BUFFER_POOL_OPTION_DMABUF_MEMORY);
|
|
|
|
if (!gst_buffer_pool_set_config (plugin->sinkpad_buffer_pool, config))
|
|
|
|
goto error_pool_config;
|
|
|
|
}
|
2013-12-17 17:52:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gst_query_add_allocation_meta (query, GST_VAAPI_VIDEO_META_API_TYPE, NULL);
|
|
|
|
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
/* ERRORS */
|
|
|
|
error_no_caps:
|
|
|
|
{
|
2015-06-22 15:38:41 +00:00
|
|
|
GST_INFO_OBJECT (plugin, "no caps specified");
|
2013-12-17 17:52:23 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2015-01-26 17:30:47 +00:00
|
|
|
error_pool_config:
|
|
|
|
{
|
2015-06-22 15:38:41 +00:00
|
|
|
GST_ERROR_OBJECT (plugin, "failed to reset buffer pool config");
|
2015-01-26 17:30:47 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2013-12-17 17:52:23 +00:00
|
|
|
}
|
|
|
|
|
2015-04-30 11:21:08 +00:00
|
|
|
/* XXXX: GStreamer 1.2 doesn't check, in gst_buffer_pool_set_config()
|
|
|
|
if the config option is already set */
|
|
|
|
static inline gboolean
|
|
|
|
gst_vaapi_plugin_base_set_pool_config (GstBufferPool * pool,
|
|
|
|
const gchar * option)
|
|
|
|
{
|
|
|
|
GstStructure *config;
|
|
|
|
|
|
|
|
config = gst_buffer_pool_get_config (pool);
|
|
|
|
if (!gst_buffer_pool_config_has_option (config, option)) {
|
|
|
|
gst_buffer_pool_config_add_option (config, option);
|
|
|
|
return gst_buffer_pool_set_config (pool, config);
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2014-08-21 12:10:36 +00:00
|
|
|
/**
|
|
|
|
* gst_vaapi_plugin_base_decide_allocation:
|
|
|
|
* @plugin: a #GstVaapiPluginBase
|
|
|
|
* @query: the allocation query to parse
|
|
|
|
* @feature: the desired #GstVaapiCapsFeature, or zero to find the
|
|
|
|
* preferred one
|
|
|
|
*
|
|
|
|
* Decides allocation parameters for the downstream elements.
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if successful, %FALSE otherwise.
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_vaapi_plugin_base_decide_allocation (GstVaapiPluginBase * plugin,
|
|
|
|
GstQuery * query, guint feature)
|
|
|
|
{
|
|
|
|
GstCaps *caps = NULL;
|
|
|
|
GstBufferPool *pool;
|
|
|
|
GstStructure *config;
|
|
|
|
GstVideoInfo vi;
|
|
|
|
guint size, min, max;
|
2015-04-29 10:22:29 +00:00
|
|
|
gboolean update_pool = FALSE;
|
2014-08-21 12:10:36 +00:00
|
|
|
gboolean has_video_meta = FALSE;
|
|
|
|
gboolean has_video_alignment = FALSE;
|
2015-04-03 14:09:08 +00:00
|
|
|
#if (USE_GLX || USE_EGL)
|
2014-08-21 12:10:36 +00:00
|
|
|
gboolean has_texture_upload_meta = FALSE;
|
2014-12-03 13:14:30 +00:00
|
|
|
guint idx;
|
2014-08-21 12:10:36 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
g_return_val_if_fail (plugin->display != NULL, FALSE);
|
|
|
|
|
2015-04-29 10:22:29 +00:00
|
|
|
gst_query_parse_allocation (query, &caps, NULL);
|
2014-08-21 12:10:36 +00:00
|
|
|
|
2014-12-03 13:14:30 +00:00
|
|
|
/* We don't need any GL context beyond this point if not requested
|
|
|
|
so explicitly through GstVideoGLTextureUploadMeta */
|
|
|
|
gst_object_replace (&plugin->gl_context, NULL);
|
|
|
|
|
2014-08-21 12:10:36 +00:00
|
|
|
if (!caps)
|
|
|
|
goto error_no_caps;
|
|
|
|
|
|
|
|
if (!feature)
|
|
|
|
feature =
|
|
|
|
gst_vaapi_find_preferred_caps_feature (plugin->srcpad,
|
2015-02-09 20:09:07 +00:00
|
|
|
GST_VIDEO_FORMAT_ENCODED, NULL);
|
2014-08-21 12:10:36 +00:00
|
|
|
|
|
|
|
has_video_meta = gst_query_find_allocation_meta (query,
|
|
|
|
GST_VIDEO_META_API_TYPE, NULL);
|
|
|
|
|
2015-04-03 14:09:08 +00:00
|
|
|
#if (USE_GLX || USE_EGL)
|
2014-08-21 12:10:36 +00:00
|
|
|
has_texture_upload_meta = gst_query_find_allocation_meta (query,
|
plugins: upload meta only if feature and allocation
Working on bug #743687, I realized that vaapidecode always adds to its buffer
pool the config option GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META if
the decide_allocation()'s query has GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE.
Nevertheless, there are occasions where the query has the API type, but the
last negotiated caps don't have the feature meta:GstVideoGLTextureUploadMeta.
Under this contradiction, vaapidecode adds the GLTextureUploadMeta API to its
buffer pool configuration, and adds its buffer's meta to each output buffer,
even if the negotiated caps feature is memory:SystemMemory with I420 color
format.
This kind of output buffers chokes ClutterAutoVideosSink, since it uses a map
that relates caps <-> GL upload method. If it receives a buffer with color
format I420, it assumes that it doesn't have a texture upload meta, because
only those with RGB color format has it. Our buffers, with I420 format, say
that they have the upload meta too. In that case the mapped method is a dummy
one which does nothing. I reported this issue in bug #744039 (the patch,
obviously, was rejected).
This patch workarounds the problem: the buffer pool's configuration option
GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META is set if and only if the
query has the GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE *and* the negotiated
caps feature is meta:GstVideoGLTextureUploadMeta.
I have tested these patches with gst-master (1.5), gst-1.4 and gst-1.2 and
in all they seem to work correctly.
https://bugzilla.gnome.org/show_bug.cgi?id=744618
[adapted to fit current EGL changes]
Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
2015-02-23 15:55:36 +00:00
|
|
|
GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, &idx) &&
|
|
|
|
(feature == GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META);
|
2014-12-03 13:14:30 +00:00
|
|
|
|
|
|
|
#if USE_GST_GL_HELPERS
|
|
|
|
if (has_texture_upload_meta) {
|
|
|
|
const GstStructure *params;
|
|
|
|
GstObject *gl_context;
|
|
|
|
|
|
|
|
gst_query_parse_nth_allocation_meta (query, idx, ¶ms);
|
|
|
|
if (params) {
|
|
|
|
if (gst_structure_get (params, "gst.gl.GstGLContext", GST_GL_TYPE_CONTEXT,
|
|
|
|
&gl_context, NULL) && gl_context) {
|
|
|
|
gst_vaapi_plugin_base_set_gl_context (plugin, gl_context);
|
|
|
|
gst_object_unref (gl_context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2014-08-21 12:10:36 +00:00
|
|
|
#endif
|
|
|
|
|
2014-12-03 14:45:52 +00:00
|
|
|
/* Make sure the display we pass down to the buffer pool is actually
|
|
|
|
the expected one, especially when the downstream element requires
|
|
|
|
a GLX or EGL display */
|
|
|
|
if (!gst_vaapi_plugin_base_ensure_display (plugin))
|
|
|
|
goto error_ensure_display;
|
|
|
|
|
2014-08-21 12:10:36 +00:00
|
|
|
gst_video_info_init (&vi);
|
|
|
|
gst_video_info_from_caps (&vi, caps);
|
|
|
|
if (GST_VIDEO_INFO_FORMAT (&vi) == GST_VIDEO_FORMAT_ENCODED)
|
|
|
|
gst_video_info_set_format (&vi, GST_VIDEO_FORMAT_I420,
|
|
|
|
GST_VIDEO_INFO_WIDTH (&vi), GST_VIDEO_INFO_HEIGHT (&vi));
|
|
|
|
|
|
|
|
if (gst_query_get_n_allocation_pools (query) > 0) {
|
|
|
|
gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
|
2015-06-17 06:53:29 +00:00
|
|
|
update_pool = TRUE;
|
|
|
|
size = MAX (size, vi.size);
|
2015-04-17 19:10:35 +00:00
|
|
|
if (pool) {
|
|
|
|
/* Check whether downstream element proposed a bufferpool but did
|
|
|
|
not provide a correct propose_allocation() implementation */
|
|
|
|
has_video_alignment = gst_buffer_pool_has_option (pool,
|
|
|
|
GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
|
|
|
|
}
|
2014-08-21 12:10:36 +00:00
|
|
|
} else {
|
|
|
|
pool = NULL;
|
|
|
|
size = vi.size;
|
|
|
|
min = max = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* GstVaapiVideoMeta is mandatory, and this implies VA surface memory */
|
|
|
|
if (!pool || !gst_buffer_pool_has_option (pool,
|
|
|
|
GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) {
|
2015-04-29 10:24:52 +00:00
|
|
|
GST_INFO_OBJECT (plugin, "%s. Making a new pool", pool == NULL ? "No pool" :
|
|
|
|
"Pool hasn't GstVaapiVideoMeta");
|
2014-08-21 12:10:36 +00:00
|
|
|
if (pool)
|
|
|
|
gst_object_unref (pool);
|
|
|
|
pool = gst_vaapi_video_buffer_pool_new (plugin->display);
|
|
|
|
if (!pool)
|
|
|
|
goto error_create_pool;
|
|
|
|
|
|
|
|
config = gst_buffer_pool_get_config (pool);
|
|
|
|
gst_buffer_pool_config_set_params (config, caps, size, min, max);
|
|
|
|
gst_buffer_pool_config_add_option (config,
|
|
|
|
GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
|
2015-04-29 10:27:43 +00:00
|
|
|
if (!gst_buffer_pool_set_config (pool, config))
|
|
|
|
goto config_failed;
|
2014-08-21 12:10:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Check whether GstVideoMeta, or GstVideoAlignment, is needed (raw video) */
|
|
|
|
if (has_video_meta) {
|
2015-04-30 11:21:08 +00:00
|
|
|
if (!gst_vaapi_plugin_base_set_pool_config (pool,
|
|
|
|
GST_BUFFER_POOL_OPTION_VIDEO_META))
|
2015-04-29 10:27:43 +00:00
|
|
|
goto config_failed;
|
2014-08-21 12:10:36 +00:00
|
|
|
} else if (has_video_alignment) {
|
2015-04-30 11:21:08 +00:00
|
|
|
if (!gst_vaapi_plugin_base_set_pool_config (pool,
|
|
|
|
GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT))
|
2015-04-29 10:27:43 +00:00
|
|
|
goto config_failed;
|
2014-08-21 12:10:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* GstVideoGLTextureUploadMeta (OpenGL) */
|
2015-04-03 14:09:08 +00:00
|
|
|
#if (USE_GLX || USE_EGL)
|
plugins: upload meta only if feature and allocation
Working on bug #743687, I realized that vaapidecode always adds to its buffer
pool the config option GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META if
the decide_allocation()'s query has GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE.
Nevertheless, there are occasions where the query has the API type, but the
last negotiated caps don't have the feature meta:GstVideoGLTextureUploadMeta.
Under this contradiction, vaapidecode adds the GLTextureUploadMeta API to its
buffer pool configuration, and adds its buffer's meta to each output buffer,
even if the negotiated caps feature is memory:SystemMemory with I420 color
format.
This kind of output buffers chokes ClutterAutoVideosSink, since it uses a map
that relates caps <-> GL upload method. If it receives a buffer with color
format I420, it assumes that it doesn't have a texture upload meta, because
only those with RGB color format has it. Our buffers, with I420 format, say
that they have the upload meta too. In that case the mapped method is a dummy
one which does nothing. I reported this issue in bug #744039 (the patch,
obviously, was rejected).
This patch workarounds the problem: the buffer pool's configuration option
GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META is set if and only if the
query has the GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE *and* the negotiated
caps feature is meta:GstVideoGLTextureUploadMeta.
I have tested these patches with gst-master (1.5), gst-1.4 and gst-1.2 and
in all they seem to work correctly.
https://bugzilla.gnome.org/show_bug.cgi?id=744618
[adapted to fit current EGL changes]
Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
2015-02-23 15:55:36 +00:00
|
|
|
if (has_texture_upload_meta) {
|
2015-04-30 11:21:08 +00:00
|
|
|
if (!gst_vaapi_plugin_base_set_pool_config (pool,
|
|
|
|
GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META))
|
2015-04-29 10:27:43 +00:00
|
|
|
goto config_failed;
|
2014-08-21 12:10:36 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (update_pool)
|
|
|
|
gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
|
|
|
|
else
|
|
|
|
gst_query_add_allocation_pool (query, pool, size, min, max);
|
|
|
|
|
|
|
|
g_clear_object (&plugin->srcpad_buffer_pool);
|
|
|
|
plugin->srcpad_buffer_pool = pool;
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
/* ERRORS */
|
|
|
|
error_no_caps:
|
|
|
|
{
|
|
|
|
GST_ERROR_OBJECT (plugin, "no caps specified");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2014-12-03 14:45:52 +00:00
|
|
|
error_ensure_display:
|
|
|
|
{
|
|
|
|
GST_ERROR_OBJECT (plugin, "failed to ensure display of type %d",
|
|
|
|
plugin->display_type_req);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2014-08-21 12:10:36 +00:00
|
|
|
error_create_pool:
|
|
|
|
{
|
|
|
|
GST_ERROR_OBJECT (plugin, "failed to create buffer pool");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2015-04-29 10:27:43 +00:00
|
|
|
config_failed:
|
|
|
|
{
|
|
|
|
if (pool)
|
|
|
|
gst_object_unref (pool);
|
|
|
|
GST_ELEMENT_ERROR (plugin, RESOURCE, SETTINGS,
|
|
|
|
("Failed to configure the buffer pool"),
|
|
|
|
("Configuration is most likely invalid, please report this issue."));
|
|
|
|
return FALSE;
|
|
|
|
}
|
2014-08-21 12:10:36 +00:00
|
|
|
}
|
|
|
|
|
2013-12-17 17:52:23 +00:00
|
|
|
/**
|
|
|
|
* gst_vaapi_plugin_base_get_input_buffer:
|
|
|
|
* @plugin: a #GstVaapiPluginBase
|
|
|
|
* @incaps: the sink pad (input) buffer
|
|
|
|
* @outbuf_ptr: the pointer to location to the VA surface backed buffer
|
|
|
|
*
|
|
|
|
* Acquires the sink pad (input) buffer as a VA surface backed
|
|
|
|
* buffer. This is mostly useful for raw YUV buffers, as source
|
|
|
|
* buffers that are already backed as a VA surface are passed
|
|
|
|
* verbatim.
|
|
|
|
*
|
|
|
|
* Returns: #GST_FLOW_OK if the buffer could be acquired
|
|
|
|
*/
|
|
|
|
GstFlowReturn
|
|
|
|
gst_vaapi_plugin_base_get_input_buffer (GstVaapiPluginBase * plugin,
|
|
|
|
GstBuffer * inbuf, GstBuffer ** outbuf_ptr)
|
|
|
|
{
|
|
|
|
GstVaapiVideoMeta *meta;
|
|
|
|
GstBuffer *outbuf;
|
|
|
|
GstVideoFrame src_frame, out_frame;
|
|
|
|
gboolean success;
|
|
|
|
|
|
|
|
g_return_val_if_fail (inbuf != NULL, GST_FLOW_ERROR);
|
|
|
|
g_return_val_if_fail (outbuf_ptr != NULL, GST_FLOW_ERROR);
|
|
|
|
|
|
|
|
meta = gst_buffer_get_vaapi_video_meta (inbuf);
|
|
|
|
if (meta) {
|
|
|
|
*outbuf_ptr = gst_buffer_ref (inbuf);
|
|
|
|
return GST_FLOW_OK;
|
|
|
|
}
|
|
|
|
|
2014-08-20 09:43:08 +00:00
|
|
|
if (!plugin->sinkpad_caps_is_raw)
|
2013-12-17 17:52:23 +00:00
|
|
|
goto error_invalid_buffer;
|
|
|
|
|
|
|
|
if (!plugin->sinkpad_buffer_pool)
|
|
|
|
goto error_no_pool;
|
|
|
|
|
|
|
|
if (!gst_buffer_pool_set_active (plugin->sinkpad_buffer_pool, TRUE))
|
|
|
|
goto error_active_pool;
|
|
|
|
|
|
|
|
outbuf = NULL;
|
|
|
|
if (gst_buffer_pool_acquire_buffer (plugin->sinkpad_buffer_pool,
|
|
|
|
&outbuf, NULL) != GST_FLOW_OK)
|
|
|
|
goto error_create_buffer;
|
|
|
|
|
2014-01-23 10:00:09 +00:00
|
|
|
if (is_dma_buffer (inbuf)) {
|
|
|
|
if (!plugin_bind_dma_to_vaapi_buffer (plugin, inbuf, outbuf))
|
|
|
|
goto error_bind_dma_buffer;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2013-12-17 17:52:23 +00:00
|
|
|
if (!gst_video_frame_map (&src_frame, &plugin->sinkpad_info, inbuf,
|
|
|
|
GST_MAP_READ))
|
|
|
|
goto error_map_src_buffer;
|
|
|
|
|
|
|
|
if (!gst_video_frame_map (&out_frame, &plugin->sinkpad_info, outbuf,
|
|
|
|
GST_MAP_WRITE))
|
|
|
|
goto error_map_dst_buffer;
|
|
|
|
|
|
|
|
success = gst_video_frame_copy (&out_frame, &src_frame);
|
|
|
|
gst_video_frame_unmap (&out_frame);
|
|
|
|
gst_video_frame_unmap (&src_frame);
|
|
|
|
if (!success)
|
|
|
|
goto error_copy_buffer;
|
|
|
|
|
2014-01-23 10:00:09 +00:00
|
|
|
done:
|
2014-03-13 18:38:33 +00:00
|
|
|
gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_FLAGS |
|
|
|
|
GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
|
2013-12-17 17:52:23 +00:00
|
|
|
*outbuf_ptr = outbuf;
|
|
|
|
return GST_FLOW_OK;
|
|
|
|
|
|
|
|
/* ERRORS */
|
|
|
|
error_no_pool:
|
|
|
|
{
|
2015-02-18 09:19:26 +00:00
|
|
|
GST_ELEMENT_ERROR (plugin, STREAM, FAILED,
|
2015-06-30 06:44:18 +00:00
|
|
|
("no buffer pool was negotiated"), ("no buffer pool was negotiated"));
|
2013-12-17 17:52:23 +00:00
|
|
|
return GST_FLOW_ERROR;
|
|
|
|
}
|
|
|
|
error_active_pool:
|
|
|
|
{
|
2015-02-18 09:19:26 +00:00
|
|
|
GST_ELEMENT_ERROR (plugin, STREAM, FAILED,
|
2015-06-30 06:44:18 +00:00
|
|
|
("failed to activate buffer pool"), ("failed to activate buffer pool"));
|
2013-12-17 17:52:23 +00:00
|
|
|
return GST_FLOW_ERROR;
|
|
|
|
}
|
|
|
|
error_map_dst_buffer:
|
|
|
|
{
|
|
|
|
gst_video_frame_unmap (&src_frame);
|
|
|
|
// fall-through
|
|
|
|
}
|
|
|
|
error_map_src_buffer:
|
|
|
|
{
|
|
|
|
GST_WARNING ("failed to map buffer");
|
|
|
|
gst_buffer_unref (outbuf);
|
|
|
|
return GST_FLOW_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ERRORS */
|
|
|
|
error_invalid_buffer:
|
|
|
|
{
|
2015-02-18 09:19:26 +00:00
|
|
|
GST_ELEMENT_ERROR (plugin, STREAM, FAILED,
|
|
|
|
("failed to validate source buffer"),
|
|
|
|
("failed to validate source buffer"));
|
2013-12-17 17:52:23 +00:00
|
|
|
return GST_FLOW_ERROR;
|
|
|
|
}
|
|
|
|
error_create_buffer:
|
|
|
|
{
|
2015-02-18 09:19:26 +00:00
|
|
|
GST_ELEMENT_ERROR (plugin, STREAM, FAILED, ("Allocation failed"),
|
|
|
|
("failed to create buffer"));
|
2013-12-17 17:52:23 +00:00
|
|
|
return GST_FLOW_ERROR;
|
|
|
|
}
|
2014-01-23 10:00:09 +00:00
|
|
|
error_bind_dma_buffer:
|
|
|
|
{
|
2015-02-18 09:19:26 +00:00
|
|
|
GST_ELEMENT_ERROR (plugin, STREAM, FAILED, ("Allocation failed"),
|
|
|
|
("failed to bind dma_buf to VA surface buffer"));
|
2014-01-23 10:00:09 +00:00
|
|
|
gst_buffer_unref (outbuf);
|
|
|
|
return GST_FLOW_ERROR;
|
|
|
|
}
|
2013-12-17 17:52:23 +00:00
|
|
|
error_copy_buffer:
|
|
|
|
{
|
|
|
|
GST_WARNING ("failed to upload buffer to VA surface");
|
|
|
|
gst_buffer_unref (outbuf);
|
|
|
|
return GST_FLOW_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
}
|
2014-12-03 13:14:30 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_vaapi_plugin_base_set_gl_context:
|
|
|
|
* @plugin: a #GstVaapiPluginBase
|
|
|
|
* @object: the new GL context from downstream
|
|
|
|
*
|
|
|
|
* Registers the new GL context. The change is effective at the next
|
|
|
|
* call to gst_vaapi_plugin_base_ensure_display(), where the
|
|
|
|
* underlying display object could be re-allocated to fit the GL
|
|
|
|
* context needs
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_vaapi_plugin_base_set_gl_context (GstVaapiPluginBase * plugin,
|
|
|
|
GstObject * object)
|
|
|
|
{
|
|
|
|
#if USE_GST_GL_HELPERS
|
2014-12-03 14:45:52 +00:00
|
|
|
GstGLContext *const gl_context = GST_GL_CONTEXT (object);
|
|
|
|
GstVaapiDisplayType display_type;
|
|
|
|
|
2014-12-03 13:14:30 +00:00
|
|
|
gst_object_replace (&plugin->gl_context, object);
|
2014-12-03 14:45:52 +00:00
|
|
|
|
|
|
|
switch (gst_gl_context_get_gl_platform (gl_context)) {
|
|
|
|
#if USE_GLX
|
|
|
|
case GST_GL_PLATFORM_GLX:
|
|
|
|
display_type = GST_VAAPI_DISPLAY_TYPE_GLX;
|
|
|
|
break;
|
2015-02-20 14:29:17 +00:00
|
|
|
#endif
|
|
|
|
#if USE_EGL
|
|
|
|
case GST_GL_PLATFORM_EGL:
|
|
|
|
display_type = GST_VAAPI_DISPLAY_TYPE_EGL;
|
|
|
|
break;
|
2014-12-03 14:45:52 +00:00
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
display_type = plugin->display_type;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
gst_vaapi_plugin_base_set_display_type (plugin, display_type);
|
2014-12-03 13:14:30 +00:00
|
|
|
#endif
|
|
|
|
}
|
2015-07-23 11:11:40 +00:00
|
|
|
|
|
|
|
static gboolean
|
|
|
|
ensure_allowed_raw_caps (GstVaapiPluginBase * plugin)
|
|
|
|
{
|
|
|
|
GArray *formats, *out_formats;
|
|
|
|
GstVaapiSurface *surface;
|
|
|
|
guint i;
|
|
|
|
GstCaps *out_caps;
|
|
|
|
gboolean ret = FALSE;
|
|
|
|
|
|
|
|
if (plugin->allowed_raw_caps)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
out_formats = formats = NULL;
|
|
|
|
surface = NULL;
|
|
|
|
|
|
|
|
formats = gst_vaapi_display_get_image_formats (plugin->display);
|
|
|
|
if (!formats)
|
|
|
|
goto bail;
|
|
|
|
|
|
|
|
out_formats =
|
|
|
|
g_array_sized_new (FALSE, FALSE, sizeof (GstVideoFormat), formats->len);
|
|
|
|
if (!out_formats)
|
|
|
|
goto bail;
|
|
|
|
|
|
|
|
surface =
|
|
|
|
gst_vaapi_surface_new (plugin->display, GST_VAAPI_CHROMA_TYPE_YUV420, 64,
|
|
|
|
64);
|
|
|
|
if (!surface)
|
|
|
|
goto bail;
|
|
|
|
|
|
|
|
for (i = 0; i < formats->len; i++) {
|
|
|
|
const GstVideoFormat format = g_array_index (formats, GstVideoFormat, i);
|
|
|
|
GstVaapiImage *image;
|
|
|
|
|
|
|
|
if (format == GST_VIDEO_FORMAT_UNKNOWN)
|
|
|
|
continue;
|
|
|
|
image = gst_vaapi_image_new (plugin->display, format, 64, 64);
|
|
|
|
if (!image)
|
|
|
|
continue;
|
|
|
|
if (gst_vaapi_surface_put_image (surface, image))
|
|
|
|
g_array_append_val (out_formats, format);
|
|
|
|
gst_vaapi_object_unref (image);
|
|
|
|
}
|
|
|
|
|
|
|
|
out_caps = gst_vaapi_video_format_new_template_caps_from_list (out_formats);
|
|
|
|
if (!out_caps)
|
|
|
|
goto bail;
|
|
|
|
|
|
|
|
gst_caps_replace (&plugin->allowed_raw_caps, out_caps);
|
|
|
|
gst_caps_unref (out_caps);
|
|
|
|
ret = TRUE;
|
|
|
|
|
|
|
|
bail:
|
|
|
|
if (formats)
|
|
|
|
g_array_unref (formats);
|
|
|
|
if (out_formats)
|
|
|
|
g_array_unref (out_formats);
|
|
|
|
if (surface)
|
|
|
|
gst_vaapi_object_unref (surface);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_vaapi_plugin_base_get_allowed_raw_caps:
|
|
|
|
* @plugin: a #GstVaapiPluginBase
|
|
|
|
*
|
|
|
|
* Returns the raw #GstCaps allowed by the element.
|
|
|
|
*
|
|
|
|
* Returns: the allowed raw #GstCaps or %NULL
|
|
|
|
**/
|
|
|
|
GstCaps *
|
|
|
|
gst_vaapi_plugin_base_get_allowed_raw_caps (GstVaapiPluginBase * plugin)
|
|
|
|
{
|
|
|
|
if (!ensure_allowed_raw_caps (plugin))
|
|
|
|
return NULL;
|
|
|
|
return plugin->allowed_raw_caps;
|
|
|
|
}
|