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:
Seungha Yang 2022-02-20 03:59:32 +09:00 committed by GStreamer Marge Bot
parent 4de365b31c
commit c4ac657364
12 changed files with 2303 additions and 89 deletions

View file

@ -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;
}

View file

@ -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

View file

@ -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)
{

View file

@ -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)
{

File diff suppressed because it is too large Load diff

View 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

View file

@ -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 (&param, &param);
/* 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 (&param, &param);
CHECK_STATUS (status, MFXVideoENCODE::Query);
QSV_CHECK_STATUS (self, status, MFXVideoENCODE::Query);
status = encoder_handle->QueryIOSurf (&param, &alloc_request);
CHECK_STATUS (status, MFXVideoENCODE::QueryIOSurf);
QSV_CHECK_STATUS (self, status, MFXVideoENCODE::QueryIOSurf);
status = encoder_handle->Init (&param);
CHECK_STATUS (status, MFXVideoENCODE::Init);
QSV_CHECK_STATUS (self, status, MFXVideoENCODE::Init);
status = encoder_handle->GetVideoParam (&param);
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);

View 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 (&param, 0, sizeof (mfxVideoParam));
memset (&max_resolution, 0, sizeof (Resolution));
param.AsyncDepth = 4;
param.IOPattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY;
mfx = &param.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, &param, &param) != 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);
}

View 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

View file

@ -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)
{

View file

@ -1,6 +1,8 @@
qsv_sources = [
'gstqsvallocator.cpp',
'gstqsvdecoder.cpp',
'gstqsvencoder.cpp',
'gstqsvh264dec.cpp',
'gstqsvh264enc.cpp',
'gstqsvh265enc.cpp',
'gstqsvutils.cpp',

View file

@ -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);