mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-21 07:46:38 +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;
|
||||
GstVideoFrame frame;
|
||||
GstQsvMemoryType mem_type;
|
||||
|
||||
/* For direct GPU access */
|
||||
GstMapInfo map_info;
|
||||
GstMapFlags map_flags;
|
||||
};
|
||||
|
||||
GST_DEFINE_MINI_OBJECT_TYPE (GstQsvFrame, gst_qsv_frame);
|
||||
|
@ -82,11 +80,39 @@ gst_qsv_frame_peek_buffer (GstQsvFrame * frame)
|
|||
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
|
||||
{
|
||||
GstAtomicQueue *queue;
|
||||
|
||||
mfxFrameAllocator allocator;
|
||||
mfxFrameAllocResponse response;
|
||||
guint16 extra_alloc_size;
|
||||
gboolean dummy_alloc;
|
||||
};
|
||||
|
||||
#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);
|
||||
static mfxStatus gst_qsv_allocator_free (mfxHDL pthis,
|
||||
mfxFrameAllocResponse * response);
|
||||
static GstBuffer *gst_qsv_allocator_download_default (GstQsvAllocator * self,
|
||||
const GstVideoInfo * info, gboolean force_copy, GstQsvFrame * frame,
|
||||
GstBufferPool * pool);
|
||||
|
||||
static void
|
||||
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);
|
||||
|
||||
object_class->finalize = gst_qsv_allocator_finalize;
|
||||
|
||||
klass->download = GST_DEBUG_FUNCPTR (gst_qsv_allocator_download_default);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -144,19 +175,22 @@ gst_qsv_allocator_finalize (GObject * object)
|
|||
gst_qsv_frame_unref (frame);
|
||||
|
||||
gst_atomic_queue_unref (priv->queue);
|
||||
gst_qsv_allocator_free ((mfxHDL) self, &priv->response);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static mfxStatus
|
||||
gst_qsv_allocator_alloc_default (GstQsvAllocator * self,
|
||||
gst_qsv_allocator_alloc_default (GstQsvAllocator * self, gboolean dummy_alloc,
|
||||
mfxFrameAllocRequest * request, mfxFrameAllocResponse * response)
|
||||
{
|
||||
GstQsvFrame **mids = nullptr;
|
||||
GstVideoInfo info;
|
||||
GstVideoAlignment align;
|
||||
GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
|
||||
|
||||
GST_TRACE_OBJECT (self, "Alloc");
|
||||
GstBufferPool *pool;
|
||||
GstCaps *caps;
|
||||
GstStructure *config;
|
||||
|
||||
/* Something unexpected and went wrong */
|
||||
if ((request->Type & MFX_MEMTYPE_SYSTEM_MEMORY) == 0) {
|
||||
|
@ -194,19 +228,96 @@ gst_qsv_allocator_alloc_default (GstQsvAllocator * self,
|
|||
response->NumFrameActual = request->NumFrameSuggested;
|
||||
|
||||
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 (self,
|
||||
GST_QSV_SYSTEM_MEMORY, &info, nullptr, nullptr);
|
||||
}
|
||||
|
||||
response->mids = (mfxMemId *) mids;
|
||||
|
||||
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;
|
||||
|
||||
buffer = gst_buffer_new_and_alloc (info.size);
|
||||
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_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 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
|
||||
|
@ -214,16 +325,52 @@ gst_qsv_allocator_alloc (mfxHDL pthis,
|
|||
mfxFrameAllocRequest * request, mfxFrameAllocResponse * response)
|
||||
{
|
||||
GstQsvAllocator *self = GST_QSV_ALLOCATOR (pthis);
|
||||
GstQsvAllocatorPrivate *priv = self->priv;
|
||||
GstQsvAllocatorClass *klass;
|
||||
mfxStatus status;
|
||||
mfxFrameAllocRequest req = *request;
|
||||
gboolean dummy_alloc = priv->dummy_alloc;
|
||||
|
||||
if ((request->Type & MFX_MEMTYPE_SYSTEM_MEMORY) != 0)
|
||||
return gst_qsv_allocator_alloc_default (self, request, response);
|
||||
GST_INFO_OBJECT (self, "Alloc, Request Type: 0x%x, %dx%d (%dx%d)",
|
||||
req.Type, req.Info.Width, req.Info.Height,
|
||||
req.Info.CropW, req.Info.CropH);
|
||||
|
||||
klass = GST_QSV_ALLOCATOR_GET_CLASS (self);
|
||||
/* Apply extra_alloc_size only for GST internal use case */
|
||||
if ((request->Type & MFX_MEMTYPE_EXTERNAL_FRAME) != 0)
|
||||
req.NumFrameSuggested += priv->extra_alloc_size;
|
||||
|
||||
g_assert (klass->alloc);
|
||||
if (req.Info.CropW == 0 || req.Info.CropH == 0) {
|
||||
req.Info.CropW = req.Info.Width;
|
||||
req.Info.CropH = req.Info.Height;
|
||||
}
|
||||
|
||||
return klass->alloc (self, request, response);
|
||||
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);
|
||||
g_assert (klass->alloc);
|
||||
|
||||
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
|
||||
|
@ -236,9 +383,15 @@ gst_qsv_allocator_lock (mfxHDL pthis, mfxMemId mid, mfxFrameData * ptr)
|
|||
GST_TRACE_OBJECT (self, "Lock mfxMemId %p", mid);
|
||||
|
||||
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) {
|
||||
gst_video_frame_map (&frame->frame, &frame->info, frame->buffer,
|
||||
GST_MAP_READ);
|
||||
(GstMapFlags) GST_MAP_READWRITE);
|
||||
}
|
||||
|
||||
frame->map_count++;
|
||||
|
@ -303,15 +456,26 @@ gst_qsv_allocator_get_hdl (mfxHDL pthis, mfxMemId mid, mfxHDL * handle)
|
|||
{
|
||||
GstQsvAllocator *self = GST_QSV_ALLOCATOR (pthis);
|
||||
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");
|
||||
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;
|
||||
}
|
||||
|
||||
if (!frame->map_info.data) {
|
||||
GST_ERROR_OBJECT (self, "No mapped data");
|
||||
g_assert ((frame->map_flags & GST_MAP_QSV) != 0);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -319,14 +483,18 @@ gst_qsv_allocator_get_hdl (mfxHDL pthis, mfxMemId mid, mfxHDL * handle)
|
|||
|
||||
#ifdef G_OS_WIN32
|
||||
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 */
|
||||
pair->second = (mfxHDL) frame->map_info.user_data[0];
|
||||
pair->second = (mfxHDL) map_info.user_data[0];
|
||||
#else
|
||||
*handle = (mfxHDL) frame->map_info.data;
|
||||
*handle = (mfxHDL) map_info.data;
|
||||
#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;
|
||||
}
|
||||
|
||||
|
@ -339,6 +507,7 @@ gst_qsv_allocator_free (mfxHDL pthis, mfxFrameAllocResponse * response)
|
|||
gst_clear_qsv_frame (&frames[i]);
|
||||
|
||||
g_clear_pointer (&response->mids, g_free);
|
||||
response->NumFrameActual = 0;
|
||||
|
||||
return MFX_ERR_NONE;
|
||||
}
|
||||
|
@ -354,14 +523,9 @@ gst_qsv_frame_release (GstQsvFrame * frame)
|
|||
gst_video_frame_unmap (&frame->frame);
|
||||
}
|
||||
frame->map_count = 0;
|
||||
gst_clear_buffer (&frame->buffer);
|
||||
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;
|
||||
|
||||
|
@ -451,7 +615,7 @@ gst_qsv_allocator_upload_default (GstQsvAllocator * allocator,
|
|||
* @allocator: a #GstQsvAllocator
|
||||
* @mem_type: a memory type
|
||||
* @info: a #GstVideoInfo
|
||||
* @buffer: (transfer none): a #GstBuffer
|
||||
* @buffer: (nullable) (transfer full): a #GstBuffer
|
||||
* @pool: (nullable): a #GstBufferPool
|
||||
*
|
||||
* Uploads @buffer to video memory if required, and wraps GstBuffer using
|
||||
|
@ -467,9 +631,32 @@ gst_qsv_allocator_acquire_frame (GstQsvAllocator * allocator,
|
|||
{
|
||||
GstQsvAllocatorPrivate *priv;
|
||||
GstQsvFrame *frame;
|
||||
guint32 map_flags = 0;
|
||||
|
||||
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;
|
||||
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->mem_type = mem_type;
|
||||
frame->allocator = (GstQsvAllocator *) gst_object_ref (allocator);
|
||||
GST_MINI_OBJECT_CAST (frame)->dispose =
|
||||
(GstMiniObjectDisposeFunction) gst_qsv_frame_dispose;
|
||||
frame->map_flags = (GstMapFlags) map_flags;
|
||||
frame->info = *info;
|
||||
|
||||
if (!pool) {
|
||||
frame->buffer = gst_buffer_ref (buffer);
|
||||
frame->info = *info;
|
||||
} else {
|
||||
frame->buffer = buffer;
|
||||
} else if (buffer) {
|
||||
GstBuffer *upload_buf;
|
||||
|
||||
if (mem_type == GST_QSV_SYSTEM_MEMORY) {
|
||||
frame->allocator = (GstQsvAllocator *) gst_object_ref (allocator);
|
||||
GST_MINI_OBJECT_CAST (frame)->dispose =
|
||||
(GstMiniObjectDisposeFunction) gst_qsv_frame_dispose;
|
||||
|
||||
if (GST_QSV_MEM_TYPE_IS_SYSTEM (mem_type)) {
|
||||
upload_buf = gst_qsv_allocator_upload_default (allocator, info, buffer,
|
||||
pool);
|
||||
} else {
|
||||
|
@ -499,6 +688,8 @@ gst_qsv_allocator_acquire_frame (GstQsvAllocator * allocator,
|
|||
upload_buf = klass->upload (allocator, info, buffer, pool);
|
||||
}
|
||||
|
||||
gst_buffer_unref (buffer);
|
||||
|
||||
if (!upload_buf) {
|
||||
GST_WARNING_OBJECT (allocator, "Failed to upload buffer");
|
||||
gst_qsv_frame_unref (frame);
|
||||
|
@ -507,25 +698,85 @@ gst_qsv_allocator_acquire_frame (GstQsvAllocator * allocator,
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 *
|
||||
gst_qsv_allocator_get_allocator_handle (GstQsvAllocator * allocator)
|
||||
{
|
||||
|
@ -533,3 +784,23 @@ gst_qsv_allocator_get_allocator_handle (GstQsvAllocator * 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);
|
||||
|
||||
gboolean gst_qsv_frame_set_buffer (GstQsvFrame * frame,
|
||||
GstBuffer * buffer);
|
||||
|
||||
static inline GstQsvFrame *
|
||||
gst_qsv_frame_ref (GstQsvFrame * frame)
|
||||
{
|
||||
|
@ -66,10 +69,15 @@ gst_clear_qsv_frame (GstQsvFrame ** frame)
|
|||
|
||||
typedef enum
|
||||
{
|
||||
GST_QSV_SYSTEM_MEMORY,
|
||||
GST_QSV_VIDEO_MEMORY,
|
||||
GST_QSV_SYSTEM_MEMORY = (1 << 0),
|
||||
GST_QSV_VIDEO_MEMORY = (1 << 1),
|
||||
GST_QSV_ENCODER_IN_MEMORY = (1 << 2),
|
||||
GST_QSV_DECODER_OUT_MEMORY = (1 << 3),
|
||||
} 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
|
||||
{
|
||||
GstObject parent;
|
||||
|
@ -82,6 +90,7 @@ struct _GstQsvAllocatorClass
|
|||
GstObjectClass parent_class;
|
||||
|
||||
mfxStatus (*alloc) (GstQsvAllocator * allocator,
|
||||
gboolean dummy_alloc,
|
||||
mfxFrameAllocRequest * request,
|
||||
mfxFrameAllocResponse * response);
|
||||
|
||||
|
@ -89,6 +98,12 @@ struct _GstQsvAllocatorClass
|
|||
const GstVideoInfo * info,
|
||||
GstBuffer * buffer,
|
||||
GstBufferPool * pool);
|
||||
|
||||
GstBuffer * (*download) (GstQsvAllocator * allocator,
|
||||
const GstVideoInfo * info,
|
||||
gboolean force_copy,
|
||||
GstQsvFrame * frame,
|
||||
GstBufferPool * pool);
|
||||
};
|
||||
|
||||
GType gst_qsv_allocator_get_type (void);
|
||||
|
@ -99,8 +114,35 @@ GstQsvFrame * gst_qsv_allocator_acquire_frame (GstQsvAllocator * allocat
|
|||
GstBuffer * buffer,
|
||||
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);
|
||||
|
||||
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_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 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,
|
||||
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
|
||||
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->upload = GST_DEBUG_FUNCPTR (gst_qsv_d3d11_allocator_upload);
|
||||
alloc_class->download = GST_DEBUG_FUNCPTR (gst_qsv_d3d11_allocator_download);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -73,14 +78,13 @@ gst_qsv_d3d11_allocator_dispose (GObject * object)
|
|||
|
||||
static mfxStatus
|
||||
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);
|
||||
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,
|
||||
|
@ -143,7 +147,6 @@ gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator,
|
|||
|
||||
if (!mem) {
|
||||
GST_ERROR_OBJECT (self, "Failed to allocate buffer");
|
||||
|
||||
return MFX_ERR_MEMORY_ALLOC;
|
||||
}
|
||||
|
||||
|
@ -160,8 +163,8 @@ gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator,
|
|||
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);
|
||||
GST_QSV_VIDEO_MEMORY | GST_QSV_ENCODER_IN_MEMORY, &info, buffer,
|
||||
nullptr);
|
||||
} else {
|
||||
GstBufferPool *pool;
|
||||
GstVideoFormat format;
|
||||
|
@ -170,19 +173,53 @@ gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator,
|
|||
GstStructure *config;
|
||||
GstD3D11AllocationParams *params;
|
||||
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;
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
params = gst_d3d11_allocation_params_new (self->device, &info,
|
||||
(GstD3D11AllocationFlags) 0, bind_flags);
|
||||
|
||||
gst_d3d11_allocation_params_alignment (params, &align);
|
||||
|
||||
config = gst_buffer_pool_get_config (pool);
|
||||
gst_buffer_pool_config_set_d3d11_allocation_params (config, 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_active (pool, TRUE);
|
||||
|
||||
mids = g_new0 (GstQsvFrame *, request->NumFrameSuggested);
|
||||
response->NumFrameActual = request->NumFrameSuggested;
|
||||
for (guint i = 0; i < request->NumFrameSuggested; i++) {
|
||||
GstBuffer *buffer;
|
||||
|
||||
|
@ -206,9 +241,9 @@ gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator,
|
|||
}
|
||||
|
||||
mids[i] = gst_qsv_allocator_acquire_frame (allocator,
|
||||
GST_QSV_VIDEO_MEMORY, &info, buffer, nullptr);
|
||||
gst_buffer_unref (buffer);
|
||||
mem_type, &info, buffer, nullptr);
|
||||
}
|
||||
|
||||
gst_buffer_pool_set_active (pool, FALSE);
|
||||
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);
|
||||
}
|
||||
|
||||
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 *
|
||||
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 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,
|
||||
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
|
||||
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->upload = GST_DEBUG_FUNCPTR (gst_qsv_va_allocator_upload);
|
||||
alloc_class->download = GST_DEBUG_FUNCPTR (gst_qsv_va_allocator_download);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -70,7 +75,7 @@ gst_qsv_va_allocator_dispose (GObject * object)
|
|||
}
|
||||
|
||||
static mfxStatus
|
||||
gst_qsv_va_allocator_alloc (GstQsvAllocator * allocator,
|
||||
gst_qsv_va_allocator_alloc (GstQsvAllocator * allocator, gboolean dummy_alloc,
|
||||
mfxFrameAllocRequest * request, mfxFrameAllocResponse * response)
|
||||
{
|
||||
GST_ERROR_OBJECT (allocator, "Not implemented");
|
||||
|
@ -87,6 +92,16 @@ gst_qsv_va_allocator_upload (GstQsvAllocator * allocator,
|
|||
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 *
|
||||
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 */
|
||||
#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;
|
||||
|
||||
ret = gst_qsv_encoder_prepare_d3d11_pool (self, aligned_caps, aligned_info);
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
ret = gst_qsv_encoder_prepare_system_pool (self,
|
||||
|
@ -988,17 +988,6 @@ gst_qsv_encoder_set_format (GstVideoEncoder * encoder,
|
|||
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);
|
||||
/* If device is unhappy with LowPower = OFF, try again with unknown */
|
||||
if (status < MFX_ERR_NONE) {
|
||||
|
@ -1008,18 +997,16 @@ gst_qsv_encoder_set_format (GstVideoEncoder * encoder,
|
|||
}
|
||||
|
||||
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);
|
||||
CHECK_STATUS (status, MFXVideoENCODE::QueryIOSurf);
|
||||
QSV_CHECK_STATUS (self, status, MFXVideoENCODE::QueryIOSurf);
|
||||
|
||||
status = encoder_handle->Init (¶m);
|
||||
CHECK_STATUS (status, MFXVideoENCODE::Init);
|
||||
QSV_CHECK_STATUS (self, status, MFXVideoENCODE::Init);
|
||||
|
||||
status = encoder_handle->GetVideoParam (¶m);
|
||||
CHECK_STATUS (status, MFXVideoENCODE::GetVideoParam);
|
||||
|
||||
#undef CHECK_STATUS
|
||||
QSV_CHECK_STATUS (self, status, MFXVideoENCODE::GetVideoParam);
|
||||
|
||||
GST_DEBUG_OBJECT (self, "NumFrameSuggested: %d, AsyncDepth %d",
|
||||
alloc_request.NumFrameSuggested, param.AsyncDepth);
|
||||
|
@ -1185,7 +1172,9 @@ gst_qsv_encoder_handle_frame (GstVideoEncoder * encoder,
|
|||
|
||||
surface->qsv_frame =
|
||||
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) {
|
||||
GST_ERROR_OBJECT (self, "Failed to wrap buffer with qsv frame");
|
||||
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);
|
||||
|
||||
/* helper macro for debugging log */
|
||||
#define QSV_STATUS_ARGS(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
|
||||
gst_qsv_timestamp_to_gst (mfxU64 timestamp)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
qsv_sources = [
|
||||
'gstqsvallocator.cpp',
|
||||
'gstqsvdecoder.cpp',
|
||||
'gstqsvencoder.cpp',
|
||||
'gstqsvh264dec.cpp',
|
||||
'gstqsvh264enc.cpp',
|
||||
'gstqsvh265enc.cpp',
|
||||
'gstqsvutils.cpp',
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <gst/gst.h>
|
||||
#include <mfx.h>
|
||||
#include "gstqsvutils.h"
|
||||
#include "gstqsvh264dec.h"
|
||||
#include "gstqsvh264enc.h"
|
||||
#include "gstqsvh265enc.h"
|
||||
#include "gstqsvvp9enc.h"
|
||||
|
@ -41,7 +42,9 @@
|
|||
|
||||
GST_DEBUG_CATEGORY (gst_qsv_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_h264_dec_debug);
|
||||
GST_DEBUG_CATEGORY (gst_qsv_h264_enc_debug);
|
||||
GST_DEBUG_CATEGORY (gst_qsv_h265_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_DEBUG_CATEGORY_INIT (gst_qsv_encoder_debug,
|
||||
"qsvencoder", 0, "qsvencoder");
|
||||
GST_DEBUG_CATEGORY_INIT (gst_qsv_allocator_debug,
|
||||
"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,
|
||||
"qsvh264enc", 0, "qsvh264enc");
|
||||
GST_DEBUG_CATEGORY_INIT (gst_qsv_h265_enc_debug,
|
||||
|
@ -246,6 +253,8 @@ plugin_init (GstPlugin * plugin)
|
|||
if (!session)
|
||||
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_h265_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