plugins: Add a vaapidecodebin element
authorSreerenj Balachandran <sreerenj.balachandran@intel.com>
Mon, 2 Mar 2015 13:19:40 +0000 (15:19 +0200)
committerSreerenj Balachandran <sreerenj.balachandran@intel.com>
Mon, 2 Mar 2015 14:51:55 +0000 (16:51 +0200)
Add a "vaapidecodebin" element to vaapi plugins.

Child Elements: "vaapidecode ! queue ! vaapipostproc"

The Reasons for implementing a new bin element:

-- Help to Autoplug Hardware Accelerated Video Postprocessing element in playbin
with out any dependency to upstream gstreamer.
This is to overcome the *unacceptable* delay in upstream gstreamer to get new
features in. Eg: https://bugzilla.gnome.org/show_bug.cgi?id=687182.
Also customers using older gstreamer versions (1.2 and 1.4) will get the
benefit of autoplugging, hardware accelerated deinterlacing support etc.

-- Help to maintain a single thread implementation in vaapidecode.
This will result a dead-lock free vaapidecode in most of the cases.
More details here: https://bugzilla.gnome.org/show_bug.cgi?id=742605

https://bugzilla.gnome.org/show_bug.cgi?id=745216

gst/vaapi/Makefile.am
gst/vaapi/gstvaapi.c
gst/vaapi/gstvaapidecodebin.c [new file with mode: 0644]
gst/vaapi/gstvaapidecodebin.h [new file with mode: 0644]

index d2ff9455b37c7145d9831ead9342b216f01d6a05..69fb6bf5a68e7c3723c9b4f825030648b607bcdf 100644 (file)
@@ -56,6 +56,7 @@ libgstvaapi_source_c = \
        gstvaapivideobuffer.c   \
        gstvaapivideocontext.c  \
        gstvaapivideometa.c     \
+       gstvaapidecodebin.c     \
        $(NULL)
 
 libgstvaapi_source_h = \
@@ -68,6 +69,7 @@ libgstvaapi_source_h = \
        gstvaapivideobuffer.h   \
        gstvaapivideocontext.h  \
        gstvaapivideometa.h     \
+       gstvaapidecodebin.h     \
        $(NULL)
 
 libgstvaapi_enc_source_c =     \
@@ -189,7 +191,7 @@ libgstvaapi_la_LIBADD =     \
        $(libgstvaapi_LIBS)     \
        $(GST_LIBS)             \
        $(GST_BASE_LIBS)        \
-       $(GST_VIDEO_LIBS)       \
+       $(GST_VIDEO_LIBS) -lgstpbutils-$(GST_PKG_VERSION) \
        $(GST_INTERFACES_LIBS)  \
        $(GST_BASEVIDEO_LIBS)   \
        $(GST_PLUGINS_BASE_LIBS) \
index f15731b66fa8d6a0f584be3671d0b77eb336a784..44bbc84bff77403878be829912641603cb9da533 100644 (file)
@@ -29,6 +29,7 @@
 #include "gstvaapidecode.h"
 #include "gstvaapipostproc.h"
 #include "gstvaapisink.h"
+#include "gstvaapidecodebin.h"
 
 #if USE_ENCODERS
 #include "gstvaapiencode_h264.h"
@@ -86,6 +87,9 @@ plugin_init (GstPlugin *plugin)
                          GST_TYPE_VAAPIENCODE_VP8);
 #endif
 
+    gst_element_register(plugin, "vaapidecodebin",
+                         GST_RANK_PRIMARY + 2,
+                         GST_TYPE_VAAPI_DECODE_BIN);
     return TRUE;
 }
 
diff --git a/gst/vaapi/gstvaapidecodebin.c b/gst/vaapi/gstvaapidecodebin.c
new file mode 100644 (file)
index 0000000..388ff02
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ *  gstvaapidecodebin.c
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gst/vaapi/sysdeps.h"
+#include <stdio.h>
+#include <string.h>
+#include <gst/gst.h>
+#include <gst/pbutils/pbutils.h>
+#include "gstvaapipluginutil.h"
+#include "gstvaapidecodebin.h"
+
+#define GST_PLUGIN_NAME "vaapidecodebin"
+#define GST_PLUGIN_DESC "A Bin of VA-API elements: vaapidecode ! queue ! vaapipostproc"
+
+GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapi_decode_bin);
+#define GST_CAT_DEFAULT gst_debug_vaapi_decode_bin
+
+#define DEFAULT_QUEUE_MAX_SIZE_BUFFERS 0
+#define DEFAULT_QUEUE_MAX_SIZE_BYTES   0
+#define DEFAULT_QUEUE_MAX_SIZE_TIME    0
+
+enum
+{
+  PROP_0,
+  PROP_MAX_SIZE_BUFFERS,
+  PROP_MAX_SIZE_BYTES,
+  PROP_MAX_SIZE_TIME
+};
+
+#if GST_CHECK_VERSION(1,1,0)
+#define GST_VAAPI_DECODE_BIN_SURFACE_CAPS \
+    GST_VIDEO_CAPS_MAKE_WITH_FEATURES(  \
+        GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, "{ ENCODED, I420, YV12, NV12 }")
+#else
+#define GST_VAAPI_DECODE_BIN_SURFACE_CAPS \
+    GST_VAAPI_SURFACE_CAPS
+#endif
+
+/* Default templates */
+#define GST_CAPS_CODEC(CODEC) CODEC "; "
+/* *INDENT-OFF* */
+static const char gst_vaapi_decode_bin_sink_caps_str[] =
+    GST_CAPS_CODEC("video/mpeg, mpegversion=2, systemstream=(boolean)false")
+    GST_CAPS_CODEC("video/mpeg, mpegversion=4")
+    GST_CAPS_CODEC("video/x-divx")
+    GST_CAPS_CODEC("video/x-xvid")
+    GST_CAPS_CODEC("video/x-h263")
+    GST_CAPS_CODEC("video/x-h264")
+    GST_CAPS_CODEC("video/x-wmv")
+    GST_CAPS_CODEC("video/x-vp8")
+    GST_CAPS_CODEC("image/jpeg")
+    ;
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+static const char gst_vaapi_decode_bin_src_caps_str[] =
+  GST_VAAPI_DECODE_BIN_SURFACE_CAPS ", "
+  GST_CAPS_INTERLACED_FALSE "; "
+#if GST_CHECK_VERSION(1,1,0)
+  GST_VIDEO_CAPS_MAKE_WITH_FEATURES (
+      GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, "{ RGBA, BGRA }") ", "
+  GST_CAPS_INTERLACED_FALSE "; "
+#endif
+#if GST_CHECK_VERSION(1,0,0)
+  GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL) ", "
+#endif
+  GST_CAPS_INTERLACED_FALSE;
+/* *INDENT-ON* */
+
+static GstStaticPadTemplate gst_vaapi_decode_bin_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (gst_vaapi_decode_bin_sink_caps_str));
+
+static GstStaticPadTemplate gst_vaapi_decode_bin_src_factory =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (gst_vaapi_decode_bin_src_caps_str));
+
+G_DEFINE_TYPE (GstVaapiDecodeBin, gst_vaapi_decode_bin, GST_TYPE_BIN);
+
+static void
+gst_vaapi_decode_bin_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiDecodeBin *vaapidecbin = GST_VAAPI_DECODE_BIN (object);
+
+  switch (prop_id) {
+    case PROP_MAX_SIZE_BYTES:
+      vaapidecbin->max_size_bytes = g_value_get_uint (value);
+      g_object_set (G_OBJECT (vaapidecbin->queue), "max-size-bytes",
+          vaapidecbin->max_size_bytes, NULL);
+      break;
+    case PROP_MAX_SIZE_BUFFERS:
+      vaapidecbin->max_size_buffers = g_value_get_uint (value);
+      g_object_set (G_OBJECT (vaapidecbin->queue), "max-size-buffers",
+          vaapidecbin->max_size_buffers, NULL);
+      break;
+    case PROP_MAX_SIZE_TIME:
+      vaapidecbin->max_size_time = g_value_get_uint64 (value);
+      g_object_set (G_OBJECT (vaapidecbin->queue), "max-size-time",
+          vaapidecbin->max_size_time, NULL);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_vaapi_decode_bin_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstVaapiDecodeBin *vaapidecbin = GST_VAAPI_DECODE_BIN (object);
+
+  switch (prop_id) {
+    case PROP_MAX_SIZE_BYTES:
+      g_value_set_uint (value, vaapidecbin->max_size_bytes);
+      break;
+    case PROP_MAX_SIZE_BUFFERS:
+      g_value_set_uint (value, vaapidecbin->max_size_buffers);
+      break;
+    case PROP_MAX_SIZE_TIME:
+      g_value_set_uint64 (value, vaapidecbin->max_size_time);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_vaapi_decode_bin_class_init (GstVaapiDecodeBinClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->set_property = gst_vaapi_decode_bin_set_property;
+  gobject_class->get_property = gst_vaapi_decode_bin_get_property;
+
+  gst_element_class_set_static_metadata (element_class,
+      "VA-API Decode Bin",
+      "Codec/Decoder/Video",
+      GST_PLUGIN_DESC,
+      "Sreerenj Balachandran <sreerenj.balachandran@intel.com>");
+
+  g_object_class_install_property (gobject_class, PROP_MAX_SIZE_BYTES,
+      g_param_spec_uint ("max-size-bytes", "Max. size (kB)",
+          "Max. amount of data in the queue (bytes, 0=disable)",
+          0, G_MAXUINT, DEFAULT_QUEUE_MAX_SIZE_BYTES,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_MAX_SIZE_BUFFERS,
+      g_param_spec_uint ("max-size-buffers", "Max. size (buffers)",
+          "Max. number of buffers in the queue (0=disable)", 0, G_MAXUINT,
+          DEFAULT_QUEUE_MAX_SIZE_BUFFERS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_MAX_SIZE_TIME,
+      g_param_spec_uint64 ("max-size-time", "Max. size (ns)",
+          "Max. amount of data in the queue (in ns, 0=disable)", 0, G_MAXUINT64,
+          DEFAULT_QUEUE_MAX_SIZE_TIME,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&gst_vaapi_decode_bin_sink_factory));
+
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&gst_vaapi_decode_bin_src_factory));
+
+  GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_decode_bin,
+      GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
+}
+
+static gboolean
+gst_vaapi_decode_bin_configure (GstVaapiDecodeBin * vaapidecbin)
+{
+  gchar *missing_factory = NULL;
+
+  /* create the decoder */
+  vaapidecbin->decoder =
+      gst_element_factory_make ("vaapidecode", "vaapidecode");
+  if (!vaapidecbin->decoder) {
+    missing_factory = "vaapidecode";
+    goto error_element_missing;
+  }
+  /* create the queue */
+  vaapidecbin->queue = gst_element_factory_make ("queue", "queue");
+  if (!vaapidecbin->queue) {
+    missing_factory = "queue";
+    goto error_element_missing;
+  }
+  /* create the postproc */
+  vaapidecbin->postproc =
+      gst_element_factory_make ("vaapipostproc", "vaapipostproc");
+  if (!vaapidecbin->postproc) {
+    missing_factory = "vaapipostproc";
+    goto error_element_missing;
+  }
+
+  g_object_set (G_OBJECT (vaapidecbin->queue),
+      "max-size-bytes", vaapidecbin->max_size_bytes,
+      "max-size-buffers", vaapidecbin->max_size_buffers,
+      "max-size-time", vaapidecbin->max_size_time, NULL);
+
+  gst_bin_add_many (GST_BIN (vaapidecbin),
+      vaapidecbin->decoder, vaapidecbin->queue, vaapidecbin->postproc, NULL);
+
+  if (!gst_element_link_pads_full (vaapidecbin->decoder, "src",
+          vaapidecbin->queue, "sink", GST_PAD_LINK_CHECK_NOTHING))
+    goto error_link_pad;
+
+  if (!gst_element_link_pads_full (vaapidecbin->queue, "src",
+          vaapidecbin->postproc, "sink", GST_PAD_LINK_CHECK_NOTHING))
+    goto error_link_pad;
+
+  return TRUE;
+
+error_element_missing:
+  {
+    GstMessage *msg;
+    GST_ERROR_OBJECT (vaapidecbin, "Failed to create %s element",
+        missing_factory);
+    msg =
+        gst_missing_element_message_new (GST_ELEMENT_CAST (vaapidecbin),
+        missing_factory);
+    gst_element_post_message (GST_ELEMENT_CAST (vaapidecbin), msg);
+    return FALSE;
+  }
+error_link_pad:
+  {
+    GST_ERROR_OBJECT (vaapidecbin, "Failed to link the child elements");
+    return FALSE;
+  }
+}
+
+static void
+gst_vaapi_decode_bin_init (GstVaapiDecodeBin * vaapidecbin)
+{
+  GstPad *element_pad, *ghost_pad;
+
+  if (!gst_vaapi_decode_bin_configure (vaapidecbin))
+    return;
+
+  /* create ghost pad sink */
+  element_pad =
+      gst_element_get_static_pad (GST_ELEMENT (vaapidecbin->decoder), "sink");
+  ghost_pad =
+      gst_ghost_pad_new_from_template ("sink", element_pad,
+      GST_PAD_PAD_TEMPLATE (element_pad));
+  gst_object_unref (element_pad);
+  gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghost_pad);
+
+  /* create ghost pad src */
+  element_pad =
+      gst_element_get_static_pad (GST_ELEMENT (vaapidecbin->postproc), "src");
+  ghost_pad =
+      gst_ghost_pad_new_from_template ("src", element_pad,
+      GST_PAD_PAD_TEMPLATE (element_pad));
+  gst_object_unref (element_pad);
+  gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghost_pad);
+}
diff --git a/gst/vaapi/gstvaapidecodebin.h b/gst/vaapi/gstvaapidecodebin.h
new file mode 100644 (file)
index 0000000..2477635
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *  gstvaapidecodebin.h
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GST_VAAPI_DECODE_BIN_H__
+#define __GST_VAAPI_DECODE_BIN_H__
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_DECODE_BIN (gst_vaapi_decode_bin_get_type ())
+#define GST_VAAPI_DECODE_BIN(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODE_BIN, GstVaapiDecodeBin))
+#define GST_VAAPI_DECODE_BIN_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_DECODE_BIN, GstVaapiDecodeBinClass))
+#define GST_IS_AUTO_DETECT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODE_BIN))
+#define GST_IS_AUTO_DETECT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_DECODE_BIN))
+#define GST_VAAPI_DECODE_BIN_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_DECODE_BIN, GstVaapiDecodeBinClass))
+
+typedef struct _GstVaapiDecodeBin {
+  /* < private > */
+  GstBin parent;
+
+  GstElement *decoder;
+  GstElement *queue;
+  GstElement *postproc;
+
+  /* properties */
+  guint   max_size_buffers;
+  guint   max_size_bytes;
+  guint64 max_size_time;
+
+} GstVaapiDecodeBin;
+
+typedef struct _GstVaapiDecodeBinClass {
+  GstBinClass parent_class;
+
+} GstVaapiDecodeBinClass;
+
+GType   gst_vaapi_decode_bin_get_type    (void);
+
+G_END_DECLS
+
+#endif /* __GST_VAAPI_DECODE_BIN_H__ */