qsv: Add JPEG decoder
authorSeungha Yang <seungha@centricular.com>
Wed, 2 Nov 2022 20:12:31 +0000 (05:12 +0900)
committerSeungha Yang <seungha@centricular.com>
Wed, 2 Nov 2022 21:40:10 +0000 (06:40 +0900)
Because DXVA does not define JPEG decoding, we need this
vendor specific API for Windows

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3316>

subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json
subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator.cpp
subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator.h
subprojects/gst-plugins-bad/sys/qsv/gstqsvallocator_d3d11.cpp
subprojects/gst-plugins-bad/sys/qsv/gstqsvdecoder.cpp
subprojects/gst-plugins-bad/sys/qsv/gstqsvjpegdec.cpp [new file with mode: 0644]
subprojects/gst-plugins-bad/sys/qsv/gstqsvjpegdec.h [new file with mode: 0644]
subprojects/gst-plugins-bad/sys/qsv/meson.build
subprojects/gst-plugins-bad/sys/qsv/plugin.cpp

index 619e4b3..119cc2f 100644 (file)
                 },
                 "rank": "none"
             },
+            "qsvjpegdec": {
+                "author": "Seungha Yang <seungha@centricular.com>",
+                "description": "Intel Quick Sync Video JPEG Decoder",
+                "hierarchy": [
+                    "GstQsvJpegDec",
+                    "GstQsvDecoder",
+                    "GstVideoDecoder",
+                    "GstElement",
+                    "GstObject",
+                    "GInitiallyUnowned",
+                    "GObject"
+                ],
+                "klass": "Codec/Decoder/Video/Hardware",
+                "pad-templates": {
+                    "sink": {
+                        "caps": "image/jpeg:\n          width: [ 1, 16384 ]\n         height: [ 1, 16384 ]\n",
+                        "direction": "sink",
+                        "presence": "always"
+                    },
+                    "src": {
+                        "caps": "video/x-raw(memory:D3D11Memory):\n         format: { NV12, YUY2, BGRA }\n          width: [ 1, 16384 ]\n         height: [ 1, 16384 ]\nvideo/x-raw:\n         format: { NV12, YUY2, BGRA }\n          width: [ 1, 16384 ]\n         height: [ 1, 16384 ]\n",
+                        "direction": "src",
+                        "presence": "always"
+                    }
+                },
+                "rank": "secondary"
+            },
             "qsvjpegenc": {
                 "author": "Seungha Yang <seungha@centricular.com>",
                 "description": "Intel Quick Sync Video JPEG Encoder",
index 86030f5..a022719 100644 (file)
@@ -215,6 +215,12 @@ gst_qsv_allocator_alloc_default (GstQsvAllocator * self, gboolean dummy_alloc,
     case MFX_FOURCC_Y410:
       format = GST_VIDEO_FORMAT_Y410;
       break;
+    case MFX_FOURCC_YUY2:
+      format = GST_VIDEO_FORMAT_YUY2;
+      break;
+    case MFX_FOURCC_RGB4:
+      format = GST_VIDEO_FORMAT_BGRA;
+      break;
     default:
       /* TODO: add more formats */
       break;
@@ -407,6 +413,7 @@ gst_qsv_allocator_lock (mfxHDL pthis, mfxMemId mid, mfxFrameData * ptr)
   switch (GST_VIDEO_INFO_FORMAT (&frame->info)) {
     case GST_VIDEO_FORMAT_NV12:
     case GST_VIDEO_FORMAT_P010_10LE:
+    case GST_VIDEO_FORMAT_P016_LE:
       ptr->Pitch = (mfxU16) stride;
       ptr->Y = (mfxU8 *) GST_VIDEO_FRAME_PLANE_DATA (&frame->frame, 0);
       ptr->UV = (mfxU8 *) GST_VIDEO_FRAME_PLANE_DATA (&frame->frame, 1);
@@ -438,6 +445,12 @@ gst_qsv_allocator_lock (mfxHDL pthis, mfxMemId mid, mfxFrameData * ptr)
       ptr->B = ptr->R + 2;
       ptr->A = ptr->R + 3;
       break;
+    case GST_VIDEO_FORMAT_YUY2:
+      ptr->Pitch = (mfxU16) stride;
+      ptr->Y = (mfxU8 *) GST_VIDEO_FRAME_PLANE_DATA (&frame->frame, 0);
+      ptr->U = ptr->Y + 1;
+      ptr->V = ptr->Y + 3;
+      break;
     default:
       break;
   }
@@ -485,10 +498,8 @@ gst_qsv_allocator_get_hdl (mfxHDL pthis, mfxMemId mid, mfxHDL * handle)
   GstQsvFrame *frame = GST_QSV_FRAME_CAST (mid);
   GstMapInfo map_info;
 
-  if (!GST_QSV_MEM_TYPE_IS_VIDEO (frame->mem_type)) {
-    GST_ERROR_OBJECT (self, "Unexpected call");
+  if (!GST_QSV_MEM_TYPE_IS_VIDEO (frame->mem_type))
     return MFX_ERR_UNSUPPORTED;
-  }
 
   g_mutex_lock (&frame->lock);
   if (!frame->buffer) {
@@ -673,7 +684,8 @@ gst_qsv_allocator_acquire_frame (GstQsvAllocator * allocator,
 
     if ((mem_type & GST_QSV_ENCODER_IN_MEMORY) != 0) {
       map_flags |= GST_MAP_READ;
-    } else if ((mem_type & GST_QSV_DECODER_OUT_MEMORY) != 0) {
+    } else if ((mem_type & GST_QSV_DECODER_OUT_MEMORY) != 0 ||
+        (mem_type & GST_QSV_PROCESS_TARGET) != 0) {
       map_flags |= GST_MAP_WRITE;
     } else {
       GST_ERROR_OBJECT (allocator,
index fc1e68e..10227fa 100644 (file)
@@ -73,6 +73,7 @@ typedef enum
   GST_QSV_VIDEO_MEMORY = (1 << 1),
   GST_QSV_ENCODER_IN_MEMORY = (1 << 2),
   GST_QSV_DECODER_OUT_MEMORY = (1 << 3),
+  GST_QSV_PROCESS_TARGET = (1 << 4),
 } GstQsvMemoryType;
 
 #define GST_QSV_MEM_TYPE_IS_SYSTEM(type) ((type & GST_QSV_SYSTEM_MEMORY) != 0)
index fa94e2f..d70077d 100644 (file)
@@ -121,6 +121,9 @@ gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator,
     case MFX_FOURCC_BGR4:
       dxgi_format = DXGI_FORMAT_R8G8B8A8_UNORM;
       break;
+    case MFX_FOURCC_YUY2:
+      dxgi_format = DXGI_FORMAT_YUY2;
+      break;
     default:
       /* TODO: add more formats */
       break;
@@ -191,6 +194,11 @@ gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator,
       mem_type |= GST_QSV_DECODER_OUT_MEMORY;
     }
 
+    if ((request->Type & MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET) != 0) {
+      bind_flags |= D3D11_BIND_RENDER_TARGET;
+      mem_type |= GST_QSV_PROCESS_TARGET;
+    }
+
     if (mem_type == GST_QSV_VIDEO_MEMORY) {
       GST_ERROR_OBJECT (self, "Unknown read/write access");
       return MFX_ERR_UNSUPPORTED;
index 2176dce..e737355 100644 (file)
@@ -912,16 +912,33 @@ gst_qsv_decoder_prepare_d3d11_pool (GstQsvDecoder * self,
   GstStructure *config;
   GstD3D11AllocationParams *params;
   GstD3D11Device *device = GST_D3D11_DEVICE_CAST (priv->device);
+  guint bind_flags = 0;
+  GstD3D11Format d3d11_format;
 
   GST_DEBUG_OBJECT (self, "Use d3d11 memory pool");
 
   priv->internal_pool = gst_d3d11_buffer_pool_new (device);
   config = gst_buffer_pool_get_config (priv->internal_pool);
+
+  gst_d3d11_device_get_format (device, GST_VIDEO_INFO_FORMAT (info),
+      &d3d11_format);
+
+  /* May not support DOV, specifically RGB output case */
+  if ((d3d11_format.format_support[0] &
+          (guint) D3D11_FORMAT_SUPPORT_DECODER_OUTPUT) != 0) {
+    bind_flags |= D3D11_BIND_DECODER;
+  } else if ((d3d11_format.format_support[0] &
+          (guint) D3D11_FORMAT_SUPPORT_RENDER_TARGET) != 0) {
+    bind_flags |= D3D11_BIND_RENDER_TARGET;
+  }
   /* Bind to shader resource as well for this texture can be used
    * in generic pixel shader */
+  if ((d3d11_format.format_support[0] & (guint)
+          D3D11_FORMAT_SUPPORT_SHADER_SAMPLE) != 0)
+    bind_flags |= D3D11_BIND_SHADER_RESOURCE;
+
   params = gst_d3d11_allocation_params_new (device, info,
-      GST_D3D11_ALLOCATION_FLAG_DEFAULT,
-      D3D11_BIND_DECODER | D3D11_BIND_SHADER_RESOURCE, 0);
+      GST_D3D11_ALLOCATION_FLAG_DEFAULT, bind_flags, 0);
   gst_d3d11_allocation_params_alignment (params, align);
   gst_buffer_pool_config_set_d3d11_allocation_params (config, params);
   gst_d3d11_allocation_params_free (params);
@@ -1201,10 +1218,25 @@ gst_qsv_decoder_negotiate (GstVideoDecoder * decoder)
     case MFX_FOURCC_P016:
       format = GST_VIDEO_FORMAT_P016_LE;
       break;
+    case MFX_FOURCC_RGB4:
+      format = GST_VIDEO_FORMAT_BGRA;
+      break;
     default:
       break;
   }
 
+  if (klass->codec_id == MFX_CODEC_JPEG) {
+    if (param->mfx.JPEGChromaFormat == MFX_CHROMAFORMAT_YUV422) {
+      format = GST_VIDEO_FORMAT_YUY2;
+      frame_info->FourCC = MFX_FOURCC_YUY2;
+      frame_info->ChromaFormat = MFX_CHROMAFORMAT_YUV422;
+    } else if (param->mfx.JPEGColorFormat == MFX_JPEG_COLORFORMAT_RGB) {
+      format = GST_VIDEO_FORMAT_BGRA;
+      frame_info->FourCC = MFX_FOURCC_RGB4;
+      frame_info->ChromaFormat = MFX_CHROMAFORMAT_YUV444;
+    }
+  }
+
   if (format == GST_VIDEO_FORMAT_UNKNOWN) {
     GST_ERROR_OBJECT (self, "Unknown video format");
     return FALSE;
@@ -1296,17 +1328,31 @@ gst_qsv_decoder_decide_allocation (GstVideoDecoder * decoder, GstQuery * query)
   /* Decoder will use internal pool to output but this pool is required for
    * copying in case of reverse playback */
   if (use_d3d11_pool) {
+    guint bind_flags = 0;
+    GstD3D11Format d3d11_format;
+
     d3d11_params = gst_buffer_pool_config_get_d3d11_allocation_params (config);
     if (!d3d11_params) {
       d3d11_params = gst_d3d11_allocation_params_new (device, &vinfo,
           GST_D3D11_ALLOCATION_FLAG_DEFAULT, 0, 0);
     }
+
+    gst_d3d11_device_get_format (device, GST_VIDEO_INFO_FORMAT (&vinfo),
+        &d3d11_format);
+
     /* Use both render target (for videoprocessor) and shader resource
      * for (pixel shader) bind flags for downstream to be able to use consistent
      * conversion path even when we copy textures */
-    d3d11_params->desc[0].BindFlags |=
-        (D3D11_BIND_DECODER | D3D11_BIND_SHADER_RESOURCE);
+    if ((d3d11_format.format_support[0] &
+            (guint) D3D11_FORMAT_SUPPORT_RENDER_TARGET) != 0) {
+      bind_flags |= D3D11_BIND_RENDER_TARGET;
+    }
+
+    if ((d3d11_format.format_support[0] & (guint)
+            D3D11_FORMAT_SUPPORT_SHADER_SAMPLE) != 0)
+      bind_flags |= D3D11_BIND_SHADER_RESOURCE;
 
+    d3d11_params->desc[0].BindFlags |= bind_flags;
     gst_buffer_pool_config_set_d3d11_allocation_params (config, d3d11_params);
     gst_d3d11_allocation_params_free (d3d11_params);
   }
diff --git a/subprojects/gst-plugins-bad/sys/qsv/gstqsvjpegdec.cpp b/subprojects/gst-plugins-bad/sys/qsv/gstqsvjpegdec.cpp
new file mode 100644 (file)
index 0000000..7017c87
--- /dev/null
@@ -0,0 +1,303 @@
+/* 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.
+ */
+
+/**
+ * SECTION:element-qsvjpegdec
+ * @title: qsvjpegdec
+ *
+ * Intel Quick Sync JPEG decoder
+ *
+ * ## Example launch line
+ * ```
+ * gst-launch-1.0 filesrc location=/path/to/jpeg/file ! parsebin ! qsvjpegdec ! videoconvert ! autovideosink
+ * ```
+ *
+ * Since: 1.22
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstqsvjpegdec.h"
+#include <string>
+#include <string.h>
+#include <vector>
+
+#ifdef G_OS_WIN32
+#include <gst/d3d11/gstd3d11.h>
+#else
+#include <gst/va/gstva.h>
+#endif
+
+GST_DEBUG_CATEGORY_STATIC (gst_qsv_jpeg_dec_debug);
+#define GST_CAT_DEFAULT gst_qsv_jpeg_dec_debug
+
+#define DOC_SINK_CAPS \
+    "image/jpeg, width = (int) [ 1, 16384 ], height = (int) [ 1, 16384 ]"
+
+#define DOC_SRC_CAPS_COMM \
+    "format = (string) { NV12, YUY2, BGRA }, " \
+    "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 _GstQsvJpegDec
+{
+  GstQsvDecoder parent;
+} GstQsvJpegDec;
+
+typedef struct _GstQsvJpegDecClass
+{
+  GstQsvDecoderClass parent_class;
+} GstQsvJpegDecClass;
+
+static GTypeClass *parent_class = nullptr;
+
+#define GST_QSV_JPEG_DEC(object) ((GstQsvJpegDec *) (object))
+#define GST_QSV_JPEG_DEC_GET_CLASS(object) \
+    (G_TYPE_INSTANCE_GET_CLASS ((object),G_TYPE_FROM_INSTANCE (object),GstQsvJpegDecClass))
+
+static void
+gst_qsv_jpeg_dec_class_init (GstQsvJpegDecClass * 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) + " JPEG Decoder";
+
+  gst_element_class_set_metadata (element_class, long_name.c_str (),
+      "Codec/Decoder/Video/Hardware",
+      "Intel Quick Sync Video JPEG Decoder",
+      "Seungha Yang <seungha@centricular.com>");
+#else
+  gst_element_class_set_static_metadata (element_class,
+      "Intel Quick Sync Video JPEG Decoder",
+      "Codec/Decoder/Video/Hardware",
+      "Intel Quick Sync Video JPEG Decoder",
+      "Seungha Yang <seungha@centricular.com>");
+#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_JPEG;
+  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_jpeg_dec_init (GstQsvJpegDec * self)
+{
+}
+
+void
+gst_qsv_jpeg_dec_register (GstPlugin * plugin, guint rank, guint impl_index,
+    GstObject * device, mfxSession session)
+{
+  mfxVideoParam param;
+  mfxInfoMFX *mfx;
+  GstQsvResolution max_resolution;
+  std::vector < std::string > supported_formats;
+
+  GST_DEBUG_CATEGORY_INIT (gst_qsv_jpeg_dec_debug, "qsvjpegdec", 0,
+      "qsvjpegdec");
+
+  memset (&param, 0, sizeof (mfxVideoParam));
+  memset (&max_resolution, 0, sizeof (GstQsvResolution));
+
+  param.AsyncDepth = 4;
+  param.IOPattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY;
+
+  mfx = &param.mfx;
+  mfx->CodecId = MFX_CODEC_JPEG;
+
+  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_JPEG_BASELINE;
+  mfx->JPEGChromaFormat = MFX_CHROMAFORMAT_YUV420;
+  mfx->JPEGColorFormat = MFX_JPEG_COLORFORMAT_YCbCr;
+
+  /* Check max-resolution */
+  for (guint i = 0; i < G_N_ELEMENTS (gst_qsv_resolutions); i++) {
+    mfx->FrameInfo.Width = GST_ROUND_UP_16 (gst_qsv_resolutions[i].width);
+    mfx->FrameInfo.Height = GST_ROUND_UP_16 (gst_qsv_resolutions[i].height);
+    mfx->FrameInfo.CropW = gst_qsv_resolutions[i].width;
+    mfx->FrameInfo.CropH = gst_qsv_resolutions[i].height;
+
+    if (MFXVideoDECODE_Query (session, &param, &param) != MFX_ERR_NONE)
+      break;
+
+    max_resolution.width = gst_qsv_resolutions[i].width;
+    max_resolution.height = gst_qsv_resolutions[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");
+
+  mfx->FrameInfo.FourCC = MFX_FOURCC_YUY2;
+  mfx->FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
+  mfx->JPEGChromaFormat = MFX_CHROMAFORMAT_YUV422;
+  if (MFXVideoDECODE_Query (session, &param, &param) == MFX_ERR_NONE)
+    supported_formats.push_back ("YUY2");
+
+  mfx->FrameInfo.FourCC = MFX_FOURCC_RGB4;
+  mfx->FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
+  mfx->JPEGChromaFormat = MFX_CHROMAFORMAT_YUV444;
+  mfx->JPEGColorFormat = MFX_JPEG_COLORFORMAT_RGB;
+  if (MFXVideoDECODE_Query (session, &param, &param) == MFX_ERR_NONE)
+    supported_formats.push_back ("BGRA");
+
+  /* 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 = "image/jpeg";
+  sink_caps_str += ", width=(int) [ 1, " + std::to_string (resolution) + " ]";
+  sink_caps_str += ", height=(int) [ 1, " + std::to_string (resolution) + " ]";
+
+  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 (GstQsvJpegDecClass),
+    nullptr,
+    nullptr,
+    (GClassInitFunc) gst_qsv_jpeg_dec_class_init,
+    nullptr,
+    cdata,
+    sizeof (GstQsvJpegDec),
+    0,
+    (GInstanceInitFunc) gst_qsv_jpeg_dec_init,
+  };
+
+  type_name = g_strdup ("GstQsvJpegDec");
+  feature_name = g_strdup ("qsvjpegdec");
+
+  gint index = 0;
+  while (g_type_from_name (type_name)) {
+    index++;
+    g_free (type_name);
+    g_free (feature_name);
+    type_name = g_strdup_printf ("GstQsvJPEGDevice%dDec", index);
+    feature_name = g_strdup_printf ("qsvjpegdevice%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/gstqsvjpegdec.h b/subprojects/gst-plugins-bad/sys/qsv/gstqsvjpegdec.h
new file mode 100644 (file)
index 0000000..092bb1e
--- /dev/null
@@ -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_jpeg_dec_register (GstPlugin * plugin,
+                                guint rank,
+                                guint impl_index,
+                                GstObject * device,
+                                mfxSession session);
+
+G_END_DECLS
index ea0fc5a..dff24d0 100644 (file)
@@ -7,6 +7,7 @@ qsv_sources = [
   'gstqsvh264enc.cpp',
   'gstqsvh265dec.cpp',
   'gstqsvh265enc.cpp',
+  'gstqsvjpegdec.cpp',
   'gstqsvjpegenc.cpp',
   'gstqsvutils.cpp',
   'gstqsvvp9dec.cpp',
index 6b448fa..b71a01a 100644 (file)
@@ -45,6 +45,7 @@
 #include "gstqsvh264enc.h"
 #include "gstqsvh265dec.h"
 #include "gstqsvh265enc.h"
+#include "gstqsvjpegdec.h"
 #include "gstqsvjpegenc.h"
 #include "gstqsvvp9dec.h"
 #include "gstqsvvp9enc.h"
@@ -257,6 +258,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_jpeg_dec_register (plugin, GST_RANK_SECONDARY, 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);