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:
Gwenole Beauchesne 2013-04-09 16:02:06 +02:00
parent 1ed3df201e
commit c698a015a3
3 changed files with 241 additions and 4 deletions

View file

@ -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;

View file

@ -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);
} }

View file

@ -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;
}; };
/** /**