mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 13:41:48 +00:00
plugins: implement uploads from raw YUV buffers for GStreamer 1.0.
Implement GstVideoMeta::{,un}map() to support raw YUV buffer upload when the last component is unmapped. Downloads are not supported yet. The aim was to first support SW decoding + HW accelerated rendering (vaapisink). e.g. for Wayland.
This commit is contained in:
parent
1ed3df201e
commit
c698a015a3
3 changed files with 241 additions and 4 deletions
|
@ -185,10 +185,16 @@ gst_vaapi_video_buffer_pool_alloc_buffer(GstBufferPool *pool,
|
||||||
|
|
||||||
if (priv->has_video_meta) {
|
if (priv->has_video_meta) {
|
||||||
GstVideoInfo * const vip =
|
GstVideoInfo * const vip =
|
||||||
&GST_VAAPI_VIDEO_ALLOCATOR_CAST(priv->allocator)->video_info;
|
&GST_VAAPI_VIDEO_ALLOCATOR_CAST(priv->allocator)->image_info;
|
||||||
|
GstVideoMeta *vmeta;
|
||||||
|
|
||||||
gst_buffer_add_video_meta(buffer, 0, GST_VIDEO_INFO_FORMAT(vip),
|
vmeta = gst_buffer_add_video_meta_full(buffer, 0,
|
||||||
GST_VIDEO_INFO_WIDTH(vip), GST_VIDEO_INFO_HEIGHT(vip));
|
GST_VIDEO_INFO_FORMAT(vip), GST_VIDEO_INFO_WIDTH(vip),
|
||||||
|
GST_VIDEO_INFO_HEIGHT(vip), GST_VIDEO_INFO_N_PLANES(vip),
|
||||||
|
&GST_VIDEO_INFO_PLANE_OFFSET(vip, 0),
|
||||||
|
&GST_VIDEO_INFO_PLANE_STRIDE(vip, 0));
|
||||||
|
vmeta->map = gst_video_meta_map_vaapi_memory;
|
||||||
|
vmeta->unmap = gst_video_meta_unmap_vaapi_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_buffer_ptr = buffer;
|
*out_buffer_ptr = buffer;
|
||||||
|
|
|
@ -25,10 +25,160 @@
|
||||||
GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapivideomemory);
|
GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapivideomemory);
|
||||||
#define GST_CAT_DEFAULT gst_debug_vaapivideomemory
|
#define GST_CAT_DEFAULT gst_debug_vaapivideomemory
|
||||||
|
|
||||||
|
#ifndef GST_VIDEO_INFO_FORMAT_STRING
|
||||||
|
#define GST_VIDEO_INFO_FORMAT_STRING(vip) \
|
||||||
|
gst_video_format_to_string(GST_VIDEO_INFO_FORMAT(vip))
|
||||||
|
#endif
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------------ */
|
||||||
/* --- GstVaapiVideoMemory --- */
|
/* --- GstVaapiVideoMemory --- */
|
||||||
/* ------------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
static GstVaapiImage *
|
||||||
|
new_image(GstVaapiDisplay *display, const GstVideoInfo *vip)
|
||||||
|
{
|
||||||
|
GstVaapiImageFormat format;
|
||||||
|
|
||||||
|
format = gst_vaapi_image_format_from_video(GST_VIDEO_INFO_FORMAT(vip));
|
||||||
|
if (!format)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return gst_vaapi_image_new(display, format,
|
||||||
|
GST_VIDEO_INFO_WIDTH(vip), GST_VIDEO_INFO_HEIGHT(vip));
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
ensure_image(GstVaapiVideoMemory *mem)
|
||||||
|
{
|
||||||
|
if (!mem->image) {
|
||||||
|
GstVaapiDisplay * const display =
|
||||||
|
gst_vaapi_video_meta_get_display(mem->meta);
|
||||||
|
|
||||||
|
mem->image = new_image(display, mem->image_info);
|
||||||
|
if (!mem->image)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
gst_vaapi_video_meta_set_image(mem->meta, mem->image);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstVaapiSurface *
|
||||||
|
new_surface(GstVaapiDisplay *display, const GstVideoInfo *vip)
|
||||||
|
{
|
||||||
|
if (GST_VIDEO_INFO_FORMAT(vip) != GST_VIDEO_FORMAT_NV12)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return gst_vaapi_surface_new(display, GST_VAAPI_CHROMA_TYPE_YUV420,
|
||||||
|
GST_VIDEO_INFO_WIDTH(vip), GST_VIDEO_INFO_HEIGHT(vip));
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
ensure_surface(GstVaapiVideoMemory *mem)
|
||||||
|
{
|
||||||
|
if (!mem->surface) {
|
||||||
|
GstVaapiDisplay * const display =
|
||||||
|
gst_vaapi_video_meta_get_display(mem->meta);
|
||||||
|
|
||||||
|
mem->surface = new_surface(display, mem->surface_info);
|
||||||
|
if (!mem->surface)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
gst_vaapi_video_meta_set_surface(mem->meta, mem->surface);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_video_meta_map_vaapi_memory(GstVideoMeta *meta, guint plane,
|
||||||
|
GstMapInfo *info, gpointer *data, gint *stride, GstMapFlags flags)
|
||||||
|
{
|
||||||
|
GstVaapiVideoMemory * const mem =
|
||||||
|
GST_VAAPI_VIDEO_MEMORY_CAST(gst_buffer_get_memory(meta->buffer, 0));
|
||||||
|
|
||||||
|
g_return_val_if_fail(mem, FALSE);
|
||||||
|
g_return_val_if_fail(GST_VAAPI_IS_VIDEO_ALLOCATOR(mem->parent_instance.
|
||||||
|
allocator), FALSE);
|
||||||
|
g_return_val_if_fail(mem->meta, FALSE);
|
||||||
|
|
||||||
|
if ((flags & GST_MAP_READWRITE) == GST_MAP_READ)
|
||||||
|
goto error_unsupported_map;
|
||||||
|
|
||||||
|
if (++mem->map_count == 1) {
|
||||||
|
if (!ensure_surface(mem))
|
||||||
|
goto error_ensure_surface;
|
||||||
|
if (!ensure_image(mem))
|
||||||
|
goto error_ensure_image;
|
||||||
|
if (!gst_vaapi_image_map(mem->image))
|
||||||
|
goto error_map_image;
|
||||||
|
}
|
||||||
|
|
||||||
|
*data = gst_vaapi_image_get_plane(mem->image, plane);
|
||||||
|
*stride = gst_vaapi_image_get_pitch(mem->image, plane);
|
||||||
|
info->flags = flags;
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
error_unsupported_map:
|
||||||
|
{
|
||||||
|
GST_ERROR("unsupported map flags (0x%x)", flags);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
error_ensure_surface:
|
||||||
|
{
|
||||||
|
const GstVideoInfo * const vip = mem->surface_info;
|
||||||
|
GST_ERROR("failed to create %s surface of size %ux%u",
|
||||||
|
GST_VIDEO_INFO_FORMAT_STRING(vip),
|
||||||
|
GST_VIDEO_INFO_WIDTH(vip), GST_VIDEO_INFO_HEIGHT(vip));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
error_ensure_image:
|
||||||
|
{
|
||||||
|
const GstVideoInfo * const vip = mem->image_info;
|
||||||
|
GST_ERROR("failed to create %s image of size %ux%u",
|
||||||
|
GST_VIDEO_INFO_FORMAT_STRING(vip),
|
||||||
|
GST_VIDEO_INFO_WIDTH(vip), GST_VIDEO_INFO_HEIGHT(vip));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
error_map_image:
|
||||||
|
{
|
||||||
|
GST_ERROR("failed to map image %" GST_VAAPI_ID_FORMAT,
|
||||||
|
GST_VAAPI_ID_ARGS(gst_vaapi_image_get_id(mem->image)));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_video_meta_unmap_vaapi_memory(GstVideoMeta *meta, guint plane,
|
||||||
|
GstMapInfo *info)
|
||||||
|
{
|
||||||
|
GstVaapiVideoMemory * const mem =
|
||||||
|
GST_VAAPI_VIDEO_MEMORY_CAST(gst_buffer_get_memory(meta->buffer, 0));
|
||||||
|
|
||||||
|
g_return_val_if_fail(mem, FALSE);
|
||||||
|
g_return_val_if_fail(GST_VAAPI_IS_VIDEO_ALLOCATOR(mem->parent_instance.
|
||||||
|
allocator), FALSE);
|
||||||
|
g_return_val_if_fail(mem->meta, FALSE);
|
||||||
|
g_return_val_if_fail(mem->surface, FALSE);
|
||||||
|
g_return_val_if_fail(mem->image, FALSE);
|
||||||
|
|
||||||
|
if (--mem->map_count == 0) {
|
||||||
|
gst_vaapi_image_unmap(mem->image);
|
||||||
|
|
||||||
|
/* Commit VA image to surface */
|
||||||
|
if (info->flags & GST_MAP_WRITE) {
|
||||||
|
if (!gst_vaapi_surface_put_image(mem->surface, mem->image))
|
||||||
|
goto error_upload_image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
error_upload_image:
|
||||||
|
{
|
||||||
|
GST_ERROR("failed to upload image");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GstMemory *
|
GstMemory *
|
||||||
gst_vaapi_video_memory_new(GstAllocator *base_allocator,
|
gst_vaapi_video_memory_new(GstAllocator *base_allocator,
|
||||||
GstVaapiVideoMeta *meta)
|
GstVaapiVideoMeta *meta)
|
||||||
|
@ -42,17 +192,24 @@ gst_vaapi_video_memory_new(GstAllocator *base_allocator,
|
||||||
if (!mem)
|
if (!mem)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
vip = &allocator->video_info;
|
vip = &allocator->image_info;
|
||||||
gst_memory_init(&mem->parent_instance, 0, base_allocator, NULL,
|
gst_memory_init(&mem->parent_instance, 0, base_allocator, NULL,
|
||||||
GST_VIDEO_INFO_SIZE(vip), 0, 0, GST_VIDEO_INFO_SIZE(vip));
|
GST_VIDEO_INFO_SIZE(vip), 0, 0, GST_VIDEO_INFO_SIZE(vip));
|
||||||
|
|
||||||
|
mem->surface_info = &allocator->surface_info;
|
||||||
|
mem->surface = NULL;
|
||||||
|
mem->image_info = &allocator->image_info;
|
||||||
|
mem->image = NULL;
|
||||||
mem->meta = gst_vaapi_video_meta_ref(meta);
|
mem->meta = gst_vaapi_video_meta_ref(meta);
|
||||||
|
mem->map_count = 0;
|
||||||
return GST_MEMORY_CAST(mem);
|
return GST_MEMORY_CAST(mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_vaapi_video_memory_free(GstVaapiVideoMemory *mem)
|
gst_vaapi_video_memory_free(GstVaapiVideoMemory *mem)
|
||||||
{
|
{
|
||||||
|
g_clear_object(&mem->surface);
|
||||||
|
g_clear_object(&mem->image);
|
||||||
gst_vaapi_video_meta_unref(mem->meta);
|
gst_vaapi_video_meta_unref(mem->meta);
|
||||||
g_slice_free(GstVaapiVideoMemory, mem);
|
g_slice_free(GstVaapiVideoMemory, mem);
|
||||||
}
|
}
|
||||||
|
@ -156,11 +313,48 @@ gst_vaapi_video_allocator_init(GstVaapiVideoAllocator *allocator)
|
||||||
gst_vaapi_video_memory_is_span;
|
gst_vaapi_video_memory_is_span;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_video_info_update_from_image(GstVideoInfo *vip, GstVaapiImage *image)
|
||||||
|
{
|
||||||
|
const guchar *data;
|
||||||
|
guint i, num_planes, data_size;
|
||||||
|
|
||||||
|
num_planes = gst_vaapi_image_get_plane_count(image);
|
||||||
|
g_return_val_if_fail(num_planes == GST_VIDEO_INFO_N_PLANES(vip), FALSE);
|
||||||
|
|
||||||
|
/* Determine the base data pointer */
|
||||||
|
data = gst_vaapi_image_get_plane(image, 0);
|
||||||
|
for (i = 1; i < num_planes; i++) {
|
||||||
|
const guchar * const plane = gst_vaapi_image_get_plane(image, i);
|
||||||
|
if (data > plane)
|
||||||
|
data = plane;
|
||||||
|
}
|
||||||
|
data_size = gst_vaapi_image_get_data_size(image);
|
||||||
|
|
||||||
|
/* Check that we don't have disjoint planes */
|
||||||
|
for (i = 0; i < num_planes; i++) {
|
||||||
|
const guchar * const plane = gst_vaapi_image_get_plane(image, i);
|
||||||
|
if (plane - data > data_size)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update GstVideoInfo structure */
|
||||||
|
for (i = 0; i < num_planes; i++) {
|
||||||
|
const guchar * const plane = gst_vaapi_image_get_plane(image, i);
|
||||||
|
GST_VIDEO_INFO_PLANE_OFFSET(vip, i) = plane - data;
|
||||||
|
GST_VIDEO_INFO_PLANE_STRIDE(vip, i) =
|
||||||
|
gst_vaapi_image_get_pitch(image, i);
|
||||||
|
}
|
||||||
|
GST_VIDEO_INFO_SIZE(vip) = data_size;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
GstAllocator *
|
GstAllocator *
|
||||||
gst_vaapi_video_allocator_new(GstVaapiDisplay *display, GstCaps *caps)
|
gst_vaapi_video_allocator_new(GstVaapiDisplay *display, GstCaps *caps)
|
||||||
{
|
{
|
||||||
GstVaapiVideoAllocator *allocator;
|
GstVaapiVideoAllocator *allocator;
|
||||||
GstVideoInfo *vip;
|
GstVideoInfo *vip;
|
||||||
|
GstVaapiImage *image;
|
||||||
|
|
||||||
g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
|
g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
|
||||||
g_return_val_if_fail(GST_IS_CAPS(caps), NULL);
|
g_return_val_if_fail(GST_IS_CAPS(caps), NULL);
|
||||||
|
@ -173,5 +367,25 @@ gst_vaapi_video_allocator_new(GstVaapiDisplay *display, GstCaps *caps)
|
||||||
gst_video_info_init(vip);
|
gst_video_info_init(vip);
|
||||||
gst_video_info_from_caps(vip, caps);
|
gst_video_info_from_caps(vip, caps);
|
||||||
|
|
||||||
|
gst_video_info_set_format(&allocator->surface_info, GST_VIDEO_FORMAT_NV12,
|
||||||
|
GST_VIDEO_INFO_WIDTH(vip), GST_VIDEO_INFO_HEIGHT(vip));
|
||||||
|
|
||||||
|
allocator->image_info = *vip;
|
||||||
|
if (GST_VIDEO_INFO_FORMAT(vip) == GST_VIDEO_FORMAT_ENCODED)
|
||||||
|
gst_video_info_set_format(&allocator->image_info, GST_VIDEO_FORMAT_NV12,
|
||||||
|
GST_VIDEO_INFO_WIDTH(vip), GST_VIDEO_INFO_HEIGHT(vip));
|
||||||
|
|
||||||
|
if (1) {
|
||||||
|
do {
|
||||||
|
image = new_image(display, &allocator->image_info);
|
||||||
|
if (!image)
|
||||||
|
break;
|
||||||
|
if (!gst_vaapi_image_map(image))
|
||||||
|
break;
|
||||||
|
gst_video_info_update_from_image(&allocator->image_info, image);
|
||||||
|
gst_vaapi_image_unmap(image);
|
||||||
|
} while (0);
|
||||||
|
g_clear_object(&image);
|
||||||
|
}
|
||||||
return GST_ALLOCATOR_CAST(allocator);
|
return GST_ALLOCATOR_CAST(allocator);
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,13 +52,28 @@ struct _GstVaapiVideoMemory {
|
||||||
GstMemory parent_instance;
|
GstMemory parent_instance;
|
||||||
|
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
|
const GstVideoInfo *surface_info;
|
||||||
|
GstVaapiSurface *surface;
|
||||||
|
const GstVideoInfo *image_info;
|
||||||
|
GstVaapiImage *image;
|
||||||
GstVaapiVideoMeta *meta;
|
GstVaapiVideoMeta *meta;
|
||||||
|
gint map_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
GstMemory *
|
GstMemory *
|
||||||
gst_vaapi_video_memory_new(GstAllocator *allocator, GstVaapiVideoMeta *meta);
|
gst_vaapi_video_memory_new(GstAllocator *allocator, GstVaapiVideoMeta *meta);
|
||||||
|
|
||||||
|
G_GNUC_INTERNAL
|
||||||
|
gboolean
|
||||||
|
gst_video_meta_map_vaapi_memory(GstVideoMeta *meta, guint plane,
|
||||||
|
GstMapInfo *info, gpointer *data, gint *stride, GstMapFlags flags);
|
||||||
|
|
||||||
|
G_GNUC_INTERNAL
|
||||||
|
gboolean
|
||||||
|
gst_video_meta_unmap_vaapi_memory(GstVideoMeta *meta, guint plane,
|
||||||
|
GstMapInfo *info);
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------------ */
|
||||||
/* --- GstVaapiVideoAllocator --- */
|
/* --- GstVaapiVideoAllocator --- */
|
||||||
/* ------------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------------ */
|
||||||
|
@ -89,6 +104,8 @@ struct _GstVaapiVideoAllocator {
|
||||||
|
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
GstVideoInfo video_info;
|
GstVideoInfo video_info;
|
||||||
|
GstVideoInfo surface_info;
|
||||||
|
GstVideoInfo image_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue