4 * Copyright (C) 2015 Intel Corporation
5 * Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
6 * Author: Victor Jaquez <victorx.jaquez@intel.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1
11 * of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301 USA
25 * SECTION:element-vaapidecodebin
26 * @short_description: A VA-API based video decoder with a
29 * vaapidecodebin is similar vaapi{CODEC}dec, but it is composed by
30 * the unregistered vaapidecode, a #GstQueue, and the
31 * #GstVaapiPostproc, if it is available and functional in the setup.
33 * It offers the functionality of GstVaapiDecoder and the many options
34 * of #GstVaapiPostproc.
36 * ## Example launch line
39 * gst-launch-1.0 filesrc location=~/big_buck_bunny.mov ! qtdemux ! h264parse ! vaapidecodebin ! vaapisink
43 #include "gstcompat.h"
47 #include <gst/pbutils/pbutils.h>
48 #include "gstvaapipluginutil.h"
49 #include "gstvaapidecodebin.h"
50 #include "gstvaapivideocontext.h"
51 #include "gstvaapipluginbase.h"
54 #define GST_PLUGIN_NAME "vaapidecodebin"
55 #define GST_PLUGIN_DESC "A VA-API based bin with a decoder and a postprocessor"
57 GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapi_decode_bin);
58 #define GST_CAT_DEFAULT gst_debug_vaapi_decode_bin
60 #define DEFAULT_QUEUE_MAX_SIZE_BUFFERS 1
61 #define DEFAULT_QUEUE_MAX_SIZE_BYTES 0
62 #define DEFAULT_QUEUE_MAX_SIZE_TIME 0
63 #define DEFAULT_DEINTERLACE_METHOD GST_VAAPI_DEINTERLACE_METHOD_BOB
68 PROP_MAX_SIZE_BUFFERS,
71 PROP_DEINTERLACE_METHOD,
76 static GParamSpec *properties[PROP_LAST];
78 /* Default templates */
79 #define GST_CAPS_CODEC(CODEC) CODEC "; "
81 static const char gst_vaapi_decode_bin_sink_caps_str[] =
82 GST_CAPS_CODEC("video/mpeg, mpegversion=2, systemstream=(boolean)false")
83 GST_CAPS_CODEC("video/mpeg, mpegversion=4")
84 GST_CAPS_CODEC("video/x-divx")
85 GST_CAPS_CODEC("video/x-xvid")
86 GST_CAPS_CODEC("video/x-h263")
87 GST_CAPS_CODEC("video/x-h264")
88 GST_CAPS_CODEC("video/x-h265")
89 GST_CAPS_CODEC("video/x-wmv")
90 GST_CAPS_CODEC("video/x-vp8")
91 GST_CAPS_CODEC("video/x-vp9")
96 static const char gst_vaapi_decode_bin_src_caps_str[] =
97 GST_VAAPI_MAKE_SURFACE_CAPS ", "
98 GST_CAPS_INTERLACED_FALSE "; "
99 #if (USE_GLX || USE_EGL)
100 GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS ", "
101 GST_CAPS_INTERLACED_FALSE "; "
103 GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL) ", "
104 GST_CAPS_INTERLACED_FALSE;
107 static GstStaticPadTemplate gst_vaapi_decode_bin_sink_factory =
108 GST_STATIC_PAD_TEMPLATE ("sink",
111 GST_STATIC_CAPS (gst_vaapi_decode_bin_sink_caps_str));
113 static GstStaticPadTemplate gst_vaapi_decode_bin_src_factory =
114 GST_STATIC_PAD_TEMPLATE ("src",
117 GST_STATIC_CAPS (gst_vaapi_decode_bin_src_caps_str));
119 G_DEFINE_TYPE (GstVaapiDecodeBin, gst_vaapi_decode_bin, GST_TYPE_BIN);
121 extern gboolean _gst_vaapi_has_video_processing;
123 static gboolean gst_vaapi_decode_bin_configure (GstVaapiDecodeBin * self);
126 post_missing_element_message (GstVaapiDecodeBin * vaapidecbin,
127 const gchar * missing_factory)
131 msg = gst_missing_element_message_new (GST_ELEMENT_CAST (vaapidecbin),
133 gst_element_post_message (GST_ELEMENT_CAST (vaapidecbin), msg);
135 GST_ELEMENT_WARNING (vaapidecbin, CORE, MISSING_PLUGIN,
136 ("Missing element '%s' - check your GStreamer installation.",
137 missing_factory), ("video decoding might fail"));
141 gst_vaapi_decode_bin_set_property (GObject * object,
142 guint prop_id, const GValue * value, GParamSpec * pspec)
144 GstVaapiDecodeBin *vaapidecbin = GST_VAAPI_DECODE_BIN (object);
147 case PROP_MAX_SIZE_BYTES:
148 vaapidecbin->max_size_bytes = g_value_get_uint (value);
149 g_object_set (G_OBJECT (vaapidecbin->queue), "max-size-bytes",
150 vaapidecbin->max_size_bytes, NULL);
152 case PROP_MAX_SIZE_BUFFERS:
153 vaapidecbin->max_size_buffers = g_value_get_uint (value);
154 g_object_set (G_OBJECT (vaapidecbin->queue), "max-size-buffers",
155 vaapidecbin->max_size_buffers, NULL);
157 case PROP_MAX_SIZE_TIME:
158 vaapidecbin->max_size_time = g_value_get_uint64 (value);
159 g_object_set (G_OBJECT (vaapidecbin->queue), "max-size-time",
160 vaapidecbin->max_size_time, NULL);
162 case PROP_DEINTERLACE_METHOD:
163 vaapidecbin->deinterlace_method = g_value_get_enum (value);
164 if (vaapidecbin->postproc)
165 g_object_set (G_OBJECT (vaapidecbin->postproc), "deinterlace-method",
166 vaapidecbin->deinterlace_method, NULL);
168 case PROP_DISABLE_VPP:
169 /* @TODO: Add run-time disabling support */
170 vaapidecbin->disable_vpp = g_value_get_boolean (value);
173 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
179 gst_vaapi_decode_bin_get_property (GObject * object,
180 guint prop_id, GValue * value, GParamSpec * pspec)
182 GstVaapiDecodeBin *vaapidecbin = GST_VAAPI_DECODE_BIN (object);
185 case PROP_MAX_SIZE_BYTES:
186 g_value_set_uint (value, vaapidecbin->max_size_bytes);
188 case PROP_MAX_SIZE_BUFFERS:
189 g_value_set_uint (value, vaapidecbin->max_size_buffers);
191 case PROP_MAX_SIZE_TIME:
192 g_value_set_uint64 (value, vaapidecbin->max_size_time);
194 case PROP_DEINTERLACE_METHOD:
195 g_value_set_enum (value, vaapidecbin->deinterlace_method);
197 case PROP_DISABLE_VPP:
198 g_value_set_boolean (value, vaapidecbin->disable_vpp);
201 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
206 static GstStateChangeReturn
207 gst_vaapi_decode_bin_change_state (GstElement * element,
208 GstStateChange transition)
210 GstVaapiDecodeBin *vaapidecbin = GST_VAAPI_DECODE_BIN (element);
211 GstStateChangeReturn ret;
213 switch (transition) {
218 ret = GST_ELEMENT_CLASS (gst_vaapi_decode_bin_parent_class)->change_state
219 (element, transition);
220 if (ret == GST_STATE_CHANGE_FAILURE)
223 switch (transition) {
224 case GST_STATE_CHANGE_NULL_TO_READY:
225 if (!gst_vaapi_decode_bin_configure (vaapidecbin))
226 return GST_STATE_CHANGE_FAILURE;
236 gst_vaapi_decode_bin_class_init (GstVaapiDecodeBinClass * klass)
238 GObjectClass *gobject_class;
239 GstElementClass *element_class;
241 gobject_class = G_OBJECT_CLASS (klass);
242 element_class = GST_ELEMENT_CLASS (klass);
244 gobject_class->set_property = gst_vaapi_decode_bin_set_property;
245 gobject_class->get_property = gst_vaapi_decode_bin_get_property;
247 element_class->change_state = gst_vaapi_decode_bin_change_state;
248 gst_element_class_set_static_metadata (element_class,
250 "Codec/Decoder/Video/Hardware",
252 "Sreerenj Balachandran <sreerenj.balachandran@intel.com>, "
253 "Victor Jaquez <victorx.jaquez@intel.com>");
255 properties[PROP_MAX_SIZE_BYTES] = g_param_spec_uint ("max-size-bytes",
256 "Max. size (kB)", "Max. amount of data in the queue (bytes, 0=disable)",
257 0, G_MAXUINT, DEFAULT_QUEUE_MAX_SIZE_BYTES,
258 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
259 properties[PROP_MAX_SIZE_BUFFERS] = g_param_spec_uint ("max-size-buffers",
260 "Max. size (buffers)", "Max. number of buffers in the queue (0=disable)",
261 0, G_MAXUINT, DEFAULT_QUEUE_MAX_SIZE_BUFFERS,
262 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
263 properties[PROP_MAX_SIZE_TIME] = g_param_spec_uint64 ("max-size-time",
264 "Max. size (ns)", "Max. amount of data in the queue (in ns, 0=disable)",
265 0, G_MAXUINT64, DEFAULT_QUEUE_MAX_SIZE_TIME,
266 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
267 properties[PROP_DEINTERLACE_METHOD] = g_param_spec_enum ("deinterlace-method",
268 "Deinterlace method", "Deinterlace method to use",
269 GST_VAAPI_TYPE_DEINTERLACE_METHOD, DEFAULT_DEINTERLACE_METHOD,
270 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
271 properties[PROP_DISABLE_VPP] = g_param_spec_boolean ("disable-vpp",
273 "Disable Video Post Processing (No support for run time disabling)",
274 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
276 g_object_class_install_properties (gobject_class, PROP_LAST, properties);
278 gst_element_class_add_static_pad_template (element_class,
279 &gst_vaapi_decode_bin_sink_factory);
281 gst_element_class_add_static_pad_template (element_class,
282 &gst_vaapi_decode_bin_src_factory);
284 GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_decode_bin,
285 GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
289 gst_vaapi_decode_bin_configure (GstVaapiDecodeBin * vaapidecbin)
291 GstElement *capsfilter;
293 GstPad *queue_srcpad, *bin_srcpad, *capsfilter_sinkpad, *vpp_srcpad;
297 g_object_set (G_OBJECT (vaapidecbin->queue),
298 "max-size-bytes", vaapidecbin->max_size_bytes,
299 "max-size-buffers", vaapidecbin->max_size_buffers,
300 "max-size-time", vaapidecbin->max_size_time, NULL);
302 if (vaapidecbin->disable_vpp || vaapidecbin->configured)
305 has_vpp = _gst_vaapi_has_video_processing;
307 if (!has_vpp && (vaapidecbin->deinterlace_method ==
308 GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE
309 || vaapidecbin->deinterlace_method ==
310 GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED)) {
311 GST_ERROR_OBJECT (vaapidecbin,
312 "Don't have VPP support but advanced deinterlacing selected");
316 GST_INFO_OBJECT (vaapidecbin, "enabling VPP");
318 /* capsfilter to force memory:VASurface */
319 caps = gst_caps_from_string ("video/x-raw(memory:VASurface)");
321 goto error_cannot_set_caps;
322 capsfilter = gst_element_factory_make ("capsfilter", NULL);
323 g_object_set (capsfilter, "caps", caps, NULL);
324 gst_caps_unref (caps);
326 /* create the postproc */
327 vaapidecbin->postproc = gst_element_factory_make ("vaapipostproc", NULL);
328 if (!vaapidecbin->postproc)
329 goto error_vpp_missing;
330 g_object_set (G_OBJECT (vaapidecbin->postproc), "deinterlace-method",
331 vaapidecbin->deinterlace_method, NULL);
333 gst_bin_add_many (GST_BIN (vaapidecbin), capsfilter, vaapidecbin->postproc,
336 if (!gst_element_link (capsfilter, vaapidecbin->postproc))
337 goto error_sync_state;
339 if (!gst_element_sync_state_with_parent (capsfilter))
340 goto error_sync_state;
341 if (!gst_element_sync_state_with_parent (vaapidecbin->postproc))
342 goto error_sync_state;
344 /* break source ghost pad target */
346 gst_element_get_static_pad (GST_ELEMENT_CAST (vaapidecbin), "src");
347 if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (bin_srcpad), NULL))
350 /* link decoder and queue */
351 queue_srcpad = gst_element_get_static_pad (vaapidecbin->queue, "src");
352 capsfilter_sinkpad = gst_element_get_static_pad (capsfilter, "sink");
353 res = (gst_pad_link (queue_srcpad, capsfilter_sinkpad) == GST_PAD_LINK_OK);
354 gst_object_unref (capsfilter_sinkpad);
355 gst_object_unref (queue_srcpad);
359 /* set vpp source pad as source ghost pad target */
360 vpp_srcpad = gst_element_get_static_pad (vaapidecbin->postproc, "src");
361 res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (bin_srcpad), vpp_srcpad);
362 gst_object_unref (vpp_srcpad);
366 gst_object_unref (bin_srcpad);
367 vaapidecbin->configured = TRUE;
372 error_cannot_set_caps:
374 GST_ELEMENT_ERROR (vaapidecbin, CORE, PAD,
375 ("Failed to configure caps for VA Surfaces."), (NULL));
380 post_missing_element_message (vaapidecbin, "vaapipostproc");
385 GST_ELEMENT_ERROR (vaapidecbin, CORE, STATE_CHANGE,
386 ("Failed to sync state of vaapipostproc"), (NULL));
391 gst_object_unref (bin_srcpad);
392 GST_ELEMENT_ERROR (vaapidecbin, CORE, PAD,
393 ("Failed to configure the vaapidecodebin."), (NULL));
399 gst_vaapi_decode_bin_init (GstVaapiDecodeBin * vaapidecbin)
401 GstPad *pad, *ghostpad;
403 vaapidecbin->max_size_bytes = DEFAULT_QUEUE_MAX_SIZE_BYTES;
404 vaapidecbin->max_size_buffers = DEFAULT_QUEUE_MAX_SIZE_BUFFERS;
405 vaapidecbin->max_size_time = DEFAULT_QUEUE_MAX_SIZE_TIME;
406 vaapidecbin->disable_vpp = (g_getenv ("GST_VAAPI_DISABLE_VPP") != NULL);
408 /* create the decoder */
409 vaapidecbin->decoder =
410 g_object_new (g_type_from_name ("GstVaapiDecode"), NULL);
411 g_assert (vaapidecbin->decoder);
413 /* create the queue */
414 vaapidecbin->queue = gst_element_factory_make ("queue", NULL);
415 g_assert (vaapidecbin->queue);
417 gst_bin_add_many (GST_BIN (vaapidecbin), vaapidecbin->decoder,
418 vaapidecbin->queue, NULL);
420 if (!gst_element_link (vaapidecbin->decoder, vaapidecbin->queue)) {
421 GST_WARNING_OBJECT (vaapidecbin, "Failed to link decoder and queue");
425 /* create ghost pad sink */
426 pad = gst_element_get_static_pad (vaapidecbin->decoder, "sink");
428 GST_WARNING_OBJECT (vaapidecbin, "Failed to get decoder sink pad");
432 ghostpad = gst_ghost_pad_new ("sink", pad);
433 gst_object_unref (pad);
434 if (!gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghostpad)) {
435 GST_WARNING_OBJECT (vaapidecbin, "Failed to add decoder sink pad to bin");
439 /* create ghost pad src */
440 pad = gst_element_get_static_pad (GST_ELEMENT (vaapidecbin->queue), "src");
441 ghostpad = gst_ghost_pad_new_from_template ("src", pad,
442 GST_PAD_PAD_TEMPLATE (pad));
443 gst_object_unref (pad);
444 if (!gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghostpad))
445 GST_WARNING_OBJECT (vaapidecbin, "Failed to add queue source pad to bin");