From 8eabe9f3774eedf14a029da3385b744f38af4b19 Mon Sep 17 00:00:00 2001 From: Sreerenj Balachandran Date: Mon, 2 Mar 2015 15:19:40 +0200 Subject: [PATCH] plugins: Add a vaapidecodebin element 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 | 4 +- gst/vaapi/gstvaapi.c | 4 + gst/vaapi/gstvaapidecodebin.c | 284 ++++++++++++++++++++++++++++++++++ gst/vaapi/gstvaapidecodebin.h | 64 ++++++++ 4 files changed, 355 insertions(+), 1 deletion(-) create mode 100644 gst/vaapi/gstvaapidecodebin.c create mode 100644 gst/vaapi/gstvaapidecodebin.h diff --git a/gst/vaapi/Makefile.am b/gst/vaapi/Makefile.am index d2ff9455b3..69fb6bf5a6 100644 --- a/gst/vaapi/Makefile.am +++ b/gst/vaapi/Makefile.am @@ -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) \ diff --git a/gst/vaapi/gstvaapi.c b/gst/vaapi/gstvaapi.c index f15731b66f..44bbc84bff 100644 --- a/gst/vaapi/gstvaapi.c +++ b/gst/vaapi/gstvaapi.c @@ -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 index 0000000000..388ff02463 --- /dev/null +++ b/gst/vaapi/gstvaapidecodebin.c @@ -0,0 +1,284 @@ +/* + * gstvaapidecodebin.c + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * 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 +#include +#include +#include +#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 "); + + 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 index 0000000000..24776358f8 --- /dev/null +++ b/gst/vaapi/gstvaapidecodebin.h @@ -0,0 +1,64 @@ +/* + * gstvaapidecodebin.h + * + * Copyright (C) 2015 Intel Corporation + * Author: Sreerenj Balachandran + * + * 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__ */