gstreamer/sys/msdk/gstmsdksystemmemory.c
Seungha Yang d4112d3d7b msdk: Allow video and system memory share among buffers
gst_buffer_make_writable() requires exclusive reference to the
GstMemory so the _make_writable() for the msdk buffer will result
to fallback system memory copy, because the msdk memory were initialized
with GST_MEMORY_FLAG_NO_SHARE flag.

Note that, disable sharing GstMemory brings high overhead but actually
the msdk memory objects can be shared over multiple buffers.
If the memory is not shareable, newly added GstAllocator::mem_copy will
create copied msdk memory.
2019-09-10 13:29:11 +00:00

327 lines
10 KiB
C

/* GStreamer Intel MSDK plugin
* Copyright (c) 2018, Intel Corporation
* Copyright (c) 2018, Igalia S.L.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGDECE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _WIN32
#include <unistd.h>
#endif
#include <stdlib.h>
#include "gstmsdksystemmemory.h"
#include <string.h>
#ifdef _WIN32
#define posix_memalign(d, a, s) ((*((void**)d) = _aligned_malloc(s, a)) ? 0 : -1)
#endif
#ifndef _WIN32
#define _aligned_free free
#endif
static gboolean
ensure_data (GstMsdkSystemMemory * mem)
{
gsize size;
void *data;
GstVideoInfo *info;
GstAllocator *allocator;
GstMsdkSystemAllocator *msdk_allocator;
allocator = GST_MEMORY_CAST (mem)->allocator;
msdk_allocator = GST_MSDK_SYSTEM_ALLOCATOR_CAST (allocator);
info = &msdk_allocator->image_info;
size = GST_VIDEO_INFO_SIZE (info);
if (mem->cache)
return TRUE;
if (posix_memalign (&data, 32, size) != 0) {
GST_ERROR ("Memory allocation failed");
return FALSE;
}
mem->cache = data;
mem->cached_data[0] = mem->cache;
mem->cached_data[1] = mem->cache + GST_VIDEO_INFO_PLANE_OFFSET (info, 1);
mem->cached_data[2] = mem->cache + GST_VIDEO_INFO_PLANE_OFFSET (info, 2);
mem->destination_pitches[0] = GST_VIDEO_INFO_PLANE_STRIDE (info, 0);
mem->destination_pitches[1] = GST_VIDEO_INFO_PLANE_STRIDE (info, 1);
mem->destination_pitches[2] = GST_VIDEO_INFO_PLANE_STRIDE (info, 2);
switch (GST_VIDEO_INFO_FORMAT (info)) {
case GST_VIDEO_FORMAT_NV12:
case GST_VIDEO_FORMAT_P010_10LE:
mem->surface->Data.Y = mem->cached_data[0];
mem->surface->Data.UV = mem->cached_data[1];
mem->surface->Data.Pitch = mem->destination_pitches[0];
break;
case GST_VIDEO_FORMAT_YV12:
mem->surface->Data.Y = mem->cached_data[0];
mem->surface->Data.U = mem->cached_data[2];
mem->surface->Data.V = mem->cached_data[1];
mem->surface->Data.Pitch = mem->destination_pitches[0];
break;
case GST_VIDEO_FORMAT_I420:
mem->surface->Data.Y = mem->cached_data[0];
mem->surface->Data.U = mem->cached_data[1];
mem->surface->Data.V = mem->cached_data[2];
mem->surface->Data.Pitch = mem->destination_pitches[0];
break;
case GST_VIDEO_FORMAT_YUY2:
mem->surface->Data.Y = mem->cached_data[0];
mem->surface->Data.U = mem->surface->Data.Y + 1;
mem->surface->Data.V = mem->surface->Data.Y + 3;
mem->surface->Data.Pitch = mem->destination_pitches[0];
break;
case GST_VIDEO_FORMAT_UYVY:
mem->surface->Data.Y = mem->cached_data[0];
mem->surface->Data.U = mem->surface->Data.Y;
mem->surface->Data.V = mem->surface->Data.U + 2;
mem->surface->Data.Pitch = mem->destination_pitches[0];
break;
case GST_VIDEO_FORMAT_BGRA:
mem->surface->Data.R = mem->cached_data[0];
mem->surface->Data.G = mem->surface->Data.R + 1;
mem->surface->Data.B = mem->surface->Data.R + 2;
mem->surface->Data.Pitch = mem->destination_pitches[0];
break;
#if (MFX_VERSION >= 1028)
case GST_VIDEO_FORMAT_RGB16:
mem->surface->Data.R = mem->cached_data[0];
mem->surface->Data.G = mem->surface->Data.R;
mem->surface->Data.B = mem->surface->Data.R;
mem->surface->Data.Pitch = mem->destination_pitches[0];
break;
#endif
case GST_VIDEO_FORMAT_VUYA:
mem->surface->Data.V = mem->cached_data[0];
mem->surface->Data.U = mem->surface->Data.V + 1;
mem->surface->Data.Y = mem->surface->Data.V + 2;
mem->surface->Data.A = mem->surface->Data.V + 3;
mem->surface->Data.PitchHigh =
(mfxU16) (mem->destination_pitches[0] / (1 << 16));
mem->surface->Data.PitchLow =
(mfxU16) (mem->destination_pitches[0] % (1 << 16));
break;
case GST_VIDEO_FORMAT_BGR10A2_LE:
mem->surface->Data.R = mem->cached_data[0];
mem->surface->Data.G = mem->surface->Data.R;
mem->surface->Data.B = mem->surface->Data.R;
mem->surface->Data.A = mem->surface->Data.R;
mem->surface->Data.Pitch = mem->destination_pitches[0];
break;
case GST_VIDEO_FORMAT_Y210:
mem->surface->Data.Y = mem->cached_data[0];
mem->surface->Data.U = mem->surface->Data.Y + 2;
mem->surface->Data.V = mem->surface->Data.Y + 6;
mem->surface->Data.Pitch = mem->destination_pitches[0];
break;
case GST_VIDEO_FORMAT_Y410:
mem->surface->Data.U = mem->cached_data[0]; /* Data.Y410 */
mem->surface->Data.Pitch = mem->destination_pitches[0];
break;
default:
g_assert_not_reached ();
break;
}
return TRUE;
}
static mfxFrameSurface1 *
gst_msdk_system_allocator_create_surface (GstAllocator * allocator)
{
mfxFrameInfo frame_info = { {0,}, 0, };
mfxFrameSurface1 *surface;
GstMsdkSystemAllocator *msdk_system_allocator =
GST_MSDK_SYSTEM_ALLOCATOR_CAST (allocator);
surface = (mfxFrameSurface1 *) g_slice_new0 (mfxFrameSurface1);
if (!surface) {
GST_ERROR ("failed to allocate surface");
return NULL;
}
gst_msdk_set_mfx_frame_info_from_video_info (&frame_info,
&msdk_system_allocator->image_info);
surface->Info = frame_info;
return surface;
}
GstMemory *
gst_msdk_system_memory_new (GstAllocator * base_allocator)
{
GstMsdkSystemAllocator *allocator;
GstVideoInfo *vip;
GstMsdkSystemMemory *mem;
g_return_val_if_fail (base_allocator, NULL);
g_return_val_if_fail (GST_IS_MSDK_SYSTEM_ALLOCATOR (base_allocator), NULL);
allocator = GST_MSDK_SYSTEM_ALLOCATOR_CAST (base_allocator);
mem = g_slice_new0 (GstMsdkSystemMemory);
if (!mem)
return NULL;
mem->surface = gst_msdk_system_allocator_create_surface (base_allocator);
vip = &allocator->image_info;
gst_memory_init (&mem->parent_instance, 0,
base_allocator, NULL, GST_VIDEO_INFO_SIZE (vip), 0, 0,
GST_VIDEO_INFO_SIZE (vip));
if (!ensure_data (mem))
return NULL;
return GST_MEMORY_CAST (mem);
}
static gpointer
gst_msdk_system_memory_map_full (GstMemory * base_mem, GstMapInfo * info,
gsize maxsize)
{
GstMsdkSystemMemory *const mem = GST_MSDK_SYSTEM_MEMORY_CAST (base_mem);
g_return_val_if_fail (mem, NULL);
if (!mem->surface) {
GST_WARNING ("The surface is not allocated");
return NULL;
}
if ((info->flags & GST_MAP_WRITE) && mem->surface
&& mem->surface->Data.Locked) {
GST_WARNING ("The surface in memory %p is not still avaliable", mem);
return NULL;
}
/* The first channel in memory is V for MFX_FOURCC_AYUV (GST_VIDEO_FORMAT_VUYA) format */
if (mem->surface->Info.FourCC == MFX_FOURCC_AYUV)
return mem->surface->Data.V;
#if (MFX_VERSION >= 1027)
else if (mem->surface->Info.FourCC == MFX_FOURCC_Y410)
return mem->surface->Data.U; /* Data.Y410 */
#endif
else
return mem->surface->Data.Y;
}
static void
gst_msdk_system_memory_unmap (GstMemory * base_mem)
{
}
static GstMemory *
gst_msdk_system_memory_copy (GstMemory * base_mem, gssize offset, gssize size)
{
GstMsdkSystemMemory *copy;
GstVideoInfo *info;
GstMsdkSystemAllocator *msdk_allocator;
gsize mem_size;
/* FIXME: can we consider offset and size here ? */
copy =
(GstMsdkSystemMemory *) gst_msdk_system_memory_new (base_mem->allocator);
msdk_allocator = GST_MSDK_SYSTEM_ALLOCATOR_CAST (base_mem->allocator);
info = &msdk_allocator->image_info;
mem_size = GST_VIDEO_INFO_SIZE (info);
memcpy (copy->cache, GST_MSDK_SYSTEM_MEMORY_CAST (base_mem)->cache, mem_size);
return GST_MEMORY_CAST (copy);
}
/* GstMsdkSystemAllocator */
G_DEFINE_TYPE (GstMsdkSystemAllocator, gst_msdk_system_allocator,
GST_TYPE_ALLOCATOR);
static void
gst_msdk_system_allocator_free (GstAllocator * allocator, GstMemory * base_mem)
{
GstMsdkSystemMemory *const mem = GST_MSDK_SYSTEM_MEMORY_CAST (base_mem);
_aligned_free (mem->cache);
g_slice_free (mfxFrameSurface1, mem->surface);
}
static GstMemory *
gst_msdk_system_allocator_alloc (GstAllocator * allocator, gsize size,
GstAllocationParams * params)
{
return gst_msdk_system_memory_new (allocator);
}
static void
gst_msdk_system_allocator_class_init (GstMsdkSystemAllocatorClass * klass)
{
GstAllocatorClass *const allocator_class = GST_ALLOCATOR_CLASS (klass);
allocator_class->alloc = gst_msdk_system_allocator_alloc;
allocator_class->free = gst_msdk_system_allocator_free;
}
static void
gst_msdk_system_allocator_init (GstMsdkSystemAllocator * allocator)
{
GstAllocator *const base_allocator = GST_ALLOCATOR_CAST (allocator);
base_allocator->mem_type = GST_MSDK_SYSTEM_MEMORY_NAME;
base_allocator->mem_map_full = gst_msdk_system_memory_map_full;
base_allocator->mem_unmap = gst_msdk_system_memory_unmap;
base_allocator->mem_copy = gst_msdk_system_memory_copy;
GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
}
GstAllocator *
gst_msdk_system_allocator_new (GstVideoInfo * image_info)
{
GstMsdkSystemAllocator *allocator;
g_return_val_if_fail (image_info != NULL, NULL);
allocator = g_object_new (GST_TYPE_MSDK_SYSTEM_ALLOCATOR, NULL);
if (!allocator)
return NULL;
allocator->image_info = *image_info;
return GST_ALLOCATOR_CAST (allocator);
}