From: Seungha Yang Date: Thu, 27 Oct 2022 18:25:38 +0000 (+0900) Subject: qsv: Add VP9 decoder X-Git-Tag: 1.22.0~643 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5e66dde1b2063d272405cb3572865d91347e5373;p=platform%2Fupstream%2Fgstreamer.git qsv: Add VP9 decoder Recent Intel GPU supports 12bits VP9 decoding but only VP9 profile2 with 10bits is defined by DXVA spec. Thus, we need this vendor specific decoder element Part-of: --- diff --git a/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json b/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json index 2e24fc2..2c57a42 100644 --- a/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json +++ b/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json @@ -226106,6 +226106,33 @@ }, "rank": "none" }, + "qsvvp9dec": { + "author": "Seungha Yang ", + "description": "Intel Quick Sync Video VP9 Decoder", + "hierarchy": [ + "GstQsvVP9Dec", + "GstQsvDecoder", + "GstVideoDecoder", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Decoder/Video/Hardware", + "pad-templates": { + "sink": { + "caps": "video/x-vp9:\n width: [ 1, 16384 ]\n height: [ 1, 16384 ]\n alignment: frame\n profile: { (string)0, (string)2 }\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/x-raw(memory:D3D11Memory):\n format: { NV12, P010_10LE, P016_LE }\n width: [ 1, 16384 ]\n height: [ 1, 16384 ]\nvideo/x-raw:\n format: { NV12, P010_10LE, P016_LE }\n width: [ 1, 16384 ]\n height: [ 1, 16384 ]\n", + "direction": "src", + "presence": "always" + } + }, + "rank": "marginal" + }, "qsvvp9enc": { "author": "Seungha Yang ", "description": "Intel Quick Sync Video VP9 Encoder", diff --git a/subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator.cpp b/subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator.cpp index 8155319..86030f5 100644 --- a/subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator.cpp +++ b/subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator.cpp @@ -206,6 +206,9 @@ gst_qsv_allocator_alloc_default (GstQsvAllocator * self, gboolean dummy_alloc, case MFX_FOURCC_P010: format = GST_VIDEO_FORMAT_P010_10LE; break; + case MFX_FOURCC_P016: + format = GST_VIDEO_FORMAT_P016_LE; + break; case MFX_FOURCC_AYUV: format = GST_VIDEO_FORMAT_VUYA; break; @@ -762,7 +765,7 @@ gst_qsv_allocator_download_default (GstQsvAllocator * self, return nullptr; } - if (!gst_video_frame_map (&dst_frame, &frame->info, buffer, GST_MAP_WRITE)) { + if (!gst_video_frame_map (&dst_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"); @@ -784,7 +787,8 @@ gst_qsv_allocator_download_default (GstQsvAllocator * self, GstBuffer * gst_qsv_allocator_download_frame (GstQsvAllocator * allocator, - gboolean force_copy, GstQsvFrame * frame, GstBufferPool * pool) + gboolean force_copy, GstQsvFrame * frame, const GstVideoInfo * pool_info, + GstBufferPool * pool) { GstQsvAllocatorClass *klass; @@ -793,14 +797,14 @@ gst_qsv_allocator_download_frame (GstQsvAllocator * allocator, 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, + return gst_qsv_allocator_download_default (allocator, pool_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); + return klass->download (allocator, pool_info, force_copy, frame, pool); } mfxFrameAllocator * diff --git a/subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator.h b/subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator.h index 94a581c..fc1e68e 100644 --- a/subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator.h +++ b/subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator.h @@ -117,6 +117,7 @@ GstQsvFrame * gst_qsv_allocator_acquire_frame (GstQsvAllocator * allocat GstBuffer * gst_qsv_allocator_download_frame (GstQsvAllocator * allocator, gboolean force_copy, GstQsvFrame * frame, + const GstVideoInfo *pool_info, GstBufferPool * pool); mfxFrameAllocator * gst_qsv_allocator_get_allocator_handle (GstQsvAllocator * allocator); diff --git a/subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator_d3d11.cpp b/subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator_d3d11.cpp index d48784a..fa94e2f 100644 --- a/subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator_d3d11.cpp +++ b/subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator_d3d11.cpp @@ -106,6 +106,9 @@ gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator, case MFX_FOURCC_P010: dxgi_format = DXGI_FORMAT_P010; break; + case MFX_FOURCC_P016: + dxgi_format = DXGI_FORMAT_P016; + break; case MFX_FOURCC_AYUV: dxgi_format = DXGI_FORMAT_AYUV; break; diff --git a/subprojects/gst-plugins-bad/sys/qsv/gstqsvdecoder.cpp b/subprojects/gst-plugins-bad/sys/qsv/gstqsvdecoder.cpp index 10f3eae..2176dce 100644 --- a/subprojects/gst-plugins-bad/sys/qsv/gstqsvdecoder.cpp +++ b/subprojects/gst-plugins-bad/sys/qsv/gstqsvdecoder.cpp @@ -142,6 +142,8 @@ static GstFlowReturn gst_qsv_decoder_drain (GstVideoDecoder * decoder); static void gst_qsv_decoder_surface_clear (GstQsvDecoderSurface * surface); static void gst_qsv_decoder_task_clear (GstQsvDecoderTask * task); +static gboolean gst_qsv_decoder_negotiate_internal (GstVideoDecoder * decoder, + const mfxFrameInfo * frame_info); static void gst_qsv_decoder_class_init (GstQsvDecoderClass * klass) @@ -592,6 +594,7 @@ gst_qsv_decoder_finish_frame (GstQsvDecoder * self, GstQsvDecoderTask * task, { GstVideoDecoder *vdec = GST_VIDEO_DECODER (self); GstQsvDecoderPrivate *priv = self->priv; + GstQsvDecoderClass *klass = GST_QSV_DECODER_GET_CLASS (self); mfxStatus status; GstVideoCodecFrame *frame; GstClockTime pts = GST_CLOCK_TIME_NONE; @@ -643,6 +646,37 @@ gst_qsv_decoder_finish_frame (GstQsvDecoder * self, GstQsvDecoderTask * task, return GST_FLOW_ERROR; } + /* Handle non-keyframe resolution change */ + if (klass->codec_id == MFX_CODEC_VP9) { + guint width, height; + + if (surface->surface.Info.CropW > 0 && surface->surface.Info.CropH > 0) { + width = surface->surface.Info.CropW; + height = surface->surface.Info.CropH; + } else { + width = surface->surface.Info.Width; + height = surface->surface.Info.Height; + } + + if (width != (guint) priv->output_state->info.width || + height != (guint) priv->output_state->info.height) { + GST_DEBUG_OBJECT (self, + "VP9 resolution change %dx%d -> %dx%d, negotiate again", + priv->output_state->info.width, priv->output_state->info.height, + width, height); + if (!gst_qsv_decoder_negotiate_internal (vdec, &surface->surface.Info)) { + GST_ERROR_OBJECT (self, "Could not negotiate with downstream"); + return GST_FLOW_NOT_NEGOTIATED; + } + } + + /* TODO: Use crop meta if supported by downstream. + * Most d3d11 elements supports crop meta */ + if (width != (guint) priv->info.width + || height != (guint) priv->info.height) + force_copy = TRUE; + } + pts = gst_qsv_timestamp_to_gst (surface->surface.Data.TimeStamp); pool = gst_video_decoder_get_buffer_pool (vdec); if (!pool) { @@ -663,7 +697,7 @@ gst_qsv_decoder_finish_frame (GstQsvDecoder * self, GstQsvDecoderTask * task, /* TODO: Handle non-zero crop-{x,y} position via crop meta or similar */ buffer = gst_qsv_allocator_download_frame (priv->allocator, force_copy, - surface->frame, pool); + surface->frame, &priv->output_state->info, pool); gst_object_unref (pool); gst_qsv_decoder_task_clear (task); @@ -761,15 +795,13 @@ gst_qsv_decoder_decode_frame (GstQsvDecoder * self, mfxBitstream * bitstream, switch (status) { case MFX_ERR_NONE: - case MFX_WRN_VIDEO_PARAM_CHANGED:{ + case MFX_WRN_VIDEO_PARAM_CHANGED: if (surface->surface.Data.Locked > 0) surface = nullptr; if (bitstream && bitstream->DataLength == 0) return GST_FLOW_OK; - break; - } case MFX_ERR_MORE_SURFACE: return GST_FLOW_OK; case MFX_ERR_INCOMPATIBLE_VIDEO_PARAM: @@ -1072,6 +1104,72 @@ error: } static gboolean +gst_qsv_decoder_negotiate_internal (GstVideoDecoder * decoder, + const mfxFrameInfo * frame_info) +{ + GstQsvDecoder *self = GST_QSV_DECODER (decoder); + GstQsvDecoderPrivate *priv = self->priv; + guint width, height; + + width = frame_info->Width; + height = frame_info->Height; + + if (frame_info->CropW > 0 && frame_info->CropH > 0) { + width = frame_info->CropW; + height = frame_info->CropH; + } + + g_clear_pointer (&priv->output_state, gst_video_codec_state_unref); + priv->output_state = + gst_video_decoder_set_interlaced_output_state (GST_VIDEO_DECODER (self), + GST_VIDEO_INFO_FORMAT (&priv->info), + GST_VIDEO_INFO_INTERLACE_MODE (&priv->info), + width, height, priv->input_state); + + priv->output_state->caps = gst_video_info_to_caps (&priv->output_state->info); + priv->use_video_memory = FALSE; + +#ifdef G_OS_WIN32 + GstCaps *peer_caps = + gst_pad_get_allowed_caps (GST_VIDEO_DECODER_SRC_PAD (self)); + GST_DEBUG_OBJECT (self, "Allowed caps %" GST_PTR_FORMAT, peer_caps); + + if (!peer_caps || gst_caps_is_any (peer_caps)) { + GST_DEBUG_OBJECT (self, + "cannot determine output format, use system memory"); + } else { + GstCapsFeatures *features; + guint size = gst_caps_get_size (peer_caps); + + for (guint i = 0; i < size; i++) { + features = gst_caps_get_features (peer_caps, i); + + if (!features) + continue; + + if (gst_caps_features_contains (features, + GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)) { + priv->use_video_memory = TRUE; + break; + } + } + } + gst_clear_caps (&peer_caps); + + if (priv->use_video_memory) { + GST_DEBUG_OBJECT (self, "Downstream supports D3D11 memory"); + gst_caps_set_features (priv->output_state->caps, 0, + gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, nullptr)); + } +#endif + + GST_DEBUG_OBJECT (self, + "Negotiating with %" GST_PTR_FORMAT, priv->output_state->caps); + + return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder); +} + +static gboolean gst_qsv_decoder_negotiate (GstVideoDecoder * decoder) { GstQsvDecoder *self = GST_QSV_DECODER (decoder); @@ -1100,6 +1198,9 @@ gst_qsv_decoder_negotiate (GstVideoDecoder * decoder) case MFX_FOURCC_P010: format = GST_VIDEO_FORMAT_P010_10LE; break; + case MFX_FOURCC_P016: + format = GST_VIDEO_FORMAT_P016_LE; + break; default: break; } @@ -1130,52 +1231,8 @@ gst_qsv_decoder_negotiate (GstVideoDecoder * decoder) gst_video_info_set_interlaced_format (&priv->aligned_info, format, interlace_mode, aligned_width, aligned_height); - g_clear_pointer (&priv->output_state, gst_video_codec_state_unref); - priv->output_state = - gst_video_decoder_set_interlaced_output_state (GST_VIDEO_DECODER (self), - format, interlace_mode, width, height, priv->input_state); - - priv->output_state->caps = gst_video_info_to_caps (&priv->output_state->info); - priv->use_video_memory = FALSE; - -#ifdef G_OS_WIN32 - GstCaps *peer_caps = - gst_pad_get_allowed_caps (GST_VIDEO_DECODER_SRC_PAD (self)); - GST_DEBUG_OBJECT (self, "Allowed caps %" GST_PTR_FORMAT, peer_caps); - - if (!peer_caps || gst_caps_is_any (peer_caps)) { - GST_DEBUG_OBJECT (self, - "cannot determine output format, use system memory"); - } else { - GstCapsFeatures *features; - guint size = gst_caps_get_size (peer_caps); - - for (guint i = 0; i < size; i++) { - features = gst_caps_get_features (peer_caps, i); - - if (!features) - continue; - - if (gst_caps_features_contains (features, - GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)) { - priv->use_video_memory = TRUE; - break; - } - } - } - gst_clear_caps (&peer_caps); - - if (priv->use_video_memory) { - GST_DEBUG_OBJECT (self, "Downstream supports D3D11 memory"); - gst_caps_set_features (priv->output_state->caps, 0, - gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, nullptr)); - } -#endif - - GST_DEBUG_OBJECT (self, - "Negotiating with %" GST_PTR_FORMAT, priv->output_state->caps); - - return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder); + return gst_qsv_decoder_negotiate_internal (decoder, + &priv->video_param.mfx.FrameInfo); } #ifdef G_OS_WIN32 diff --git a/subprojects/gst-plugins-bad/sys/qsv/gstqsvvp9dec.cpp b/subprojects/gst-plugins-bad/sys/qsv/gstqsvvp9dec.cpp new file mode 100644 index 0000000..f2789a2 --- /dev/null +++ b/subprojects/gst-plugins-bad/sys/qsv/gstqsvvp9dec.cpp @@ -0,0 +1,331 @@ +/* GStreamer + * Copyright (C) 2022 Seungha Yang + * + * 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. + */ + +/** + * SECTION:element-qsvvp9dec + * @title: qsvvp9dec + * + * Intel Quick Sync VP9 decoder + * + * ## Example launch line + * ``` + * gst-launch-1.0 filesrc location=/path/to/vp9/file ! parsebin ! qsvvp9dec ! videoconvert ! autovideosink + * ``` + * + * Since: 1.22 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstqsvvp9dec.h" +#include +#include +#include + +#ifdef G_OS_WIN32 +#include +#else +#include +#endif + +GST_DEBUG_CATEGORY_STATIC (gst_qsv_vp9_dec_debug); +#define GST_CAT_DEFAULT gst_qsv_vp9_dec_debug + +#define DOC_SINK_CAPS \ + "video/x-vp9, width = (int) [ 1, 16384 ], height = (int) [ 1, 16384 ], " \ + "alignment = (string) frame, profile = (string) { 0, 2 }" + +#define DOC_SRC_CAPS_COMM \ + "format = (string) { NV12, P010_10LE, P016_LE}, " \ + "width = (int) [ 1, 16384 ], height = (int) [ 1, 16384 ]" + +#define DOC_SRC_CAPS \ + "video/x-raw(memory:D3D11Memory), " DOC_SRC_CAPS_COMM "; " \ + "video/x-raw, " DOC_SRC_CAPS_COMM + +typedef struct _GstQsvVP9Dec +{ + GstQsvDecoder parent; +} GstQsvVP9Dec; + +typedef struct _GstQsvVP9DecClass +{ + GstQsvDecoderClass parent_class; +} GstQsvVP9DecClass; + +static GTypeClass *parent_class = nullptr; + +#define GST_QSV_VP9_DEC(object) ((GstQsvVP9Dec *) (object)) +#define GST_QSV_VP9_DEC_GET_CLASS(object) \ + (G_TYPE_INSTANCE_GET_CLASS ((object),G_TYPE_FROM_INSTANCE (object),GstQsvVP9DecClass)) + +static void +gst_qsv_vp9_dec_class_init (GstQsvVP9DecClass * klass, gpointer data) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GstQsvDecoderClass *qsvdec_class = GST_QSV_DECODER_CLASS (klass); + GstQsvDecoderClassData *cdata = (GstQsvDecoderClassData *) data; + GstPadTemplate *pad_templ; + GstCaps *doc_caps; + + parent_class = (GTypeClass *) g_type_class_peek_parent (klass); + +#ifdef G_OS_WIN32 + std::string long_name = "Intel Quick Sync Video " + + std::string (cdata->description) + " VP9 Decoder"; + + gst_element_class_set_metadata (element_class, long_name.c_str (), + "Codec/Decoder/Video/Hardware", + "Intel Quick Sync Video VP9 Decoder", + "Seungha Yang "); +#else + gst_element_class_set_static_metadata (element_class, + "Intel Quick Sync Video VP9 Decoder", + "Codec/Decoder/Video/Hardware", + "Intel Quick Sync Video VP9 Decoder", + "Seungha Yang "); +#endif + + pad_templ = gst_pad_template_new ("sink", + GST_PAD_SINK, GST_PAD_ALWAYS, cdata->sink_caps); + doc_caps = gst_caps_from_string (DOC_SINK_CAPS); + gst_pad_template_set_documentation_caps (pad_templ, doc_caps); + gst_caps_unref (doc_caps); + gst_element_class_add_pad_template (element_class, pad_templ); + + pad_templ = gst_pad_template_new ("src", + GST_PAD_SRC, GST_PAD_ALWAYS, cdata->src_caps); + doc_caps = gst_caps_from_string (DOC_SRC_CAPS); + gst_pad_template_set_documentation_caps (pad_templ, doc_caps); + gst_caps_unref (doc_caps); + gst_element_class_add_pad_template (element_class, pad_templ); + + qsvdec_class->codec_id = MFX_CODEC_VP9; + qsvdec_class->impl_index = cdata->impl_index; + qsvdec_class->adapter_luid = cdata->adapter_luid; + qsvdec_class->display_path = cdata->display_path; + + gst_caps_unref (cdata->sink_caps); + gst_caps_unref (cdata->src_caps); + g_free (cdata); +} + +static void +gst_qsv_vp9_dec_init (GstQsvVP9Dec * self) +{ +} + +typedef struct +{ + guint width; + guint height; +} Resolution; + +void +gst_qsv_vp9_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}, {15360, 8640}, {16384, 8640} + }; + Resolution max_resolution; + std::vector < std::string > supported_formats; + gboolean have_profile_2 = FALSE; + gboolean have_profile_2_12bits = FALSE; + + GST_DEBUG_CATEGORY_INIT (gst_qsv_vp9_dec_debug, "qsvvp9dec", 0, "qsvvp9dec"); + + 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_VP9; + + 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_VP9_0; + + /* 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; + } + + if (max_resolution.width == 0 || max_resolution.height == 0) + return; + + GST_INFO ("Maximum supported resolution: %dx%d", + max_resolution.width, max_resolution.height); + + supported_formats.push_back ("NV12"); + + /* Check other profile/formats */ + mfx->FrameInfo.FourCC = MFX_FOURCC_P010; + mfx->FrameInfo.BitDepthLuma = 10; + mfx->FrameInfo.BitDepthChroma = 10; + mfx->FrameInfo.Shift = 1; + mfx->CodecProfile = MFX_PROFILE_VP9_2; + if (MFXVideoDECODE_Query (session, ¶m, ¶m) == MFX_ERR_NONE) { + have_profile_2 = TRUE; + supported_formats.push_back ("P010_10LE"); + + mfx->FrameInfo.FourCC = MFX_FOURCC_P016; + mfx->FrameInfo.BitDepthLuma = 12; + mfx->FrameInfo.BitDepthChroma = 12; + + if (MFXVideoDECODE_Query (session, ¶m, ¶m) == MFX_ERR_NONE) { + have_profile_2_12bits = TRUE; + supported_formats.push_back ("P016_LE"); + } + } + + /* 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"; + + src_caps_str += ", width=(int) [ 1, " + std::to_string (resolution) + " ]"; + src_caps_str += ", height=(int) [ 1, " + std::to_string (resolution) + " ]"; + + /* *INDENT-OFF* */ + if (supported_formats.size () > 1) { + src_caps_str += ", format=(string) { "; + bool first = true; + for (const auto &iter: supported_formats) { + if (!first) { + src_caps_str += ", "; + } + + src_caps_str += iter; + first = false; + } + src_caps_str += " }"; + } else { + src_caps_str += ", format=(string) " + supported_formats[0]; + } + /* *INDENT-ON* */ + + 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-vp9"; + sink_caps_str += ", width=(int) [ 1, " + std::to_string (resolution) + " ]"; + sink_caps_str += ", height=(int) [ 1, " + std::to_string (resolution) + " ]"; + sink_caps_str += ", alignment=(string) frame"; + if (have_profile_2 && have_profile_2_12bits) { + sink_caps_str += ", profile=(string) { 0, 2 }"; + } else if (have_profile_2) { + std::string profile2_str = sink_caps_str; + + profile2_str += ", profile = (string) 2, bit-depth-luma = (uint) 10, " + "bit-depth-chroma = (uint) 10"; + + sink_caps_str += ", profile = (string) 0; " + profile2_str; + } + + 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 + g_object_get (device, "adapter-luid", &cdata->adapter_luid, + "description", &cdata->description, nullptr); +#else + g_object_get (device, "path", &cdata->display_path, nullptr); +#endif + + GType type; + gchar *type_name; + gchar *feature_name; + GTypeInfo type_info = { + sizeof (GstQsvVP9DecClass), + nullptr, + nullptr, + (GClassInitFunc) gst_qsv_vp9_dec_class_init, + nullptr, + cdata, + sizeof (GstQsvVP9Dec), + 0, + (GInstanceInitFunc) gst_qsv_vp9_dec_init, + }; + + type_name = g_strdup ("GstQsvVP9Dec"); + feature_name = g_strdup ("qsvvp9dec"); + + gint index = 0; + while (g_type_from_name (type_name)) { + index++; + g_free (type_name); + g_free (feature_name); + type_name = g_strdup_printf ("GstQsvVP9Device%dDec", index); + feature_name = g_strdup_printf ("qsvvp9device%ddec", index); + } + + type = g_type_register_static (GST_TYPE_QSV_DECODER, type_name, &type_info, + (GTypeFlags) 0); + + if (rank > 0 && index != 0) + rank--; + + if (index != 0) + gst_element_type_set_skip_documentation (type); + + 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); +} diff --git a/subprojects/gst-plugins-bad/sys/qsv/gstqsvvp9dec.h b/subprojects/gst-plugins-bad/sys/qsv/gstqsvvp9dec.h new file mode 100644 index 0000000..4366df4 --- /dev/null +++ b/subprojects/gst-plugins-bad/sys/qsv/gstqsvvp9dec.h @@ -0,0 +1,34 @@ +/* GStreamer + * Copyright (C) 2022 Seungha Yang + * + * 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 +#include +#include "gstqsvdecoder.h" + +G_BEGIN_DECLS + +void gst_qsv_vp9_dec_register (GstPlugin * plugin, + guint rank, + guint impl_index, + GstObject * device, + mfxSession session); + +G_END_DECLS diff --git a/subprojects/gst-plugins-bad/sys/qsv/meson.build b/subprojects/gst-plugins-bad/sys/qsv/meson.build index 527c340..ea0fc5a 100644 --- a/subprojects/gst-plugins-bad/sys/qsv/meson.build +++ b/subprojects/gst-plugins-bad/sys/qsv/meson.build @@ -9,6 +9,7 @@ qsv_sources = [ 'gstqsvh265enc.cpp', 'gstqsvjpegenc.cpp', 'gstqsvutils.cpp', + 'gstqsvvp9dec.cpp', 'gstqsvvp9enc.cpp', 'plugin.cpp', ] diff --git a/subprojects/gst-plugins-bad/sys/qsv/plugin.cpp b/subprojects/gst-plugins-bad/sys/qsv/plugin.cpp index 59c6e67..6b448fa 100644 --- a/subprojects/gst-plugins-bad/sys/qsv/plugin.cpp +++ b/subprojects/gst-plugins-bad/sys/qsv/plugin.cpp @@ -46,6 +46,7 @@ #include "gstqsvh265dec.h" #include "gstqsvh265enc.h" #include "gstqsvjpegenc.h" +#include "gstqsvvp9dec.h" #include "gstqsvvp9enc.h" #include "gstqsvutils.h" #include @@ -256,6 +257,7 @@ plugin_init (GstPlugin * plugin) gst_qsv_h264_dec_register (plugin, GST_RANK_MARGINAL, i, device, session); gst_qsv_h265_dec_register (plugin, GST_RANK_MARGINAL, i, device, session); + gst_qsv_vp9_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);