67bd4e0e9b4f4ba39266ecabeb289693c18a7ecf
[platform/upstream/gstreamer.git] / subprojects / gstreamer-vaapi / gst / vaapi / gstvaapidecodebin.c
1 /*
2  *  gstvaapidecodebin.c
3  *
4  *  Copyright (C) 2015 Intel Corporation
5  *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
6  *    Author: Victor Jaquez <victorx.jaquez@intel.com>
7  *
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.
12  *
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.
17  *
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
22  */
23
24 /**
25  * SECTION:element-vaapidecodebin
26  * @short_description: A VA-API based video decoder with a
27  * post-processor
28  *
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.
32  *
33  * It offers the functionality of GstVaapiDecoder and the many options
34  * of #GstVaapiPostproc.
35  *
36  * ## Example launch line
37  *
38  * |[
39  * gst-launch-1.0 filesrc location=~/big_buck_bunny.mov ! qtdemux ! h264parse ! vaapidecodebin ! vaapisink
40  * ]|
41  */
42
43 #include "gstcompat.h"
44 #include <stdio.h>
45 #include <string.h>
46 #include <gst/gst.h>
47 #include <gst/pbutils/pbutils.h>
48 #include "gstvaapipluginutil.h"
49 #include "gstvaapidecodebin.h"
50 #include "gstvaapivideocontext.h"
51 #include "gstvaapipluginbase.h"
52 #include "gstvaapi.h"
53
54 #define GST_PLUGIN_NAME "vaapidecodebin"
55 #define GST_PLUGIN_DESC "A VA-API based bin with a decoder and a postprocessor"
56
57 GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapi_decode_bin);
58 #define GST_CAT_DEFAULT gst_debug_vaapi_decode_bin
59
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
64
65 enum
66 {
67   PROP_0,
68   PROP_MAX_SIZE_BUFFERS,
69   PROP_MAX_SIZE_BYTES,
70   PROP_MAX_SIZE_TIME,
71   PROP_DEINTERLACE_METHOD,
72   PROP_DISABLE_VPP,
73   PROP_LAST
74 };
75
76 static GParamSpec *properties[PROP_LAST];
77
78 /* Default templates */
79 #define GST_CAPS_CODEC(CODEC) CODEC "; "
80 /* *INDENT-OFF* */
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")
92     ;
93 /* *INDENT-ON* */
94
95 /* *INDENT-OFF* */
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 "; "
102 #endif
103   GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL) ", "
104   GST_CAPS_INTERLACED_FALSE;
105 /* *INDENT-ON* */
106
107 static GstStaticPadTemplate gst_vaapi_decode_bin_sink_factory =
108 GST_STATIC_PAD_TEMPLATE ("sink",
109     GST_PAD_SINK,
110     GST_PAD_ALWAYS,
111     GST_STATIC_CAPS (gst_vaapi_decode_bin_sink_caps_str));
112
113 static GstStaticPadTemplate gst_vaapi_decode_bin_src_factory =
114 GST_STATIC_PAD_TEMPLATE ("src",
115     GST_PAD_SRC,
116     GST_PAD_ALWAYS,
117     GST_STATIC_CAPS (gst_vaapi_decode_bin_src_caps_str));
118
119 G_DEFINE_TYPE (GstVaapiDecodeBin, gst_vaapi_decode_bin, GST_TYPE_BIN);
120
121 extern gboolean _gst_vaapi_has_video_processing;
122
123 static gboolean gst_vaapi_decode_bin_configure (GstVaapiDecodeBin * self);
124
125 static void
126 post_missing_element_message (GstVaapiDecodeBin * vaapidecbin,
127     const gchar * missing_factory)
128 {
129   GstMessage *msg;
130
131   msg = gst_missing_element_message_new (GST_ELEMENT_CAST (vaapidecbin),
132       missing_factory);
133   gst_element_post_message (GST_ELEMENT_CAST (vaapidecbin), msg);
134
135   GST_ELEMENT_WARNING (vaapidecbin, CORE, MISSING_PLUGIN,
136       ("Missing element '%s' - check your GStreamer installation.",
137           missing_factory), ("video decoding might fail"));
138 }
139
140 static void
141 gst_vaapi_decode_bin_set_property (GObject * object,
142     guint prop_id, const GValue * value, GParamSpec * pspec)
143 {
144   GstVaapiDecodeBin *vaapidecbin = GST_VAAPI_DECODE_BIN (object);
145
146   switch (prop_id) {
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);
151       break;
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);
156       break;
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);
161       break;
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);
167       break;
168     case PROP_DISABLE_VPP:
169       /* @TODO: Add run-time disabling support */
170       vaapidecbin->disable_vpp = g_value_get_boolean (value);
171       break;
172     default:
173       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
174       break;
175   }
176 }
177
178 static void
179 gst_vaapi_decode_bin_get_property (GObject * object,
180     guint prop_id, GValue * value, GParamSpec * pspec)
181 {
182   GstVaapiDecodeBin *vaapidecbin = GST_VAAPI_DECODE_BIN (object);
183
184   switch (prop_id) {
185     case PROP_MAX_SIZE_BYTES:
186       g_value_set_uint (value, vaapidecbin->max_size_bytes);
187       break;
188     case PROP_MAX_SIZE_BUFFERS:
189       g_value_set_uint (value, vaapidecbin->max_size_buffers);
190       break;
191     case PROP_MAX_SIZE_TIME:
192       g_value_set_uint64 (value, vaapidecbin->max_size_time);
193       break;
194     case PROP_DEINTERLACE_METHOD:
195       g_value_set_enum (value, vaapidecbin->deinterlace_method);
196       break;
197     case PROP_DISABLE_VPP:
198       g_value_set_boolean (value, vaapidecbin->disable_vpp);
199       break;
200     default:
201       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
202       break;
203   }
204 }
205
206 static GstStateChangeReturn
207 gst_vaapi_decode_bin_change_state (GstElement * element,
208     GstStateChange transition)
209 {
210   GstVaapiDecodeBin *vaapidecbin = GST_VAAPI_DECODE_BIN (element);
211   GstStateChangeReturn ret;
212
213   switch (transition) {
214     default:
215       break;
216   }
217
218   ret = GST_ELEMENT_CLASS (gst_vaapi_decode_bin_parent_class)->change_state
219       (element, transition);
220   if (ret == GST_STATE_CHANGE_FAILURE)
221     return ret;
222
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;
227       break;
228     default:
229       break;
230   }
231
232   return ret;
233 }
234
235 static void
236 gst_vaapi_decode_bin_class_init (GstVaapiDecodeBinClass * klass)
237 {
238   GObjectClass *gobject_class;
239   GstElementClass *element_class;
240
241   gobject_class = G_OBJECT_CLASS (klass);
242   element_class = GST_ELEMENT_CLASS (klass);
243
244   gobject_class->set_property = gst_vaapi_decode_bin_set_property;
245   gobject_class->get_property = gst_vaapi_decode_bin_get_property;
246
247   element_class->change_state = gst_vaapi_decode_bin_change_state;
248   gst_element_class_set_static_metadata (element_class,
249       "VA-API Decode Bin",
250       "Codec/Decoder/Video/Hardware",
251       GST_PLUGIN_DESC,
252       "Sreerenj Balachandran <sreerenj.balachandran@intel.com>, "
253       "Victor Jaquez <victorx.jaquez@intel.com>");
254
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",
272       "Disable VPP",
273       "Disable Video Post Processing (No support for run time disabling)",
274       FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
275
276   g_object_class_install_properties (gobject_class, PROP_LAST, properties);
277
278   gst_element_class_add_static_pad_template (element_class,
279       &gst_vaapi_decode_bin_sink_factory);
280
281   gst_element_class_add_static_pad_template (element_class,
282       &gst_vaapi_decode_bin_src_factory);
283
284   GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_decode_bin,
285       GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
286 }
287
288 static gboolean
289 gst_vaapi_decode_bin_configure (GstVaapiDecodeBin * vaapidecbin)
290 {
291   GstElement *capsfilter;
292   GstCaps *caps;
293   GstPad *queue_srcpad, *bin_srcpad, *capsfilter_sinkpad, *vpp_srcpad;
294   gboolean res;
295   gboolean has_vpp;
296
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);
301
302   if (vaapidecbin->disable_vpp || vaapidecbin->configured)
303     return TRUE;
304
305   has_vpp = _gst_vaapi_has_video_processing;
306
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");
313     return FALSE;
314   }
315
316   GST_INFO_OBJECT (vaapidecbin, "enabling VPP");
317
318   /* capsfilter to force memory:VASurface */
319   caps = gst_caps_from_string ("video/x-raw(memory:VASurface)");
320   if (!caps)
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);
325
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);
332
333   gst_bin_add_many (GST_BIN (vaapidecbin), capsfilter, vaapidecbin->postproc,
334       NULL);
335
336   if (!gst_element_link (capsfilter, vaapidecbin->postproc))
337     goto error_sync_state;
338
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;
343
344   /* break source ghost pad target */
345   bin_srcpad =
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))
348     goto error_link_pad;
349
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);
356   if (!res)
357     goto error_link_pad;
358
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);
363   if (!res)
364     goto error_link_pad;
365
366   gst_object_unref (bin_srcpad);
367   vaapidecbin->configured = TRUE;
368
369   return TRUE;
370
371   /* ERRORS */
372 error_cannot_set_caps:
373   {
374     GST_ELEMENT_ERROR (vaapidecbin, CORE, PAD,
375         ("Failed to configure caps for VA Surfaces."), (NULL));
376     return FALSE;
377   }
378 error_vpp_missing:
379   {
380     post_missing_element_message (vaapidecbin, "vaapipostproc");
381     return FALSE;
382   }
383 error_sync_state:
384   {
385     GST_ELEMENT_ERROR (vaapidecbin, CORE, STATE_CHANGE,
386         ("Failed to sync state of vaapipostproc"), (NULL));
387     return FALSE;
388   }
389 error_link_pad:
390   {
391     gst_object_unref (bin_srcpad);
392     GST_ELEMENT_ERROR (vaapidecbin, CORE, PAD,
393         ("Failed to configure the vaapidecodebin."), (NULL));
394     return FALSE;
395   }
396 }
397
398 static void
399 gst_vaapi_decode_bin_init (GstVaapiDecodeBin * vaapidecbin)
400 {
401   GstPad *pad, *ghostpad;
402
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);
407
408   /* create the decoder */
409   vaapidecbin->decoder =
410       g_object_new (g_type_from_name ("GstVaapiDecode"), NULL);
411   g_assert (vaapidecbin->decoder);
412
413   /* create the queue */
414   vaapidecbin->queue = gst_element_factory_make ("queue", NULL);
415   g_assert (vaapidecbin->queue);
416
417   gst_bin_add_many (GST_BIN (vaapidecbin), vaapidecbin->decoder,
418       vaapidecbin->queue, NULL);
419
420   if (!gst_element_link (vaapidecbin->decoder, vaapidecbin->queue)) {
421     GST_WARNING_OBJECT (vaapidecbin, "Failed to link decoder and queue");
422     return;
423   }
424
425   /* create ghost pad sink */
426   pad = gst_element_get_static_pad (vaapidecbin->decoder, "sink");
427   if (!pad) {
428     GST_WARNING_OBJECT (vaapidecbin, "Failed to get decoder sink pad");
429     return;
430   }
431
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");
436     return;
437   }
438
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");
446 }