mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-02 21:48:55 +00:00
qsv: Add H.264 decoder
Initial decoder implementation with baseclass Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1786>
This commit is contained in:
parent
4de365b31c
commit
c4ac657364
12 changed files with 2303 additions and 89 deletions
|
@ -43,9 +43,7 @@ struct _GstQsvFrame
|
||||||
GstVideoInfo info;
|
GstVideoInfo info;
|
||||||
GstVideoFrame frame;
|
GstVideoFrame frame;
|
||||||
GstQsvMemoryType mem_type;
|
GstQsvMemoryType mem_type;
|
||||||
|
GstMapFlags map_flags;
|
||||||
/* For direct GPU access */
|
|
||||||
GstMapInfo map_info;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GST_DEFINE_MINI_OBJECT_TYPE (GstQsvFrame, gst_qsv_frame);
|
GST_DEFINE_MINI_OBJECT_TYPE (GstQsvFrame, gst_qsv_frame);
|
||||||
|
@ -82,11 +80,39 @@ gst_qsv_frame_peek_buffer (GstQsvFrame * frame)
|
||||||
return frame->buffer;
|
return frame->buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_qsv_frame_set_buffer (GstQsvFrame * frame, GstBuffer * buffer)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (GST_IS_QSV_FRAME (frame), FALSE);
|
||||||
|
|
||||||
|
g_mutex_lock (&frame->lock);
|
||||||
|
if (frame->buffer == buffer) {
|
||||||
|
g_mutex_unlock (&frame->lock);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame->map_count > 0) {
|
||||||
|
GST_ERROR ("frame is locked");
|
||||||
|
g_mutex_unlock (&frame->lock);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_clear_buffer (&frame->buffer);
|
||||||
|
frame->buffer = buffer;
|
||||||
|
g_mutex_unlock (&frame->lock);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
struct _GstQsvAllocatorPrivate
|
struct _GstQsvAllocatorPrivate
|
||||||
{
|
{
|
||||||
GstAtomicQueue *queue;
|
GstAtomicQueue *queue;
|
||||||
|
|
||||||
mfxFrameAllocator allocator;
|
mfxFrameAllocator allocator;
|
||||||
|
mfxFrameAllocResponse response;
|
||||||
|
guint16 extra_alloc_size;
|
||||||
|
gboolean dummy_alloc;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define gst_qsv_allocator_parent_class parent_class
|
#define gst_qsv_allocator_parent_class parent_class
|
||||||
|
@ -104,6 +130,9 @@ static mfxStatus gst_qsv_allocator_get_hdl (mfxHDL pthis, mfxMemId mid,
|
||||||
mfxHDL * handle);
|
mfxHDL * handle);
|
||||||
static mfxStatus gst_qsv_allocator_free (mfxHDL pthis,
|
static mfxStatus gst_qsv_allocator_free (mfxHDL pthis,
|
||||||
mfxFrameAllocResponse * response);
|
mfxFrameAllocResponse * response);
|
||||||
|
static GstBuffer *gst_qsv_allocator_download_default (GstQsvAllocator * self,
|
||||||
|
const GstVideoInfo * info, gboolean force_copy, GstQsvFrame * frame,
|
||||||
|
GstBufferPool * pool);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_qsv_allocator_class_init (GstQsvAllocatorClass * klass)
|
gst_qsv_allocator_class_init (GstQsvAllocatorClass * klass)
|
||||||
|
@ -111,6 +140,8 @@ gst_qsv_allocator_class_init (GstQsvAllocatorClass * klass)
|
||||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
object_class->finalize = gst_qsv_allocator_finalize;
|
object_class->finalize = gst_qsv_allocator_finalize;
|
||||||
|
|
||||||
|
klass->download = GST_DEBUG_FUNCPTR (gst_qsv_allocator_download_default);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -144,19 +175,22 @@ gst_qsv_allocator_finalize (GObject * object)
|
||||||
gst_qsv_frame_unref (frame);
|
gst_qsv_frame_unref (frame);
|
||||||
|
|
||||||
gst_atomic_queue_unref (priv->queue);
|
gst_atomic_queue_unref (priv->queue);
|
||||||
|
gst_qsv_allocator_free ((mfxHDL) self, &priv->response);
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static mfxStatus
|
static mfxStatus
|
||||||
gst_qsv_allocator_alloc_default (GstQsvAllocator * self,
|
gst_qsv_allocator_alloc_default (GstQsvAllocator * self, gboolean dummy_alloc,
|
||||||
mfxFrameAllocRequest * request, mfxFrameAllocResponse * response)
|
mfxFrameAllocRequest * request, mfxFrameAllocResponse * response)
|
||||||
{
|
{
|
||||||
GstQsvFrame **mids = nullptr;
|
GstQsvFrame **mids = nullptr;
|
||||||
GstVideoInfo info;
|
GstVideoInfo info;
|
||||||
|
GstVideoAlignment align;
|
||||||
GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
|
GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
|
||||||
|
GstBufferPool *pool;
|
||||||
GST_TRACE_OBJECT (self, "Alloc");
|
GstCaps *caps;
|
||||||
|
GstStructure *config;
|
||||||
|
|
||||||
/* Something unexpected and went wrong */
|
/* Something unexpected and went wrong */
|
||||||
if ((request->Type & MFX_MEMTYPE_SYSTEM_MEMORY) == 0) {
|
if ((request->Type & MFX_MEMTYPE_SYSTEM_MEMORY) == 0) {
|
||||||
|
@ -194,19 +228,96 @@ gst_qsv_allocator_alloc_default (GstQsvAllocator * self,
|
||||||
response->NumFrameActual = request->NumFrameSuggested;
|
response->NumFrameActual = request->NumFrameSuggested;
|
||||||
|
|
||||||
gst_video_info_set_format (&info,
|
gst_video_info_set_format (&info,
|
||||||
format, request->Info.Width, request->Info.Height);
|
format, request->Info.CropW, request->Info.CropH);
|
||||||
for (guint i = 0; i < request->NumFrameSuggested; i++) {
|
|
||||||
GstBuffer *buffer;
|
|
||||||
|
|
||||||
buffer = gst_buffer_new_and_alloc (info.size);
|
if (dummy_alloc) {
|
||||||
|
for (guint i = 0; i < request->NumFrameSuggested; i++) {
|
||||||
mids[i] = gst_qsv_allocator_acquire_frame (self,
|
mids[i] = gst_qsv_allocator_acquire_frame (self,
|
||||||
GST_QSV_SYSTEM_MEMORY, &info, buffer, nullptr);
|
GST_QSV_SYSTEM_MEMORY, &info, nullptr, nullptr);
|
||||||
gst_buffer_unref (buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
response->mids = (mfxMemId *) mids;
|
response->mids = (mfxMemId *) mids;
|
||||||
|
|
||||||
return MFX_ERR_NONE;
|
return MFX_ERR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
caps = gst_video_info_to_caps (&info);
|
||||||
|
if (!caps) {
|
||||||
|
GST_ERROR_OBJECT (self, "Failed to convert video-info to caps");
|
||||||
|
return MFX_ERR_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_video_alignment_reset (&align);
|
||||||
|
align.padding_right = request->Info.Width - request->Info.CropW;
|
||||||
|
align.padding_bottom = request->Info.Height - request->Info.CropH;
|
||||||
|
|
||||||
|
pool = gst_video_buffer_pool_new ();
|
||||||
|
config = gst_buffer_pool_get_config (pool);
|
||||||
|
gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
|
||||||
|
gst_buffer_pool_config_add_option (config,
|
||||||
|
GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
|
||||||
|
gst_buffer_pool_config_set_video_alignment (config, &align);
|
||||||
|
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);
|
||||||
|
|
||||||
|
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 (self,
|
||||||
|
GST_QSV_SYSTEM_MEMORY, &info, buffer, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 gboolean
|
||||||
|
gst_qsv_allocator_copy_cached_response (GstQsvAllocator * self,
|
||||||
|
mfxFrameAllocResponse * dst, mfxFrameAllocResponse * src)
|
||||||
|
{
|
||||||
|
GstQsvFrame **mids;
|
||||||
|
|
||||||
|
if (src->NumFrameActual == 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
mids = g_new0 (GstQsvFrame *, src->NumFrameActual);
|
||||||
|
|
||||||
|
for (guint i = 0; i < src->NumFrameActual; i++) {
|
||||||
|
GstQsvFrame *frame = (GstQsvFrame *) src->mids[i];
|
||||||
|
|
||||||
|
mids[i] = gst_qsv_frame_ref (frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
dst->NumFrameActual = src->NumFrameActual;
|
||||||
|
dst->mids = (mfxMemId *) mids;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static mfxStatus
|
static mfxStatus
|
||||||
|
@ -214,16 +325,52 @@ gst_qsv_allocator_alloc (mfxHDL pthis,
|
||||||
mfxFrameAllocRequest * request, mfxFrameAllocResponse * response)
|
mfxFrameAllocRequest * request, mfxFrameAllocResponse * response)
|
||||||
{
|
{
|
||||||
GstQsvAllocator *self = GST_QSV_ALLOCATOR (pthis);
|
GstQsvAllocator *self = GST_QSV_ALLOCATOR (pthis);
|
||||||
|
GstQsvAllocatorPrivate *priv = self->priv;
|
||||||
GstQsvAllocatorClass *klass;
|
GstQsvAllocatorClass *klass;
|
||||||
|
mfxStatus status;
|
||||||
|
mfxFrameAllocRequest req = *request;
|
||||||
|
gboolean dummy_alloc = priv->dummy_alloc;
|
||||||
|
|
||||||
if ((request->Type & MFX_MEMTYPE_SYSTEM_MEMORY) != 0)
|
GST_INFO_OBJECT (self, "Alloc, Request Type: 0x%x, %dx%d (%dx%d)",
|
||||||
return gst_qsv_allocator_alloc_default (self, request, response);
|
req.Type, req.Info.Width, req.Info.Height,
|
||||||
|
req.Info.CropW, req.Info.CropH);
|
||||||
|
|
||||||
|
/* Apply extra_alloc_size only for GST internal use case */
|
||||||
|
if ((request->Type & MFX_MEMTYPE_EXTERNAL_FRAME) != 0)
|
||||||
|
req.NumFrameSuggested += priv->extra_alloc_size;
|
||||||
|
|
||||||
|
if (req.Info.CropW == 0 || req.Info.CropH == 0) {
|
||||||
|
req.Info.CropW = req.Info.Width;
|
||||||
|
req.Info.CropH = req.Info.Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->Info.FourCC == MFX_FOURCC_P8 ||
|
||||||
|
(request->Type & MFX_MEMTYPE_EXTERNAL_FRAME) == 0) {
|
||||||
|
dummy_alloc = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_INFO_OBJECT (self, "Dummy alloc %d", dummy_alloc);
|
||||||
|
|
||||||
|
if ((request->Type & MFX_MEMTYPE_SYSTEM_MEMORY) != 0) {
|
||||||
|
status = gst_qsv_allocator_alloc_default (self,
|
||||||
|
dummy_alloc, &req, response);
|
||||||
|
} else {
|
||||||
klass = GST_QSV_ALLOCATOR_GET_CLASS (self);
|
klass = GST_QSV_ALLOCATOR_GET_CLASS (self);
|
||||||
|
|
||||||
g_assert (klass->alloc);
|
g_assert (klass->alloc);
|
||||||
|
|
||||||
return klass->alloc (self, request, response);
|
status = klass->alloc (self, dummy_alloc, &req, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != MFX_ERR_NONE)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
/* Cache this respons so that this can be accessible from GST side */
|
||||||
|
if (dummy_alloc) {
|
||||||
|
gst_qsv_allocator_free ((mfxHDL) self, &priv->response);
|
||||||
|
gst_qsv_allocator_copy_cached_response (self, &priv->response, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return MFX_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static mfxStatus
|
static mfxStatus
|
||||||
|
@ -236,9 +383,15 @@ gst_qsv_allocator_lock (mfxHDL pthis, mfxMemId mid, mfxFrameData * ptr)
|
||||||
GST_TRACE_OBJECT (self, "Lock mfxMemId %p", mid);
|
GST_TRACE_OBJECT (self, "Lock mfxMemId %p", mid);
|
||||||
|
|
||||||
g_mutex_lock (&frame->lock);
|
g_mutex_lock (&frame->lock);
|
||||||
|
if (!frame->buffer) {
|
||||||
|
GST_ERROR_OBJECT (self, "MemId %p doesn't hold buffer", mid);
|
||||||
|
g_mutex_unlock (&frame->lock);
|
||||||
|
return MFX_ERR_LOCK_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
if (frame->map_count == 0) {
|
if (frame->map_count == 0) {
|
||||||
gst_video_frame_map (&frame->frame, &frame->info, frame->buffer,
|
gst_video_frame_map (&frame->frame, &frame->info, frame->buffer,
|
||||||
GST_MAP_READ);
|
(GstMapFlags) GST_MAP_READWRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
frame->map_count++;
|
frame->map_count++;
|
||||||
|
@ -303,15 +456,26 @@ gst_qsv_allocator_get_hdl (mfxHDL pthis, mfxMemId mid, mfxHDL * handle)
|
||||||
{
|
{
|
||||||
GstQsvAllocator *self = GST_QSV_ALLOCATOR (pthis);
|
GstQsvAllocator *self = GST_QSV_ALLOCATOR (pthis);
|
||||||
GstQsvFrame *frame = GST_QSV_FRAME_CAST (mid);
|
GstQsvFrame *frame = GST_QSV_FRAME_CAST (mid);
|
||||||
|
GstMapInfo map_info;
|
||||||
|
|
||||||
if (frame->mem_type != GST_QSV_VIDEO_MEMORY) {
|
if (!GST_QSV_MEM_TYPE_IS_VIDEO (frame->mem_type)) {
|
||||||
GST_ERROR_OBJECT (self, "Unexpected call");
|
GST_ERROR_OBJECT (self, "Unexpected call");
|
||||||
|
return MFX_ERR_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_mutex_lock (&frame->lock);
|
||||||
|
if (!frame->buffer) {
|
||||||
|
GST_ERROR_OBJECT (self, "MemId %p doesn't hold buffer", mid);
|
||||||
|
g_mutex_unlock (&frame->lock);
|
||||||
|
|
||||||
return MFX_ERR_UNSUPPORTED;
|
return MFX_ERR_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!frame->map_info.data) {
|
g_assert ((frame->map_flags & GST_MAP_QSV) != 0);
|
||||||
GST_ERROR_OBJECT (self, "No mapped data");
|
if (!gst_buffer_map (frame->buffer, &map_info, frame->map_flags)) {
|
||||||
|
GST_ERROR_OBJECT (self, "Failed to map buffer");
|
||||||
|
g_mutex_unlock (&frame->lock);
|
||||||
|
|
||||||
return MFX_ERR_UNSUPPORTED;
|
return MFX_ERR_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,14 +483,18 @@ gst_qsv_allocator_get_hdl (mfxHDL pthis, mfxMemId mid, mfxHDL * handle)
|
||||||
|
|
||||||
#ifdef G_OS_WIN32
|
#ifdef G_OS_WIN32
|
||||||
mfxHDLPair *pair = (mfxHDLPair *) handle;
|
mfxHDLPair *pair = (mfxHDLPair *) handle;
|
||||||
pair->first = (mfxHDL) frame->map_info.data;
|
pair->first = (mfxHDL) map_info.data;
|
||||||
|
|
||||||
/* GstD3D11 will fill user_data[0] with subresource index */
|
/* GstD3D11 will fill user_data[0] with subresource index */
|
||||||
pair->second = (mfxHDL) frame->map_info.user_data[0];
|
pair->second = (mfxHDL) map_info.user_data[0];
|
||||||
#else
|
#else
|
||||||
*handle = (mfxHDL) frame->map_info.data;
|
*handle = (mfxHDL) map_info.data;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* XXX: Ideally we should unmap only when this surface is unlocked... */
|
||||||
|
gst_buffer_unmap (frame->buffer, &map_info);
|
||||||
|
g_mutex_unlock (&frame->lock);
|
||||||
|
|
||||||
return MFX_ERR_NONE;
|
return MFX_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,6 +507,7 @@ gst_qsv_allocator_free (mfxHDL pthis, mfxFrameAllocResponse * response)
|
||||||
gst_clear_qsv_frame (&frames[i]);
|
gst_clear_qsv_frame (&frames[i]);
|
||||||
|
|
||||||
g_clear_pointer (&response->mids, g_free);
|
g_clear_pointer (&response->mids, g_free);
|
||||||
|
response->NumFrameActual = 0;
|
||||||
|
|
||||||
return MFX_ERR_NONE;
|
return MFX_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
@ -354,14 +523,9 @@ gst_qsv_frame_release (GstQsvFrame * frame)
|
||||||
gst_video_frame_unmap (&frame->frame);
|
gst_video_frame_unmap (&frame->frame);
|
||||||
}
|
}
|
||||||
frame->map_count = 0;
|
frame->map_count = 0;
|
||||||
|
gst_clear_buffer (&frame->buffer);
|
||||||
g_mutex_unlock (&frame->lock);
|
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;
|
GST_MINI_OBJECT_CAST (frame)->dispose = nullptr;
|
||||||
frame->allocator = nullptr;
|
frame->allocator = nullptr;
|
||||||
|
|
||||||
|
@ -451,7 +615,7 @@ gst_qsv_allocator_upload_default (GstQsvAllocator * allocator,
|
||||||
* @allocator: a #GstQsvAllocator
|
* @allocator: a #GstQsvAllocator
|
||||||
* @mem_type: a memory type
|
* @mem_type: a memory type
|
||||||
* @info: a #GstVideoInfo
|
* @info: a #GstVideoInfo
|
||||||
* @buffer: (transfer none): a #GstBuffer
|
* @buffer: (nullable) (transfer full): a #GstBuffer
|
||||||
* @pool: (nullable): a #GstBufferPool
|
* @pool: (nullable): a #GstBufferPool
|
||||||
*
|
*
|
||||||
* Uploads @buffer to video memory if required, and wraps GstBuffer using
|
* Uploads @buffer to video memory if required, and wraps GstBuffer using
|
||||||
|
@ -467,9 +631,32 @@ gst_qsv_allocator_acquire_frame (GstQsvAllocator * allocator,
|
||||||
{
|
{
|
||||||
GstQsvAllocatorPrivate *priv;
|
GstQsvAllocatorPrivate *priv;
|
||||||
GstQsvFrame *frame;
|
GstQsvFrame *frame;
|
||||||
|
guint32 map_flags = 0;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_QSV_ALLOCATOR (allocator), nullptr);
|
g_return_val_if_fail (GST_IS_QSV_ALLOCATOR (allocator), nullptr);
|
||||||
|
|
||||||
|
if (GST_QSV_MEM_TYPE_IS_SYSTEM (mem_type) &&
|
||||||
|
GST_QSV_MEM_TYPE_IS_VIDEO (mem_type)) {
|
||||||
|
GST_ERROR_OBJECT (allocator, "Invalid memory type");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GST_QSV_MEM_TYPE_IS_VIDEO (mem_type)) {
|
||||||
|
map_flags = GST_MAP_QSV;
|
||||||
|
|
||||||
|
if ((mem_type & GST_QSV_ENCODER_IN_MEMORY) != 0) {
|
||||||
|
map_flags |= GST_MAP_READ;
|
||||||
|
} else if ((mem_type & GST_QSV_DECODER_OUT_MEMORY) != 0) {
|
||||||
|
map_flags |= GST_MAP_WRITE;
|
||||||
|
} else {
|
||||||
|
GST_ERROR_OBJECT (allocator,
|
||||||
|
"Unknown read/write access for video memory");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
map_flags = GST_MAP_READWRITE;
|
||||||
|
}
|
||||||
|
|
||||||
priv = allocator->priv;
|
priv = allocator->priv;
|
||||||
frame = (GstQsvFrame *) gst_atomic_queue_pop (priv->queue);
|
frame = (GstQsvFrame *) gst_atomic_queue_pop (priv->queue);
|
||||||
|
|
||||||
|
@ -477,17 +664,19 @@ gst_qsv_allocator_acquire_frame (GstQsvAllocator * allocator,
|
||||||
frame = gst_qsv_frame_new ();
|
frame = gst_qsv_frame_new ();
|
||||||
|
|
||||||
frame->mem_type = mem_type;
|
frame->mem_type = mem_type;
|
||||||
|
frame->map_flags = (GstMapFlags) map_flags;
|
||||||
|
frame->info = *info;
|
||||||
|
|
||||||
|
if (!pool) {
|
||||||
|
frame->buffer = buffer;
|
||||||
|
} else if (buffer) {
|
||||||
|
GstBuffer *upload_buf;
|
||||||
|
|
||||||
frame->allocator = (GstQsvAllocator *) gst_object_ref (allocator);
|
frame->allocator = (GstQsvAllocator *) gst_object_ref (allocator);
|
||||||
GST_MINI_OBJECT_CAST (frame)->dispose =
|
GST_MINI_OBJECT_CAST (frame)->dispose =
|
||||||
(GstMiniObjectDisposeFunction) gst_qsv_frame_dispose;
|
(GstMiniObjectDisposeFunction) gst_qsv_frame_dispose;
|
||||||
|
|
||||||
if (!pool) {
|
if (GST_QSV_MEM_TYPE_IS_SYSTEM (mem_type)) {
|
||||||
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,
|
upload_buf = gst_qsv_allocator_upload_default (allocator, info, buffer,
|
||||||
pool);
|
pool);
|
||||||
} else {
|
} else {
|
||||||
|
@ -499,6 +688,8 @@ gst_qsv_allocator_acquire_frame (GstQsvAllocator * allocator,
|
||||||
upload_buf = klass->upload (allocator, info, buffer, pool);
|
upload_buf = klass->upload (allocator, info, buffer, pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gst_buffer_unref (buffer);
|
||||||
|
|
||||||
if (!upload_buf) {
|
if (!upload_buf) {
|
||||||
GST_WARNING_OBJECT (allocator, "Failed to upload buffer");
|
GST_WARNING_OBJECT (allocator, "Failed to upload buffer");
|
||||||
gst_qsv_frame_unref (frame);
|
gst_qsv_frame_unref (frame);
|
||||||
|
@ -507,25 +698,85 @@ gst_qsv_allocator_acquire_frame (GstQsvAllocator * allocator,
|
||||||
}
|
}
|
||||||
|
|
||||||
frame->buffer = upload_buf;
|
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;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstBuffer *
|
||||||
|
gst_qsv_allocator_download_default (GstQsvAllocator * self,
|
||||||
|
const GstVideoInfo * info, gboolean force_copy, GstQsvFrame * frame,
|
||||||
|
GstBufferPool * pool)
|
||||||
|
{
|
||||||
|
GstBuffer *buffer = nullptr;
|
||||||
|
GstFlowReturn ret;
|
||||||
|
GstVideoFrame dst_frame;
|
||||||
|
mfxStatus status;
|
||||||
|
mfxFrameData dummy;
|
||||||
|
gboolean copy_ret;
|
||||||
|
|
||||||
|
GST_TRACE_OBJECT (self, "Download");
|
||||||
|
|
||||||
|
if (!force_copy)
|
||||||
|
return gst_buffer_ref (frame->buffer);
|
||||||
|
|
||||||
|
ret = gst_buffer_pool_acquire_buffer (pool, &buffer, nullptr);
|
||||||
|
if (ret != GST_FLOW_OK) {
|
||||||
|
GST_WARNING_OBJECT (self, "Failed to acquire buffer");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use gst_qsv_allocator_lock() instead of gst_video_frame_map() to avoid
|
||||||
|
* redundant map if it's already locked by driver, already locked by driver
|
||||||
|
* sounds unsafe situaltion though */
|
||||||
|
status = gst_qsv_allocator_lock ((mfxHDL) self, (mfxMemId) frame, &dummy);
|
||||||
|
if (status != MFX_ERR_NONE) {
|
||||||
|
gst_buffer_unref (buffer);
|
||||||
|
GST_ERROR_OBJECT (self, "Failed to lock frame");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gst_video_frame_map (&dst_frame, &frame->info, buffer, GST_MAP_WRITE)) {
|
||||||
|
gst_qsv_allocator_unlock ((mfxHDL) self, (mfxMemId) frame, &dummy);
|
||||||
|
gst_buffer_unref (buffer);
|
||||||
|
GST_ERROR_OBJECT (self, "Failed to map output buffer");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_ret = gst_video_frame_copy (&dst_frame, &frame->frame);
|
||||||
|
gst_qsv_allocator_unlock ((mfxHDL) self, (mfxMemId) frame, &dummy);
|
||||||
|
gst_video_frame_unmap (&dst_frame);
|
||||||
|
|
||||||
|
if (!copy_ret) {
|
||||||
|
GST_ERROR_OBJECT (self, "Failed to copy frame");
|
||||||
|
gst_buffer_unref (buffer);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
GstBuffer *
|
||||||
|
gst_qsv_allocator_download_frame (GstQsvAllocator * allocator,
|
||||||
|
gboolean force_copy, GstQsvFrame * frame, GstBufferPool * pool)
|
||||||
|
{
|
||||||
|
GstQsvAllocatorClass *klass;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_QSV_ALLOCATOR (allocator), nullptr);
|
||||||
|
g_return_val_if_fail (GST_IS_QSV_FRAME (frame), nullptr);
|
||||||
|
g_return_val_if_fail (GST_IS_BUFFER_POOL (pool), nullptr);
|
||||||
|
|
||||||
|
if (GST_QSV_MEM_TYPE_IS_SYSTEM (frame->mem_type)) {
|
||||||
|
return gst_qsv_allocator_download_default (allocator, &frame->info,
|
||||||
|
force_copy, frame, pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
klass = GST_QSV_ALLOCATOR_GET_CLASS (allocator);
|
||||||
|
g_assert (klass->download);
|
||||||
|
|
||||||
|
return klass->download (allocator, &frame->info, force_copy, frame, pool);
|
||||||
|
}
|
||||||
|
|
||||||
mfxFrameAllocator *
|
mfxFrameAllocator *
|
||||||
gst_qsv_allocator_get_allocator_handle (GstQsvAllocator * allocator)
|
gst_qsv_allocator_get_allocator_handle (GstQsvAllocator * allocator)
|
||||||
{
|
{
|
||||||
|
@ -533,3 +784,23 @@ gst_qsv_allocator_get_allocator_handle (GstQsvAllocator * allocator)
|
||||||
|
|
||||||
return &allocator->priv->allocator;
|
return &allocator->priv->allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_qsv_allocator_get_cached_response (GstQsvAllocator * allocator,
|
||||||
|
mfxFrameAllocResponse * response)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (GST_IS_QSV_ALLOCATOR (allocator), FALSE);
|
||||||
|
|
||||||
|
return gst_qsv_allocator_copy_cached_response (allocator,
|
||||||
|
response, &allocator->priv->response);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_qsv_allocator_set_options (GstQsvAllocator * allocator,
|
||||||
|
guint16 extra_alloc_size, gboolean dummy_alloc)
|
||||||
|
{
|
||||||
|
g_return_if_fail (GST_IS_QSV_ALLOCATOR (allocator));
|
||||||
|
|
||||||
|
allocator->priv->extra_alloc_size = extra_alloc_size;
|
||||||
|
allocator->priv->dummy_alloc = dummy_alloc;
|
||||||
|
}
|
||||||
|
|
|
@ -46,6 +46,9 @@ GType gst_qsv_frame_get_type (void);
|
||||||
|
|
||||||
GstBuffer * gst_qsv_frame_peek_buffer (GstQsvFrame * frame);
|
GstBuffer * gst_qsv_frame_peek_buffer (GstQsvFrame * frame);
|
||||||
|
|
||||||
|
gboolean gst_qsv_frame_set_buffer (GstQsvFrame * frame,
|
||||||
|
GstBuffer * buffer);
|
||||||
|
|
||||||
static inline GstQsvFrame *
|
static inline GstQsvFrame *
|
||||||
gst_qsv_frame_ref (GstQsvFrame * frame)
|
gst_qsv_frame_ref (GstQsvFrame * frame)
|
||||||
{
|
{
|
||||||
|
@ -66,10 +69,15 @@ gst_clear_qsv_frame (GstQsvFrame ** frame)
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
GST_QSV_SYSTEM_MEMORY,
|
GST_QSV_SYSTEM_MEMORY = (1 << 0),
|
||||||
GST_QSV_VIDEO_MEMORY,
|
GST_QSV_VIDEO_MEMORY = (1 << 1),
|
||||||
|
GST_QSV_ENCODER_IN_MEMORY = (1 << 2),
|
||||||
|
GST_QSV_DECODER_OUT_MEMORY = (1 << 3),
|
||||||
} GstQsvMemoryType;
|
} GstQsvMemoryType;
|
||||||
|
|
||||||
|
#define GST_QSV_MEM_TYPE_IS_SYSTEM(type) ((type & GST_QSV_SYSTEM_MEMORY) != 0)
|
||||||
|
#define GST_QSV_MEM_TYPE_IS_VIDEO(type) ((type & GST_QSV_VIDEO_MEMORY) != 0)
|
||||||
|
|
||||||
struct _GstQsvAllocator
|
struct _GstQsvAllocator
|
||||||
{
|
{
|
||||||
GstObject parent;
|
GstObject parent;
|
||||||
|
@ -82,6 +90,7 @@ struct _GstQsvAllocatorClass
|
||||||
GstObjectClass parent_class;
|
GstObjectClass parent_class;
|
||||||
|
|
||||||
mfxStatus (*alloc) (GstQsvAllocator * allocator,
|
mfxStatus (*alloc) (GstQsvAllocator * allocator,
|
||||||
|
gboolean dummy_alloc,
|
||||||
mfxFrameAllocRequest * request,
|
mfxFrameAllocRequest * request,
|
||||||
mfxFrameAllocResponse * response);
|
mfxFrameAllocResponse * response);
|
||||||
|
|
||||||
|
@ -89,6 +98,12 @@ struct _GstQsvAllocatorClass
|
||||||
const GstVideoInfo * info,
|
const GstVideoInfo * info,
|
||||||
GstBuffer * buffer,
|
GstBuffer * buffer,
|
||||||
GstBufferPool * pool);
|
GstBufferPool * pool);
|
||||||
|
|
||||||
|
GstBuffer * (*download) (GstQsvAllocator * allocator,
|
||||||
|
const GstVideoInfo * info,
|
||||||
|
gboolean force_copy,
|
||||||
|
GstQsvFrame * frame,
|
||||||
|
GstBufferPool * pool);
|
||||||
};
|
};
|
||||||
|
|
||||||
GType gst_qsv_allocator_get_type (void);
|
GType gst_qsv_allocator_get_type (void);
|
||||||
|
@ -99,8 +114,35 @@ GstQsvFrame * gst_qsv_allocator_acquire_frame (GstQsvAllocator * allocat
|
||||||
GstBuffer * buffer,
|
GstBuffer * buffer,
|
||||||
GstBufferPool * pool);
|
GstBufferPool * pool);
|
||||||
|
|
||||||
|
GstBuffer * gst_qsv_allocator_download_frame (GstQsvAllocator * allocator,
|
||||||
|
gboolean force_copy,
|
||||||
|
GstQsvFrame * frame,
|
||||||
|
GstBufferPool * pool);
|
||||||
|
|
||||||
mfxFrameAllocator * gst_qsv_allocator_get_allocator_handle (GstQsvAllocator * allocator);
|
mfxFrameAllocator * gst_qsv_allocator_get_allocator_handle (GstQsvAllocator * allocator);
|
||||||
|
|
||||||
|
gboolean gst_qsv_allocator_get_cached_response (GstQsvAllocator * allocator,
|
||||||
|
mfxFrameAllocResponse * response);
|
||||||
|
|
||||||
|
void gst_qsv_allocator_set_options (GstQsvAllocator * allocator,
|
||||||
|
guint16 extra_alloc_size,
|
||||||
|
gboolean dummy_alloc);
|
||||||
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstQsvAllocator, gst_object_unref)
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstQsvAllocator, gst_object_unref)
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
inline GstQsvMemoryType
|
||||||
|
operator | (const GstQsvMemoryType & lhs, const GstQsvMemoryType & rhs)
|
||||||
|
{
|
||||||
|
return static_cast<GstQsvMemoryType> (static_cast<guint>(lhs) |
|
||||||
|
static_cast<guint> (rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline GstQsvMemoryType &
|
||||||
|
operator |= (GstQsvMemoryType & lhs, const GstQsvMemoryType & rhs)
|
||||||
|
{
|
||||||
|
return lhs = lhs | rhs;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -40,9 +40,13 @@ G_DEFINE_TYPE (GstQsvD3D11Allocator, gst_qsv_d3d11_allocator,
|
||||||
|
|
||||||
static void gst_qsv_d3d11_allocator_dispose (GObject * object);
|
static void gst_qsv_d3d11_allocator_dispose (GObject * object);
|
||||||
static mfxStatus gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator,
|
static mfxStatus gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator,
|
||||||
mfxFrameAllocRequest * request, mfxFrameAllocResponse * response);
|
gboolean dummy_alloc, mfxFrameAllocRequest * request,
|
||||||
|
mfxFrameAllocResponse * response);
|
||||||
static GstBuffer *gst_qsv_d3d11_allocator_upload (GstQsvAllocator * allocator,
|
static GstBuffer *gst_qsv_d3d11_allocator_upload (GstQsvAllocator * allocator,
|
||||||
const GstVideoInfo * info, GstBuffer * buffer, GstBufferPool * pool);
|
const GstVideoInfo * info, GstBuffer * buffer, GstBufferPool * pool);
|
||||||
|
static GstBuffer *gst_qsv_d3d11_allocator_download (GstQsvAllocator * allocator,
|
||||||
|
const GstVideoInfo * info, gboolean force_copy, GstQsvFrame * frame,
|
||||||
|
GstBufferPool * pool);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_qsv_d3d11_allocator_class_init (GstQsvD3D11AllocatorClass * klass)
|
gst_qsv_d3d11_allocator_class_init (GstQsvD3D11AllocatorClass * klass)
|
||||||
|
@ -54,6 +58,7 @@ gst_qsv_d3d11_allocator_class_init (GstQsvD3D11AllocatorClass * klass)
|
||||||
|
|
||||||
alloc_class->alloc = GST_DEBUG_FUNCPTR (gst_qsv_d3d11_allocator_alloc);
|
alloc_class->alloc = GST_DEBUG_FUNCPTR (gst_qsv_d3d11_allocator_alloc);
|
||||||
alloc_class->upload = GST_DEBUG_FUNCPTR (gst_qsv_d3d11_allocator_upload);
|
alloc_class->upload = GST_DEBUG_FUNCPTR (gst_qsv_d3d11_allocator_upload);
|
||||||
|
alloc_class->download = GST_DEBUG_FUNCPTR (gst_qsv_d3d11_allocator_download);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -73,14 +78,13 @@ gst_qsv_d3d11_allocator_dispose (GObject * object)
|
||||||
|
|
||||||
static mfxStatus
|
static mfxStatus
|
||||||
gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator,
|
gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator,
|
||||||
mfxFrameAllocRequest * request, mfxFrameAllocResponse * response)
|
gboolean dummy_alloc, mfxFrameAllocRequest * request,
|
||||||
|
mfxFrameAllocResponse * response)
|
||||||
{
|
{
|
||||||
GstQsvD3D11Allocator *self = GST_QSV_D3D11_ALLOCATOR (allocator);
|
GstQsvD3D11Allocator *self = GST_QSV_D3D11_ALLOCATOR (allocator);
|
||||||
DXGI_FORMAT dxgi_format = DXGI_FORMAT_UNKNOWN;
|
DXGI_FORMAT dxgi_format = DXGI_FORMAT_UNKNOWN;
|
||||||
GstQsvFrame **mids = nullptr;
|
GstQsvFrame **mids = nullptr;
|
||||||
|
|
||||||
GST_TRACE_OBJECT (self, "Alloc");
|
|
||||||
|
|
||||||
/* Something unexpected and went wrong */
|
/* Something unexpected and went wrong */
|
||||||
if ((request->Type & MFX_MEMTYPE_SYSTEM_MEMORY) != 0) {
|
if ((request->Type & MFX_MEMTYPE_SYSTEM_MEMORY) != 0) {
|
||||||
GST_ERROR_OBJECT (self,
|
GST_ERROR_OBJECT (self,
|
||||||
|
@ -143,7 +147,6 @@ gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator,
|
||||||
|
|
||||||
if (!mem) {
|
if (!mem) {
|
||||||
GST_ERROR_OBJECT (self, "Failed to allocate buffer");
|
GST_ERROR_OBJECT (self, "Failed to allocate buffer");
|
||||||
|
|
||||||
return MFX_ERR_MEMORY_ALLOC;
|
return MFX_ERR_MEMORY_ALLOC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,8 +163,8 @@ gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator,
|
||||||
mids = g_new0 (GstQsvFrame *, 1);
|
mids = g_new0 (GstQsvFrame *, 1);
|
||||||
response->NumFrameActual = 1;
|
response->NumFrameActual = 1;
|
||||||
mids[0] = gst_qsv_allocator_acquire_frame (allocator,
|
mids[0] = gst_qsv_allocator_acquire_frame (allocator,
|
||||||
GST_QSV_VIDEO_MEMORY, &info, buffer, nullptr);
|
GST_QSV_VIDEO_MEMORY | GST_QSV_ENCODER_IN_MEMORY, &info, buffer,
|
||||||
gst_buffer_unref (buffer);
|
nullptr);
|
||||||
} else {
|
} else {
|
||||||
GstBufferPool *pool;
|
GstBufferPool *pool;
|
||||||
GstVideoFormat format;
|
GstVideoFormat format;
|
||||||
|
@ -170,19 +173,53 @@ gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator,
|
||||||
GstStructure *config;
|
GstStructure *config;
|
||||||
GstD3D11AllocationParams *params;
|
GstD3D11AllocationParams *params;
|
||||||
guint bind_flags = 0;
|
guint bind_flags = 0;
|
||||||
|
GstVideoAlignment align;
|
||||||
|
GstQsvMemoryType mem_type = GST_QSV_VIDEO_MEMORY;
|
||||||
|
|
||||||
if ((request->Type & MFX_MEMTYPE_VIDEO_MEMORY_ENCODER_TARGET) != 0)
|
if ((request->Type & MFX_MEMTYPE_VIDEO_MEMORY_ENCODER_TARGET) != 0) {
|
||||||
bind_flags |= D3D11_BIND_VIDEO_ENCODER;
|
bind_flags |= D3D11_BIND_VIDEO_ENCODER;
|
||||||
|
mem_type |= GST_QSV_ENCODER_IN_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((request->Type & MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET) != 0) {
|
||||||
|
bind_flags |= D3D11_BIND_DECODER;
|
||||||
|
mem_type |= GST_QSV_DECODER_OUT_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mem_type == GST_QSV_VIDEO_MEMORY) {
|
||||||
|
GST_ERROR_OBJECT (self, "Unknown read/write access");
|
||||||
|
return MFX_ERR_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
mids = g_new0 (GstQsvFrame *, request->NumFrameSuggested);
|
||||||
|
response->NumFrameActual = request->NumFrameSuggested;
|
||||||
|
|
||||||
format = gst_d3d11_dxgi_format_to_gst (dxgi_format);
|
format = gst_d3d11_dxgi_format_to_gst (dxgi_format);
|
||||||
gst_video_info_set_format (&info,
|
gst_video_info_set_format (&info,
|
||||||
format, request->Info.Width, request->Info.Height);
|
format, request->Info.CropW, request->Info.CropH);
|
||||||
|
|
||||||
|
if (dummy_alloc) {
|
||||||
|
for (guint i = 0; i < request->NumFrameSuggested; i++) {
|
||||||
|
mids[i] = gst_qsv_allocator_acquire_frame (allocator,
|
||||||
|
mem_type, &info, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
response->mids = (mfxMemId *) mids;
|
||||||
|
|
||||||
|
return MFX_ERR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
caps = gst_video_info_to_caps (&info);
|
caps = gst_video_info_to_caps (&info);
|
||||||
|
gst_video_alignment_reset (&align);
|
||||||
|
align.padding_right = request->Info.Width - request->Info.CropW;
|
||||||
|
align.padding_bottom = request->Info.Height - request->Info.CropH;
|
||||||
|
|
||||||
pool = gst_d3d11_buffer_pool_new (self->device);
|
pool = gst_d3d11_buffer_pool_new (self->device);
|
||||||
params = gst_d3d11_allocation_params_new (self->device, &info,
|
params = gst_d3d11_allocation_params_new (self->device, &info,
|
||||||
(GstD3D11AllocationFlags) 0, bind_flags);
|
(GstD3D11AllocationFlags) 0, bind_flags);
|
||||||
|
|
||||||
|
gst_d3d11_allocation_params_alignment (params, &align);
|
||||||
|
|
||||||
config = gst_buffer_pool_get_config (pool);
|
config = gst_buffer_pool_get_config (pool);
|
||||||
gst_buffer_pool_config_set_d3d11_allocation_params (config, params);
|
gst_buffer_pool_config_set_d3d11_allocation_params (config, params);
|
||||||
gst_d3d11_allocation_params_free (params);
|
gst_d3d11_allocation_params_free (params);
|
||||||
|
@ -192,8 +229,6 @@ gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator,
|
||||||
gst_buffer_pool_set_config (pool, config);
|
gst_buffer_pool_set_config (pool, config);
|
||||||
gst_buffer_pool_set_active (pool, TRUE);
|
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++) {
|
for (guint i = 0; i < request->NumFrameSuggested; i++) {
|
||||||
GstBuffer *buffer;
|
GstBuffer *buffer;
|
||||||
|
|
||||||
|
@ -206,9 +241,9 @@ gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator,
|
||||||
}
|
}
|
||||||
|
|
||||||
mids[i] = gst_qsv_allocator_acquire_frame (allocator,
|
mids[i] = gst_qsv_allocator_acquire_frame (allocator,
|
||||||
GST_QSV_VIDEO_MEMORY, &info, buffer, nullptr);
|
mem_type, &info, buffer, nullptr);
|
||||||
gst_buffer_unref (buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_buffer_pool_set_active (pool, FALSE);
|
gst_buffer_pool_set_active (pool, FALSE);
|
||||||
gst_object_unref (pool);
|
gst_object_unref (pool);
|
||||||
}
|
}
|
||||||
|
@ -409,6 +444,70 @@ gst_qsv_d3d11_allocator_upload (GstQsvAllocator * allocator,
|
||||||
return gst_qsv_frame_copy_d3d11 (info, buffer, dst_buf);
|
return gst_qsv_frame_copy_d3d11 (info, buffer, dst_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstBuffer *
|
||||||
|
gst_qsv_d3d11_allocator_download (GstQsvAllocator * allocator,
|
||||||
|
const GstVideoInfo * info, gboolean force_copy, GstQsvFrame * frame,
|
||||||
|
GstBufferPool * pool)
|
||||||
|
{
|
||||||
|
GstBuffer *src_buf, *dst_buf;
|
||||||
|
GstMemory *mem;
|
||||||
|
GstD3D11Memory *dmem;
|
||||||
|
GstFlowReturn ret;
|
||||||
|
|
||||||
|
GST_TRACE_OBJECT (allocator, "Download");
|
||||||
|
|
||||||
|
src_buf = gst_qsv_frame_peek_buffer (frame);
|
||||||
|
|
||||||
|
if (!force_copy)
|
||||||
|
return gst_buffer_ref (src_buf);
|
||||||
|
|
||||||
|
mem = gst_buffer_peek_memory (src_buf, 0);
|
||||||
|
if (!gst_is_d3d11_memory (mem) || gst_buffer_n_memory (src_buf) != 1) {
|
||||||
|
GST_ERROR_OBJECT (allocator, "frame holds invalid d3d11 memory");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GST_IS_D3D11_BUFFER_POOL (pool) &&
|
||||||
|
!GST_IS_D3D11_STAGING_BUFFER_POOL (pool)) {
|
||||||
|
GST_TRACE_OBJECT (allocator, "Output is not d3d11 memory");
|
||||||
|
goto fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
dmem = GST_D3D11_MEMORY_CAST (mem);
|
||||||
|
|
||||||
|
/* both pool and qsvframe should hold the same d3d11 device already */
|
||||||
|
if (GST_IS_D3D11_BUFFER_POOL (pool)) {
|
||||||
|
GstD3D11BufferPool *d3d11_pool = GST_D3D11_BUFFER_POOL (pool);
|
||||||
|
|
||||||
|
if (d3d11_pool->device != dmem->device) {
|
||||||
|
GST_WARNING_OBJECT (allocator, "Pool holds different device");
|
||||||
|
goto fallback;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GstD3D11StagingBufferPool *d3d11_pool =
|
||||||
|
GST_D3D11_STAGING_BUFFER_POOL (pool);
|
||||||
|
|
||||||
|
if (d3d11_pool->device != dmem->device) {
|
||||||
|
GST_WARNING_OBJECT (allocator, "Staging pool holds different device");
|
||||||
|
goto fallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gst_buffer_pool_acquire_buffer (pool, &dst_buf, nullptr);
|
||||||
|
if (ret != GST_FLOW_OK) {
|
||||||
|
GST_WARNING_OBJECT (allocator, "Failed to allocate output buffer");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return gst_qsv_frame_copy_d3d11 (info, src_buf, dst_buf);
|
||||||
|
|
||||||
|
fallback:
|
||||||
|
GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
|
||||||
|
|
||||||
|
return GST_QSV_ALLOCATOR_CLASS (parent_class)->download (allocator,
|
||||||
|
info, TRUE, frame, pool);
|
||||||
|
}
|
||||||
|
|
||||||
GstQsvAllocator *
|
GstQsvAllocator *
|
||||||
gst_qsv_d3d11_allocator_new (GstD3D11Device * device)
|
gst_qsv_d3d11_allocator_new (GstD3D11Device * device)
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,9 +38,13 @@ G_DEFINE_TYPE (GstQsvVaAllocator, gst_qsv_va_allocator, GST_TYPE_QSV_ALLOCATOR);
|
||||||
|
|
||||||
static void gst_qsv_va_allocator_dispose (GObject * object);
|
static void gst_qsv_va_allocator_dispose (GObject * object);
|
||||||
static mfxStatus gst_qsv_va_allocator_alloc (GstQsvAllocator * allocator,
|
static mfxStatus gst_qsv_va_allocator_alloc (GstQsvAllocator * allocator,
|
||||||
mfxFrameAllocRequest * request, mfxFrameAllocResponse * response);
|
gboolean dummy_alloc, mfxFrameAllocRequest * request,
|
||||||
|
mfxFrameAllocResponse * response);
|
||||||
static GstBuffer *gst_qsv_va_allocator_upload (GstQsvAllocator * allocator,
|
static GstBuffer *gst_qsv_va_allocator_upload (GstQsvAllocator * allocator,
|
||||||
const GstVideoInfo * info, GstBuffer * buffer, GstBufferPool * pool);
|
const GstVideoInfo * info, GstBuffer * buffer, GstBufferPool * pool);
|
||||||
|
static GstBuffer *gst_qsv_va_allocator_download (GstQsvAllocator * allocator,
|
||||||
|
const GstVideoInfo * info, gboolean force_copy, GstQsvFrame * frame,
|
||||||
|
GstBufferPool * pool);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_qsv_va_allocator_class_init (GstQsvVaAllocatorClass * klass)
|
gst_qsv_va_allocator_class_init (GstQsvVaAllocatorClass * klass)
|
||||||
|
@ -52,6 +56,7 @@ gst_qsv_va_allocator_class_init (GstQsvVaAllocatorClass * klass)
|
||||||
|
|
||||||
alloc_class->alloc = GST_DEBUG_FUNCPTR (gst_qsv_va_allocator_alloc);
|
alloc_class->alloc = GST_DEBUG_FUNCPTR (gst_qsv_va_allocator_alloc);
|
||||||
alloc_class->upload = GST_DEBUG_FUNCPTR (gst_qsv_va_allocator_upload);
|
alloc_class->upload = GST_DEBUG_FUNCPTR (gst_qsv_va_allocator_upload);
|
||||||
|
alloc_class->download = GST_DEBUG_FUNCPTR (gst_qsv_va_allocator_download);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -70,7 +75,7 @@ gst_qsv_va_allocator_dispose (GObject * object)
|
||||||
}
|
}
|
||||||
|
|
||||||
static mfxStatus
|
static mfxStatus
|
||||||
gst_qsv_va_allocator_alloc (GstQsvAllocator * allocator,
|
gst_qsv_va_allocator_alloc (GstQsvAllocator * allocator, gboolean dummy_alloc,
|
||||||
mfxFrameAllocRequest * request, mfxFrameAllocResponse * response)
|
mfxFrameAllocRequest * request, mfxFrameAllocResponse * response)
|
||||||
{
|
{
|
||||||
GST_ERROR_OBJECT (allocator, "Not implemented");
|
GST_ERROR_OBJECT (allocator, "Not implemented");
|
||||||
|
@ -87,6 +92,16 @@ gst_qsv_va_allocator_upload (GstQsvAllocator * allocator,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstBuffer *
|
||||||
|
gst_qsv_va_allocator_download (GstQsvAllocator * allocator,
|
||||||
|
const GstVideoInfo * info, gboolean force_copy, GstQsvFrame * frame,
|
||||||
|
GstBufferPool * pool)
|
||||||
|
{
|
||||||
|
GST_ERROR_OBJECT (allocator, "Not implemented");
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
GstQsvAllocator *
|
GstQsvAllocator *
|
||||||
gst_qsv_va_allocator_new (GstVaDisplay * display)
|
gst_qsv_va_allocator_new (GstVaDisplay * display)
|
||||||
{
|
{
|
||||||
|
|
1439
subprojects/gst-plugins-bad/sys/qsv/gstqsvdecoder.cpp
Normal file
1439
subprojects/gst-plugins-bad/sys/qsv/gstqsvdecoder.cpp
Normal file
File diff suppressed because it is too large
Load diff
76
subprojects/gst-plugins-bad/sys/qsv/gstqsvdecoder.h
Normal file
76
subprojects/gst-plugins-bad/sys/qsv/gstqsvdecoder.h
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2022 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_DECODER (gst_qsv_decoder_get_type())
|
||||||
|
#define GST_QSV_DECODER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_QSV_DECODER, GstQsvDecoder))
|
||||||
|
#define GST_QSV_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_QSV_DECODER, GstQsvDecoderClass))
|
||||||
|
#define GST_IS_QSV_DECODER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_QSV_DECODER))
|
||||||
|
#define GST_IS_QSV_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_QSV_DECODER))
|
||||||
|
#define GST_QSV_DECODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_QSV_DECODER, GstQsvDecoderClass))
|
||||||
|
#define GST_QSV_DECODER_CAST(obj) ((GstQsvDecoder *)obj)
|
||||||
|
|
||||||
|
typedef struct _GstQsvDecoder GstQsvDecoder;
|
||||||
|
typedef struct _GstQsvDecoderClass GstQsvDecoderClass;
|
||||||
|
typedef struct _GstQsvDecoderPrivate GstQsvDecoderPrivate;
|
||||||
|
|
||||||
|
typedef struct _GstQsvDecoderClassData
|
||||||
|
{
|
||||||
|
guint impl_index;
|
||||||
|
gint64 adapter_luid;
|
||||||
|
gchar *display_path;
|
||||||
|
|
||||||
|
GstCaps *sink_caps;
|
||||||
|
GstCaps *src_caps;
|
||||||
|
} GstQsvDecoderClassData;
|
||||||
|
|
||||||
|
struct _GstQsvDecoder
|
||||||
|
{
|
||||||
|
GstVideoDecoder parent;
|
||||||
|
|
||||||
|
GstQsvDecoderPrivate *priv;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstQsvDecoderClass
|
||||||
|
{
|
||||||
|
GstVideoDecoderClass 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];
|
||||||
|
};
|
||||||
|
|
||||||
|
GType gst_qsv_decoder_get_type (void);
|
||||||
|
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstQsvDecoder, gst_object_unref)
|
||||||
|
|
||||||
|
G_END_DECLS
|
|
@ -913,14 +913,14 @@ gst_qsv_encoder_prepare_pool (GstQsvEncoder * self, GstCaps * caps,
|
||||||
|
|
||||||
/* TODO: Add Linux video memory (VA/DMABuf) support */
|
/* TODO: Add Linux video memory (VA/DMABuf) support */
|
||||||
#ifdef G_OS_WIN32
|
#ifdef G_OS_WIN32
|
||||||
priv->mem_type = GST_QSV_VIDEO_MEMORY;
|
priv->mem_type = GST_QSV_VIDEO_MEMORY | GST_QSV_ENCODER_IN_MEMORY;
|
||||||
*io_pattern = MFX_IOPATTERN_IN_VIDEO_MEMORY;
|
*io_pattern = MFX_IOPATTERN_IN_VIDEO_MEMORY;
|
||||||
|
|
||||||
ret = gst_qsv_encoder_prepare_d3d11_pool (self, aligned_caps, aligned_info);
|
ret = gst_qsv_encoder_prepare_d3d11_pool (self, aligned_caps, aligned_info);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
priv->mem_type = GST_QSV_SYSTEM_MEMORY;
|
priv->mem_type = GST_QSV_SYSTEM_MEMORY | GST_QSV_ENCODER_IN_MEMORY;
|
||||||
*io_pattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
|
*io_pattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
|
||||||
|
|
||||||
ret = gst_qsv_encoder_prepare_system_pool (self,
|
ret = gst_qsv_encoder_prepare_system_pool (self,
|
||||||
|
@ -988,17 +988,6 @@ gst_qsv_encoder_set_format (GstVideoEncoder * encoder,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHECK_STATUS(s,func) G_STMT_START { \
|
|
||||||
if (s < MFX_ERR_NONE) { \
|
|
||||||
GST_ERROR_OBJECT (self, G_STRINGIFY (func) " failed %d (%s)", \
|
|
||||||
QSV_STATUS_ARGS (s)); \
|
|
||||||
goto error; \
|
|
||||||
} else if (status != MFX_ERR_NONE) { \
|
|
||||||
GST_WARNING_OBJECT (self, G_STRINGIFY (func) " returned warning %d (%s)", \
|
|
||||||
QSV_STATUS_ARGS (s)); \
|
|
||||||
} \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
status = encoder_handle->Query (¶m, ¶m);
|
status = encoder_handle->Query (¶m, ¶m);
|
||||||
/* If device is unhappy with LowPower = OFF, try again with unknown */
|
/* If device is unhappy with LowPower = OFF, try again with unknown */
|
||||||
if (status < MFX_ERR_NONE) {
|
if (status < MFX_ERR_NONE) {
|
||||||
|
@ -1008,18 +997,16 @@ gst_qsv_encoder_set_format (GstVideoEncoder * encoder,
|
||||||
}
|
}
|
||||||
|
|
||||||
status = encoder_handle->Query (¶m, ¶m);
|
status = encoder_handle->Query (¶m, ¶m);
|
||||||
CHECK_STATUS (status, MFXVideoENCODE::Query);
|
QSV_CHECK_STATUS (self, status, MFXVideoENCODE::Query);
|
||||||
|
|
||||||
status = encoder_handle->QueryIOSurf (¶m, &alloc_request);
|
status = encoder_handle->QueryIOSurf (¶m, &alloc_request);
|
||||||
CHECK_STATUS (status, MFXVideoENCODE::QueryIOSurf);
|
QSV_CHECK_STATUS (self, status, MFXVideoENCODE::QueryIOSurf);
|
||||||
|
|
||||||
status = encoder_handle->Init (¶m);
|
status = encoder_handle->Init (¶m);
|
||||||
CHECK_STATUS (status, MFXVideoENCODE::Init);
|
QSV_CHECK_STATUS (self, status, MFXVideoENCODE::Init);
|
||||||
|
|
||||||
status = encoder_handle->GetVideoParam (¶m);
|
status = encoder_handle->GetVideoParam (¶m);
|
||||||
CHECK_STATUS (status, MFXVideoENCODE::GetVideoParam);
|
QSV_CHECK_STATUS (self, status, MFXVideoENCODE::GetVideoParam);
|
||||||
|
|
||||||
#undef CHECK_STATUS
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "NumFrameSuggested: %d, AsyncDepth %d",
|
GST_DEBUG_OBJECT (self, "NumFrameSuggested: %d, AsyncDepth %d",
|
||||||
alloc_request.NumFrameSuggested, param.AsyncDepth);
|
alloc_request.NumFrameSuggested, param.AsyncDepth);
|
||||||
|
@ -1185,7 +1172,9 @@ gst_qsv_encoder_handle_frame (GstVideoEncoder * encoder,
|
||||||
|
|
||||||
surface->qsv_frame =
|
surface->qsv_frame =
|
||||||
gst_qsv_allocator_acquire_frame (priv->allocator, priv->mem_type,
|
gst_qsv_allocator_acquire_frame (priv->allocator, priv->mem_type,
|
||||||
&priv->input_state->info, frame->input_buffer, priv->internal_pool);
|
&priv->input_state->info, gst_buffer_ref (frame->input_buffer),
|
||||||
|
priv->internal_pool);
|
||||||
|
|
||||||
if (!surface->qsv_frame) {
|
if (!surface->qsv_frame) {
|
||||||
GST_ERROR_OBJECT (self, "Failed to wrap buffer with qsv frame");
|
GST_ERROR_OBJECT (self, "Failed to wrap buffer with qsv frame");
|
||||||
gst_qsv_encoder_task_reset (self, task);
|
gst_qsv_encoder_task_reset (self, task);
|
||||||
|
|
228
subprojects/gst-plugins-bad/sys/qsv/gstqsvh264dec.cpp
Normal file
228
subprojects/gst-plugins-bad/sys/qsv/gstqsvh264dec.cpp
Normal file
|
@ -0,0 +1,228 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2022 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 "gstqsvh264dec.h"
|
||||||
|
#include <string>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef G_OS_WIN32
|
||||||
|
#include <gst/d3d11/gstd3d11.h>
|
||||||
|
#else
|
||||||
|
#include <gst/va/gstvadisplay_drm.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_EXTERN (gst_qsv_h264_dec_debug);
|
||||||
|
#define GST_CAT_DEFAULT gst_qsv_h264_dec_debug
|
||||||
|
|
||||||
|
typedef struct _GstQsvH264Dec
|
||||||
|
{
|
||||||
|
GstQsvDecoder parent;
|
||||||
|
} GstQsvH264Dec;
|
||||||
|
|
||||||
|
typedef struct _GstQsvH264DecClass
|
||||||
|
{
|
||||||
|
GstQsvDecoderClass parent_class;
|
||||||
|
} GstQsvH264DecClass;
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_qsv_h264_dec_class_init (GstQsvH264DecClass * klass, gpointer data)
|
||||||
|
{
|
||||||
|
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
||||||
|
GstQsvDecoderClass *qsvdec_class = GST_QSV_DECODER_CLASS (klass);
|
||||||
|
GstQsvDecoderClassData *cdata = (GstQsvDecoderClassData *) data;
|
||||||
|
|
||||||
|
qsvdec_class->codec_id = MFX_CODEC_AVC;
|
||||||
|
qsvdec_class->impl_index = cdata->impl_index;
|
||||||
|
qsvdec_class->adapter_luid = cdata->adapter_luid;
|
||||||
|
if (cdata->display_path) {
|
||||||
|
strncpy (qsvdec_class->display_path, cdata->display_path,
|
||||||
|
sizeof (qsvdec_class->display_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_element_class_set_static_metadata (element_class,
|
||||||
|
"Intel Quick Sync Video H.264 Decoder",
|
||||||
|
"Codec/Decoder/Video/Hardware",
|
||||||
|
"Intel Quick Sync Video H.264 Decoder",
|
||||||
|
"Seungha Yang <seungha@centricular.com>");
|
||||||
|
|
||||||
|
gst_element_class_add_pad_template (element_class,
|
||||||
|
gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
|
||||||
|
cdata->sink_caps));
|
||||||
|
gst_element_class_add_pad_template (element_class,
|
||||||
|
gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
|
||||||
|
cdata->src_caps));
|
||||||
|
|
||||||
|
gst_caps_unref (cdata->sink_caps);
|
||||||
|
gst_caps_unref (cdata->src_caps);
|
||||||
|
g_free (cdata->display_path);
|
||||||
|
g_free (cdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_qsv_h264_dec_init (GstQsvH264Dec * self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
guint width;
|
||||||
|
guint height;
|
||||||
|
} Resolution;
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_qsv_h264_dec_register (GstPlugin * plugin, guint rank, guint impl_index,
|
||||||
|
GstObject * device, mfxSession session)
|
||||||
|
{
|
||||||
|
mfxVideoParam param;
|
||||||
|
mfxInfoMFX *mfx;
|
||||||
|
static const Resolution resolutions_to_check[] = {
|
||||||
|
{1280, 720}, {1920, 1088}, {2560, 1440}, {3840, 2160}, {4096, 2160},
|
||||||
|
{7680, 4320}, {8192, 4320}
|
||||||
|
};
|
||||||
|
Resolution max_resolution;
|
||||||
|
|
||||||
|
memset (¶m, 0, sizeof (mfxVideoParam));
|
||||||
|
memset (&max_resolution, 0, sizeof (Resolution));
|
||||||
|
|
||||||
|
param.AsyncDepth = 4;
|
||||||
|
param.IOPattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY;
|
||||||
|
|
||||||
|
mfx = ¶m.mfx;
|
||||||
|
mfx->CodecId = MFX_CODEC_AVC;
|
||||||
|
|
||||||
|
mfx->FrameInfo.FrameRateExtN = 30;
|
||||||
|
mfx->FrameInfo.FrameRateExtD = 1;
|
||||||
|
mfx->FrameInfo.AspectRatioW = 1;
|
||||||
|
mfx->FrameInfo.AspectRatioH = 1;
|
||||||
|
mfx->FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
|
||||||
|
mfx->FrameInfo.FourCC = MFX_FOURCC_NV12;
|
||||||
|
mfx->FrameInfo.BitDepthLuma = 8;
|
||||||
|
mfx->FrameInfo.BitDepthChroma = 8;
|
||||||
|
mfx->FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
|
||||||
|
mfx->CodecProfile = MFX_PROFILE_AVC_MAIN;
|
||||||
|
|
||||||
|
/* Check max-resolution */
|
||||||
|
for (guint i = 0; i < G_N_ELEMENTS (resolutions_to_check); i++) {
|
||||||
|
mfx->FrameInfo.Width = GST_ROUND_UP_16 (resolutions_to_check[i].width);
|
||||||
|
mfx->FrameInfo.Height = GST_ROUND_UP_16 (resolutions_to_check[i].height);
|
||||||
|
mfx->FrameInfo.CropW = resolutions_to_check[i].width;
|
||||||
|
mfx->FrameInfo.CropH = resolutions_to_check[i].height;
|
||||||
|
|
||||||
|
if (MFXVideoDECODE_Query (session, ¶m, ¶m) != MFX_ERR_NONE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
max_resolution.width = resolutions_to_check[i].width;
|
||||||
|
max_resolution.height = resolutions_to_check[i].height;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_INFO ("Maximum supported resolution: %dx%d",
|
||||||
|
max_resolution.width, max_resolution.height);
|
||||||
|
|
||||||
|
/* To cover both landscape and portrait,
|
||||||
|
* select max value (width in this case) */
|
||||||
|
guint resolution = MAX (max_resolution.width, max_resolution.height);
|
||||||
|
std::string src_caps_str = "video/x-raw, format=(string) NV12";
|
||||||
|
|
||||||
|
src_caps_str += ", width=(int) [ 16, " + std::to_string (resolution) + " ]";
|
||||||
|
src_caps_str += ", height=(int) [ 16, " + std::to_string (resolution) + " ]";
|
||||||
|
|
||||||
|
GstCaps *src_caps = gst_caps_from_string (src_caps_str.c_str ());
|
||||||
|
|
||||||
|
/* TODO: Add support for VA */
|
||||||
|
#ifdef G_OS_WIN32
|
||||||
|
GstCaps *d3d11_caps = gst_caps_copy (src_caps);
|
||||||
|
GstCapsFeatures *caps_features =
|
||||||
|
gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, nullptr);
|
||||||
|
gst_caps_set_features_simple (d3d11_caps, caps_features);
|
||||||
|
gst_caps_append (d3d11_caps, src_caps);
|
||||||
|
src_caps = d3d11_caps;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string sink_caps_str = "video/x-h264";
|
||||||
|
sink_caps_str += ", width=(int) [ 16, " + std::to_string (resolution) + " ]";
|
||||||
|
sink_caps_str += ", height=(int) [ 16, " + std::to_string (resolution) + " ]";
|
||||||
|
|
||||||
|
sink_caps_str += ", stream-format=(string) byte-stream";
|
||||||
|
sink_caps_str += ", alignment=(string) au";
|
||||||
|
sink_caps_str += ", profile=(string) { high, progressive-high, "
|
||||||
|
"constrained-high, main, constrained-baseline, baseline } ";
|
||||||
|
|
||||||
|
GstCaps *sink_caps = gst_caps_from_string (sink_caps_str.c_str ());
|
||||||
|
|
||||||
|
GST_MINI_OBJECT_FLAG_SET (sink_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
|
||||||
|
GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
|
||||||
|
|
||||||
|
GstQsvDecoderClassData *cdata = g_new0 (GstQsvDecoderClassData, 1);
|
||||||
|
cdata->sink_caps = sink_caps;
|
||||||
|
cdata->src_caps = src_caps;
|
||||||
|
cdata->impl_index = impl_index;
|
||||||
|
|
||||||
|
#ifdef G_OS_WIN32
|
||||||
|
gint64 device_luid;
|
||||||
|
g_object_get (device, "adapter-luid", &device_luid, nullptr);
|
||||||
|
cdata->adapter_luid = device_luid;
|
||||||
|
#else
|
||||||
|
gchar *display_path;
|
||||||
|
g_object_get (device, "path", &display_path, nullptr);
|
||||||
|
cdata->display_path = display_path;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GType type;
|
||||||
|
gchar *type_name;
|
||||||
|
gchar *feature_name;
|
||||||
|
GTypeInfo type_info = {
|
||||||
|
sizeof (GstQsvH264DecClass),
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
(GClassInitFunc) gst_qsv_h264_dec_class_init,
|
||||||
|
nullptr,
|
||||||
|
cdata,
|
||||||
|
sizeof (GstQsvH264Dec),
|
||||||
|
0,
|
||||||
|
(GInstanceInitFunc) gst_qsv_h264_dec_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
type_name = g_strdup ("GstQsvH264Dec");
|
||||||
|
feature_name = g_strdup ("qsvh264dec");
|
||||||
|
|
||||||
|
gint index = 0;
|
||||||
|
while (g_type_from_name (type_name)) {
|
||||||
|
index++;
|
||||||
|
g_free (type_name);
|
||||||
|
g_free (feature_name);
|
||||||
|
type_name = g_strdup_printf ("GstQsvH264Device%dDec", index);
|
||||||
|
feature_name = g_strdup_printf ("qsvh264device%ddec", index);
|
||||||
|
}
|
||||||
|
|
||||||
|
type = g_type_register_static (GST_TYPE_QSV_DECODER, type_name, &type_info,
|
||||||
|
(GTypeFlags) 0);
|
||||||
|
|
||||||
|
if (rank > 0 && index != 0)
|
||||||
|
rank--;
|
||||||
|
|
||||||
|
if (!gst_element_register (plugin, feature_name, rank, type))
|
||||||
|
GST_WARNING ("Failed to register plugin '%s'", type_name);
|
||||||
|
|
||||||
|
g_free (type_name);
|
||||||
|
g_free (feature_name);
|
||||||
|
}
|
34
subprojects/gst-plugins-bad/sys/qsv/gstqsvh264dec.h
Normal file
34
subprojects/gst-plugins-bad/sys/qsv/gstqsvh264dec.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2022 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 "gstqsvdecoder.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
void gst_qsv_h264_dec_register (GstPlugin * plugin,
|
||||||
|
guint rank,
|
||||||
|
guint impl_index,
|
||||||
|
GstObject * device,
|
||||||
|
mfxSession session);
|
||||||
|
|
||||||
|
G_END_DECLS
|
|
@ -32,10 +32,20 @@ GList * gst_qsv_get_platform_devices (void);
|
||||||
|
|
||||||
const gchar * gst_qsv_status_to_string (mfxStatus status);
|
const gchar * gst_qsv_status_to_string (mfxStatus status);
|
||||||
|
|
||||||
/* helper macro for debugging log */
|
|
||||||
#define QSV_STATUS_ARGS(status) \
|
#define QSV_STATUS_ARGS(status) \
|
||||||
status, gst_qsv_status_to_string (status)
|
status, gst_qsv_status_to_string (status)
|
||||||
|
|
||||||
|
#define QSV_CHECK_STATUS(e,s,f) G_STMT_START { \
|
||||||
|
if (s < MFX_ERR_NONE) { \
|
||||||
|
GST_ERROR_OBJECT (e, G_STRINGIFY (f) " failed %d (%s)", \
|
||||||
|
QSV_STATUS_ARGS (s)); \
|
||||||
|
goto error; \
|
||||||
|
} else if (status != MFX_ERR_NONE) { \
|
||||||
|
GST_WARNING_OBJECT (e, G_STRINGIFY (f) " returned warning %d (%s)", \
|
||||||
|
QSV_STATUS_ARGS (s)); \
|
||||||
|
} \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
static inline GstClockTime
|
static inline GstClockTime
|
||||||
gst_qsv_timestamp_to_gst (mfxU64 timestamp)
|
gst_qsv_timestamp_to_gst (mfxU64 timestamp)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
qsv_sources = [
|
qsv_sources = [
|
||||||
'gstqsvallocator.cpp',
|
'gstqsvallocator.cpp',
|
||||||
|
'gstqsvdecoder.cpp',
|
||||||
'gstqsvencoder.cpp',
|
'gstqsvencoder.cpp',
|
||||||
|
'gstqsvh264dec.cpp',
|
||||||
'gstqsvh264enc.cpp',
|
'gstqsvh264enc.cpp',
|
||||||
'gstqsvh265enc.cpp',
|
'gstqsvh265enc.cpp',
|
||||||
'gstqsvutils.cpp',
|
'gstqsvutils.cpp',
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <mfx.h>
|
#include <mfx.h>
|
||||||
#include "gstqsvutils.h"
|
#include "gstqsvutils.h"
|
||||||
|
#include "gstqsvh264dec.h"
|
||||||
#include "gstqsvh264enc.h"
|
#include "gstqsvh264enc.h"
|
||||||
#include "gstqsvh265enc.h"
|
#include "gstqsvh265enc.h"
|
||||||
#include "gstqsvvp9enc.h"
|
#include "gstqsvvp9enc.h"
|
||||||
|
@ -41,7 +42,9 @@
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY (gst_qsv_debug);
|
GST_DEBUG_CATEGORY (gst_qsv_debug);
|
||||||
GST_DEBUG_CATEGORY (gst_qsv_allocator_debug);
|
GST_DEBUG_CATEGORY (gst_qsv_allocator_debug);
|
||||||
|
GST_DEBUG_CATEGORY (gst_qsv_decoder_debug);
|
||||||
GST_DEBUG_CATEGORY (gst_qsv_encoder_debug);
|
GST_DEBUG_CATEGORY (gst_qsv_encoder_debug);
|
||||||
|
GST_DEBUG_CATEGORY (gst_qsv_h264_dec_debug);
|
||||||
GST_DEBUG_CATEGORY (gst_qsv_h264_enc_debug);
|
GST_DEBUG_CATEGORY (gst_qsv_h264_enc_debug);
|
||||||
GST_DEBUG_CATEGORY (gst_qsv_h265_enc_debug);
|
GST_DEBUG_CATEGORY (gst_qsv_h265_enc_debug);
|
||||||
GST_DEBUG_CATEGORY (gst_qsv_vp9_enc_debug);
|
GST_DEBUG_CATEGORY (gst_qsv_vp9_enc_debug);
|
||||||
|
@ -213,10 +216,14 @@ plugin_init (GstPlugin * plugin)
|
||||||
|
|
||||||
GST_INFO ("Found %d platform devices", g_list_length (platform_devices));
|
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,
|
GST_DEBUG_CATEGORY_INIT (gst_qsv_allocator_debug,
|
||||||
"qsvallocator", 0, "qsvallocator");
|
"qsvallocator", 0, "qsvallocator");
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_qsv_decoder_debug,
|
||||||
|
"qsvdecoder", 0, "qsvdecoder");
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_qsv_encoder_debug,
|
||||||
|
"qsvencoder", 0, "qsvencoder");
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_qsv_h264_dec_debug,
|
||||||
|
"qsvh264dec", 0, "qsvh264dec");
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_qsv_h264_enc_debug,
|
GST_DEBUG_CATEGORY_INIT (gst_qsv_h264_enc_debug,
|
||||||
"qsvh264enc", 0, "qsvh264enc");
|
"qsvh264enc", 0, "qsvh264enc");
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_qsv_h265_enc_debug,
|
GST_DEBUG_CATEGORY_INIT (gst_qsv_h265_enc_debug,
|
||||||
|
@ -246,6 +253,8 @@ plugin_init (GstPlugin * plugin)
|
||||||
if (!session)
|
if (!session)
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
|
gst_qsv_h264_dec_register (plugin, GST_RANK_MARGINAL, i, device, session);
|
||||||
|
|
||||||
gst_qsv_h264_enc_register (plugin, GST_RANK_NONE, i, device, session);
|
gst_qsv_h264_enc_register (plugin, GST_RANK_NONE, i, device, session);
|
||||||
gst_qsv_h265_enc_register (plugin, GST_RANK_NONE, i, device, session);
|
gst_qsv_h265_enc_register (plugin, GST_RANK_NONE, i, device, session);
|
||||||
gst_qsv_vp9_enc_register (plugin, GST_RANK_NONE, i, device, session);
|
gst_qsv_vp9_enc_register (plugin, GST_RANK_NONE, i, device, session);
|
||||||
|
|
Loading…
Reference in a new issue