plugins: factor out support for raw YUV buffers on sink pads.

Factor out propose_allocation() hooks, creation of video buffer pool
for the sink pad, conversion from raw YUV buffers to VA surface backed
buffers. Update vaapidecode, vaapiencode and vaapipostproc to cope
with the new GstVaapiPluginBase abilities.
This commit is contained in:
Gwenole Beauchesne 2013-12-17 18:52:23 +01:00
parent b324fc6add
commit e3dcd33114
8 changed files with 402 additions and 776 deletions

View file

@ -61,33 +61,10 @@ ensure_display (GstVaapiEncode * encode)
static gboolean static gboolean
ensure_uploader (GstVaapiEncode * encode) ensure_uploader (GstVaapiEncode * encode)
{ {
#if !GST_CHECK_VERSION(1,0,0)
if (!ensure_display (encode)) if (!ensure_display (encode))
return FALSE; return FALSE;
if (!gst_vaapi_plugin_base_ensure_uploader (GST_VAAPI_PLUGIN_BASE (encode)))
if (!encode->uploader) {
encode->uploader = gst_vaapi_uploader_new (
GST_VAAPI_PLUGIN_BASE_DISPLAY (encode));
if (!encode->uploader)
return FALSE;
}
if (!gst_vaapi_uploader_ensure_display (encode->uploader,
GST_VAAPI_PLUGIN_BASE_DISPLAY (encode)))
return FALSE; return FALSE;
#endif
return TRUE;
}
static gboolean
ensure_uploader_caps (GstVaapiEncode * encode)
{
#if !GST_CHECK_VERSION(1,0,0)
if (GST_VIDEO_INFO_IS_YUV (&encode->sink_video_info) &&
!gst_vaapi_uploader_ensure_caps (encode->uploader, encode->sinkpad_caps,
NULL))
return FALSE;
#endif
return TRUE; return TRUE;
} }
@ -283,7 +260,7 @@ gst_vaapiencode_get_caps_impl (GstVideoEncoder * venc)
caps = gst_caps_from_string (GST_VAAPI_SURFACE_CAPS); caps = gst_caps_from_string (GST_VAAPI_SURFACE_CAPS);
if (caps && ensure_uploader (encode)) { if (caps && ensure_uploader (encode)) {
GstCaps *const yuv_caps = gst_vaapi_uploader_get_caps (encode->uploader); GstCaps *const yuv_caps = GST_VAAPI_PLUGIN_BASE_UPLOADER_CAPS (encode);
if (yuv_caps) { if (yuv_caps) {
caps = gst_caps_make_writable (caps); caps = gst_caps_make_writable (caps);
gst_caps_append (caps, gst_caps_copy (yuv_caps)); gst_caps_append (caps, gst_caps_copy (yuv_caps));
@ -316,10 +293,6 @@ static gboolean
gst_vaapiencode_destroy (GstVaapiEncode * encode) gst_vaapiencode_destroy (GstVaapiEncode * encode)
{ {
gst_vaapi_encoder_replace (&encode->encoder, NULL); gst_vaapi_encoder_replace (&encode->encoder, NULL);
#if GST_CHECK_VERSION(1,0,0)
g_clear_object (&encode->video_buffer_pool);
#endif
g_clear_object (&encode->uploader);
gst_caps_replace (&encode->sinkpad_caps, NULL); gst_caps_replace (&encode->sinkpad_caps, NULL);
gst_caps_replace (&encode->srcpad_caps, NULL); gst_caps_replace (&encode->srcpad_caps, NULL);
return TRUE; return TRUE;
@ -332,12 +305,8 @@ ensure_encoder (GstVaapiEncode * encode)
g_return_val_if_fail (klass->create_encoder, FALSE); g_return_val_if_fail (klass->create_encoder, FALSE);
if (!ensure_display (encode))
return FALSE;
if (!ensure_uploader (encode)) if (!ensure_uploader (encode))
return FALSE; return FALSE;
if (!ensure_uploader_caps (encode))
return FALSE;
encode->encoder = klass->create_encoder (encode, encode->encoder = klass->create_encoder (encode,
GST_VAAPI_PLUGIN_BASE_DISPLAY (encode)); GST_VAAPI_PLUGIN_BASE_DISPLAY (encode));
@ -378,18 +347,6 @@ gst_vaapiencode_update_sink_caps (GstVaapiEncode * encode,
GstVideoCodecState * state) GstVideoCodecState * state)
{ {
gst_caps_replace (&encode->sinkpad_caps, state->caps); gst_caps_replace (&encode->sinkpad_caps, state->caps);
encode->sink_video_info = state->info;
#if !GST_CHECK_VERSION(1,0,0)
if (GST_VIDEO_INFO_IS_YUV (&encode->sink_video_info)) {
/* Ensure the uploader is set up for upstream allocated buffers */
GstVaapiUploader *const uploader = encode->uploader;
if (!gst_vaapi_uploader_ensure_display (uploader, GST_VAAPI_PLUGIN_BASE_DISPLAY (encode)))
return FALSE;
if (!gst_vaapi_uploader_ensure_caps (uploader, state->caps, NULL))
return FALSE;
}
#endif
return TRUE; return TRUE;
} }
@ -450,72 +407,6 @@ gst_vaapiencode_update_src_caps (GstVaapiEncode * encode,
return TRUE; return TRUE;
} }
static gboolean
gst_vaapiencode_ensure_video_buffer_pool (GstVaapiEncode * encode,
GstCaps * caps)
{
#if GST_CHECK_VERSION(1,0,0)
GstBufferPool *pool;
GstCaps *pool_caps;
GstStructure *config;
GstVideoInfo vi;
gboolean need_pool;
if (!ensure_display (encode))
return FALSE;
if (encode->video_buffer_pool) {
config = gst_buffer_pool_get_config (encode->video_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 (&encode->video_buffer_pool);
encode->video_buffer_size = 0;
}
pool = gst_vaapi_video_buffer_pool_new (GST_VAAPI_PLUGIN_BASE_DISPLAY (encode));
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));
}
encode->video_buffer_size = vi.size;
config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_set_params (config, caps, encode->video_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;
encode->video_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
}
static gboolean static gboolean
gst_vaapiencode_set_format (GstVideoEncoder * venc, GstVideoCodecState * state) gst_vaapiencode_set_format (GstVideoEncoder * venc, GstVideoCodecState * state)
{ {
@ -523,9 +414,6 @@ gst_vaapiencode_set_format (GstVideoEncoder * venc, GstVideoCodecState * state)
g_return_val_if_fail (state->caps != NULL, FALSE); g_return_val_if_fail (state->caps != NULL, FALSE);
if (!gst_vaapiencode_ensure_video_buffer_pool (encode, state->caps))
return FALSE;
if (!ensure_encoder (encode)) if (!ensure_encoder (encode))
return FALSE; return FALSE;
if (!gst_vaapiencode_update_sink_caps (encode, state)) if (!gst_vaapiencode_update_sink_caps (encode, state))
@ -533,6 +421,10 @@ gst_vaapiencode_set_format (GstVideoEncoder * venc, GstVideoCodecState * state)
if (!gst_vaapiencode_update_src_caps (encode, state)) if (!gst_vaapiencode_update_src_caps (encode, state))
return FALSE; return FALSE;
if (!gst_vaapi_plugin_base_set_caps (GST_VAAPI_PLUGIN_BASE (encode),
encode->sinkpad_caps, encode->srcpad_caps))
return FALSE;
#if GST_CHECK_VERSION(1,0,0) #if GST_CHECK_VERSION(1,0,0)
if (encode->out_caps_done && !gst_video_encoder_negotiate (venc)) { if (encode->out_caps_done && !gst_video_encoder_negotiate (venc)) {
GST_ERROR ("failed to negotiate with caps %" GST_PTR_FORMAT, GST_ERROR ("failed to negotiate with caps %" GST_PTR_FORMAT,
@ -557,114 +449,6 @@ gst_vaapiencode_reset (GstVideoEncoder * venc, gboolean hard)
return TRUE; return TRUE;
} }
static GstFlowReturn
get_source_buffer (GstVaapiEncode * encode, GstBuffer * src_buffer,
GstBuffer ** out_buffer_ptr)
{
GstVaapiVideoMeta *meta;
GstBuffer *out_buffer;
#if GST_CHECK_VERSION(1,0,0)
GstVideoFrame src_frame, out_frame;
gboolean success;
#endif
meta = gst_buffer_get_vaapi_video_meta (src_buffer);
if (meta) {
*out_buffer_ptr = gst_buffer_ref (src_buffer);
return GST_FLOW_OK;
}
#if GST_CHECK_VERSION(1,0,0)
if (!GST_VIDEO_INFO_IS_YUV (&encode->sink_video_info))
goto error_invalid_buffer;
if (!encode->video_buffer_pool)
goto error_no_pool;
if (!gst_buffer_pool_set_active (encode->video_buffer_pool, TRUE))
goto error_activate_pool;
out_buffer = NULL;
success = gst_buffer_pool_acquire_buffer (encode->video_buffer_pool,
&out_buffer, NULL) == GST_FLOW_OK;
if (!success)
goto error_create_buffer;
if (!gst_video_frame_map (&src_frame, &encode->sink_video_info, src_buffer,
GST_MAP_READ))
goto error_map_src_buffer;
if (!gst_video_frame_map (&out_frame, &encode->sink_video_info, out_buffer,
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 (out_buffer, src_buffer, GST_BUFFER_COPY_TIMESTAMPS, 0,
-1);
*out_buffer_ptr = out_buffer;
return GST_FLOW_OK;
/* ERRORS */
error_invalid_buffer:
{
GST_ERROR ("unsupported video buffer");
return GST_FLOW_EOS;
}
error_no_pool:
{
GST_ERROR ("no buffer pool was negotiated");
return GST_FLOW_ERROR;
}
error_activate_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. Skipping this frame");
gst_buffer_unref (out_buffer);
return GST_FLOW_OK;
}
#else
out_buffer = gst_vaapi_uploader_get_buffer (encode->uploader);
if (!out_buffer)
goto error_create_buffer;
if (!gst_vaapi_uploader_process (encode->uploader, src_buffer, out_buffer))
goto error_copy_buffer;
gst_buffer_copy_metadata (out_buffer, src_buffer,
GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
*out_buffer_ptr = out_buffer;
return GST_FLOW_OK;
#endif
/* ERRORS */
error_create_buffer:
{
GST_WARNING ("failed to create buffer. Skipping this frame");
return GST_FLOW_OK;
}
error_copy_buffer:
{
GST_WARNING ("failed to upload buffer to VA surface. Skipping this frame");
gst_buffer_unref (out_buffer);
return GST_FLOW_OK;
}
}
static GstFlowReturn static GstFlowReturn
gst_vaapiencode_handle_frame (GstVideoEncoder * venc, gst_vaapiencode_handle_frame (GstVideoEncoder * venc,
GstVideoCodecFrame * frame) GstVideoCodecFrame * frame)
@ -677,7 +461,8 @@ gst_vaapiencode_handle_frame (GstVideoEncoder * venc,
GstBuffer *buf; GstBuffer *buf;
buf = NULL; buf = NULL;
ret = get_source_buffer (encode, frame->input_buffer, &buf); ret = gst_vaapi_plugin_base_get_input_buffer (GST_VAAPI_PLUGIN_BASE (encode),
frame->input_buffer, &buf);
if (ret != GST_FLOW_OK) if (ret != GST_FLOW_OK)
goto error_buffer_invalid; goto error_buffer_invalid;
@ -759,31 +544,11 @@ gst_vaapiencode_finish (GstVideoEncoder * venc)
static gboolean static gboolean
gst_vaapiencode_propose_allocation (GstVideoEncoder * venc, GstQuery * query) gst_vaapiencode_propose_allocation (GstVideoEncoder * venc, GstQuery * query)
{ {
GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc); GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (venc);
GstCaps *caps = NULL;
gboolean need_pool;
gst_query_parse_allocation (query, &caps, &need_pool); if (!gst_vaapi_plugin_base_propose_allocation (plugin, query))
if (need_pool) {
if (!caps)
goto error_no_caps;
if (!gst_vaapiencode_ensure_video_buffer_pool (encode, caps))
return FALSE;
gst_query_add_allocation_pool (query, encode->video_buffer_pool,
encode->video_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; return FALSE;
} return TRUE;
} }
#endif #endif
@ -864,7 +629,6 @@ gst_vaapiencode_init (GstVaapiEncode * encode)
encode->sinkpad = GST_VIDEO_ENCODER_SINK_PAD (encode); encode->sinkpad = GST_VIDEO_ENCODER_SINK_PAD (encode);
encode->sinkpad_query = GST_PAD_QUERYFUNC (encode->sinkpad); encode->sinkpad_query = GST_PAD_QUERYFUNC (encode->sinkpad);
gst_pad_set_query_function (encode->sinkpad, gst_vaapiencode_query); gst_pad_set_query_function (encode->sinkpad, gst_vaapiencode_query);
gst_video_info_init (&encode->sink_video_info);
/* src pad */ /* src pad */
encode->srcpad = GST_VIDEO_ENCODER_SRC_PAD (encode); encode->srcpad = GST_VIDEO_ENCODER_SRC_PAD (encode);

View file

@ -24,7 +24,6 @@
#include "gstvaapipluginbase.h" #include "gstvaapipluginbase.h"
#include <gst/vaapi/gstvaapiencoder.h> #include <gst/vaapi/gstvaapiencoder.h>
#include "gstvaapiuploader.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -54,19 +53,12 @@ struct _GstVaapiEncode
GstPad *sinkpad; GstPad *sinkpad;
GstCaps *sinkpad_caps; GstCaps *sinkpad_caps;
GstPadQueryFunction sinkpad_query; GstPadQueryFunction sinkpad_query;
GstVideoInfo sink_video_info;
GstPad *srcpad; GstPad *srcpad;
GstCaps *srcpad_caps; GstCaps *srcpad_caps;
GstPadQueryFunction srcpad_query; GstPadQueryFunction srcpad_query;
GstVaapiEncoder *encoder; GstVaapiEncoder *encoder;
GstVaapiUploader *uploader;
#if GST_CHECK_VERSION(1,0,0)
GstBufferPool *video_buffer_pool;
#endif
guint video_buffer_size;
GstVaapiRateControl rate_control; GstVaapiRateControl rate_control;
guint32 bitrate; /* kbps */ guint32 bitrate; /* kbps */

View file

@ -26,6 +26,10 @@
#include "gstvaapipluginbase.h" #include "gstvaapipluginbase.h"
#include "gstvaapipluginutil.h" #include "gstvaapipluginutil.h"
#include "gstvaapivideocontext.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 */ /* Default debug category is from the subclass */
#define GST_CAT_DEFAULT (plugin->debug_category) #define GST_CAT_DEFAULT (plugin->debug_category)
@ -174,11 +178,18 @@ gst_vaapi_plugin_base_open (GstVaapiPluginBase * plugin)
void void
gst_vaapi_plugin_base_close (GstVaapiPluginBase * plugin) gst_vaapi_plugin_base_close (GstVaapiPluginBase * plugin)
{ {
g_clear_object (&plugin->uploader);
gst_vaapi_display_replace (&plugin->display, NULL); gst_vaapi_display_replace (&plugin->display, NULL);
gst_caps_replace (&plugin->sinkpad_caps, NULL); gst_caps_replace (&plugin->sinkpad_caps, NULL);
plugin->sinkpad_caps_changed = FALSE; plugin->sinkpad_caps_changed = FALSE;
gst_video_info_init (&plugin->sinkpad_info); 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;
}
#endif
gst_caps_replace (&plugin->srcpad_caps, NULL); gst_caps_replace (&plugin->srcpad_caps, NULL);
plugin->srcpad_caps_changed = FALSE; plugin->srcpad_caps_changed = FALSE;
@ -227,6 +238,104 @@ gst_vaapi_plugin_base_ensure_display (GstVaapiPluginBase * plugin)
return TRUE; 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: * gst_vaapi_plugin_base_set_caps:
* @plugin: a #GstVaapiPluginBase * @plugin: a #GstVaapiPluginBase
@ -255,5 +364,227 @@ gst_vaapi_plugin_base_set_caps (GstVaapiPluginBase * plugin, GstCaps * incaps,
return FALSE; return FALSE;
plugin->srcpad_caps_changed = TRUE; plugin->srcpad_caps_changed = TRUE;
} }
if (plugin->uploader && GST_VIDEO_INFO_IS_YUV (&plugin->sinkpad_info)) {
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; 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_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 (!GST_VIDEO_INFO_IS_YUV (&plugin->sinkpad_info))
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 (!GST_VIDEO_INFO_IS_YUV (&plugin->sinkpad_info))
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_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 (GST_VIDEO_INFO_IS_YUV (&plugin->sinkpad_info)) {
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 (GST_VIDEO_INFO_IS_YUV (&plugin->sinkpad_info) &&
!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;
}
}

View file

@ -30,6 +30,7 @@
#include <gst/video/gstvideoencoder.h> #include <gst/video/gstvideoencoder.h>
#include <gst/video/gstvideosink.h> #include <gst/video/gstvideosink.h>
#include <gst/vaapi/gstvaapidisplay.h> #include <gst/vaapi/gstvaapidisplay.h>
#include "gstvaapiuploader.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -96,6 +97,13 @@ typedef struct _GstVaapiPluginBaseClass GstVaapiPluginBaseClass;
(gst_vaapi_display_replace(&GST_VAAPI_PLUGIN_BASE_DISPLAY(plugin), \ (gst_vaapi_display_replace(&GST_VAAPI_PLUGIN_BASE_DISPLAY(plugin), \
(new_display))) (new_display)))
#define GST_VAAPI_PLUGIN_BASE_UPLOADER(plugin) \
(GST_VAAPI_PLUGIN_BASE(plugin)->uploader)
#define GST_VAAPI_PLUGIN_BASE_UPLOADER_CAPS(plugin) \
(gst_vaapi_uploader_get_caps(GST_VAAPI_PLUGIN_BASE_UPLOADER(plugin)))
#define GST_VAAPI_PLUGIN_BASE_UPLOADER_USED(plugin) \
(GST_VAAPI_PLUGIN_BASE(plugin)->uploader_used)
struct _GstVaapiPluginBase struct _GstVaapiPluginBase
{ {
/*< private >*/ /*< private >*/
@ -115,6 +123,10 @@ struct _GstVaapiPluginBase
gboolean sinkpad_caps_changed; gboolean sinkpad_caps_changed;
GstVideoInfo sinkpad_info; GstVideoInfo sinkpad_info;
GstPadQueryFunction sinkpad_query; GstPadQueryFunction sinkpad_query;
#if GST_CHECK_VERSION(1,0,0)
GstBufferPool *sinkpad_buffer_pool;
guint sinkpad_buffer_size;
#endif
GstPad *srcpad; GstPad *srcpad;
GstCaps *srcpad_caps; GstCaps *srcpad_caps;
@ -125,6 +137,9 @@ struct _GstVaapiPluginBase
GstVaapiDisplay *display; GstVaapiDisplay *display;
GstVaapiDisplayType display_type; GstVaapiDisplayType display_type;
GstVaapiDisplayType display_type_req; GstVaapiDisplayType display_type_req;
GstVaapiUploader *uploader;
gboolean uploader_used;
}; };
struct _GstVaapiPluginBaseClass struct _GstVaapiPluginBaseClass
@ -177,11 +192,30 @@ G_GNUC_INTERNAL
gboolean gboolean
gst_vaapi_plugin_base_ensure_display (GstVaapiPluginBase * plugin); gst_vaapi_plugin_base_ensure_display (GstVaapiPluginBase * plugin);
G_GNUC_INTERNAL
gboolean
gst_vaapi_plugin_base_ensure_uploader (GstVaapiPluginBase * plugin);
G_GNUC_INTERNAL G_GNUC_INTERNAL
gboolean gboolean
gst_vaapi_plugin_base_set_caps (GstVaapiPluginBase * plugin, GstCaps * incaps, gst_vaapi_plugin_base_set_caps (GstVaapiPluginBase * plugin, GstCaps * incaps,
GstCaps * outcaps); GstCaps * outcaps);
G_GNUC_INTERNAL
gboolean
gst_vaapi_plugin_base_propose_allocation (GstVaapiPluginBase * plugin,
GstQuery * query);
G_GNUC_INTERNAL
GstFlowReturn
gst_vaapi_plugin_base_allocate_input_buffer (GstVaapiPluginBase * plugin,
GstCaps * caps, GstBuffer ** outbuf_ptr);
G_GNUC_INTERNAL
GstFlowReturn
gst_vaapi_plugin_base_get_input_buffer (GstVaapiPluginBase * plugin,
GstBuffer * inbuf, GstBuffer ** outbuf_ptr);
G_END_DECLS G_END_DECLS
#endif /* GST_VAAPI_PLUGIN_BASE_H */ #endif /* GST_VAAPI_PLUGIN_BASE_H */

View file

@ -212,32 +212,11 @@ gst_vaapipostproc_ensure_uploader(GstVaapiPostproc *postproc)
{ {
if (!gst_vaapipostproc_ensure_display(postproc)) if (!gst_vaapipostproc_ensure_display(postproc))
return FALSE; return FALSE;
if (!gst_vaapi_plugin_base_ensure_uploader(GST_VAAPI_PLUGIN_BASE(postproc)))
if (!postproc->uploader) {
postproc->uploader = gst_vaapi_uploader_new(
GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc));
if (!postproc->uploader)
return FALSE;
}
if (!gst_vaapi_uploader_ensure_display(postproc->uploader,
GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc)))
return FALSE; return FALSE;
return TRUE; return TRUE;
} }
static gboolean
gst_vaapipostproc_ensure_uploader_caps(GstVaapiPostproc *postproc)
{
#if !GST_CHECK_VERSION(1,0,0)
GstVaapiPluginBase * const plugin = GST_VAAPI_PLUGIN_BASE(postproc);
if (postproc->is_raw_yuv && !gst_vaapi_uploader_ensure_caps(
postproc->uploader, plugin->sinkpad_caps, NULL))
return FALSE;
#endif
return TRUE;
}
static gboolean static gboolean
gst_vaapipostproc_ensure_filter(GstVaapiPostproc *postproc) gst_vaapipostproc_ensure_filter(GstVaapiPostproc *postproc)
{ {
@ -279,8 +258,6 @@ gst_vaapipostproc_create(GstVaapiPostproc *postproc)
return FALSE; return FALSE;
if (!gst_vaapipostproc_ensure_uploader(postproc)) if (!gst_vaapipostproc_ensure_uploader(postproc))
return FALSE; return FALSE;
if (!gst_vaapipostproc_ensure_uploader_caps(postproc))
return FALSE;
if (gst_vaapipostproc_ensure_filter(postproc)) if (gst_vaapipostproc_ensure_filter(postproc))
postproc->use_vpp = TRUE; postproc->use_vpp = TRUE;
return TRUE; return TRUE;
@ -306,10 +283,6 @@ static void
gst_vaapipostproc_destroy(GstVaapiPostproc *postproc) gst_vaapipostproc_destroy(GstVaapiPostproc *postproc)
{ {
ds_reset(&postproc->deinterlace_state); ds_reset(&postproc->deinterlace_state);
#if GST_CHECK_VERSION(1,0,0)
g_clear_object(&postproc->sinkpad_buffer_pool);
#endif
g_clear_object(&postproc->uploader);
gst_vaapipostproc_destroy_filter(postproc); gst_vaapipostproc_destroy_filter(postproc);
gst_caps_replace(&postproc->allowed_sinkpad_caps, NULL); gst_caps_replace(&postproc->allowed_sinkpad_caps, NULL);
@ -791,16 +764,6 @@ gst_vaapipostproc_update_sink_caps(GstVaapiPostproc *postproc, GstCaps *caps,
(1 + deinterlace) * GST_VIDEO_INFO_FPS_N(&vi)); (1 + deinterlace) * GST_VIDEO_INFO_FPS_N(&vi));
postproc->is_raw_yuv = GST_VIDEO_INFO_IS_YUV(&vi); postproc->is_raw_yuv = GST_VIDEO_INFO_IS_YUV(&vi);
#if !GST_CHECK_VERSION(1,0,0)
if (postproc->is_raw_yuv) {
/* Ensure the uploader is set up for upstream allocated buffers */
GstVaapiUploader * const uploader = postproc->uploader;
if (!gst_vaapi_uploader_ensure_display(uploader, GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc)))
return FALSE;
if (!gst_vaapi_uploader_ensure_caps(uploader, caps, NULL))
return FALSE;
}
#endif
return TRUE; return TRUE;
} }
@ -849,7 +812,7 @@ ensure_allowed_sinkpad_caps(GstVaapiPostproc *postproc)
/* Append YUV caps */ /* Append YUV caps */
if (gst_vaapipostproc_ensure_uploader(postproc)) { if (gst_vaapipostproc_ensure_uploader(postproc)) {
yuv_caps = gst_vaapi_uploader_get_caps(postproc->uploader); yuv_caps = GST_VAAPI_PLUGIN_BASE_UPLOADER_CAPS(postproc);
if (yuv_caps) { if (yuv_caps) {
out_caps = gst_caps_make_writable(out_caps); out_caps = gst_caps_make_writable(out_caps);
gst_caps_append(out_caps, gst_caps_copy(yuv_caps)); gst_caps_append(out_caps, gst_caps_copy(yuv_caps));
@ -1117,107 +1080,6 @@ gst_vaapipostproc_transform_size(GstBaseTransform *trans,
return TRUE; return TRUE;
} }
static GstBuffer *
get_source_buffer(GstVaapiPostproc *postproc, GstBuffer *inbuf)
{
GstVaapiVideoMeta *meta;
GstBuffer *outbuf;
#if GST_CHECK_VERSION(1,0,0)
GstVideoFrame src_frame, out_frame;
#endif
meta = gst_buffer_get_vaapi_video_meta(inbuf);
if (meta)
return gst_buffer_ref(inbuf);
#if GST_CHECK_VERSION(1,0,0)
if (!postproc->is_raw_yuv)
goto error_invalid_buffer;
if (!postproc->sinkpad_buffer_pool)
goto error_no_pool;
if (!gst_buffer_pool_set_active(postproc->sinkpad_buffer_pool, TRUE))
goto error_active_pool;
outbuf = NULL;
if (gst_buffer_pool_acquire_buffer(postproc->sinkpad_buffer_pool,
&outbuf, NULL) != GST_FLOW_OK)
goto error_create_buffer;
if (!gst_video_frame_map(&src_frame, &postproc->sinkpad_info, inbuf,
GST_MAP_READ))
goto error_map_src_buffer;
if (!gst_video_frame_map(&out_frame, &postproc->sinkpad_info, outbuf,
GST_MAP_WRITE))
goto error_map_dst_buffer;
if (!gst_video_frame_copy(&out_frame, &src_frame))
goto error_copy_buffer;
gst_video_frame_unmap(&out_frame);
gst_video_frame_unmap(&src_frame);
gst_buffer_copy_into(outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
return outbuf;
/* ERRORS */
error_invalid_buffer:
{
GST_ERROR("failed to validate source buffer");
return NULL;
}
error_no_pool:
{
GST_ERROR("no buffer pool was negotiated");
return NULL;
}
error_active_pool:
{
GST_ERROR("failed to activate buffer pool");
return NULL;
}
error_map_dst_buffer:
{
gst_video_frame_unmap(&src_frame);
// fall-through
}
error_map_src_buffer:
{
GST_ERROR("failed to map buffer");
gst_buffer_unref(outbuf);
return NULL;
}
#else
outbuf = gst_vaapi_uploader_get_buffer(postproc->uploader);
if (!outbuf)
goto error_create_buffer;
if (!gst_vaapi_uploader_process(postproc->uploader, inbuf, outbuf))
goto error_copy_buffer;
gst_buffer_copy_metadata(outbuf, inbuf,
GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
return outbuf;
#endif
/* ERRORS */
error_create_buffer:
{
GST_ERROR("failed to create buffer");
return NULL;
}
error_copy_buffer:
{
GST_ERROR("failed to upload buffer to VA surface");
#if GST_CHECK_VERSION(1,0,0)
gst_video_frame_unmap(&out_frame);
gst_video_frame_unmap(&src_frame);
#endif
gst_buffer_unref(outbuf);
return NULL;
}
}
static GstFlowReturn static GstFlowReturn
gst_vaapipostproc_transform(GstBaseTransform *trans, GstBuffer *inbuf, gst_vaapipostproc_transform(GstBaseTransform *trans, GstBuffer *inbuf,
GstBuffer *outbuf) GstBuffer *outbuf)
@ -1226,8 +1088,9 @@ gst_vaapipostproc_transform(GstBaseTransform *trans, GstBuffer *inbuf,
GstBuffer *buf; GstBuffer *buf;
GstFlowReturn ret; GstFlowReturn ret;
buf = get_source_buffer(postproc, inbuf); ret = gst_vaapi_plugin_base_get_input_buffer(
if (!buf) GST_VAAPI_PLUGIN_BASE(postproc), inbuf, &buf);
if (ret != GST_FLOW_OK)
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
ret = GST_FLOW_NOT_SUPPORTED; ret = GST_FLOW_NOT_SUPPORTED;
@ -1272,73 +1135,6 @@ gst_vaapipostproc_prepare_output_buffer(GstBaseTransform *trans,
return *outbuf_ptr ? GST_FLOW_OK : GST_FLOW_ERROR; return *outbuf_ptr ? GST_FLOW_OK : GST_FLOW_ERROR;
} }
static gboolean
ensure_sinkpad_buffer_pool(GstVaapiPostproc *postproc, GstCaps *caps)
{
#if GST_CHECK_VERSION(1,0,0)
GstBufferPool *pool;
GstCaps *pool_caps;
GstStructure *config;
GstVideoInfo vi;
gboolean need_pool;
if (!gst_vaapipostproc_ensure_display(postproc))
return FALSE;
if (postproc->sinkpad_buffer_pool) {
config = gst_buffer_pool_get_config(postproc->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(&postproc->sinkpad_buffer_pool);
postproc->sinkpad_buffer_size = 0;
}
pool = gst_vaapi_video_buffer_pool_new(
GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc));
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 sink pad 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));
}
postproc->sinkpad_buffer_size = vi.size;
config = gst_buffer_pool_get_config(pool);
gst_buffer_pool_config_set_params(config, caps,
postproc->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;
postproc->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
}
static gboolean static gboolean
ensure_srcpad_buffer_pool(GstVaapiPostproc *postproc, GstCaps *caps) ensure_srcpad_buffer_pool(GstVaapiPostproc *postproc, GstCaps *caps)
{ {
@ -1378,15 +1174,13 @@ gst_vaapipostproc_set_caps(GstBaseTransform *trans, GstCaps *caps,
if (caps_changed) { if (caps_changed) {
gst_vaapipostproc_destroy(postproc); gst_vaapipostproc_destroy(postproc);
if (!gst_vaapipostproc_create(postproc))
return FALSE;
if (!gst_vaapi_plugin_base_set_caps(GST_VAAPI_PLUGIN_BASE(trans), if (!gst_vaapi_plugin_base_set_caps(GST_VAAPI_PLUGIN_BASE(trans),
caps, out_caps)) caps, out_caps))
return FALSE; return FALSE;
if (!gst_vaapipostproc_create(postproc))
return FALSE;
} }
if (!ensure_sinkpad_buffer_pool(postproc, caps))
return FALSE;
if (!ensure_srcpad_buffer_pool(postproc, out_caps)) if (!ensure_srcpad_buffer_pool(postproc, out_caps))
return FALSE; return FALSE;
return TRUE; return TRUE;
@ -1415,40 +1209,14 @@ gst_vaapipostproc_propose_allocation(GstBaseTransform *trans,
GstQuery *decide_query, GstQuery *query) GstQuery *decide_query, GstQuery *query)
{ {
GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans); GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
GstCaps *caps = NULL; GstVaapiPluginBase * const plugin = GST_VAAPI_PLUGIN_BASE(trans);
gboolean need_pool;
/* Let vaapidecode allocate the video buffers */ /* Let vaapidecode allocate the video buffers */
if (!postproc->is_raw_yuv) if (!postproc->is_raw_yuv)
return FALSE; return FALSE;
if (!gst_vaapi_plugin_base_propose_allocation(plugin, query))
gst_query_parse_allocation(query, &caps, &need_pool);
if (need_pool) {
if (!caps)
goto error_no_caps;
if (!ensure_sinkpad_buffer_pool(postproc, caps))
return FALSE;
gst_query_add_allocation_pool(query, postproc->sinkpad_buffer_pool,
postproc->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);
gst_query_add_allocation_meta(query,
GST_VIDEO_CROP_META_API_TYPE, NULL);
gst_query_add_allocation_meta(query,
GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL);
return TRUE;
/* ERRORS */
error_no_caps:
{
GST_ERROR("no caps specified");
return FALSE; return FALSE;
} return TRUE;
} }
#endif #endif

View file

@ -27,7 +27,6 @@
#include <gst/vaapi/gstvaapisurface.h> #include <gst/vaapi/gstvaapisurface.h>
#include <gst/vaapi/gstvaapisurfacepool.h> #include <gst/vaapi/gstvaapisurfacepool.h>
#include <gst/vaapi/gstvaapifilter.h> #include <gst/vaapi/gstvaapifilter.h>
#include "gstvaapiuploader.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -136,7 +135,6 @@ struct _GstVaapiPostproc {
/*< private >*/ /*< private >*/
GstVaapiPluginBase parent_instance; GstVaapiPluginBase parent_instance;
GstVaapiUploader *uploader;
GstVaapiFilter *filter; GstVaapiFilter *filter;
GPtrArray *filter_ops; GPtrArray *filter_ops;
GstVaapiVideoPool *filter_pool; GstVaapiVideoPool *filter_pool;
@ -149,10 +147,6 @@ struct _GstVaapiPostproc {
GstCaps *allowed_sinkpad_caps; GstCaps *allowed_sinkpad_caps;
GstVideoInfo sinkpad_info; GstVideoInfo sinkpad_info;
#if GST_CHECK_VERSION(1,0,0)
GstBufferPool *sinkpad_buffer_pool;
#endif
guint sinkpad_buffer_size;
GstCaps *allowed_srcpad_caps; GstCaps *allowed_srcpad_caps;
GstVideoInfo srcpad_info; GstVideoInfo srcpad_info;

View file

@ -239,10 +239,7 @@ gst_vaapisink_destroy(GstVaapiSink *sink)
#if USE_GLX #if USE_GLX
gst_vaapi_texture_replace(&sink->texture, NULL); gst_vaapi_texture_replace(&sink->texture, NULL);
#endif #endif
g_clear_object(&sink->uploader);
gst_caps_replace(&sink->caps, NULL); gst_caps_replace(&sink->caps, NULL);
gst_vaapi_plugin_base_close(GST_VAAPI_PLUGIN_BASE(sink));
} }
#if USE_X11 #if USE_X11
@ -341,13 +338,8 @@ gst_vaapisink_ensure_uploader(GstVaapiSink *sink)
{ {
if (!gst_vaapisink_ensure_display(sink)) if (!gst_vaapisink_ensure_display(sink))
return FALSE; return FALSE;
if (!gst_vaapi_plugin_base_ensure_uploader(GST_VAAPI_PLUGIN_BASE(sink)))
if (!sink->uploader) { return FALSE;
sink->uploader = gst_vaapi_uploader_new(
GST_VAAPI_PLUGIN_BASE_DISPLAY(sink));
if (!sink->uploader)
return FALSE;
}
return TRUE; return TRUE;
} }
@ -605,72 +597,6 @@ end:
return success; return success;
} }
static gboolean
gst_vaapisink_ensure_video_buffer_pool(GstVaapiSink *sink, GstCaps *caps)
{
#if GST_CHECK_VERSION(1,0,0)
GstBufferPool *pool;
GstCaps *pool_caps;
GstStructure *config;
GstVideoInfo vi;
gboolean need_pool;
if (!gst_vaapisink_ensure_display(sink))
return FALSE;
if (sink->video_buffer_pool) {
config = gst_buffer_pool_get_config(sink->video_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(&sink->video_buffer_pool);
sink->video_buffer_size = 0;
}
pool = gst_vaapi_video_buffer_pool_new(GST_VAAPI_PLUGIN_BASE_DISPLAY(sink));
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));
}
sink->video_buffer_size = vi.size;
config = gst_buffer_pool_get_config(pool);
gst_buffer_pool_config_set_params(config, caps, sink->video_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;
sink->video_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
}
static gboolean static gboolean
gst_vaapisink_start(GstBaseSink *base_sink) gst_vaapisink_start(GstBaseSink *base_sink)
{ {
@ -691,7 +617,7 @@ gst_vaapisink_stop(GstBaseSink *base_sink)
g_clear_object(&sink->video_buffer_pool); g_clear_object(&sink->video_buffer_pool);
#endif #endif
gst_vaapi_window_replace(&sink->window, NULL); gst_vaapi_window_replace(&sink->window, NULL);
g_clear_object(&sink->uploader);
gst_vaapi_plugin_base_close(GST_VAAPI_PLUGIN_BASE(sink)); gst_vaapi_plugin_base_close(GST_VAAPI_PLUGIN_BASE(sink));
return TRUE; return TRUE;
} }
@ -711,7 +637,7 @@ gst_vaapisink_get_caps_impl(GstBaseSink *base_sink)
return NULL; return NULL;
if (gst_vaapisink_ensure_uploader(sink)) { if (gst_vaapisink_ensure_uploader(sink)) {
yuv_caps = gst_vaapi_uploader_get_caps(sink->uploader); yuv_caps = GST_VAAPI_PLUGIN_BASE_UPLOADER_CAPS(sink);
if (yuv_caps) { if (yuv_caps) {
out_caps = gst_caps_make_writable(out_caps); out_caps = gst_caps_make_writable(out_caps);
gst_caps_append(out_caps, gst_caps_copy(yuv_caps)); gst_caps_append(out_caps, gst_caps_copy(yuv_caps));
@ -745,7 +671,7 @@ gst_vaapisink_set_caps(GstBaseSink *base_sink, GstCaps *caps)
{ {
GstVaapiPluginBase * const plugin = GST_VAAPI_PLUGIN_BASE(base_sink); GstVaapiPluginBase * const plugin = GST_VAAPI_PLUGIN_BASE(base_sink);
GstVaapiSink * const sink = GST_VAAPISINK(base_sink); GstVaapiSink * const sink = GST_VAAPISINK(base_sink);
GstVideoInfo * const vip = &sink->video_info; GstVideoInfo * const vip = GST_VAAPI_PLUGIN_BASE_SINK_PAD_INFO(sink);
GstVaapiDisplay *display; GstVaapiDisplay *display;
guint win_width, win_height; guint win_width, win_height;
@ -761,12 +687,6 @@ gst_vaapisink_set_caps(GstBaseSink *base_sink, GstCaps *caps)
if (!gst_vaapi_plugin_base_set_caps(plugin, caps, NULL)) if (!gst_vaapi_plugin_base_set_caps(plugin, caps, NULL))
return FALSE; return FALSE;
if (!gst_vaapisink_ensure_video_buffer_pool(sink, caps))
return FALSE;
if (!gst_video_info_from_caps(vip, caps))
return FALSE;
sink->use_video_raw = GST_VIDEO_INFO_IS_YUV(vip);
sink->video_width = GST_VIDEO_INFO_WIDTH(vip); sink->video_width = GST_VIDEO_INFO_WIDTH(vip);
sink->video_height = GST_VIDEO_INFO_HEIGHT(vip); sink->video_height = GST_VIDEO_INFO_HEIGHT(vip);
sink->video_par_n = GST_VIDEO_INFO_PAR_N(vip); sink->video_par_n = GST_VIDEO_INFO_PAR_N(vip);
@ -776,16 +696,6 @@ gst_vaapisink_set_caps(GstBaseSink *base_sink, GstCaps *caps)
gst_caps_replace(&sink->caps, caps); gst_caps_replace(&sink->caps, caps);
#if !GST_CHECK_VERSION(1,0,0)
if (sink->use_video_raw) {
/* Ensure the uploader is set up for upstream allocated buffers */
if (!gst_vaapi_uploader_ensure_display(sink->uploader, display))
return FALSE;
if (!gst_vaapi_uploader_ensure_caps(sink->uploader, caps, NULL))
return FALSE;
}
#endif
gst_vaapisink_ensure_rotation(sink, FALSE); gst_vaapisink_ensure_rotation(sink, FALSE);
gst_vaapisink_ensure_window_size(sink, &win_width, &win_height); gst_vaapisink_ensure_window_size(sink, &win_width, &win_height);
@ -1029,116 +939,6 @@ gst_vaapisink_put_surface(
return TRUE; return TRUE;
} }
#if GST_CHECK_VERSION(1,0,0)
static GstFlowReturn
gst_vaapisink_get_render_buffer(GstVaapiSink *sink, GstBuffer *src_buffer,
GstBuffer **out_buffer_ptr)
{
GstVaapiVideoMeta *meta;
GstBuffer *out_buffer;
GstBufferPoolAcquireParams params = { 0, };
GstVideoFrame src_frame, out_frame;
GstFlowReturn ret;
meta = gst_buffer_get_vaapi_video_meta(src_buffer);
if (meta) {
*out_buffer_ptr = gst_buffer_ref(src_buffer);
return GST_FLOW_OK;
}
if (!sink->use_video_raw) {
GST_ERROR("unsupported video buffer");
return GST_FLOW_EOS;
}
GST_DEBUG("buffer %p not from our pool, copying", src_buffer);
*out_buffer_ptr = NULL;
if (!sink->video_buffer_pool)
goto error_no_pool;
if (!gst_buffer_pool_set_active(sink->video_buffer_pool, TRUE))
goto error_activate_pool;
params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
ret = gst_buffer_pool_acquire_buffer(sink->video_buffer_pool, &out_buffer,
&params);
if (ret != GST_FLOW_OK)
goto error_create_buffer;
if (!gst_video_frame_map(&src_frame, &sink->video_info, src_buffer,
GST_MAP_READ))
goto error_map_src_buffer;
if (!gst_video_frame_map(&out_frame, &sink->video_info, out_buffer,
GST_MAP_WRITE))
goto error_map_dst_buffer;
gst_video_frame_copy(&out_frame, &src_frame);
gst_video_frame_unmap(&out_frame);
gst_video_frame_unmap(&src_frame);
*out_buffer_ptr = out_buffer;
return GST_FLOW_OK;
/* ERRORS */
error_no_pool:
GST_ERROR("no buffer pool was negotiated");
return GST_FLOW_ERROR;
error_activate_pool:
GST_ERROR("failed to activate buffer pool");
return GST_FLOW_ERROR;
error_create_buffer:
GST_WARNING("failed to create image. Skipping this frame");
return GST_FLOW_OK;
error_map_dst_buffer:
gst_video_frame_unmap(&src_frame);
// fall-through
error_map_src_buffer:
GST_WARNING("failed to map buffer. Skipping this frame");
gst_buffer_unref(out_buffer);
return GST_FLOW_OK;
}
#else
static GstFlowReturn
gst_vaapisink_get_render_buffer(GstVaapiSink *sink, GstBuffer *src_buffer,
GstBuffer **out_buffer_ptr)
{
GstVaapiVideoMeta *meta;
GstBuffer *out_buffer;
*out_buffer_ptr = NULL;
meta = gst_buffer_get_vaapi_video_meta(src_buffer);
if (meta)
out_buffer = gst_buffer_ref(src_buffer);
else if (sink->use_video_raw) {
out_buffer = gst_vaapi_uploader_get_buffer(sink->uploader);
if (!out_buffer)
goto error_create_buffer;
}
else {
GST_ERROR("unsupported video buffer");
return GST_FLOW_EOS;
}
if (sink->use_video_raw &&
!gst_vaapi_uploader_process(sink->uploader, src_buffer, out_buffer))
goto error_copy_buffer;
*out_buffer_ptr = out_buffer;
return GST_FLOW_OK;
/* ERRORS */
error_create_buffer:
GST_WARNING("failed to create buffer. Skipping this frame");
return GST_FLOW_OK;
error_copy_buffer:
GST_WARNING("failed to copy buffers. Skipping this frame");
gst_buffer_unref(out_buffer);
return GST_FLOW_OK;
}
#endif
static GstFlowReturn static GstFlowReturn
gst_vaapisink_show_frame(GstBaseSink *base_sink, GstBuffer *src_buffer) gst_vaapisink_show_frame(GstBaseSink *base_sink, GstBuffer *src_buffer)
{ {
@ -1166,8 +966,9 @@ gst_vaapisink_show_frame(GstBaseSink *base_sink, GstBuffer *src_buffer)
} }
#endif #endif
ret = gst_vaapisink_get_render_buffer(sink, src_buffer, &buffer); ret = gst_vaapi_plugin_base_get_input_buffer(GST_VAAPI_PLUGIN_BASE(sink),
if (ret != GST_FLOW_OK || !buffer) src_buffer, &buffer);
if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_SUPPORTED)
return ret; return ret;
meta = gst_buffer_get_vaapi_video_meta(buffer); meta = gst_buffer_get_vaapi_video_meta(buffer);
@ -1249,78 +1050,23 @@ error:
static gboolean static gboolean
gst_vaapisink_propose_allocation(GstBaseSink *base_sink, GstQuery *query) gst_vaapisink_propose_allocation(GstBaseSink *base_sink, GstQuery *query)
{ {
GstVaapiSink * const sink = GST_VAAPISINK(base_sink); GstVaapiPluginBase * const plugin = GST_VAAPI_PLUGIN_BASE(base_sink);
GstCaps *caps = NULL;
gboolean need_pool;
gst_query_parse_allocation(query, &caps, &need_pool); if (!gst_vaapi_plugin_base_propose_allocation(plugin, query))
return FALSE;
if (need_pool) { gst_query_add_allocation_meta(query, GST_VIDEO_CROP_META_API_TYPE, NULL);
if (!caps)
goto error_no_caps;
if (!gst_vaapisink_ensure_video_buffer_pool(sink, caps))
return FALSE;
gst_query_add_allocation_pool(query, sink->video_buffer_pool,
sink->video_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);
gst_query_add_allocation_meta(query,
GST_VIDEO_CROP_META_API_TYPE, NULL);
gst_query_add_allocation_meta(query, gst_query_add_allocation_meta(query,
GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL); GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL);
return TRUE; return TRUE;
/* ERRORS */
error_no_caps:
{
GST_ERROR("no caps specified");
return FALSE;
}
} }
#else #else
static GstFlowReturn static GstFlowReturn
gst_vaapisink_buffer_alloc( gst_vaapisink_buffer_alloc(GstBaseSink *base_sink, guint64 offset, guint size,
GstBaseSink *base_sink, GstCaps *caps, GstBuffer **outbuf_ptr)
guint64 offset,
guint size,
GstCaps *caps,
GstBuffer **pbuf
)
{ {
GstVaapiSink * const sink = GST_VAAPISINK(base_sink); return gst_vaapi_plugin_base_allocate_input_buffer(
GstVideoInfo vi; GST_VAAPI_PLUGIN_BASE(base_sink), caps, outbuf_ptr);
GstBuffer *buf;
*pbuf = NULL;
if (!sink->use_video_raw) {
/* Note: this code path is rarely used but for raw YUV formats
from custom pipeline. Otherwise, GstBaseSink::set_caps() is
called first, and GstBaseSink::buffer_alloc() is not called
in VA surface format mode */
if (!gst_video_info_from_caps(&vi, caps))
return GST_FLOW_NOT_SUPPORTED;
if (!GST_VIDEO_INFO_IS_YUV(&vi))
return GST_FLOW_OK;
}
if (!gst_vaapi_uploader_ensure_display(sink->uploader, GST_VAAPI_PLUGIN_BASE_DISPLAY(sink)))
return GST_FLOW_NOT_SUPPORTED;
if (!gst_vaapi_uploader_ensure_caps(sink->uploader, caps, NULL))
return GST_FLOW_NOT_SUPPORTED;
buf = gst_vaapi_uploader_get_buffer(sink->uploader);
if (!buf) {
GST_WARNING("failed to allocate resources for raw YUV buffer");
return GST_FLOW_NOT_SUPPORTED;
}
*pbuf = buf;
return GST_FLOW_OK;
} }
#endif #endif

View file

@ -31,7 +31,6 @@
#include <gst/vaapi/gstvaapitexture.h> #include <gst/vaapi/gstvaapitexture.h>
#endif #endif
#include "gstvaapipluginutil.h" #include "gstvaapipluginutil.h"
#include "gstvaapiuploader.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -69,7 +68,6 @@ struct _GstVaapiSink {
/*< private >*/ /*< private >*/
GstVaapiPluginBase parent_instance; GstVaapiPluginBase parent_instance;
GstVaapiUploader *uploader;
GstCaps *caps; GstCaps *caps;
GstVaapiWindow *window; GstVaapiWindow *window;
guint window_width; guint window_width;
@ -96,7 +94,6 @@ struct _GstVaapiSink {
guint use_overlay : 1; guint use_overlay : 1;
guint use_rotation : 1; guint use_rotation : 1;
guint keep_aspect : 1; guint keep_aspect : 1;
guint use_video_raw : 1;
}; };
struct _GstVaapiSinkClass { struct _GstVaapiSinkClass {