mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-22 16:26:39 +00:00
6750123d5c
Otherwise when mapping BGRx frame onto CPU's memory, CPU will get wrong data for B, G, R components Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2205>
358 lines
11 KiB
C
358 lines
11 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;
|
|
|
|
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
|
|
|
|
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);
|
|
}
|