mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-26 10:10:32 +00:00
406aa37373
When we copy a buffer because we're moving it into VA-API memory, we need to copy flags. Otherwise, interlaced YUV buffers from a capture source (e.g. V4L2) don't get flagged as interlaced. https://bugzilla.gnome.org/show_bug.cgi?id=726270 Signed-off-by: Simon Farnsworth <simon.farnsworth@onelan.co.uk> [reversed order of gst_buffer_copy_into() flags to match <1.0 code] Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
767 lines
22 KiB
C
767 lines
22 KiB
C
/*
|
|
* gstvaapipluginbase.c - Base GStreamer VA-API Plugin element
|
|
*
|
|
* Copyright (C) 2010-2011 Splitted-Desktop Systems
|
|
* Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
|
|
* Copyright (C) 2011-2014 Intel Corporation
|
|
* 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
|
|
*/
|
|
|
|
#include "gst/vaapi/sysdeps.h"
|
|
#include "gstvaapipluginbase.h"
|
|
#include "gstvaapipluginutil.h"
|
|
#include "gstvaapivideocontext.h"
|
|
#include "gstvaapivideometa.h"
|
|
#if GST_CHECK_VERSION(1,0,0)
|
|
#include "gstvaapivideobufferpool.h"
|
|
#endif
|
|
|
|
/* Default debug category is from the subclass */
|
|
#define GST_CAT_DEFAULT (plugin->debug_category)
|
|
|
|
/* GstImplementsInterface interface */
|
|
#if !GST_CHECK_VERSION(1,0,0)
|
|
static gboolean
|
|
implements_interface_supported (GstImplementsInterface * iface, GType type)
|
|
{
|
|
GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (iface);
|
|
|
|
if (type == GST_TYPE_VIDEO_CONTEXT)
|
|
return TRUE;
|
|
return GST_VAAPI_PLUGIN_BASE_GET_CLASS (plugin)->has_interface (plugin, type);
|
|
}
|
|
|
|
static void
|
|
implements_interface_init (GstImplementsInterfaceClass * iface)
|
|
{
|
|
iface->supported = implements_interface_supported;
|
|
}
|
|
#endif
|
|
|
|
/* GstVideoContext interface */
|
|
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);
|
|
}
|
|
|
|
#if GST_CHECK_VERSION(1,1,0)
|
|
static void
|
|
plugin_set_context (GstElement * element, GstContext * context)
|
|
{
|
|
GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element);
|
|
GstVaapiDisplay *display = NULL;
|
|
|
|
if (gst_vaapi_video_context_get_display (context, &display))
|
|
plugin_set_display (plugin, display);
|
|
}
|
|
#else
|
|
static void
|
|
plugin_set_context (GstVideoContext * context, const gchar * type,
|
|
const GValue * value)
|
|
{
|
|
GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (context);
|
|
GstVaapiDisplay *display = NULL;
|
|
|
|
gst_vaapi_set_display (type, value, &display);
|
|
plugin_set_display (plugin, display);
|
|
}
|
|
|
|
static void
|
|
video_context_interface_init (GstVideoContextInterface * iface)
|
|
{
|
|
iface->set_context = plugin_set_context;
|
|
}
|
|
|
|
#define GstVideoContextClass GstVideoContextInterface
|
|
#endif
|
|
|
|
void
|
|
gst_vaapi_plugin_base_init_interfaces (GType g_define_type_id)
|
|
{
|
|
#if !GST_CHECK_VERSION(1,0,0)
|
|
G_IMPLEMENT_INTERFACE (GST_TYPE_IMPLEMENTS_INTERFACE,
|
|
implements_interface_init);
|
|
#endif
|
|
#if !GST_CHECK_VERSION(1,1,0)
|
|
G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_CONTEXT, video_context_interface_init);
|
|
#endif
|
|
}
|
|
|
|
static gboolean
|
|
default_has_interface (GstVaapiPluginBase * plugin, GType type)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
default_display_changed (GstVaapiPluginBase * plugin)
|
|
{
|
|
}
|
|
|
|
void
|
|
gst_vaapi_plugin_base_class_init (GstVaapiPluginBaseClass * klass)
|
|
{
|
|
klass->has_interface = default_has_interface;
|
|
klass->display_changed = default_display_changed;
|
|
|
|
#if GST_CHECK_VERSION(1,1,0)
|
|
GstElementClass *const element_class = GST_ELEMENT_CLASS (klass);
|
|
element_class->set_context = GST_DEBUG_FUNCPTR (plugin_set_context);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
gst_vaapi_plugin_base_init (GstVaapiPluginBase * plugin,
|
|
GstDebugCategory * debug_category)
|
|
{
|
|
plugin->debug_category = debug_category;
|
|
plugin->display_type = GST_VAAPI_DISPLAY_TYPE_ANY;
|
|
plugin->display_type_req = GST_VAAPI_DISPLAY_TYPE_ANY;
|
|
|
|
/* 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);
|
|
}
|
|
|
|
void
|
|
gst_vaapi_plugin_base_finalize (GstVaapiPluginBase * plugin)
|
|
{
|
|
gst_vaapi_plugin_base_close (plugin);
|
|
g_free (plugin->display_name);
|
|
if (plugin->sinkpad)
|
|
gst_object_unref (plugin->sinkpad);
|
|
if (plugin->srcpad)
|
|
gst_object_unref (plugin->srcpad);
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
{
|
|
g_clear_object (&plugin->uploader);
|
|
gst_vaapi_display_replace (&plugin->display, NULL);
|
|
|
|
gst_caps_replace (&plugin->sinkpad_caps, NULL);
|
|
plugin->sinkpad_caps_changed = FALSE;
|
|
gst_video_info_init (&plugin->sinkpad_info);
|
|
#if GST_CHECK_VERSION(1,0,0)
|
|
if (plugin->sinkpad_buffer_pool) {
|
|
gst_object_unref (plugin->sinkpad_buffer_pool);
|
|
plugin->sinkpad_buffer_pool = NULL;
|
|
}
|
|
g_clear_object (&plugin->srcpad_buffer_pool);
|
|
#endif
|
|
|
|
gst_caps_replace (&plugin->srcpad_caps, NULL);
|
|
plugin->srcpad_caps_changed = FALSE;
|
|
gst_video_info_init (&plugin->srcpad_info);
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
{
|
|
if (plugin->display
|
|
&& gst_vaapi_display_type_is_compatible (plugin->display_type,
|
|
plugin->display_type_req))
|
|
return TRUE;
|
|
gst_vaapi_display_replace (&plugin->display, NULL);
|
|
|
|
if (!gst_vaapi_ensure_display (plugin, plugin->display_type_req))
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* gst_vaapi_plugin_base_ensure_uploader:
|
|
* @plugin: a #GstVaapiPluginBase
|
|
*
|
|
* Makes sure the built-in #GstVaapiUploader object is created, or
|
|
* that it was successfully notified of any VA display change.
|
|
*
|
|
* Returns: %TRUE if the uploader was successfully created, %FALSE otherwise.
|
|
*/
|
|
gboolean
|
|
gst_vaapi_plugin_base_ensure_uploader (GstVaapiPluginBase * plugin)
|
|
{
|
|
if (plugin->uploader) {
|
|
if (!gst_vaapi_uploader_ensure_display (plugin->uploader, plugin->display))
|
|
return FALSE;
|
|
} else {
|
|
plugin->uploader = gst_vaapi_uploader_new (plugin->display);
|
|
if (!plugin->uploader)
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
{
|
|
#if GST_CHECK_VERSION(1,0,0)
|
|
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;
|
|
}
|
|
#else
|
|
return TRUE;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
plugin->sinkpad_caps_is_raw = !gst_caps_has_vaapi_surface (incaps);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
if (plugin->uploader && plugin->sinkpad_caps_is_raw) {
|
|
if (!gst_vaapi_uploader_ensure_display (plugin->uploader, plugin->display))
|
|
return FALSE;
|
|
if (!gst_vaapi_uploader_ensure_caps (plugin->uploader,
|
|
plugin->sinkpad_caps, plugin->srcpad_caps))
|
|
return FALSE;
|
|
}
|
|
|
|
if (!ensure_sinkpad_buffer_pool (plugin, plugin->sinkpad_caps))
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
#if GST_CHECK_VERSION(1,0,0)
|
|
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);
|
|
}
|
|
|
|
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:
|
|
{
|
|
GST_ERROR ("no caps specified");
|
|
return FALSE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
#if GST_CHECK_VERSION(1,0,0)
|
|
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;
|
|
gboolean need_pool, update_pool;
|
|
gboolean has_video_meta = FALSE;
|
|
gboolean has_video_alignment = FALSE;
|
|
#if GST_CHECK_VERSION(1,1,0) && USE_GLX
|
|
gboolean has_texture_upload_meta = FALSE;
|
|
#endif
|
|
|
|
g_return_val_if_fail (plugin->display != NULL, FALSE);
|
|
|
|
gst_query_parse_allocation (query, &caps, &need_pool);
|
|
|
|
if (!caps)
|
|
goto error_no_caps;
|
|
|
|
if (!feature)
|
|
feature =
|
|
gst_vaapi_find_preferred_caps_feature (plugin->srcpad,
|
|
GST_VIDEO_FORMAT_ENCODED);
|
|
|
|
has_video_meta = gst_query_find_allocation_meta (query,
|
|
GST_VIDEO_META_API_TYPE, NULL);
|
|
|
|
#if GST_CHECK_VERSION(1,1,0) && USE_GLX
|
|
has_texture_upload_meta = gst_query_find_allocation_meta (query,
|
|
GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, NULL);
|
|
#endif
|
|
|
|
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);
|
|
size = MAX (size, vi.size);
|
|
update_pool = TRUE;
|
|
|
|
/* 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);
|
|
} else {
|
|
pool = NULL;
|
|
size = vi.size;
|
|
min = max = 0;
|
|
update_pool = FALSE;
|
|
}
|
|
|
|
/* GstVaapiVideoMeta is mandatory, and this implies VA surface memory */
|
|
if (!pool || !gst_buffer_pool_has_option (pool,
|
|
GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) {
|
|
GST_INFO_OBJECT (plugin, "no pool or doesn't support GstVaapiVideoMeta, "
|
|
"making new pool");
|
|
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);
|
|
gst_buffer_pool_set_config (pool, config);
|
|
}
|
|
|
|
/* Check whether GstVideoMeta, or GstVideoAlignment, is needed (raw video) */
|
|
if (has_video_meta) {
|
|
config = gst_buffer_pool_get_config (pool);
|
|
gst_buffer_pool_config_add_option (config,
|
|
GST_BUFFER_POOL_OPTION_VIDEO_META);
|
|
#if GST_CHECK_VERSION(1,1,0) && USE_GLX
|
|
if (has_texture_upload_meta)
|
|
gst_buffer_pool_config_add_option (config,
|
|
GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META);
|
|
#endif
|
|
gst_buffer_pool_set_config (pool, config);
|
|
} else if (has_video_alignment) {
|
|
config = gst_buffer_pool_get_config (pool);
|
|
gst_buffer_pool_config_add_option (config,
|
|
GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
|
|
gst_buffer_pool_set_config (pool, config);
|
|
}
|
|
|
|
/* GstVideoGLTextureUploadMeta (OpenGL) */
|
|
#if GST_CHECK_VERSION(1,1,0) && USE_GLX
|
|
if (feature == GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META
|
|
&& !has_texture_upload_meta) {
|
|
config = gst_buffer_pool_get_config (pool);
|
|
gst_buffer_pool_config_add_option (config,
|
|
GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META);
|
|
gst_buffer_pool_set_config (pool, config);
|
|
}
|
|
#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;
|
|
}
|
|
error_create_pool:
|
|
{
|
|
GST_ERROR_OBJECT (plugin, "failed to create buffer pool");
|
|
return FALSE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* gst_vaapi_plugin_base_allocate_input_buffer:
|
|
* @plugin: a #GstVaapiPluginBase
|
|
* @caps: the buffer caps constraints to honour
|
|
* @outbuf_ptr: the pointer location to the newly allocated buffer
|
|
*
|
|
* Creates a buffer that holds a VA surface memory for the sink pad to
|
|
* use it as the result for buffer_alloc() impementations.
|
|
*
|
|
* Return: #GST_FLOW_OK if the buffer could be created.
|
|
*/
|
|
GstFlowReturn
|
|
gst_vaapi_plugin_base_allocate_input_buffer (GstVaapiPluginBase * plugin,
|
|
GstCaps * caps, GstBuffer ** outbuf_ptr)
|
|
{
|
|
GstBuffer *outbuf;
|
|
|
|
*outbuf_ptr = NULL;
|
|
|
|
if (!plugin->sinkpad_caps_changed) {
|
|
if (!gst_video_info_from_caps (&plugin->sinkpad_info, caps))
|
|
return GST_FLOW_NOT_SUPPORTED;
|
|
plugin->sinkpad_caps_changed = TRUE;
|
|
}
|
|
|
|
if (!plugin->sinkpad_caps_is_raw)
|
|
return GST_FLOW_OK;
|
|
|
|
if (!gst_vaapi_uploader_ensure_display (plugin->uploader, plugin->display))
|
|
return GST_FLOW_NOT_SUPPORTED;
|
|
if (!gst_vaapi_uploader_ensure_caps (plugin->uploader, caps, NULL))
|
|
return GST_FLOW_NOT_SUPPORTED;
|
|
|
|
outbuf = gst_vaapi_uploader_get_buffer (plugin->uploader);
|
|
if (!outbuf) {
|
|
GST_WARNING ("failed to allocate resources for raw YUV buffer");
|
|
return GST_FLOW_NOT_SUPPORTED;
|
|
}
|
|
|
|
*outbuf_ptr = outbuf;
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
#if GST_CHECK_VERSION(1,0,0)
|
|
GstVideoFrame src_frame, out_frame;
|
|
gboolean success;
|
|
#endif
|
|
|
|
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 GST_CHECK_VERSION(1,0,0)
|
|
if (meta) {
|
|
*outbuf_ptr = gst_buffer_ref (inbuf);
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
if (!plugin->sinkpad_caps_is_raw)
|
|
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;
|
|
|
|
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;
|
|
|
|
gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_FLAGS |
|
|
GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
|
|
*outbuf_ptr = outbuf;
|
|
return GST_FLOW_OK;
|
|
|
|
/* ERRORS */
|
|
error_no_pool:
|
|
{
|
|
GST_ERROR ("no buffer pool was negotiated");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
error_active_pool:
|
|
{
|
|
GST_ERROR ("failed to activate buffer pool");
|
|
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;
|
|
}
|
|
#else
|
|
if (meta)
|
|
outbuf = gst_buffer_ref (inbuf);
|
|
else if (plugin->sinkpad_caps_is_raw) {
|
|
outbuf = gst_vaapi_uploader_get_buffer (plugin->uploader);
|
|
if (!outbuf)
|
|
goto error_create_buffer;
|
|
gst_buffer_copy_metadata (outbuf, inbuf,
|
|
GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
|
|
} else
|
|
goto error_invalid_buffer;
|
|
|
|
if (plugin->sinkpad_caps_is_raw &&
|
|
!gst_vaapi_uploader_process (plugin->uploader, inbuf, outbuf))
|
|
goto error_copy_buffer;
|
|
|
|
*outbuf_ptr = outbuf;
|
|
return GST_FLOW_OK;
|
|
#endif
|
|
|
|
/* ERRORS */
|
|
error_invalid_buffer:
|
|
{
|
|
GST_ERROR ("failed to validate source buffer");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
error_create_buffer:
|
|
{
|
|
GST_ERROR ("failed to create buffer");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
error_copy_buffer:
|
|
{
|
|
GST_WARNING ("failed to upload buffer to VA surface");
|
|
gst_buffer_unref (outbuf);
|
|
return GST_FLOW_NOT_SUPPORTED;
|
|
}
|
|
}
|