mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-22 17:51:16 +00:00
qsv: Introduce H.264 Intel Quick Sync Video Encoder
A new implementation of Intel Quick Sync Video plugin. This plugin supports both Windows and Linux but optimization for VA/DMABuf is not implemented yet. This new plugin has some notable differences compared with existing MSDK plugin. * Encoder will expose formats which can be natively supported without internal conversion. This will make encoder control/negotiation flow much simpler and cleaner than that of MSDK plugin. * This plugin includes QSV specific library loading helper, called dispatcher, with QSV SDK headers as a part of this plugin. So, there will be no more SDK version dependent #ifdef in the code and also there will be no more build-time MSDK/oneVPL SDK dependency. * Memory allocator interop between GStreamer and QSV is re-designed and decoupled. Instead of implementing QSV specific allocator/bufferpool, this plugin will make use of generic GStreamer memory allocator/bufferpool (e.g., GstD3D11Allocator and GstD3D11BufferPool). Specifically, GstQsvAllocator object will help interop between GstMemory and mfxFrameAllocator memory abstraction layers. Note that because of the design decision, VA/DMABuf support is not made as a part of this initial commit. We can add the optimization for Linux later once GstVA library exposes allocator/bufferpool implementation as an API like GstD3D11. * Initial encoder implementation supports interop with GstD3D11 infrastructure, including zero-copy encoding with upstream D3D11 element. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1408>
This commit is contained in:
parent
c80132e4a3
commit
64ed6075b7
17 changed files with 5352 additions and 0 deletions
|
@ -140,6 +140,7 @@ option('openni2', type : 'feature', value : 'auto', description : 'OpenNI2 libra
|
|||
option('opensles', type : 'feature', value : 'auto', description : 'OpenSL ES audio source/sink plugin')
|
||||
option('opus', type : 'feature', value : 'auto', description : 'OPUS audio parser plugin')
|
||||
option('qroverlay', type : 'feature', value : 'auto', description : 'Element to set random data on a qroverlay')
|
||||
option('qsv', type : 'feature', value : 'auto', description : 'Intel Quick Sync Video plugin')
|
||||
option('resindvd', type : 'feature', value : 'auto', description : 'Resin DVD playback plugin (GPL - only built if gpl option is also enabled!)')
|
||||
option('rsvg', type : 'feature', value : 'auto', description : 'SVG overlayer and image decoder plugin')
|
||||
option('rtmp', type : 'feature', value : 'auto', description : 'RTMP video network source and sink plugin')
|
||||
|
@ -191,6 +192,10 @@ option('sctp-internal-usrsctp', type: 'feature', value : 'enabled',
|
|||
option('mfx_api', type : 'combo', choices : ['MSDK', 'oneVPL', 'auto'], value : 'auto',
|
||||
description : 'Select MFX API to build against')
|
||||
|
||||
# QSV plugin options
|
||||
option('mfx-modules-dir', type: 'string', value : '',
|
||||
description : 'libmfx runtime module dir, linux only')
|
||||
|
||||
# License-related feature options
|
||||
option('gpl', type: 'feature', value: 'disabled', yield: true,
|
||||
description: 'Allow build plugins that have (A)GPL-licensed dependencies')
|
||||
|
|
|
@ -18,6 +18,7 @@ subdir('mediafoundation')
|
|||
subdir('msdk')
|
||||
subdir('nvcodec')
|
||||
subdir('opensles')
|
||||
subdir('qsv')
|
||||
subdir('shm')
|
||||
subdir('tinyalsa')
|
||||
subdir('uvch264')
|
||||
|
|
506
subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator.cpp
Normal file
506
subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator.cpp
Normal file
|
@ -0,0 +1,506 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstqsvallocator.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_EXTERN (gst_qsv_allocator_debug);
|
||||
#define GST_CAT_DEFAULT gst_qsv_allocator_debug
|
||||
|
||||
/* Both d3d11 and va use (GST_MAP_FLAG_LAST << 1) value
|
||||
* for GPU access */
|
||||
#define GST_MAP_QSV (GST_MAP_FLAG_LAST << 1)
|
||||
|
||||
struct _GstQsvFrame
|
||||
{
|
||||
GstMiniObject parent;
|
||||
|
||||
GstQsvAllocator *allocator;
|
||||
|
||||
GMutex lock;
|
||||
|
||||
guint map_count;
|
||||
GstBuffer *buffer;
|
||||
GstVideoInfo info;
|
||||
GstVideoFrame frame;
|
||||
GstQsvMemoryType mem_type;
|
||||
|
||||
/* For direct GPU access */
|
||||
GstMapInfo map_info;
|
||||
};
|
||||
|
||||
GST_DEFINE_MINI_OBJECT_TYPE (GstQsvFrame, gst_qsv_frame);
|
||||
|
||||
static void
|
||||
_gst_qsv_frame_free (GstQsvFrame * frame)
|
||||
{
|
||||
g_mutex_clear (&frame->lock);
|
||||
gst_clear_buffer (&frame->buffer);
|
||||
gst_clear_object (&frame->allocator);
|
||||
g_free (frame);
|
||||
}
|
||||
|
||||
static GstQsvFrame *
|
||||
gst_qsv_frame_new (void)
|
||||
{
|
||||
GstQsvFrame *self;
|
||||
|
||||
self = g_new0 (GstQsvFrame, 1);
|
||||
g_mutex_init (&self->lock);
|
||||
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (self), 0,
|
||||
GST_TYPE_QSV_FRAME, nullptr, nullptr,
|
||||
(GstMiniObjectFreeFunction) _gst_qsv_frame_free);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
GstBuffer *
|
||||
gst_qsv_frame_peek_buffer (GstQsvFrame * frame)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_QSV_FRAME (frame), nullptr);
|
||||
|
||||
return frame->buffer;
|
||||
}
|
||||
|
||||
struct _GstQsvAllocatorPrivate
|
||||
{
|
||||
GstAtomicQueue *queue;
|
||||
|
||||
mfxFrameAllocator allocator;
|
||||
};
|
||||
|
||||
#define gst_qsv_allocator_parent_class parent_class
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstQsvAllocator,
|
||||
gst_qsv_allocator, GST_TYPE_OBJECT);
|
||||
|
||||
static void gst_qsv_allocator_finalize (GObject * object);
|
||||
static mfxStatus gst_qsv_allocator_alloc (mfxHDL pthis,
|
||||
mfxFrameAllocRequest * request, mfxFrameAllocResponse * response);
|
||||
static mfxStatus gst_qsv_allocator_lock (mfxHDL pthis, mfxMemId mid,
|
||||
mfxFrameData * ptr);
|
||||
static mfxStatus gst_qsv_allocator_unlock (mfxHDL pthis, mfxMemId mid,
|
||||
mfxFrameData * ptr);
|
||||
static mfxStatus gst_qsv_allocator_get_hdl (mfxHDL pthis, mfxMemId mid,
|
||||
mfxHDL * handle);
|
||||
static mfxStatus gst_qsv_allocator_free (mfxHDL pthis,
|
||||
mfxFrameAllocResponse * response);
|
||||
|
||||
static void
|
||||
gst_qsv_allocator_class_init (GstQsvAllocatorClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = gst_qsv_allocator_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_qsv_allocator_init (GstQsvAllocator * self)
|
||||
{
|
||||
GstQsvAllocatorPrivate *priv;
|
||||
|
||||
priv = self->priv = (GstQsvAllocatorPrivate *)
|
||||
gst_qsv_allocator_get_instance_private (self);
|
||||
|
||||
priv->queue = gst_atomic_queue_new (16);
|
||||
|
||||
priv->allocator.pthis = self;
|
||||
priv->allocator.Alloc = gst_qsv_allocator_alloc;
|
||||
priv->allocator.Lock = gst_qsv_allocator_lock;
|
||||
priv->allocator.Unlock = gst_qsv_allocator_unlock;
|
||||
priv->allocator.GetHDL = gst_qsv_allocator_get_hdl;
|
||||
priv->allocator.Free = gst_qsv_allocator_free;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_qsv_allocator_finalize (GObject * object)
|
||||
{
|
||||
GstQsvAllocator *self = GST_QSV_ALLOCATOR (object);
|
||||
GstQsvAllocatorPrivate *priv = self->priv;
|
||||
GstQsvFrame *frame;
|
||||
|
||||
GST_DEBUG_OBJECT (object, "finalize");
|
||||
|
||||
while ((frame = (GstQsvFrame *) gst_atomic_queue_pop (priv->queue)))
|
||||
gst_qsv_frame_unref (frame);
|
||||
|
||||
gst_atomic_queue_unref (priv->queue);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static mfxStatus
|
||||
gst_qsv_allocator_alloc_default (GstQsvAllocator * self,
|
||||
mfxFrameAllocRequest * request, mfxFrameAllocResponse * response)
|
||||
{
|
||||
GstQsvFrame **mids = nullptr;
|
||||
GstVideoInfo info;
|
||||
GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
|
||||
|
||||
GST_TRACE_OBJECT (self, "Alloc");
|
||||
|
||||
/* Something unexpected and went wrong */
|
||||
if ((request->Type & MFX_MEMTYPE_SYSTEM_MEMORY) == 0) {
|
||||
GST_ERROR_OBJECT (self,
|
||||
"MFX is requesting system memory, type 0x%x", request->Type);
|
||||
return MFX_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
switch (request->Info.FourCC) {
|
||||
case MFX_FOURCC_NV12:
|
||||
format = GST_VIDEO_FORMAT_NV12;
|
||||
break;
|
||||
default:
|
||||
/* TODO: add more formats */
|
||||
break;
|
||||
}
|
||||
|
||||
if (format == GST_VIDEO_FORMAT_UNKNOWN) {
|
||||
GST_ERROR_OBJECT (self, "Unknown MFX format fourcc %" GST_FOURCC_FORMAT,
|
||||
GST_FOURCC_ARGS (request->Info.FourCC));
|
||||
|
||||
return MFX_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
mids = g_new0 (GstQsvFrame *, request->NumFrameSuggested);
|
||||
response->NumFrameActual = request->NumFrameSuggested;
|
||||
|
||||
gst_video_info_set_format (&info,
|
||||
format, request->Info.Width, request->Info.Height);
|
||||
for (guint i = 0; i < request->NumFrameSuggested; i++) {
|
||||
GstBuffer *buffer;
|
||||
|
||||
buffer = gst_buffer_new_and_alloc (info.size);
|
||||
mids[i] = gst_qsv_allocator_acquire_frame (self,
|
||||
GST_QSV_SYSTEM_MEMORY, &info, buffer, nullptr);
|
||||
gst_buffer_unref (buffer);
|
||||
}
|
||||
|
||||
response->mids = (mfxMemId *) mids;
|
||||
|
||||
return MFX_ERR_NONE;
|
||||
}
|
||||
|
||||
static mfxStatus
|
||||
gst_qsv_allocator_alloc (mfxHDL pthis,
|
||||
mfxFrameAllocRequest * request, mfxFrameAllocResponse * response)
|
||||
{
|
||||
GstQsvAllocator *self = GST_QSV_ALLOCATOR (pthis);
|
||||
GstQsvAllocatorClass *klass;
|
||||
|
||||
if ((request->Type & MFX_MEMTYPE_SYSTEM_MEMORY) != 0)
|
||||
return gst_qsv_allocator_alloc_default (self, request, response);
|
||||
|
||||
klass = GST_QSV_ALLOCATOR_GET_CLASS (self);
|
||||
|
||||
g_assert (klass->alloc);
|
||||
|
||||
return klass->alloc (self, request, response);
|
||||
}
|
||||
|
||||
static mfxStatus
|
||||
gst_qsv_allocator_lock (mfxHDL pthis, mfxMemId mid, mfxFrameData * ptr)
|
||||
{
|
||||
GstQsvAllocator *self = GST_QSV_ALLOCATOR (pthis);
|
||||
GstQsvFrame *frame = (GstQsvFrame *) mid;
|
||||
|
||||
GST_TRACE_OBJECT (self, "Lock mfxMemId %p", mid);
|
||||
|
||||
g_mutex_lock (&frame->lock);
|
||||
if (frame->map_count == 0) {
|
||||
gst_video_frame_map (&frame->frame, &frame->info, frame->buffer,
|
||||
GST_MAP_READ);
|
||||
}
|
||||
|
||||
frame->map_count++;
|
||||
|
||||
ptr->Pitch = (mfxU16) GST_VIDEO_FRAME_PLANE_STRIDE (&frame->frame, 0);
|
||||
ptr->Y = (mfxU8 *) GST_VIDEO_FRAME_PLANE_DATA (&frame->frame, 0);
|
||||
|
||||
/* FIXME: check and handle other formats */
|
||||
if (GST_VIDEO_INFO_FORMAT (&frame->info) == GST_VIDEO_FORMAT_NV12)
|
||||
ptr->UV = (mfxU8 *) GST_VIDEO_FRAME_PLANE_DATA (&frame->frame, 1);
|
||||
|
||||
g_mutex_unlock (&frame->lock);
|
||||
|
||||
return MFX_ERR_NONE;
|
||||
}
|
||||
|
||||
static mfxStatus
|
||||
gst_qsv_allocator_unlock (mfxHDL pthis, mfxMemId mid, mfxFrameData * ptr)
|
||||
{
|
||||
GstQsvAllocator *self = GST_QSV_ALLOCATOR (pthis);
|
||||
GstQsvFrame *frame = (GstQsvFrame *) mid;
|
||||
|
||||
GST_TRACE_OBJECT (self, "Unlock mfxMemId %p", mid);
|
||||
|
||||
g_mutex_lock (&frame->lock);
|
||||
|
||||
if (frame->map_count > 0) {
|
||||
frame->map_count--;
|
||||
|
||||
if (frame->map_count == 0)
|
||||
gst_video_frame_unmap (&frame->frame);
|
||||
} else {
|
||||
GST_WARNING_OBJECT (self, "Unlock request for non-locked memory");
|
||||
}
|
||||
|
||||
g_mutex_unlock (&frame->lock);
|
||||
|
||||
return MFX_ERR_NONE;
|
||||
}
|
||||
|
||||
static mfxStatus
|
||||
gst_qsv_allocator_get_hdl (mfxHDL pthis, mfxMemId mid, mfxHDL * handle)
|
||||
{
|
||||
GstQsvAllocator *self = GST_QSV_ALLOCATOR (pthis);
|
||||
GstQsvFrame *frame = GST_QSV_FRAME_CAST (mid);
|
||||
|
||||
if (frame->mem_type != GST_QSV_VIDEO_MEMORY) {
|
||||
GST_ERROR_OBJECT (self, "Unexpected call");
|
||||
|
||||
return MFX_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (!frame->map_info.data) {
|
||||
GST_ERROR_OBJECT (self, "No mapped data");
|
||||
return MFX_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
GST_TRACE_OBJECT (self, "Get handle for mfxMemId %p", mid);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
mfxHDLPair *pair = (mfxHDLPair *) handle;
|
||||
pair->first = (mfxHDL) frame->map_info.data;
|
||||
|
||||
/* GstD3D11 will fill user_data[0] with subresource index */
|
||||
pair->second = (mfxHDL) frame->map_info.user_data[0];
|
||||
#else
|
||||
*handle = (mfxHDL) frame->map_info.data;
|
||||
#endif
|
||||
|
||||
return MFX_ERR_NONE;
|
||||
}
|
||||
|
||||
static mfxStatus
|
||||
gst_qsv_allocator_free (mfxHDL pthis, mfxFrameAllocResponse * response)
|
||||
{
|
||||
GstQsvFrame **frames = (GstQsvFrame **) response->mids;
|
||||
|
||||
for (guint i = 0; i < response->NumFrameActual; i++)
|
||||
gst_clear_qsv_frame (&frames[i]);
|
||||
|
||||
g_clear_pointer (&response->mids, g_free);
|
||||
|
||||
return MFX_ERR_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_qsv_frame_release (GstQsvFrame * frame)
|
||||
{
|
||||
GstQsvAllocator *allocator = frame->allocator;
|
||||
|
||||
g_mutex_lock (&frame->lock);
|
||||
if (frame->map_count > 0) {
|
||||
GST_WARNING_OBJECT (allocator, "Releasing mapped frame %p", frame);
|
||||
gst_video_frame_unmap (&frame->frame);
|
||||
}
|
||||
frame->map_count = 0;
|
||||
g_mutex_unlock (&frame->lock);
|
||||
|
||||
if (frame->mem_type == GST_QSV_VIDEO_MEMORY && frame->map_info.data)
|
||||
gst_buffer_unmap (frame->buffer, &frame->map_info);
|
||||
|
||||
memset (&frame->map_info, 0, sizeof (GstMapInfo));
|
||||
|
||||
gst_clear_buffer (&frame->buffer);
|
||||
GST_MINI_OBJECT_CAST (frame)->dispose = nullptr;
|
||||
frame->allocator = nullptr;
|
||||
|
||||
GST_TRACE_OBJECT (allocator, "Moving frame %p back to pool", frame);
|
||||
|
||||
gst_atomic_queue_push (allocator->priv->queue, frame);
|
||||
gst_object_unref (allocator);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_qsv_frame_dispose (GstQsvFrame * frame)
|
||||
{
|
||||
g_assert (frame->allocator);
|
||||
|
||||
gst_qsv_frame_ref (frame);
|
||||
gst_qsv_frame_release (frame);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GstBuffer *
|
||||
gst_qsv_allocator_upload_default (GstQsvAllocator * allocator,
|
||||
const GstVideoInfo * info, GstBuffer * buffer, GstBufferPool * pool)
|
||||
{
|
||||
GstBuffer *dst_buf;
|
||||
GstFlowReturn flow_ret;
|
||||
GstVideoFrame src_frame, dst_frame;
|
||||
|
||||
flow_ret = gst_buffer_pool_acquire_buffer (pool, &dst_buf, nullptr);
|
||||
if (flow_ret != GST_FLOW_OK) {
|
||||
GST_WARNING ("Failed to acquire buffer from pool, return %s",
|
||||
gst_flow_get_name (flow_ret));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gst_video_frame_map (&src_frame, info, buffer, GST_MAP_READ);
|
||||
gst_video_frame_map (&dst_frame, info, dst_buf, GST_MAP_WRITE);
|
||||
|
||||
if (GST_VIDEO_FRAME_WIDTH (&src_frame) == GST_VIDEO_FRAME_WIDTH (&dst_frame)
|
||||
&& GST_VIDEO_FRAME_HEIGHT (&src_frame) ==
|
||||
GST_VIDEO_FRAME_HEIGHT (&dst_frame)) {
|
||||
gst_video_frame_unmap (&src_frame);
|
||||
gst_video_frame_unmap (&dst_frame);
|
||||
|
||||
gst_buffer_unref (dst_buf);
|
||||
return gst_buffer_ref (buffer);
|
||||
}
|
||||
|
||||
for (guint i = 0; i < GST_VIDEO_FRAME_N_PLANES (&src_frame); i++) {
|
||||
guint src_width_in_bytes, src_height;
|
||||
guint dst_width_in_bytes, dst_height;
|
||||
guint width_in_bytes, height;
|
||||
guint src_stride, dst_stride;
|
||||
guint8 *src_data, *dst_data;
|
||||
|
||||
src_width_in_bytes = GST_VIDEO_FRAME_COMP_WIDTH (&src_frame, i) *
|
||||
GST_VIDEO_FRAME_COMP_PSTRIDE (&src_frame, i);
|
||||
src_height = GST_VIDEO_FRAME_COMP_HEIGHT (&src_frame, i);
|
||||
src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&src_frame, i);
|
||||
|
||||
dst_width_in_bytes = GST_VIDEO_FRAME_COMP_WIDTH (&dst_frame, i) *
|
||||
GST_VIDEO_FRAME_COMP_PSTRIDE (&dst_frame, i);
|
||||
dst_height = GST_VIDEO_FRAME_COMP_HEIGHT (&dst_frame, i);
|
||||
dst_stride = GST_VIDEO_FRAME_COMP_STRIDE (&dst_frame, i);
|
||||
|
||||
width_in_bytes = MIN (src_width_in_bytes, dst_width_in_bytes);
|
||||
height = MIN (src_height, dst_height);
|
||||
|
||||
src_data = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&src_frame, i);
|
||||
dst_data = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&dst_frame, i);
|
||||
|
||||
for (guint j = 0; j < height; j++) {
|
||||
memcpy (dst_data, src_data, width_in_bytes);
|
||||
dst_data += dst_stride;
|
||||
src_data += src_stride;
|
||||
}
|
||||
}
|
||||
|
||||
gst_video_frame_unmap (&dst_frame);
|
||||
gst_video_frame_unmap (&src_frame);
|
||||
|
||||
return dst_buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_qsv_allocator_acquire_frame:
|
||||
* @allocator: a #GstQsvAllocator
|
||||
* @mem_type: a memory type
|
||||
* @info: a #GstVideoInfo
|
||||
* @buffer: (transfer none): a #GstBuffer
|
||||
* @pool: (nullable): a #GstBufferPool
|
||||
*
|
||||
* Uploads @buffer to video memory if required, and wraps GstBuffer using
|
||||
* #GstQsvFrame object so that QSV API can access native memory handle
|
||||
* via mfxFrameAllocator interface.
|
||||
*
|
||||
* Returns: a #GstQsvFrame object
|
||||
*/
|
||||
GstQsvFrame *
|
||||
gst_qsv_allocator_acquire_frame (GstQsvAllocator * allocator,
|
||||
GstQsvMemoryType mem_type, const GstVideoInfo * info, GstBuffer * buffer,
|
||||
GstBufferPool * pool)
|
||||
{
|
||||
GstQsvAllocatorPrivate *priv;
|
||||
GstQsvFrame *frame;
|
||||
|
||||
g_return_val_if_fail (GST_IS_QSV_ALLOCATOR (allocator), nullptr);
|
||||
|
||||
priv = allocator->priv;
|
||||
frame = (GstQsvFrame *) gst_atomic_queue_pop (priv->queue);
|
||||
|
||||
if (!frame)
|
||||
frame = gst_qsv_frame_new ();
|
||||
|
||||
frame->mem_type = mem_type;
|
||||
frame->allocator = (GstQsvAllocator *) gst_object_ref (allocator);
|
||||
GST_MINI_OBJECT_CAST (frame)->dispose =
|
||||
(GstMiniObjectDisposeFunction) gst_qsv_frame_dispose;
|
||||
|
||||
if (!pool) {
|
||||
frame->buffer = gst_buffer_ref (buffer);
|
||||
frame->info = *info;
|
||||
} else {
|
||||
GstBuffer *upload_buf;
|
||||
|
||||
if (mem_type == GST_QSV_SYSTEM_MEMORY) {
|
||||
upload_buf = gst_qsv_allocator_upload_default (allocator, info, buffer,
|
||||
pool);
|
||||
} else {
|
||||
GstQsvAllocatorClass *klass;
|
||||
|
||||
klass = GST_QSV_ALLOCATOR_GET_CLASS (allocator);
|
||||
g_assert (klass->upload);
|
||||
|
||||
upload_buf = klass->upload (allocator, info, buffer, pool);
|
||||
}
|
||||
|
||||
if (!upload_buf) {
|
||||
GST_WARNING_OBJECT (allocator, "Failed to upload buffer");
|
||||
gst_qsv_frame_unref (frame);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
frame->buffer = upload_buf;
|
||||
frame->info = *info;
|
||||
}
|
||||
|
||||
if (mem_type == GST_QSV_VIDEO_MEMORY) {
|
||||
/* TODO: we need to know context whether this memory is for
|
||||
* output (e.g., decoder or vpp), but we have only encoder
|
||||
* implementation at the moment, so GST_MAP_READ should be fine */
|
||||
if (!gst_buffer_map (frame->buffer, &frame->map_info,
|
||||
(GstMapFlags) (GST_MAP_READ | GST_MAP_QSV))) {
|
||||
GST_ERROR_OBJECT (allocator, "Failed to map video buffer");
|
||||
gst_qsv_frame_unref (frame);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
mfxFrameAllocator *
|
||||
gst_qsv_allocator_get_allocator_handle (GstQsvAllocator * allocator)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_QSV_ALLOCATOR (allocator), nullptr);
|
||||
|
||||
return &allocator->priv->allocator;
|
||||
}
|
106
subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator.h
Normal file
106
subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator.h
Normal file
|
@ -0,0 +1,106 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/video.h>
|
||||
#include <mfx.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_QSV_FRAME (gst_qsv_frame_get_type())
|
||||
#define GST_IS_QSV_FRAME(obj) (GST_IS_MINI_OBJECT_TYPE(obj, GST_TYPE_QSV_FRAME))
|
||||
#define GST_QSV_FRAME_CAST(obj) ((GstQsvFrame *) obj)
|
||||
|
||||
#define GST_TYPE_QSV_ALLOCATOR (gst_qsv_allocator_get_type())
|
||||
#define GST_QSV_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_QSV_ALLOCATOR, GstQsvAllocator))
|
||||
#define GST_QSV_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_QSV_ALLOCATOR, GstQsvAllocatorClass))
|
||||
#define GST_IS_QSV_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_QSV_ALLOCATOR))
|
||||
#define GST_IS_QSV_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_QSV_ALLOCATOR))
|
||||
#define GST_QSV_ALLOCATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_QSV_ALLOCATOR, GstQsvAllocatorClass))
|
||||
#define GST_QSV_ALLOCATOR_CAST(obj) ((GstQsvAllocator *)obj)
|
||||
|
||||
typedef struct _GstQsvFrame GstQsvFrame;
|
||||
typedef struct _GstQsvAllocator GstQsvAllocator;
|
||||
typedef struct _GstQsvAllocatorClass GstQsvAllocatorClass;
|
||||
typedef struct _GstQsvAllocatorPrivate GstQsvAllocatorPrivate;
|
||||
|
||||
GType gst_qsv_frame_get_type (void);
|
||||
|
||||
GstBuffer * gst_qsv_frame_peek_buffer (GstQsvFrame * frame);
|
||||
|
||||
static inline GstQsvFrame *
|
||||
gst_qsv_frame_ref (GstQsvFrame * frame)
|
||||
{
|
||||
return (GstQsvFrame *) gst_mini_object_ref (GST_MINI_OBJECT_CAST (frame));
|
||||
}
|
||||
|
||||
static inline void
|
||||
gst_qsv_frame_unref (GstQsvFrame * frame)
|
||||
{
|
||||
gst_mini_object_unref (GST_MINI_OBJECT_CAST (frame));
|
||||
}
|
||||
|
||||
static inline void
|
||||
gst_clear_qsv_frame (GstQsvFrame ** frame)
|
||||
{
|
||||
gst_clear_mini_object ((GstMiniObject **) frame);
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GST_QSV_SYSTEM_MEMORY,
|
||||
GST_QSV_VIDEO_MEMORY,
|
||||
} GstQsvMemoryType;
|
||||
|
||||
struct _GstQsvAllocator
|
||||
{
|
||||
GstObject parent;
|
||||
|
||||
GstQsvAllocatorPrivate *priv;
|
||||
};
|
||||
|
||||
struct _GstQsvAllocatorClass
|
||||
{
|
||||
GstObjectClass parent_class;
|
||||
|
||||
mfxStatus (*alloc) (GstQsvAllocator * allocator,
|
||||
mfxFrameAllocRequest * request,
|
||||
mfxFrameAllocResponse * response);
|
||||
|
||||
GstBuffer * (*upload) (GstQsvAllocator * allocator,
|
||||
const GstVideoInfo * info,
|
||||
GstBuffer * buffer,
|
||||
GstBufferPool * pool);
|
||||
};
|
||||
|
||||
GType gst_qsv_allocator_get_type (void);
|
||||
|
||||
GstQsvFrame * gst_qsv_allocator_acquire_frame (GstQsvAllocator * allocator,
|
||||
GstQsvMemoryType mem_type,
|
||||
const GstVideoInfo * info,
|
||||
GstBuffer * buffer,
|
||||
GstBufferPool * pool);
|
||||
|
||||
mfxFrameAllocator * gst_qsv_allocator_get_allocator_handle (GstQsvAllocator * allocator);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstQsvAllocator, gst_object_unref)
|
||||
|
||||
G_END_DECLS
|
417
subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator_d3d11.cpp
Normal file
417
subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator_d3d11.cpp
Normal file
|
@ -0,0 +1,417 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstqsvallocator_d3d11.h"
|
||||
#include <string.h>
|
||||
|
||||
GST_DEBUG_CATEGORY_EXTERN (gst_qsv_allocator_debug);
|
||||
#define GST_CAT_DEFAULT gst_qsv_allocator_debug
|
||||
|
||||
struct _GstQsvD3D11Allocator
|
||||
{
|
||||
GstQsvAllocator parent;
|
||||
|
||||
GstD3D11Device *device;
|
||||
};
|
||||
|
||||
#define gst_qsv_d3d11_allocator_parent_class parent_class
|
||||
G_DEFINE_TYPE (GstQsvD3D11Allocator, gst_qsv_d3d11_allocator,
|
||||
GST_TYPE_QSV_ALLOCATOR);
|
||||
|
||||
static void gst_qsv_d3d11_allocator_dispose (GObject * object);
|
||||
static mfxStatus gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator,
|
||||
mfxFrameAllocRequest * request, mfxFrameAllocResponse * response);
|
||||
static GstBuffer *gst_qsv_d3d11_allocator_upload (GstQsvAllocator * allocator,
|
||||
const GstVideoInfo * info, GstBuffer * buffer, GstBufferPool * pool);
|
||||
|
||||
static void
|
||||
gst_qsv_d3d11_allocator_class_init (GstQsvD3D11AllocatorClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GstQsvAllocatorClass *alloc_class = GST_QSV_ALLOCATOR_CLASS (klass);
|
||||
|
||||
object_class->dispose = gst_qsv_d3d11_allocator_dispose;
|
||||
|
||||
alloc_class->alloc = GST_DEBUG_FUNCPTR (gst_qsv_d3d11_allocator_alloc);
|
||||
alloc_class->upload = GST_DEBUG_FUNCPTR (gst_qsv_d3d11_allocator_upload);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_qsv_d3d11_allocator_init (GstQsvD3D11Allocator * self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gst_qsv_d3d11_allocator_dispose (GObject * object)
|
||||
{
|
||||
GstQsvD3D11Allocator *self = GST_QSV_D3D11_ALLOCATOR (object);
|
||||
|
||||
gst_clear_object (&self->device);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static mfxStatus
|
||||
gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator,
|
||||
mfxFrameAllocRequest * request, mfxFrameAllocResponse * response)
|
||||
{
|
||||
GstQsvD3D11Allocator *self = GST_QSV_D3D11_ALLOCATOR (allocator);
|
||||
DXGI_FORMAT dxgi_format = DXGI_FORMAT_UNKNOWN;
|
||||
GstQsvFrame **mids = nullptr;
|
||||
|
||||
GST_TRACE_OBJECT (self, "Alloc");
|
||||
|
||||
/* Something unexpected and went wrong */
|
||||
if ((request->Type & MFX_MEMTYPE_SYSTEM_MEMORY) != 0) {
|
||||
GST_ERROR_OBJECT (self,
|
||||
"MFX is requesting system memory, type 0x%x", request->Type);
|
||||
return MFX_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
switch (request->Info.FourCC) {
|
||||
case MFX_FOURCC_NV12:
|
||||
dxgi_format = DXGI_FORMAT_NV12;
|
||||
break;
|
||||
default:
|
||||
/* TODO: add more formats */
|
||||
break;
|
||||
}
|
||||
|
||||
if (dxgi_format == DXGI_FORMAT_UNKNOWN &&
|
||||
request->Info.FourCC != MFX_FOURCC_P8) {
|
||||
GST_ERROR_OBJECT (self, "Failed to convert %d to DXGI format",
|
||||
request->Info.FourCC);
|
||||
|
||||
return MFX_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (request->Info.FourCC == MFX_FOURCC_P8) {
|
||||
GstD3D11Allocator *d3d11_alloc = nullptr;
|
||||
D3D11_BUFFER_DESC desc;
|
||||
GstVideoInfo info;
|
||||
GstMemory *mem;
|
||||
GstBuffer *buffer;
|
||||
gsize offset[GST_VIDEO_MAX_PLANES] = { 0, };
|
||||
gint stride[GST_VIDEO_MAX_PLANES] = { 0, };
|
||||
guint size;
|
||||
|
||||
d3d11_alloc =
|
||||
(GstD3D11Allocator *) gst_allocator_find (GST_D3D11_MEMORY_NAME);
|
||||
if (!d3d11_alloc) {
|
||||
GST_ERROR_OBJECT (self, "D3D11 allocator is unavailable");
|
||||
|
||||
return MFX_ERR_MEMORY_ALLOC;
|
||||
}
|
||||
|
||||
memset (&desc, 0, sizeof (D3D11_BUFFER_DESC));
|
||||
|
||||
desc.ByteWidth = request->Info.Width * request->Info.Height;
|
||||
desc.Usage = D3D11_USAGE_STAGING;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
|
||||
mem = gst_d3d11_allocator_alloc_buffer (d3d11_alloc, self->device, &desc);
|
||||
gst_object_unref (d3d11_alloc);
|
||||
|
||||
if (!mem) {
|
||||
GST_ERROR_OBJECT (self, "Failed to allocate buffer");
|
||||
|
||||
return MFX_ERR_MEMORY_ALLOC;
|
||||
}
|
||||
|
||||
size = request->Info.Width * request->Info.Height;
|
||||
stride[0] = size;
|
||||
|
||||
gst_video_info_set_format (&info, GST_VIDEO_FORMAT_GRAY8, size, 1);
|
||||
|
||||
buffer = gst_buffer_new ();
|
||||
gst_buffer_append_memory (buffer, mem);
|
||||
gst_buffer_add_video_meta_full (buffer, GST_VIDEO_FRAME_FLAG_NONE,
|
||||
GST_VIDEO_FORMAT_GRAY8, size, 1, 1, offset, stride);
|
||||
|
||||
mids = g_new0 (GstQsvFrame *, 1);
|
||||
response->NumFrameActual = 1;
|
||||
mids[0] = gst_qsv_allocator_acquire_frame (allocator,
|
||||
GST_QSV_VIDEO_MEMORY, &info, buffer, nullptr);
|
||||
gst_buffer_unref (buffer);
|
||||
} else {
|
||||
GstBufferPool *pool;
|
||||
GstVideoFormat format;
|
||||
GstVideoInfo info;
|
||||
GstCaps *caps;
|
||||
GstStructure *config;
|
||||
GstD3D11AllocationParams *params;
|
||||
guint bind_flags = 0;
|
||||
|
||||
if ((request->Type & MFX_MEMTYPE_VIDEO_MEMORY_ENCODER_TARGET) != 0)
|
||||
bind_flags |= D3D11_BIND_VIDEO_ENCODER;
|
||||
|
||||
format = gst_d3d11_dxgi_format_to_gst (dxgi_format);
|
||||
gst_video_info_set_format (&info,
|
||||
format, request->Info.Width, request->Info.Height);
|
||||
caps = gst_video_info_to_caps (&info);
|
||||
|
||||
pool = gst_d3d11_buffer_pool_new (self->device);
|
||||
params = gst_d3d11_allocation_params_new (self->device, &info,
|
||||
(GstD3D11AllocationFlags) 0, bind_flags);
|
||||
|
||||
config = gst_buffer_pool_get_config (pool);
|
||||
gst_buffer_pool_config_set_d3d11_allocation_params (config, params);
|
||||
gst_d3d11_allocation_params_free (params);
|
||||
gst_buffer_pool_config_set_params (config, caps,
|
||||
GST_VIDEO_INFO_SIZE (&info), 0, 0);
|
||||
gst_caps_unref (caps);
|
||||
gst_buffer_pool_set_config (pool, config);
|
||||
gst_buffer_pool_set_active (pool, TRUE);
|
||||
|
||||
mids = g_new0 (GstQsvFrame *, request->NumFrameSuggested);
|
||||
response->NumFrameActual = request->NumFrameSuggested;
|
||||
for (guint i = 0; i < request->NumFrameSuggested; i++) {
|
||||
GstBuffer *buffer;
|
||||
|
||||
if (gst_buffer_pool_acquire_buffer (pool, &buffer, nullptr) !=
|
||||
GST_FLOW_OK) {
|
||||
GST_ERROR_OBJECT (self, "Failed to allocate texture buffer");
|
||||
gst_buffer_pool_set_active (pool, FALSE);
|
||||
gst_object_unref (pool);
|
||||
goto error;
|
||||
}
|
||||
|
||||
mids[i] = gst_qsv_allocator_acquire_frame (allocator,
|
||||
GST_QSV_VIDEO_MEMORY, &info, buffer, nullptr);
|
||||
gst_buffer_unref (buffer);
|
||||
}
|
||||
gst_buffer_pool_set_active (pool, FALSE);
|
||||
gst_object_unref (pool);
|
||||
}
|
||||
|
||||
response->mids = (mfxMemId *) mids;
|
||||
|
||||
return MFX_ERR_NONE;
|
||||
|
||||
error:
|
||||
if (mids) {
|
||||
for (guint i = 0; i < response->NumFrameActual; i++)
|
||||
gst_clear_qsv_frame (&mids[i]);
|
||||
|
||||
g_free (mids);
|
||||
}
|
||||
|
||||
response->NumFrameActual = 0;
|
||||
|
||||
return MFX_ERR_MEMORY_ALLOC;
|
||||
}
|
||||
|
||||
static GstBuffer *
|
||||
gst_qsv_frame_copy_d3d11 (const GstVideoInfo * info, GstBuffer * src_buf,
|
||||
GstBuffer * dst_buf)
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC src_desc, dst_desc;
|
||||
D3D11_BOX src_box;
|
||||
guint subresource_idx;
|
||||
GstMemory *src_mem, *dst_mem;
|
||||
GstMapInfo src_info, dst_info;
|
||||
ID3D11Texture2D *src_tex, *dst_tex;
|
||||
GstD3D11Device *device;
|
||||
ID3D11DeviceContext *device_context;
|
||||
|
||||
GST_TRACE ("Copying D3D11 buffer %" GST_PTR_FORMAT, src_buf);
|
||||
|
||||
src_mem = gst_buffer_peek_memory (src_buf, 0);
|
||||
dst_mem = gst_buffer_peek_memory (dst_buf, 0);
|
||||
|
||||
device = GST_D3D11_MEMORY_CAST (dst_mem)->device;
|
||||
device_context = gst_d3d11_device_get_device_context_handle (device);
|
||||
|
||||
if (!gst_memory_map (src_mem,
|
||||
&src_info, (GstMapFlags) (GST_MAP_READ | GST_MAP_D3D11))) {
|
||||
GST_WARNING ("Failed to map src memory");
|
||||
gst_buffer_unref (dst_buf);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!gst_memory_map (dst_mem,
|
||||
&dst_info, (GstMapFlags) (GST_MAP_WRITE | GST_MAP_D3D11))) {
|
||||
GST_WARNING ("Failed to map dst memory");
|
||||
gst_memory_unmap (src_mem, &src_info);
|
||||
gst_buffer_unref (dst_buf);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
src_tex = (ID3D11Texture2D *) src_info.data;
|
||||
dst_tex = (ID3D11Texture2D *) dst_info.data;
|
||||
|
||||
src_tex->GetDesc (&src_desc);
|
||||
dst_tex->GetDesc (&dst_desc);
|
||||
|
||||
subresource_idx =
|
||||
gst_d3d11_memory_get_subresource_index (GST_D3D11_MEMORY_CAST (src_mem));
|
||||
|
||||
src_box.left = 0;
|
||||
src_box.top = 0;
|
||||
src_box.front = 0;
|
||||
src_box.back = 1;
|
||||
src_box.right = MIN (src_desc.Width, dst_desc.Width);
|
||||
src_box.bottom = MIN (src_desc.Height, dst_desc.Height);
|
||||
|
||||
gst_d3d11_device_lock (device);
|
||||
device_context->CopySubresourceRegion (dst_tex, 0,
|
||||
0, 0, 0, src_tex, subresource_idx, &src_box);
|
||||
gst_d3d11_device_unlock (device);
|
||||
|
||||
gst_memory_unmap (dst_mem, &dst_info);
|
||||
gst_memory_unmap (src_mem, &src_info);
|
||||
|
||||
return dst_buf;
|
||||
}
|
||||
|
||||
static GstBuffer *
|
||||
gst_qsv_frame_upload_sysmem (const GstVideoInfo * info, GstBuffer * src_buf,
|
||||
GstBuffer * dst_buf)
|
||||
{
|
||||
GstVideoFrame src_frame, dst_frame;
|
||||
|
||||
GST_TRACE ("Uploading sysmem buffer %" GST_PTR_FORMAT, src_buf);
|
||||
|
||||
if (!gst_video_frame_map (&src_frame, info, src_buf, GST_MAP_READ)) {
|
||||
GST_WARNING ("Failed to map src frame");
|
||||
gst_buffer_unref (dst_buf);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!gst_video_frame_map (&dst_frame, info, dst_buf, GST_MAP_WRITE)) {
|
||||
GST_WARNING ("Failed to map src frame");
|
||||
gst_video_frame_unmap (&src_frame);
|
||||
gst_buffer_unref (dst_buf);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (guint i = 0; i < GST_VIDEO_FRAME_N_PLANES (&src_frame); i++) {
|
||||
guint src_width_in_bytes, src_height;
|
||||
guint dst_width_in_bytes, dst_height;
|
||||
guint width_in_bytes, height;
|
||||
guint src_stride, dst_stride;
|
||||
guint8 *src_data, *dst_data;
|
||||
|
||||
src_width_in_bytes = GST_VIDEO_FRAME_COMP_WIDTH (&src_frame, i) *
|
||||
GST_VIDEO_FRAME_COMP_PSTRIDE (&src_frame, i);
|
||||
src_height = GST_VIDEO_FRAME_COMP_HEIGHT (&src_frame, i);
|
||||
src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&src_frame, i);
|
||||
|
||||
dst_width_in_bytes = GST_VIDEO_FRAME_COMP_WIDTH (&dst_frame, i) *
|
||||
GST_VIDEO_FRAME_COMP_PSTRIDE (&src_frame, i);
|
||||
dst_height = GST_VIDEO_FRAME_COMP_HEIGHT (&src_frame, i);
|
||||
dst_stride = GST_VIDEO_FRAME_COMP_STRIDE (&dst_frame, i);
|
||||
|
||||
width_in_bytes = MIN (src_width_in_bytes, dst_width_in_bytes);
|
||||
height = MIN (src_height, dst_height);
|
||||
|
||||
src_data = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&src_frame, i);
|
||||
dst_data = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&dst_frame, i);
|
||||
|
||||
for (guint j = 0; j < height; j++) {
|
||||
memcpy (dst_data, src_data, width_in_bytes);
|
||||
dst_data += dst_stride;
|
||||
src_data += src_stride;
|
||||
}
|
||||
}
|
||||
|
||||
gst_video_frame_unmap (&dst_frame);
|
||||
gst_video_frame_unmap (&src_frame);
|
||||
|
||||
return dst_buf;
|
||||
}
|
||||
|
||||
static GstBuffer *
|
||||
gst_qsv_d3d11_allocator_upload (GstQsvAllocator * allocator,
|
||||
const GstVideoInfo * info, GstBuffer * buffer, GstBufferPool * pool)
|
||||
{
|
||||
GstMemory *mem;
|
||||
GstD3D11Memory *dmem, *dst_dmem;
|
||||
D3D11_TEXTURE2D_DESC desc, dst_desc;
|
||||
GstBuffer *dst_buf;
|
||||
GstFlowReturn flow_ret;
|
||||
|
||||
/* 1) D3D11 buffer from the same d3d11device with ours
|
||||
* 1-1) Same resolution
|
||||
* -> Increase refcount and wrap with GstQsvFrame
|
||||
* 1-2) Different resolution
|
||||
* -> GPU copy
|
||||
* 2) non-D3D11 buffer or from other d3d11 device
|
||||
* -> Always CPU copy
|
||||
*/
|
||||
|
||||
if (!GST_IS_D3D11_BUFFER_POOL (pool)) {
|
||||
GST_ERROR_OBJECT (allocator, "Not a d3d11 buffer pool");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
flow_ret = gst_buffer_pool_acquire_buffer (pool, &dst_buf, nullptr);
|
||||
if (flow_ret != GST_FLOW_OK) {
|
||||
GST_WARNING ("Failed to acquire buffer from pool, return %s",
|
||||
gst_flow_get_name (flow_ret));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mem = gst_buffer_peek_memory (buffer, 0);
|
||||
if (!gst_is_d3d11_memory (mem) || gst_buffer_n_memory (buffer) > 1) {
|
||||
/* d3d11 buffer should hold single memory object */
|
||||
return gst_qsv_frame_upload_sysmem (info, buffer, dst_buf);
|
||||
}
|
||||
|
||||
/* FIXME: Add support for shared texture for GPU copy or wrapping
|
||||
* texture from different device */
|
||||
dmem = GST_D3D11_MEMORY_CAST (mem);
|
||||
if (dmem->device != GST_D3D11_BUFFER_POOL (pool)->device)
|
||||
return gst_qsv_frame_upload_sysmem (info, buffer, dst_buf);
|
||||
|
||||
dst_dmem = (GstD3D11Memory *) gst_buffer_peek_memory (dst_buf, 0);
|
||||
gst_d3d11_memory_get_texture_desc (dmem, &desc);
|
||||
gst_d3d11_memory_get_texture_desc (dst_dmem, &dst_desc);
|
||||
|
||||
if (desc.Width == dst_desc.Width && desc.Height == dst_desc.Height &&
|
||||
desc.Usage == D3D11_USAGE_DEFAULT) {
|
||||
/* Identical size and non-staging texture, wrap without copying */
|
||||
GST_TRACE ("Wrapping D3D11 buffer without copy");
|
||||
gst_buffer_unref (dst_buf);
|
||||
|
||||
return gst_buffer_ref (buffer);
|
||||
}
|
||||
|
||||
return gst_qsv_frame_copy_d3d11 (info, buffer, dst_buf);
|
||||
}
|
||||
|
||||
GstQsvAllocator *
|
||||
gst_qsv_d3d11_allocator_new (GstD3D11Device * device)
|
||||
{
|
||||
GstQsvD3D11Allocator *self;
|
||||
|
||||
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), nullptr);
|
||||
|
||||
self = (GstQsvD3D11Allocator *)
|
||||
g_object_new (GST_TYPE_QSV_D3D11_ALLOCATOR, nullptr);
|
||||
self->device = (GstD3D11Device *) gst_object_ref (device);
|
||||
|
||||
gst_object_ref_sink (self);
|
||||
|
||||
return GST_QSV_ALLOCATOR (self);
|
||||
}
|
34
subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator_d3d11.h
Normal file
34
subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator_d3d11.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/d3d11/gstd3d11.h>
|
||||
#include "gstqsvallocator.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_QSV_D3D11_ALLOCATOR (gst_qsv_d3d11_allocator_get_type())
|
||||
G_DECLARE_FINAL_TYPE (GstQsvD3D11Allocator, gst_qsv_d3d11_allocator,
|
||||
GST, QSV_D3D11_ALLOCATOR, GstQsvAllocator);
|
||||
|
||||
GstQsvAllocator * gst_qsv_d3d11_allocator_new (GstD3D11Device * device);
|
||||
|
||||
G_END_DECLS
|
104
subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator_va.cpp
Normal file
104
subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator_va.cpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstqsvallocator_va.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_EXTERN (gst_qsv_allocator_debug);
|
||||
#define GST_CAT_DEFAULT gst_qsv_allocator_debug
|
||||
|
||||
struct _GstQsvVaAllocator
|
||||
{
|
||||
GstQsvAllocator parent;
|
||||
|
||||
GstVaDisplay *display;
|
||||
};
|
||||
|
||||
#define gst_qsv_va_allocator_parent_class parent_class
|
||||
G_DEFINE_TYPE (GstQsvVaAllocator, gst_qsv_va_allocator, GST_TYPE_QSV_ALLOCATOR);
|
||||
|
||||
static void gst_qsv_va_allocator_dispose (GObject * object);
|
||||
static mfxStatus gst_qsv_va_allocator_alloc (GstQsvAllocator * allocator,
|
||||
mfxFrameAllocRequest * request, mfxFrameAllocResponse * response);
|
||||
static GstBuffer *gst_qsv_va_allocator_upload (GstQsvAllocator * allocator,
|
||||
const GstVideoInfo * info, GstBuffer * buffer, GstBufferPool * pool);
|
||||
|
||||
static void
|
||||
gst_qsv_va_allocator_class_init (GstQsvVaAllocatorClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GstQsvAllocatorClass *alloc_class = GST_QSV_ALLOCATOR_CLASS (klass);
|
||||
|
||||
object_class->dispose = gst_qsv_va_allocator_dispose;
|
||||
|
||||
alloc_class->alloc = GST_DEBUG_FUNCPTR (gst_qsv_va_allocator_alloc);
|
||||
alloc_class->upload = GST_DEBUG_FUNCPTR (gst_qsv_va_allocator_upload);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_qsv_va_allocator_init (GstQsvVaAllocator * self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gst_qsv_va_allocator_dispose (GObject * object)
|
||||
{
|
||||
GstQsvVaAllocator *self = GST_QSV_VA_ALLOCATOR (object);
|
||||
|
||||
gst_clear_object (&self->display);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static mfxStatus
|
||||
gst_qsv_va_allocator_alloc (GstQsvAllocator * allocator,
|
||||
mfxFrameAllocRequest * request, mfxFrameAllocResponse * response)
|
||||
{
|
||||
GST_ERROR_OBJECT (allocator, "Not implemented");
|
||||
|
||||
return MFX_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static GstBuffer *
|
||||
gst_qsv_va_allocator_upload (GstQsvAllocator * allocator,
|
||||
const GstVideoInfo * info, GstBuffer * buffer, GstBufferPool * pool)
|
||||
{
|
||||
GST_ERROR_OBJECT (allocator, "Not implemented");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GstQsvAllocator *
|
||||
gst_qsv_va_allocator_new (GstVaDisplay * display)
|
||||
{
|
||||
GstQsvVaAllocator *self;
|
||||
|
||||
g_return_val_if_fail (GST_IS_VA_DISPLAY (display), nullptr);
|
||||
|
||||
self = (GstQsvVaAllocator *)
|
||||
g_object_new (GST_TYPE_QSV_VA_ALLOCATOR, nullptr);
|
||||
self->display = (GstVaDisplay *) gst_object_ref (display);
|
||||
|
||||
gst_object_ref_sink (self);
|
||||
|
||||
return GST_QSV_ALLOCATOR (self);
|
||||
}
|
34
subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator_va.h
Normal file
34
subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator_va.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/va/gstvadisplay.h>
|
||||
#include "gstqsvallocator.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_QSV_VA_ALLOCATOR (gst_qsv_va_allocator_get_type())
|
||||
G_DECLARE_FINAL_TYPE (GstQsvVaAllocator, gst_qsv_va_allocator,
|
||||
GST, QSV_VA_ALLOCATOR, GstQsvAllocator);
|
||||
|
||||
GstQsvAllocator * gst_qsv_va_allocator_new (GstVaDisplay * display);
|
||||
|
||||
G_END_DECLS
|
1452
subprojects/gst-plugins-bad/sys/qsv/gstqsvencoder.cpp
Normal file
1452
subprojects/gst-plugins-bad/sys/qsv/gstqsvencoder.cpp
Normal file
File diff suppressed because it is too large
Load diff
95
subprojects/gst-plugins-bad/sys/qsv/gstqsvencoder.h
Normal file
95
subprojects/gst-plugins-bad/sys/qsv/gstqsvencoder.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/video.h>
|
||||
#include <mfx.h>
|
||||
#include "gstqsvutils.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_QSV_ENCODER (gst_qsv_encoder_get_type())
|
||||
#define GST_QSV_ENCODER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_QSV_ENCODER, GstQsvEncoder))
|
||||
#define GST_QSV_ENCODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_QSV_ENCODER, GstQsvEncoderClass))
|
||||
#define GST_IS_QSV_ENCODER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_QSV_ENCODER))
|
||||
#define GST_IS_QSV_ENCODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_QSV_ENCODER))
|
||||
#define GST_QSV_ENCODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_QSV_ENCODER, GstQsvEncoderClass))
|
||||
#define GST_QSV_ENCODER_CAST(obj) ((GstQsvEncoder *)obj)
|
||||
|
||||
typedef struct _GstQsvEncoder GstQsvEncoder;
|
||||
typedef struct _GstQsvEncoderClass GstQsvEncoderClass;
|
||||
typedef struct _GstQsvEncoderPrivate GstQsvEncoderPrivate;
|
||||
|
||||
#define GST_TYPE_QSV_CODING_OPTION (gst_qsv_coding_option_get_type())
|
||||
GType gst_qsv_coding_option_get_type (void);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GST_QSV_ENCODER_RECONFIGURE_NONE,
|
||||
GST_QSV_ENCODER_RECONFIGURE_BITRATE,
|
||||
GST_QSV_ENCODER_RECONFIGURE_FULL,
|
||||
} GstQsvEncoderReconfigure;
|
||||
|
||||
struct _GstQsvEncoder
|
||||
{
|
||||
GstVideoEncoder parent;
|
||||
|
||||
GstQsvEncoderPrivate *priv;
|
||||
};
|
||||
|
||||
struct _GstQsvEncoderClass
|
||||
{
|
||||
GstVideoEncoderClass parent_class;
|
||||
|
||||
mfxU32 codec_id;
|
||||
mfxU32 impl_index;
|
||||
|
||||
/* DXGI adapter LUID, for Windows */
|
||||
gint64 adapter_luid;
|
||||
|
||||
/* VA display device path, for Linux */
|
||||
gchar display_path[64];
|
||||
|
||||
gboolean (*set_format) (GstQsvEncoder * encoder,
|
||||
GstVideoCodecState * state,
|
||||
mfxVideoParam * param,
|
||||
GPtrArray * extra_params);
|
||||
|
||||
gboolean (*set_output_state) (GstQsvEncoder * encoder,
|
||||
GstVideoCodecState * state,
|
||||
mfxSession session);
|
||||
|
||||
gboolean (*attach_payload) (GstQsvEncoder * encoder,
|
||||
GstVideoCodecFrame * frame,
|
||||
GPtrArray * payload);
|
||||
|
||||
GstBuffer * (*create_output_buffer) (GstQsvEncoder * encoder,
|
||||
mfxBitstream * bitstream);
|
||||
|
||||
GstQsvEncoderReconfigure (*check_reconfigure) (GstQsvEncoder * encoder,
|
||||
mfxVideoParam * param);
|
||||
};
|
||||
|
||||
GType gst_qsv_encoder_get_type (void);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstQsvEncoder, gst_object_unref)
|
||||
|
||||
G_END_DECLS
|
1846
subprojects/gst-plugins-bad/sys/qsv/gstqsvh264enc.cpp
Normal file
1846
subprojects/gst-plugins-bad/sys/qsv/gstqsvh264enc.cpp
Normal file
File diff suppressed because it is too large
Load diff
34
subprojects/gst-plugins-bad/sys/qsv/gstqsvh264enc.h
Normal file
34
subprojects/gst-plugins-bad/sys/qsv/gstqsvh264enc.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/video.h>
|
||||
#include "gstqsvencoder.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void gst_qsv_h264_enc_register (GstPlugin * plugin,
|
||||
guint rank,
|
||||
guint impl_index,
|
||||
GstObject * device,
|
||||
mfxSession session);
|
||||
|
||||
G_END_DECLS
|
203
subprojects/gst-plugins-bad/sys/qsv/gstqsvutils.cpp
Normal file
203
subprojects/gst-plugins-bad/sys/qsv/gstqsvutils.cpp
Normal file
|
@ -0,0 +1,203 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstqsvutils.h"
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
#include <gst/d3d11/gstd3d11.h>
|
||||
#include <wrl.h>
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
using namespace Microsoft::WRL;
|
||||
/* *INDENT-ON* */
|
||||
#else
|
||||
#include <gst/va/gstvadisplay_drm.h>
|
||||
#endif
|
||||
|
||||
static mfxLoader _loader = nullptr;
|
||||
|
||||
mfxLoader
|
||||
gst_qsv_get_loader (void)
|
||||
{
|
||||
static gsize load_once = 0;
|
||||
|
||||
if (g_once_init_enter (&load_once)) {
|
||||
_loader = MFXLoad ();
|
||||
g_once_init_leave (&load_once, 1);
|
||||
}
|
||||
|
||||
return _loader;
|
||||
}
|
||||
|
||||
void
|
||||
gst_qsv_deinit (void)
|
||||
{
|
||||
g_clear_pointer (&_loader, MFXUnload);
|
||||
}
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
static GList *
|
||||
gst_qsv_get_d3d11_devices (void)
|
||||
{
|
||||
GList *rst = nullptr;
|
||||
HRESULT hr;
|
||||
ComPtr < IDXGIFactory1 > factory;
|
||||
|
||||
hr = CreateDXGIFactory1 (IID_PPV_ARGS (&factory));
|
||||
if (FAILED (hr))
|
||||
return nullptr;
|
||||
|
||||
for (guint idx = 0;; idx++) {
|
||||
ComPtr < IDXGIAdapter1 > adapter;
|
||||
DXGI_ADAPTER_DESC desc;
|
||||
gint64 luid;
|
||||
GstD3D11Device *device;
|
||||
ComPtr < ID3D10Multithread > multi_thread;
|
||||
ID3D11Device *device_handle;
|
||||
|
||||
hr = factory->EnumAdapters1 (idx, &adapter);
|
||||
if (FAILED (hr))
|
||||
return rst;
|
||||
|
||||
hr = adapter->GetDesc (&desc);
|
||||
if (FAILED (hr))
|
||||
continue;
|
||||
|
||||
if (desc.VendorId != 0x8086)
|
||||
continue;
|
||||
|
||||
luid = gst_d3d11_luid_to_int64 (&desc.AdapterLuid);
|
||||
device = gst_d3d11_device_new_for_adapter_luid (luid,
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT);
|
||||
|
||||
if (!device)
|
||||
continue;
|
||||
|
||||
device_handle = gst_d3d11_device_get_device_handle (device);
|
||||
hr = device_handle->QueryInterface (IID_PPV_ARGS (&multi_thread));
|
||||
if (FAILED (hr)) {
|
||||
gst_object_unref (device);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Should enable mutithread protection layer, otherwise QSV will return
|
||||
* error code when this handle is passed to QSV via
|
||||
* MFXVideoCORE_SetHandle() */
|
||||
multi_thread->SetMultithreadProtected (TRUE);
|
||||
|
||||
rst = g_list_append (rst, device);
|
||||
}
|
||||
|
||||
return rst;
|
||||
}
|
||||
#else /* G_OS_WIN32 */
|
||||
static GList *
|
||||
gst_qsv_get_va_displays (void)
|
||||
{
|
||||
gchar path[64];
|
||||
GList *rst = nullptr;
|
||||
|
||||
for (guint i = 0; i < 8; i++) {
|
||||
GstVaDisplay *display;
|
||||
GstVaImplementation impl;
|
||||
|
||||
g_snprintf (path, sizeof (path), "/dev/dri/renderD%d", 128 + i);
|
||||
if (!g_file_test (path, G_FILE_TEST_EXISTS))
|
||||
continue;
|
||||
|
||||
display = gst_va_display_drm_new_from_path (path);
|
||||
if (!display)
|
||||
continue;
|
||||
|
||||
impl = gst_va_display_get_implementation (display);
|
||||
if (impl != GST_VA_IMPLEMENTATION_INTEL_I965 &&
|
||||
impl != GST_VA_IMPLEMENTATION_INTEL_IHD) {
|
||||
gst_object_unref (display);
|
||||
continue;
|
||||
}
|
||||
|
||||
rst = g_list_append (rst, display);
|
||||
}
|
||||
|
||||
return rst;
|
||||
}
|
||||
#endif
|
||||
|
||||
GList *
|
||||
gst_qsv_get_platform_devices (void)
|
||||
{
|
||||
#ifdef G_OS_WIN32
|
||||
return gst_qsv_get_d3d11_devices ();
|
||||
#else
|
||||
return gst_qsv_get_va_displays ();
|
||||
#endif
|
||||
}
|
||||
|
||||
const gchar *
|
||||
gst_qsv_status_to_string (mfxStatus status)
|
||||
{
|
||||
#define CASE(err) \
|
||||
case err: \
|
||||
return G_STRINGIFY (err);
|
||||
|
||||
switch (status) {
|
||||
CASE (MFX_ERR_NONE);
|
||||
CASE (MFX_ERR_UNKNOWN);
|
||||
CASE (MFX_ERR_NULL_PTR);
|
||||
CASE (MFX_ERR_UNSUPPORTED);
|
||||
CASE (MFX_ERR_MEMORY_ALLOC);
|
||||
CASE (MFX_ERR_NOT_ENOUGH_BUFFER);
|
||||
CASE (MFX_ERR_INVALID_HANDLE);
|
||||
CASE (MFX_ERR_LOCK_MEMORY);
|
||||
CASE (MFX_ERR_NOT_INITIALIZED);
|
||||
CASE (MFX_ERR_NOT_FOUND);
|
||||
CASE (MFX_ERR_MORE_DATA);
|
||||
CASE (MFX_ERR_MORE_SURFACE);
|
||||
CASE (MFX_ERR_ABORTED);
|
||||
CASE (MFX_ERR_DEVICE_LOST);
|
||||
CASE (MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
|
||||
CASE (MFX_ERR_INVALID_VIDEO_PARAM);
|
||||
CASE (MFX_ERR_UNDEFINED_BEHAVIOR);
|
||||
CASE (MFX_ERR_DEVICE_FAILED);
|
||||
CASE (MFX_ERR_MORE_BITSTREAM);
|
||||
CASE (MFX_ERR_GPU_HANG);
|
||||
CASE (MFX_ERR_REALLOC_SURFACE);
|
||||
CASE (MFX_ERR_RESOURCE_MAPPED);
|
||||
CASE (MFX_ERR_NOT_IMPLEMENTED);
|
||||
CASE (MFX_WRN_IN_EXECUTION);
|
||||
CASE (MFX_WRN_DEVICE_BUSY);
|
||||
CASE (MFX_WRN_VIDEO_PARAM_CHANGED);
|
||||
CASE (MFX_WRN_PARTIAL_ACCELERATION);
|
||||
CASE (MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
|
||||
CASE (MFX_WRN_VALUE_NOT_CHANGED);
|
||||
CASE (MFX_WRN_OUT_OF_RANGE);
|
||||
CASE (MFX_WRN_FILTER_SKIPPED);
|
||||
CASE (MFX_ERR_NONE_PARTIAL_OUTPUT);
|
||||
CASE (MFX_WRN_ALLOC_TIMEOUT_EXPIRED);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#undef CASE
|
||||
|
||||
return "Unknown";
|
||||
}
|
57
subprojects/gst-plugins-bad/sys/qsv/gstqsvutils.h
Normal file
57
subprojects/gst-plugins-bad/sys/qsv/gstqsvutils.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <mfx.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
mfxLoader gst_qsv_get_loader (void);
|
||||
|
||||
void gst_qsv_deinit (void);
|
||||
|
||||
GList * gst_qsv_get_platform_devices (void);
|
||||
|
||||
const gchar * gst_qsv_status_to_string (mfxStatus status);
|
||||
|
||||
/* helper macro for debugging log */
|
||||
#define QSV_STATUS_ARGS(status) \
|
||||
status, gst_qsv_status_to_string (status)
|
||||
|
||||
static inline GstClockTime
|
||||
gst_qsv_timestamp_to_gst (mfxU64 timestamp)
|
||||
{
|
||||
if (timestamp == (mfxU64) MFX_TIMESTAMP_UNKNOWN)
|
||||
return GST_CLOCK_TIME_NONE;
|
||||
|
||||
return gst_util_uint64_scale (timestamp, GST_SECOND, 90000);
|
||||
}
|
||||
|
||||
static inline mfxU64
|
||||
gst_qsv_timestamp_from_gst (GstClockTime timestamp)
|
||||
{
|
||||
if (!GST_CLOCK_TIME_IS_VALID (timestamp))
|
||||
return (mfxU64) MFX_TIMESTAMP_UNKNOWN;
|
||||
|
||||
return gst_util_uint64_scale (timestamp, 90000, GST_SECOND);
|
||||
}
|
||||
|
||||
G_END_DECLS
|
100
subprojects/gst-plugins-bad/sys/qsv/libmfx/meson.build
Normal file
100
subprojects/gst-plugins-bad/sys/qsv/libmfx/meson.build
Normal file
|
@ -0,0 +1,100 @@
|
|||
mfx_win_sources = [
|
||||
'dispatcher/windows/main.cpp',
|
||||
'dispatcher/windows/mfx_dispatcher_log.cpp',
|
||||
'dispatcher/windows/mfx_dispatcher.cpp',
|
||||
'dispatcher/windows/mfx_dxva2_device.cpp',
|
||||
'dispatcher/windows/mfx_function_table.cpp',
|
||||
'dispatcher/windows/mfx_load_dll.cpp',
|
||||
]
|
||||
|
||||
mfx_win32_sources = [
|
||||
'dispatcher/windows/mfx_critical_section.cpp',
|
||||
'dispatcher/windows/mfx_driver_store_loader.cpp',
|
||||
'dispatcher/windows/mfx_library_iterator.cpp',
|
||||
'dispatcher/windows/mfx_win_reg_key.cpp',
|
||||
]
|
||||
|
||||
mfx_uwp_sources = [
|
||||
'dispatcher/windows/mfx_dispatcher_uwp.cpp',
|
||||
'dispatcher/windows/mfx_driver_store_loader.cpp',
|
||||
]
|
||||
|
||||
mfx_linux_sources = [
|
||||
'dispatcher/linux/mfxloader.cpp',
|
||||
]
|
||||
|
||||
vpl_sources = [
|
||||
'dispatcher/vpl/mfx_dispatcher_vpl_config.cpp',
|
||||
'dispatcher/vpl/mfx_dispatcher_vpl_loader.cpp',
|
||||
'dispatcher/vpl/mfx_dispatcher_vpl_log.cpp',
|
||||
'dispatcher/vpl/mfx_dispatcher_vpl_lowlatency.cpp',
|
||||
'dispatcher/vpl/mfx_dispatcher_vpl_msdk.cpp',
|
||||
'dispatcher/vpl/mfx_dispatcher_vpl.cpp',
|
||||
]
|
||||
|
||||
libmfx_extra_args = [
|
||||
'-DONEVPL_EXPERIMENTAL'
|
||||
]
|
||||
libmfx_extra_deps = []
|
||||
|
||||
libmfx_sources = vpl_sources
|
||||
if host_system == 'windows'
|
||||
libmfx_sources += mfx_win_sources
|
||||
# FIXME: check UWP only
|
||||
libmfx_sources += mfx_win32_sources
|
||||
elif host_system == 'linux'
|
||||
libmfx_sources += mfx_linux_sources
|
||||
|
||||
# Unlike Windows (libmfxhw64.dll is part of driver so it's system library),
|
||||
# user can build/install libmfx on Linux, so we need to define
|
||||
# "MFX_MODULES_DIR" for dispatcher to be able to search libmfx from
|
||||
# additional search path.
|
||||
libmfx_modules_dir = get_option('mfx-modules-dir')
|
||||
if libmfx_modules_dir == ''
|
||||
# This "libdir" will be likely wrong but may be fine since libmfx library
|
||||
# will be installed in the distro default library path as part of libmfx package
|
||||
# and dispatcher will try to load library from the distro default library path first
|
||||
libmfx_modules_dir = join_paths(prefix, get_option('libdir'))
|
||||
endif
|
||||
|
||||
libmfx_extra_args += ['-DMFX_MODULES_DIR="@0@"'.format(libmfx_modules_dir)]
|
||||
libmfx_extra_deps += [
|
||||
cc.find_library('dl'),
|
||||
cc.find_library('pthread'),
|
||||
]
|
||||
else
|
||||
error('Only Windows or Linux build is supported')
|
||||
endif
|
||||
|
||||
# suppress build warnings
|
||||
if cc.get_id() == 'msvc'
|
||||
libmfx_extra_args += cc.get_supported_arguments([
|
||||
'/wd4189', # local variable is initialized but not referenced
|
||||
])
|
||||
else
|
||||
libmfx_extra_args += cc.get_supported_arguments([
|
||||
'-Wno-missing-declarations',
|
||||
'-Wno-deprecated-declarations',
|
||||
'-Wno-redundant-decls',
|
||||
'-Wno-unused-but-set-variable',
|
||||
'-Wno-unused-variable',
|
||||
# clang complains
|
||||
'-Wno-missing-braces',
|
||||
'-Wno-format-nonliteral',
|
||||
])
|
||||
endif
|
||||
|
||||
libmfx_incl = include_directories('dispatcher', 'api')
|
||||
|
||||
libmfx_static = static_library('libmfx-static',
|
||||
libmfx_sources,
|
||||
c_args : libmfx_extra_args,
|
||||
cpp_args : libmfx_extra_args,
|
||||
dependencies : libmfx_extra_deps,
|
||||
include_directories : libmfx_incl
|
||||
)
|
||||
|
||||
libmfx_internal_dep = declare_dependency(
|
||||
link_with : libmfx_static,
|
||||
include_directories: [libmfx_incl, include_directories('api/vpl')]
|
||||
)
|
92
subprojects/gst-plugins-bad/sys/qsv/meson.build
Normal file
92
subprojects/gst-plugins-bad/sys/qsv/meson.build
Normal file
|
@ -0,0 +1,92 @@
|
|||
qsv_sources = [
|
||||
'gstqsvallocator.cpp',
|
||||
'gstqsvencoder.cpp',
|
||||
'gstqsvh264enc.cpp',
|
||||
'gstqsvutils.cpp',
|
||||
'plugin.cpp',
|
||||
]
|
||||
|
||||
qsv_d3d11_sources = [
|
||||
'gstqsvallocator_d3d11.cpp',
|
||||
]
|
||||
|
||||
qsv_va_sources = [
|
||||
'gstqsvallocator_va.cpp',
|
||||
]
|
||||
|
||||
extra_args = [
|
||||
'-DGST_USE_UNSTABLE_API',
|
||||
]
|
||||
|
||||
qsv_option = get_option('qsv')
|
||||
if qsv_option.disabled()
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
qsv_platform_deps = []
|
||||
if host_system == 'windows'
|
||||
if not gstd3d11_dep.found()
|
||||
if qsv_option.enabled()
|
||||
error('The qsv was enabled explicitly, but required d3d11 was not found')
|
||||
else
|
||||
subdir_done()
|
||||
endif
|
||||
endif
|
||||
|
||||
code = '''
|
||||
#include <windows.h>
|
||||
#if !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP))
|
||||
#error "Not building for UWP"
|
||||
#endif'''
|
||||
if cc.compiles(code, name : 'building for UWP')
|
||||
if qsv_option.enabled()
|
||||
error('qsv plugin does not support UWP')
|
||||
else
|
||||
subdir_done()
|
||||
endif
|
||||
endif
|
||||
|
||||
qsv_sources += qsv_d3d11_sources
|
||||
qsv_platform_deps += [gstd3d11_dep]
|
||||
elif host_system == 'linux' and host_machine.cpu_family() == 'x86_64'
|
||||
if not gstva_dep.found()
|
||||
if qsv_option.enabled()
|
||||
error('The qsv was enabled explicitly, but required va was not found')
|
||||
else
|
||||
subdir_done()
|
||||
endif
|
||||
endif
|
||||
qsv_sources += qsv_va_sources
|
||||
qsv_platform_deps += [gstva_dep]
|
||||
else
|
||||
if qsv_option.enabled()
|
||||
error('QSV plugin supports only Windows or Linux')
|
||||
else
|
||||
subdir_done()
|
||||
endif
|
||||
endif
|
||||
|
||||
# suppress deprecated use of MFXInitEx. We don't use the method,
|
||||
# but used in "mfxvideo++.h"
|
||||
# and MinGW 32bits compiler seems to be complaining about redundant-decls
|
||||
if cc.get_id() != 'msvc'
|
||||
extra_args += cc.get_supported_arguments([
|
||||
'-Wno-redundant-decls',
|
||||
'-Wno-deprecated-declarations',
|
||||
])
|
||||
endif
|
||||
|
||||
subdir('libmfx')
|
||||
|
||||
gstqsv = library('gstqsv',
|
||||
qsv_sources,
|
||||
c_args : gst_plugins_bad_args + extra_args,
|
||||
cpp_args : gst_plugins_bad_args + extra_args,
|
||||
include_directories : [configinc],
|
||||
dependencies : [gstbase_dep, gstvideo_dep, gstcodecparsers_dep, libmfx_internal_dep] + qsv_platform_deps,
|
||||
install : true,
|
||||
install_dir : plugins_install_dir,
|
||||
)
|
||||
|
||||
pkgconfig.generate(gstqsv, install_dir : plugins_pkgconfig_install_dir)
|
||||
plugins += [gstqsv]
|
266
subprojects/gst-plugins-bad/sys/qsv/plugin.cpp
Normal file
266
subprojects/gst-plugins-bad/sys/qsv/plugin.cpp
Normal file
|
@ -0,0 +1,266 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <mfx.h>
|
||||
#include "gstqsvutils.h"
|
||||
#include "gstqsvh264enc.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <versionhelpers.h>
|
||||
#include <gst/d3d11/gstd3d11.h>
|
||||
#else
|
||||
#include <gst/va/gstvadisplay.h>
|
||||
#include <gst/va/gstvadisplay_drm.h>
|
||||
#endif
|
||||
|
||||
GST_DEBUG_CATEGORY (gst_qsv_debug);
|
||||
GST_DEBUG_CATEGORY (gst_qsv_allocator_debug);
|
||||
GST_DEBUG_CATEGORY (gst_qsv_encoder_debug);
|
||||
GST_DEBUG_CATEGORY (gst_qsv_h264_enc_debug);
|
||||
|
||||
#define GST_CAT_DEFAULT gst_qsv_debug
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
#define MFX_ACCEL_MODE MFX_ACCEL_MODE_VIA_D3D11
|
||||
#else
|
||||
#define MFX_ACCEL_MODE MFX_ACCEL_MODE_VIA_VAAPI
|
||||
#endif
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
static mfxSession
|
||||
create_session_with_platform_device (mfxLoader loader,
|
||||
mfxImplDescription * desc, guint impl_index, GstObject ** d3d11_device,
|
||||
GList ** devices)
|
||||
{
|
||||
mfxSession session = nullptr;
|
||||
mfxStatus status;
|
||||
GstD3D11Device *selected = nullptr;
|
||||
GList *list = *devices;
|
||||
GList *iter;
|
||||
mfxU16 device_id = 0;
|
||||
|
||||
*d3d11_device = nullptr;
|
||||
|
||||
status = MFXCreateSession (loader, impl_index, &session);
|
||||
if (status != MFX_ERR_NONE) {
|
||||
GST_WARNING ("Failed to create session with index %d, %d (%s)",
|
||||
impl_index, QSV_STATUS_ARGS (status));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (desc->ApiVersion.Major >= 2 ||
|
||||
(desc->ApiVersion.Major == 1 && desc->ApiVersion.Minor >= 19)) {
|
||||
mfxPlatform platform;
|
||||
|
||||
memset (&platform, 0, sizeof (mfxPlatform));
|
||||
|
||||
if (MFXVideoCORE_QueryPlatform (session, &platform) == MFX_ERR_NONE) {
|
||||
device_id = platform.DeviceId;
|
||||
|
||||
/* XXX: re-create session, MFXVideoCORE_QueryPlatform() may cause
|
||||
* later MFXVideoCORE_SetHandle() call failed with
|
||||
* MFX_ERR_UNDEFINED_BEHAVIOR error */
|
||||
g_clear_pointer (&session, MFXClose);
|
||||
|
||||
status = MFXCreateSession (loader, impl_index, &session);
|
||||
if (status != MFX_ERR_NONE) {
|
||||
GST_WARNING ("Failed to re-create session with index %d, %d (%s)",
|
||||
impl_index, QSV_STATUS_ARGS (status));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (device_id) {
|
||||
for (iter = list; iter; iter = g_list_next (iter)) {
|
||||
GstD3D11Device *dev = GST_D3D11_DEVICE (iter->data);
|
||||
guint dev_id;
|
||||
|
||||
g_object_get (dev, "device-id", &dev_id, nullptr);
|
||||
if (dev_id == (guint) device_id) {
|
||||
selected = dev;
|
||||
list = g_list_delete_link (list, iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!selected) {
|
||||
/* Unknown device id, pick the first device */
|
||||
selected = GST_D3D11_DEVICE (list->data);
|
||||
list = g_list_delete_link (list, list);
|
||||
}
|
||||
|
||||
*devices = list;
|
||||
|
||||
status = MFXVideoCORE_SetHandle (session, MFX_HANDLE_D3D11_DEVICE,
|
||||
gst_d3d11_device_get_device_handle (selected));
|
||||
if (status != MFX_ERR_NONE) {
|
||||
GST_WARNING ("Failed to set d3d11 device handle, %d (%s)",
|
||||
QSV_STATUS_ARGS (status));
|
||||
gst_object_unref (selected);
|
||||
MFXClose (session);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*d3d11_device = GST_OBJECT (selected);
|
||||
|
||||
return session;
|
||||
}
|
||||
#else
|
||||
static mfxSession
|
||||
create_session_with_platform_device (mfxLoader loader,
|
||||
mfxImplDescription * desc, guint impl_index, GstObject ** va_display,
|
||||
GList ** devices)
|
||||
{
|
||||
mfxSession session = nullptr;
|
||||
mfxStatus status;
|
||||
GstVaDisplay *selected;
|
||||
GList *list = *devices;
|
||||
|
||||
*va_display = nullptr;
|
||||
|
||||
status = MFXCreateSession (loader, impl_index, &session);
|
||||
if (status != MFX_ERR_NONE) {
|
||||
GST_WARNING ("Failed to create session with index %d, %d (%s)",
|
||||
impl_index, QSV_STATUS_ARGS (status));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* XXX: what's the relation between implementation index and VA display ?
|
||||
* Pick the first available device for now */
|
||||
selected = GST_VA_DISPLAY (list->data);
|
||||
list = g_list_delete_link (list, list);
|
||||
*devices = list;
|
||||
|
||||
status = MFXVideoCORE_SetHandle (session, MFX_HANDLE_VA_DISPLAY,
|
||||
gst_va_display_get_va_dpy (selected));
|
||||
if (status != MFX_ERR_NONE) {
|
||||
GST_WARNING ("Failed to set display handle, %d (%s)",
|
||||
QSV_STATUS_ARGS (status));
|
||||
gst_object_unref (selected);
|
||||
MFXClose (session);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*va_display = GST_OBJECT (selected);
|
||||
|
||||
return session;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
plugin_deinit (gpointer data)
|
||||
{
|
||||
gst_qsv_deinit ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
mfxLoader loader;
|
||||
guint i = 0;
|
||||
GList *platform_devices = nullptr;
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
/* D3D11 Video API is supported since Windows 8.
|
||||
* Do we want to support old OS (Windows 7 for example) with D3D9 ?? */
|
||||
if (!IsWindows8OrGreater ())
|
||||
return TRUE;
|
||||
#endif
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (gst_qsv_debug, "qsv", 0, "Intel Quick Sync Video");
|
||||
|
||||
loader = gst_qsv_get_loader ();
|
||||
if (!loader)
|
||||
return TRUE;
|
||||
|
||||
platform_devices = gst_qsv_get_platform_devices ();
|
||||
if (!platform_devices) {
|
||||
gst_qsv_deinit ();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GST_INFO ("Found %d platform devices", g_list_length (platform_devices));
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (gst_qsv_encoder_debug,
|
||||
"qsvencoder", 0, "qsvencoder");
|
||||
GST_DEBUG_CATEGORY_INIT (gst_qsv_allocator_debug,
|
||||
"gstqsvallocator", 0, "gstqsvallocator");
|
||||
GST_DEBUG_CATEGORY_INIT (gst_qsv_h264_enc_debug,
|
||||
"qsvh264enc", 0, "qsvh264enc");
|
||||
|
||||
do {
|
||||
mfxStatus status = MFX_ERR_NONE;
|
||||
mfxSession session = nullptr;
|
||||
mfxImplDescription *desc = nullptr;
|
||||
GstObject *device = nullptr;
|
||||
|
||||
status = MFXEnumImplementations (loader,
|
||||
i, MFX_IMPLCAPS_IMPLDESCSTRUCTURE, (mfxHDL *) & desc);
|
||||
|
||||
if (status != MFX_ERR_NONE)
|
||||
break;
|
||||
|
||||
if ((desc->Impl & MFX_IMPL_TYPE_HARDWARE) == 0)
|
||||
goto next;
|
||||
|
||||
if ((desc->AccelerationMode & MFX_ACCEL_MODE) == 0)
|
||||
goto next;
|
||||
|
||||
session = create_session_with_platform_device (loader, desc, i, &device,
|
||||
&platform_devices);
|
||||
if (!session)
|
||||
goto next;
|
||||
|
||||
gst_qsv_h264_enc_register (plugin, GST_RANK_NONE, i, device, session);
|
||||
|
||||
next:
|
||||
MFXDispReleaseImplDescription (loader, desc);
|
||||
g_clear_pointer (&session, MFXClose);
|
||||
gst_clear_object (&device);
|
||||
i++;
|
||||
|
||||
/* What's the possible maximum number of impl/device ? */
|
||||
} while (i < 16 && platform_devices != nullptr);
|
||||
|
||||
if (platform_devices)
|
||||
g_list_free_full (platform_devices, (GDestroyNotify) gst_object_unref);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (plugin), "plugin-qsv-shutdown",
|
||||
(gpointer) "shutdown-data", (GDestroyNotify) plugin_deinit);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
qsv,
|
||||
"Intel Quick Sync Video plugin",
|
||||
plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
|
Loading…
Reference in a new issue