* gstvaapivideomemory.c - Gstreamer/VA video memory
*
* Copyright (C) 2013 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
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,
+ return gst_vaapi_image_new(display, GST_VIDEO_INFO_FORMAT(vip),
GST_VIDEO_INFO_WIDTH(vip), GST_VIDEO_INFO_HEIGHT(vip));
}
GST_WARNING("failed to derive image, fallbacking to copy");
mem->use_direct_rendering = FALSE;
}
+ else if (gst_vaapi_surface_get_format(mem->surface) !=
+ GST_VIDEO_INFO_FORMAT(mem->image_info)) {
+ gst_vaapi_object_replace(&mem->image, NULL);
+ mem->use_direct_rendering = FALSE;
+ }
}
if (!mem->image) {
static GstVaapiSurface *
new_surface(GstVaapiDisplay *display, const GstVideoInfo *vip)
{
- if (GST_VIDEO_INFO_FORMAT(vip) != GST_VIDEO_FORMAT_NV12)
- return NULL;
+ GstVaapiSurface *surface;
+ GstVaapiChromaType chroma_type;
+
+ /* Try with explicit format first */
+ if (GST_VIDEO_INFO_FORMAT(vip) != GST_VIDEO_FORMAT_ENCODED) {
+ surface = gst_vaapi_surface_new_with_format(display,
+ GST_VIDEO_INFO_FORMAT(vip), GST_VIDEO_INFO_WIDTH(vip),
+ GST_VIDEO_INFO_HEIGHT(vip));
+ if (surface)
+ return surface;
+ }
- return gst_vaapi_surface_new(display, GST_VAAPI_CHROMA_TYPE_YUV420,
+ /* Try to pick something compatible, i.e. with same chroma type */
+ chroma_type = gst_vaapi_video_format_get_chroma_type(
+ GST_VIDEO_INFO_FORMAT(vip));
+ if (!chroma_type)
+ return NULL;
+ return gst_vaapi_surface_new(display, chroma_type,
GST_VIDEO_INFO_WIDTH(vip), GST_VIDEO_INFO_HEIGHT(vip));
}
+static GstVaapiSurfaceProxy *
+new_surface_proxy(GstVaapiVideoMemory *mem)
+{
+ GstVaapiVideoAllocator * const allocator =
+ GST_VAAPI_VIDEO_ALLOCATOR_CAST(GST_MEMORY_CAST(mem)->allocator);
+
+ return gst_vaapi_surface_proxy_new_from_pool(
+ GST_VAAPI_SURFACE_POOL(allocator->surface_pool));
+}
+
static gboolean
ensure_surface(GstVaapiVideoMemory *mem)
{
- if (!mem->surface) {
- GstVaapiDisplay * const display =
- gst_vaapi_video_meta_get_display(mem->meta);
+ if (!mem->proxy) {
+ gst_vaapi_surface_proxy_replace(&mem->proxy,
+ gst_vaapi_video_meta_get_surface_proxy(mem->meta));
- mem->surface = new_surface(display, mem->surface_info);
- if (!mem->surface)
- return FALSE;
+ if (!mem->proxy) {
+ mem->proxy = new_surface_proxy(mem);
+ if (!mem->proxy)
+ return FALSE;
+ gst_vaapi_video_meta_set_surface_proxy(mem->meta, mem->proxy);
+ }
+ mem->surface = GST_VAAPI_SURFACE_PROXY_SURFACE(mem->proxy);
}
- gst_vaapi_video_meta_set_surface(mem->meta, mem->surface);
+ g_return_val_if_fail(mem->surface != NULL, FALSE);
return TRUE;
}
GstMapInfo *info, gpointer *data, gint *stride, GstMapFlags flags)
{
GstVaapiVideoMemory * const mem =
- GST_VAAPI_VIDEO_MEMORY_CAST(gst_buffer_get_memory(meta->buffer, 0));
+ GST_VAAPI_VIDEO_MEMORY_CAST(gst_buffer_peek_memory(meta->buffer, 0));
g_return_val_if_fail(mem, FALSE);
g_return_val_if_fail(GST_VAAPI_IS_VIDEO_ALLOCATOR(mem->parent_instance.
if (mem->map_type &&
mem->map_type != GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_PLANAR)
goto error_incompatible_map;
- if ((flags & GST_MAP_READWRITE) != GST_MAP_WRITE)
- goto error_unsupported_map;
/* Map for writing */
if (++mem->map_count == 1) {
goto error_ensure_surface;
if (!ensure_image(mem))
goto error_ensure_image;
+
+ // Check that we can actually map the surface, or image
+ if ((flags & GST_MAP_READWRITE) == GST_MAP_WRITE &&
+ !mem->use_direct_rendering)
+ goto error_unsupported_map;
+
+ // Load VA image from surface
+ if ((flags & GST_MAP_READ) && !mem->use_direct_rendering)
+ gst_vaapi_surface_get_image(mem->surface, mem->image);
+
if (!gst_vaapi_image_map(mem->image))
goto error_map_image;
mem->map_type = GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_PLANAR;
GstMapInfo *info)
{
GstVaapiVideoMemory * const mem =
- GST_VAAPI_VIDEO_MEMORY_CAST(gst_buffer_get_memory(meta->buffer, 0));
+ GST_VAAPI_VIDEO_MEMORY_CAST(gst_buffer_peek_memory(meta->buffer, 0));
g_return_val_if_fail(mem, FALSE);
g_return_val_if_fail(GST_VAAPI_IS_VIDEO_ALLOCATOR(mem->parent_instance.
return NULL;
vip = &allocator->image_info;
- gst_memory_init(&mem->parent_instance, 0, base_allocator, NULL,
+ gst_memory_init(&mem->parent_instance, 0, gst_object_ref(allocator), NULL,
GST_VIDEO_INFO_SIZE(vip), 0, 0, GST_VIDEO_INFO_SIZE(vip));
mem->proxy = NULL;
static void
gst_vaapi_video_memory_free(GstVaapiVideoMemory *mem)
{
- gst_vaapi_object_replace(&mem->surface, NULL);
+ mem->surface = NULL;
+ gst_vaapi_surface_proxy_replace(&mem->proxy, NULL);
gst_vaapi_object_replace(&mem->image, NULL);
gst_vaapi_video_meta_unref(mem->meta);
+ gst_object_unref(GST_MEMORY_CAST(mem)->allocator);
g_slice_free(GstVaapiVideoMemory, mem);
}
+void
+gst_vaapi_video_memory_reset_surface(GstVaapiVideoMemory *mem)
+{
+ mem->surface = NULL;
+ gst_vaapi_surface_proxy_replace(&mem->proxy, NULL);
+ if (mem->use_direct_rendering)
+ gst_vaapi_object_replace(&mem->image, NULL);
+ gst_vaapi_video_meta_set_surface_proxy(mem->meta, NULL);
+}
+
static gpointer
gst_vaapi_video_memory_map(GstVaapiVideoMemory *mem, gsize maxsize, guint flags)
{
}
static void
+gst_vaapi_video_allocator_finalize(GObject *object)
+{
+ GstVaapiVideoAllocator * const allocator =
+ GST_VAAPI_VIDEO_ALLOCATOR_CAST(object);
+
+ gst_vaapi_video_pool_replace(&allocator->surface_pool, NULL);
+
+ G_OBJECT_CLASS(gst_vaapi_video_allocator_parent_class)->finalize(object);
+}
+
+static void
gst_vaapi_video_allocator_class_init(GstVaapiVideoAllocatorClass *klass)
{
+ GObjectClass * const object_class = G_OBJECT_CLASS(klass);
GstAllocatorClass * const allocator_class = GST_ALLOCATOR_CLASS(klass);
GST_DEBUG_CATEGORY_INIT(gst_debug_vaapivideomemory,
"vaapivideomemory", 0, "VA-API video memory allocator");
+ object_class->finalize = gst_vaapi_video_allocator_finalize;
allocator_class->alloc = gst_vaapi_video_allocator_alloc;
allocator_class->free = gst_vaapi_video_allocator_free;
}
static gboolean
gst_video_info_update_from_image(GstVideoInfo *vip, GstVaapiImage *image)
{
+ GstVideoFormat format;
const guchar *data;
- guint i, num_planes, data_size;
+ guint i, num_planes, data_size, width, height;
+
+ /* Reset format from image */
+ format = gst_vaapi_image_get_format(image);
+ gst_vaapi_image_get_size(image, &width, &height);
+ gst_video_info_set_format(vip, format, width, height);
num_planes = gst_vaapi_image_get_plane_count(image);
g_return_val_if_fail(num_planes == GST_VIDEO_INFO_N_PLANES(vip), FALSE);
}
GstAllocator *
-gst_vaapi_video_allocator_new(GstVaapiDisplay *display, GstCaps *caps)
+gst_vaapi_video_allocator_new(GstVaapiDisplay *display, const GstVideoInfo *vip)
{
GstVaapiVideoAllocator *allocator;
- GstVideoInfo *vip;
GstVaapiSurface *surface;
GstVaapiImage *image;
g_return_val_if_fail(display != NULL, NULL);
- g_return_val_if_fail(GST_IS_CAPS(caps), NULL);
+ g_return_val_if_fail(vip != NULL, NULL);
allocator = g_object_new(GST_VAAPI_TYPE_VIDEO_ALLOCATOR, NULL);
if (!allocator)
return NULL;
- vip = &allocator->video_info;
- gst_video_info_init(vip);
- gst_video_info_from_caps(vip, caps);
-
+ allocator->video_info = *vip;
gst_video_info_set_format(&allocator->surface_info, GST_VIDEO_FORMAT_NV12,
GST_VIDEO_INFO_WIDTH(vip), GST_VIDEO_INFO_HEIGHT(vip));
image = gst_vaapi_surface_derive_image(surface);
if (!image)
break;
+ if (GST_VAAPI_IMAGE_FORMAT(image) != GST_VIDEO_INFO_FORMAT(vip))
+ break;
if (!gst_vaapi_image_map(image))
break;
allocator->has_direct_rendering = gst_video_info_update_from_image(
gst_vaapi_object_unref(image);
}
+ allocator->surface_pool = gst_vaapi_surface_pool_new(display,
+ &allocator->surface_info);
+ if (!allocator->surface_pool)
+ goto error_create_pool;
+
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_vaapi_object_unref(image);
}
return GST_ALLOCATOR_CAST(allocator);
+
+ /* ERRORS */
+error_create_pool:
+ {
+ GST_ERROR("failed to allocate VA surface pool");
+ gst_object_unref(allocator);
+ return NULL;
+ }
}