gstreamer/sys/msdk/gstmsdksystemmemory.c

380 lines
12 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:
case GST_VIDEO_FORMAT_P012_LE:
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:
case GST_VIDEO_FORMAT_BGRx:
mem->surface->Data.B = mem->cached_data[0];
mem->surface->Data.G = mem->surface->Data.B + 1;
mem->surface->Data.R = mem->surface->Data.B + 2;
mem->surface->Data.A = mem->surface->Data.B + 3;
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:
case GST_VIDEO_FORMAT_Y212_LE:
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;
case GST_VIDEO_FORMAT_Y412_LE:
mem->surface->Data.U = mem->cached_data[0];
mem->surface->Data.Y = mem->surface->Data.U + 2;
mem->surface->Data.V = mem->surface->Data.U + 4;
mem->surface->Data.A = mem->surface->Data.U + 6;
mem->surface->Data.Pitch = mem->destination_pitches[0];
break;
#if (MFX_VERSION >= 2004)
case GST_VIDEO_FORMAT_RGBP:
mem->surface->Data.Pitch = mem->destination_pitches[0];
mem->surface->Data.R = mem->cached_data[0];
mem->surface->Data.G = mem->cached_data[1];
mem->surface->Data.B = mem->cached_data[2];
break;
case GST_VIDEO_FORMAT_BGRP:
mem->surface->Data.Pitch = mem->destination_pitches[0];
mem->surface->Data.B = mem->cached_data[0];
mem->surface->Data.G = mem->cached_data[1];
mem->surface->Data.R = mem->cached_data[2];
break;
#endif
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);
if (!mem->surface) {
g_slice_free (GstMsdkSystemMemory, mem);
return NULL;
}
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)) {
g_slice_free (mfxFrameSurface1, mem->surface);
g_slice_free (GstMsdkSystemMemory, 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 available", mem);
return NULL;
}
switch (mem->surface->Info.FourCC) {
case MFX_FOURCC_RGB4:
return mem->surface->Data.B; /* The first channel is B */
/* The first channel in memory is V for MFX_FOURCC_AYUV (GST_VIDEO_FORMAT_VUYA) format */
case MFX_FOURCC_AYUV:
return mem->surface->Data.V;
#if (MFX_VERSION >= 1027)
case MFX_FOURCC_Y410:
return mem->surface->Data.U; /* Data.Y410 */
#endif
#if (MFX_VERSION >= 1031)
case MFX_FOURCC_Y416:
return mem->surface->Data.U; /* The first channel is U */
#endif
#if (MFX_VERSION >= 2004)
case MFX_FOURCC_RGBP:
return mem->surface->Data.R;
case MFX_FOURCC_BGRP:
return mem->surface->Data.B;
#endif
default:
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);
g_slice_free (GstMsdkSystemMemory, mem);
}
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);
}