refactor vaapi caps strings for pad templates
[platform/upstream/gstreamer.git] / gst / vaapi / gstvaapidecodebin.c
1 /*
2  *  gstvaapidecodebin.c
3  *
4  *  Copyright (C) 2015 Intel Corporation
5  *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public License
9  *  as published by the Free Software Foundation; either version 2.1
10  *  of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free
19  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA 02110-1301 USA
21  */
22
23 #include "gstcompat.h"
24 #include <stdio.h>
25 #include <string.h>
26 #include <gst/gst.h>
27 #include <gst/pbutils/pbutils.h>
28 #include "gstvaapipluginutil.h"
29 #include "gstvaapidecodebin.h"
30 #include "gstvaapivideocontext.h"
31
32 #define GST_PLUGIN_NAME "vaapidecodebin"
33 #define GST_PLUGIN_DESC "A Bin of VA-API elements: vaapidecode ! queue ! vaapipostproc"
34
35 GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapi_decode_bin);
36 #define GST_CAT_DEFAULT gst_debug_vaapi_decode_bin
37
38 #define DEFAULT_QUEUE_MAX_SIZE_BUFFERS 0
39 #define DEFAULT_QUEUE_MAX_SIZE_BYTES   0
40 #define DEFAULT_QUEUE_MAX_SIZE_TIME    0
41 #define DEFAULT_DEINTERLACE_METHOD     GST_VAAPI_DEINTERLACE_METHOD_BOB
42
43 enum
44 {
45   PROP_0,
46   PROP_MAX_SIZE_BUFFERS,
47   PROP_MAX_SIZE_BYTES,
48   PROP_MAX_SIZE_TIME,
49   PROP_DEINTERLACE_METHOD,
50   PROP_DISABLE_VPP,
51   PROP_LAST
52 };
53
54 static GParamSpec *properties[PROP_LAST];
55
56 /* Default templates */
57 #define GST_CAPS_CODEC(CODEC) CODEC "; "
58 /* *INDENT-OFF* */
59 static const char gst_vaapi_decode_bin_sink_caps_str[] =
60     GST_CAPS_CODEC("video/mpeg, mpegversion=2, systemstream=(boolean)false")
61     GST_CAPS_CODEC("video/mpeg, mpegversion=4")
62     GST_CAPS_CODEC("video/x-divx")
63     GST_CAPS_CODEC("video/x-xvid")
64     GST_CAPS_CODEC("video/x-h263")
65     GST_CAPS_CODEC("video/x-h264")
66 #if USE_HEVC_DECODER
67     GST_CAPS_CODEC("video/x-h265")
68 #endif
69     GST_CAPS_CODEC("video/x-wmv")
70 #if USE_VP8_DECODER
71     GST_CAPS_CODEC("video/x-vp8")
72 #endif
73 #if USE_JPEG_DECODER
74     GST_CAPS_CODEC("image/jpeg")
75 #endif
76     ;
77 /* *INDENT-ON* */
78
79 /* *INDENT-OFF* */
80 static const char gst_vaapi_decode_bin_src_caps_str[] =
81   GST_VAAPI_MAKE_SURFACE_CAPS ", "
82   GST_CAPS_INTERLACED_FALSE "; "
83   GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS ", "
84   GST_CAPS_INTERLACED_FALSE "; "
85   GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL) ", "
86   GST_CAPS_INTERLACED_FALSE;
87 /* *INDENT-ON* */
88
89 static GstStaticPadTemplate gst_vaapi_decode_bin_sink_factory =
90 GST_STATIC_PAD_TEMPLATE ("sink",
91     GST_PAD_SINK,
92     GST_PAD_ALWAYS,
93     GST_STATIC_CAPS (gst_vaapi_decode_bin_sink_caps_str));
94
95 static GstStaticPadTemplate gst_vaapi_decode_bin_src_factory =
96 GST_STATIC_PAD_TEMPLATE ("src",
97     GST_PAD_SRC,
98     GST_PAD_ALWAYS,
99     GST_STATIC_CAPS (gst_vaapi_decode_bin_src_caps_str));
100
101 G_DEFINE_TYPE (GstVaapiDecodeBin, gst_vaapi_decode_bin, GST_TYPE_BIN);
102
103 static void
104 post_missing_element_message (GstVaapiDecodeBin * vaapidecbin,
105     const gchar * missing_factory)
106 {
107   GstMessage *msg;
108
109   GST_ERROR_OBJECT (vaapidecbin, "Failed to create %s element",
110       missing_factory);
111   msg =
112       gst_missing_element_message_new (GST_ELEMENT_CAST (vaapidecbin),
113       missing_factory);
114   gst_element_post_message (GST_ELEMENT_CAST (vaapidecbin), msg);
115 }
116
117 static gboolean
118 activate_vpp (GstVaapiDecodeBin * vaapidecbin)
119 {
120   GstElement *src;
121
122   if (vaapidecbin->ghost_pad_src || vaapidecbin->postproc)
123     return TRUE;
124
125   if (!vaapidecbin->has_vpp || vaapidecbin->disable_vpp) {
126     src = vaapidecbin->queue;
127     goto connect_src_ghost_pad;
128   }
129
130   /* create the postproc */
131   vaapidecbin->postproc =
132       gst_element_factory_make ("vaapipostproc", "vaapipostproc");
133   if (!vaapidecbin->postproc)
134     goto error_element_missing;
135
136   g_object_set (G_OBJECT (vaapidecbin->postproc), "deinterlace-method",
137       vaapidecbin->deinterlace_method, NULL);
138
139   gst_bin_add (GST_BIN (vaapidecbin), vaapidecbin->postproc);
140   if (!gst_element_link_pads_full (vaapidecbin->queue, "src",
141           vaapidecbin->postproc, "sink", GST_PAD_LINK_CHECK_NOTHING))
142     goto error_link_pad;
143
144   GST_DEBUG_OBJECT (vaapidecbin, "Enabling VPP");
145   src = vaapidecbin->postproc;
146
147   goto connect_src_ghost_pad;
148
149 error_element_missing:
150   {
151     post_missing_element_message (vaapidecbin, "vaapipostproc");
152     return FALSE;
153   }
154 error_link_pad:
155   {
156     GST_ERROR_OBJECT (vaapidecbin, "Failed to link the child elements");
157     return FALSE;
158   }
159 connect_src_ghost_pad:
160   {
161     GstPad *srcpad, *ghostpad;
162
163     srcpad = gst_element_get_static_pad (src, "src");
164     ghostpad = gst_ghost_pad_new ("src", srcpad);
165     vaapidecbin->ghost_pad_src = ghostpad;
166     gst_object_unref (srcpad);
167     gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghostpad);
168     return TRUE;
169   }
170 }
171
172 static void
173 gst_vaapi_decode_bin_set_property (GObject * object,
174     guint prop_id, const GValue * value, GParamSpec * pspec)
175 {
176   GstVaapiDecodeBin *vaapidecbin = GST_VAAPI_DECODE_BIN (object);
177
178   switch (prop_id) {
179     case PROP_MAX_SIZE_BYTES:
180       vaapidecbin->max_size_bytes = g_value_get_uint (value);
181       g_object_set (G_OBJECT (vaapidecbin->queue), "max-size-bytes",
182           vaapidecbin->max_size_bytes, NULL);
183       break;
184     case PROP_MAX_SIZE_BUFFERS:
185       vaapidecbin->max_size_buffers = g_value_get_uint (value);
186       g_object_set (G_OBJECT (vaapidecbin->queue), "max-size-buffers",
187           vaapidecbin->max_size_buffers, NULL);
188       break;
189     case PROP_MAX_SIZE_TIME:
190       vaapidecbin->max_size_time = g_value_get_uint64 (value);
191       g_object_set (G_OBJECT (vaapidecbin->queue), "max-size-time",
192           vaapidecbin->max_size_time, NULL);
193       break;
194     case PROP_DEINTERLACE_METHOD:
195       vaapidecbin->deinterlace_method = g_value_get_enum (value);
196       g_object_set (G_OBJECT (vaapidecbin->postproc), "deinterlace-method",
197           vaapidecbin->deinterlace_method, NULL);
198       break;
199     case PROP_DISABLE_VPP:
200     {
201       gboolean disable_vpp;
202
203       disable_vpp = g_value_get_boolean (value);
204       if (!disable_vpp && !vaapidecbin->has_vpp)
205         GST_WARNING_OBJECT (vaapidecbin,
206             "Cannot enable VPP since the VA driver does not support it");
207       else
208         vaapidecbin->disable_vpp = disable_vpp;
209
210       /* @TODO: Add run-time disabling support */
211       break;
212     }
213     default:
214       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
215       break;
216   }
217 }
218
219 static void
220 gst_vaapi_decode_bin_get_property (GObject * object,
221     guint prop_id, GValue * value, GParamSpec * pspec)
222 {
223   GstVaapiDecodeBin *vaapidecbin = GST_VAAPI_DECODE_BIN (object);
224
225   switch (prop_id) {
226     case PROP_MAX_SIZE_BYTES:
227       g_value_set_uint (value, vaapidecbin->max_size_bytes);
228       break;
229     case PROP_MAX_SIZE_BUFFERS:
230       g_value_set_uint (value, vaapidecbin->max_size_buffers);
231       break;
232     case PROP_MAX_SIZE_TIME:
233       g_value_set_uint64 (value, vaapidecbin->max_size_time);
234       break;
235     case PROP_DEINTERLACE_METHOD:
236       g_value_set_enum (value, vaapidecbin->deinterlace_method);
237       break;
238     case PROP_DISABLE_VPP:
239       g_value_set_boolean (value, vaapidecbin->disable_vpp);
240       break;
241     default:
242       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
243       break;
244   }
245 }
246
247 static void
248 gst_vaapi_decode_bin_handle_message (GstBin * bin, GstMessage * message)
249 {
250   GstVaapiDecodeBin *vaapidecbin = GST_VAAPI_DECODE_BIN (bin);
251   GstMessageType type;
252   GstContext *context = NULL;
253   const gchar *context_type;
254   GstVaapiDisplay *display = NULL;
255
256   type = GST_MESSAGE_TYPE (message);
257   if (type != GST_MESSAGE_HAVE_CONTEXT)
258     goto bail;
259   gst_message_parse_have_context (message, &context);
260   if (!context)
261     goto bail;
262   context_type = gst_context_get_context_type (context);
263   if (g_strcmp0 (context_type, GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME) != 0)
264     goto bail;
265   if (!gst_vaapi_video_context_get_display (context, &display))
266     goto bail;
267
268   vaapidecbin->has_vpp = gst_vaapi_display_has_video_processing (display);
269
270   /* the underlying VA driver implementation doesn't support video
271    * post-processing, hence we have to disable it */
272   if (!vaapidecbin->has_vpp) {
273     GST_WARNING_OBJECT (vaapidecbin, "VA driver doesn't support VPP");
274     if (!vaapidecbin->disable_vpp) {
275       vaapidecbin->disable_vpp = TRUE;
276       g_object_notify_by_pspec (G_OBJECT (vaapidecbin),
277           properties[PROP_DISABLE_VPP]);
278     }
279   }
280
281   activate_vpp (vaapidecbin);
282
283 bail:
284   GST_BIN_CLASS (gst_vaapi_decode_bin_parent_class)->handle_message (bin,
285       message);
286 }
287
288 static void
289 gst_vaapi_decode_bin_class_init (GstVaapiDecodeBinClass * klass)
290 {
291   GObjectClass *gobject_class;
292   GstElementClass *element_class;
293   GstBinClass *bin_class;
294
295   gobject_class = G_OBJECT_CLASS (klass);
296   element_class = GST_ELEMENT_CLASS (klass);
297   bin_class = GST_BIN_CLASS (klass);
298
299   gobject_class->set_property = gst_vaapi_decode_bin_set_property;
300   gobject_class->get_property = gst_vaapi_decode_bin_get_property;
301
302   bin_class->handle_message =
303       GST_DEBUG_FUNCPTR (gst_vaapi_decode_bin_handle_message);
304
305   gst_element_class_set_static_metadata (element_class,
306       "VA-API Decode Bin",
307       "Codec/Decoder/Video",
308       GST_PLUGIN_DESC,
309       "Sreerenj Balachandran <sreerenj.balachandran@intel.com>");
310
311   properties[PROP_MAX_SIZE_BYTES] = g_param_spec_uint ("max-size-bytes",
312       "Max. size (kB)", "Max. amount of data in the queue (bytes, 0=disable)",
313       0, G_MAXUINT, DEFAULT_QUEUE_MAX_SIZE_BYTES,
314       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
315   properties[PROP_MAX_SIZE_BUFFERS] = g_param_spec_uint ("max-size-buffers",
316       "Max. size (buffers)", "Max. number of buffers in the queue (0=disable)",
317       0, G_MAXUINT, DEFAULT_QUEUE_MAX_SIZE_BUFFERS,
318       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
319   properties[PROP_MAX_SIZE_TIME] = g_param_spec_uint64 ("max-size-time",
320       "Max. size (ns)", "Max. amount of data in the queue (in ns, 0=disable)",
321       0, G_MAXUINT64, DEFAULT_QUEUE_MAX_SIZE_TIME,
322       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
323   properties[PROP_DEINTERLACE_METHOD] = g_param_spec_enum ("deinterlace-method",
324       "Deinterlace method", "Deinterlace method to use",
325       GST_VAAPI_TYPE_DEINTERLACE_METHOD, DEFAULT_DEINTERLACE_METHOD,
326       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
327   properties[PROP_DISABLE_VPP] = g_param_spec_boolean ("disable-vpp",
328       "Disable VPP",
329       "Disable Video Post Processing (No support for run time disabling)",
330       FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
331
332   g_object_class_install_properties (gobject_class, PROP_LAST, properties);
333
334   gst_element_class_add_pad_template (element_class,
335       gst_static_pad_template_get (&gst_vaapi_decode_bin_sink_factory));
336
337   gst_element_class_add_pad_template (element_class,
338       gst_static_pad_template_get (&gst_vaapi_decode_bin_src_factory));
339
340   GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_decode_bin,
341       GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
342 }
343
344 static gboolean
345 gst_vaapi_decode_bin_configure (GstVaapiDecodeBin * vaapidecbin)
346 {
347   gchar *missing_factory = NULL;
348
349   /* create the decoder */
350   vaapidecbin->decoder =
351       gst_element_factory_make ("vaapidecode", "vaapidecode");
352   if (!vaapidecbin->decoder) {
353     missing_factory = "vaapidecode";
354     goto error_element_missing;
355   }
356   /* create the queue */
357   vaapidecbin->queue = gst_element_factory_make ("queue", "queue");
358   if (!vaapidecbin->queue) {
359     missing_factory = "queue";
360     goto error_element_missing;
361   }
362
363   g_object_set (G_OBJECT (vaapidecbin->queue),
364       "max-size-bytes", vaapidecbin->max_size_bytes,
365       "max-size-buffers", vaapidecbin->max_size_buffers,
366       "max-size-time", vaapidecbin->max_size_time, NULL);
367
368   gst_bin_add_many (GST_BIN (vaapidecbin),
369       vaapidecbin->decoder, vaapidecbin->queue, NULL);
370
371   if (!gst_element_link_pads_full (vaapidecbin->decoder, "src",
372           vaapidecbin->queue, "sink", GST_PAD_LINK_CHECK_NOTHING))
373     goto error_link_pad;
374
375   return TRUE;
376
377 error_element_missing:
378   {
379     post_missing_element_message (vaapidecbin, missing_factory);
380     return FALSE;
381   }
382 error_link_pad:
383   {
384     GST_ERROR_OBJECT (vaapidecbin, "Failed to link the child elements");
385     return FALSE;
386   }
387 }
388
389 static void
390 gst_vaapi_decode_bin_init (GstVaapiDecodeBin * vaapidecbin)
391 {
392   GstPad *element_pad, *ghost_pad;
393
394   /* let's assume we have VPP until we prove the opposite */
395   vaapidecbin->has_vpp = TRUE;
396
397   if (!gst_vaapi_decode_bin_configure (vaapidecbin))
398     return;
399
400   /* create ghost pad sink */
401   element_pad =
402       gst_element_get_static_pad (GST_ELEMENT (vaapidecbin->decoder), "sink");
403   ghost_pad =
404       gst_ghost_pad_new_from_template ("sink", element_pad,
405       GST_PAD_PAD_TEMPLATE (element_pad));
406   gst_object_unref (element_pad);
407   gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghost_pad);
408 }