Merge branch 'move_subdir_editing-services' into tizen_gst_1.19.2_mono
[platform/upstream/gstreamer.git] / subprojects / gstreamer-vaapi / gst-libs / gst / vaapi / gstvaapiblend.c
1 /*
2  *  gstvaapiblend.c - Video processing blend
3  *
4  *  Copyright (C) 2019 Intel Corporation
5  *    Author: U. Artie Eoff <ullysses.a.eoff@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 "sysdeps.h"
24 #include "gstvaapicompat.h"
25 #include "gstvaapiblend.h"
26 #include "gstvaapiutils.h"
27 #include "gstvaapivalue.h"
28 #include "gstvaapidisplay_priv.h"
29 #include "gstvaapisurface_priv.h"
30
31 struct _GstVaapiBlend
32 {
33   GstObject parent_instance;
34
35   GstVaapiDisplay *display;
36
37   VAConfigID va_config;
38   VAContextID va_context;
39
40   guint32 flags;
41 };
42
43 typedef struct _GstVaapiBlendClass GstVaapiBlendClass;
44 struct _GstVaapiBlendClass
45 {
46   GstObjectClass parent_class;
47 };
48
49 GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapi_blend);
50 #ifndef GST_DISABLE_GST_DEBUG
51 #define GST_CAT_DEFAULT gst_debug_vaapi_blend
52 #else
53 #define GST_CAT_DEFAULT NULL
54 #endif
55
56 G_DEFINE_TYPE_WITH_CODE (GstVaapiBlend, gst_vaapi_blend, GST_TYPE_OBJECT,
57     GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_blend, "vaapiblend", 0,
58         "VA-API Blend"));
59
60 enum
61 {
62   PROP_DISPLAY = 1,
63 };
64
65 static void
66 gst_vaapi_blend_set_property (GObject * object, guint property_id,
67     const GValue * value, GParamSpec * pspec)
68 {
69   GstVaapiBlend *const blend = GST_VAAPI_BLEND (object);
70
71   switch (property_id) {
72     case PROP_DISPLAY:{
73       GstVaapiDisplay *display = g_value_get_object (value);;
74       if (display) {
75         if (GST_VAAPI_DISPLAY_HAS_VPP (display)) {
76           blend->display = gst_object_ref (display);
77         } else {
78           GST_WARNING_OBJECT (blend, "GstVaapiDisplay doesn't support VPP");
79         }
80       }
81       break;
82     }
83     default:
84       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
85   }
86 }
87
88 static void
89 gst_vaapi_blend_get_property (GObject * object, guint property_id,
90     GValue * value, GParamSpec * pspec)
91 {
92   GstVaapiBlend *const blend = GST_VAAPI_BLEND (object);
93
94   switch (property_id) {
95     case PROP_DISPLAY:
96       g_value_set_object (value, blend->display);
97       break;
98     default:
99       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
100   }
101 }
102
103 static void
104 gst_vaapi_blend_finalize (GObject * object)
105 {
106   GstVaapiBlend *const blend = GST_VAAPI_BLEND (object);
107
108   if (!blend->display)
109     goto bail;
110
111   GST_VAAPI_DISPLAY_LOCK (blend->display);
112
113   if (blend->va_context != VA_INVALID_ID) {
114     vaDestroyContext (GST_VAAPI_DISPLAY_VADISPLAY (blend->display),
115         blend->va_context);
116     blend->va_context = VA_INVALID_ID;
117   }
118
119   if (blend->va_config != VA_INVALID_ID) {
120     vaDestroyConfig (GST_VAAPI_DISPLAY_VADISPLAY (blend->display),
121         blend->va_config);
122     blend->va_config = VA_INVALID_ID;
123   }
124
125   GST_VAAPI_DISPLAY_UNLOCK (blend->display);
126
127   gst_vaapi_display_replace (&blend->display, NULL);
128
129 bail:
130   G_OBJECT_CLASS (gst_vaapi_blend_parent_class)->finalize (object);
131 }
132
133 static void
134 gst_vaapi_blend_class_init (GstVaapiBlendClass * klass)
135 {
136   GObjectClass *const object_class = G_OBJECT_CLASS (klass);
137
138   object_class->set_property = gst_vaapi_blend_set_property;
139   object_class->get_property = gst_vaapi_blend_get_property;
140   object_class->finalize = gst_vaapi_blend_finalize;
141
142   g_object_class_install_property (object_class, PROP_DISPLAY,
143       g_param_spec_object ("display", "Gst VA-API Display",
144           "The VA-API display object to use", GST_TYPE_VAAPI_DISPLAY,
145           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME));
146 }
147
148 static void
149 gst_vaapi_blend_init (GstVaapiBlend * blend)
150 {
151   blend->display = NULL;
152   blend->va_config = VA_INVALID_ID;
153   blend->va_context = VA_INVALID_ID;
154   blend->flags = 0;
155 }
156
157 static gboolean
158 gst_vaapi_blend_initialize (GstVaapiBlend * blend)
159 {
160   VAStatus status;
161   VAProcPipelineCaps pipeline_caps = { 0, };
162
163   if (!blend->display)
164     return FALSE;
165
166   status = vaCreateConfig (GST_VAAPI_DISPLAY_VADISPLAY (blend->display),
167       VAProfileNone, VAEntrypointVideoProc, NULL, 0, &blend->va_config);
168   if (!vaapi_check_status (status, "vaCreateConfig() [VPP]"))
169     return FALSE;
170
171   status = vaCreateContext (GST_VAAPI_DISPLAY_VADISPLAY (blend->display),
172       blend->va_config, 0, 0, 0, NULL, 0, &blend->va_context);
173   if (!vaapi_check_status (status, "vaCreateContext() [VPP]"))
174     return FALSE;
175
176 #if VA_CHECK_VERSION(1,1,0)
177   status =
178       vaQueryVideoProcPipelineCaps (GST_VAAPI_DISPLAY_VADISPLAY
179       (blend->display), blend->va_context, NULL, 0, &pipeline_caps);
180   if (vaapi_check_status (status, "vaQueryVideoProcPipelineCaps()"))
181     blend->flags = pipeline_caps.blend_flags;
182
183   if (!(blend->flags & VA_BLEND_GLOBAL_ALPHA)) {
184     GST_WARNING_OBJECT (blend, "VPP does not support global alpha blending");
185     return FALSE;
186   }
187 #else
188   return FALSE;
189 #endif
190
191   return TRUE;
192 }
193
194 GstVaapiBlend *
195 gst_vaapi_blend_new (GstVaapiDisplay * display)
196 {
197   GstVaapiBlend *blend = g_object_new (GST_TYPE_VAAPI_BLEND,
198       "display", display, NULL);
199
200   if (!gst_vaapi_blend_initialize (blend)) {
201     gst_object_unref (blend);
202     blend = NULL;
203   }
204
205   return blend;
206 }
207
208 void
209 gst_vaapi_blend_replace (GstVaapiBlend ** old_blend_ptr,
210     GstVaapiBlend * new_blend)
211 {
212   g_return_if_fail (old_blend_ptr != NULL);
213
214   gst_object_replace ((GstObject **) old_blend_ptr, GST_OBJECT (new_blend));
215 }
216
217 static gboolean
218 gst_vaapi_blend_process_unlocked (GstVaapiBlend * blend,
219     GstVaapiSurface * output, GstVaapiBlendSurfaceNextFunc next,
220     gpointer user_data)
221 {
222   VAStatus va_status;
223   VADisplay va_display;
224   GstVaapiBlendSurface *current;
225
226   va_display = GST_VAAPI_DISPLAY_VADISPLAY (blend->display);
227
228   va_status = vaBeginPicture (va_display, blend->va_context,
229       GST_VAAPI_SURFACE_ID (output));
230   if (!vaapi_check_status (va_status, "vaBeginPicture()"))
231     return FALSE;
232
233   current = next (user_data);
234   for (; current; current = next (user_data)) {
235     VAProcPipelineParameterBuffer *param = NULL;
236     VABufferID id = VA_INVALID_ID;
237     VARectangle src_rect = { 0, };
238     VARectangle dst_rect = { 0, };
239 #if VA_CHECK_VERSION(1,1,0)
240     VABlendState blend_state;
241 #endif
242
243     if (!current->surface)
244       return FALSE;
245
246     /* Build surface region (source) */
247     src_rect.width = GST_VAAPI_SURFACE_WIDTH (current->surface);
248     src_rect.height = GST_VAAPI_SURFACE_HEIGHT (current->surface);
249     if (current->crop) {
250       if ((current->crop->x + current->crop->width > src_rect.width) ||
251           (current->crop->y + current->crop->height > src_rect.height))
252         return FALSE;
253       src_rect.x = current->crop->x;
254       src_rect.y = current->crop->y;
255       src_rect.width = current->crop->width;
256       src_rect.height = current->crop->height;
257     }
258
259     /* Build output region (target) */
260     dst_rect.x = current->target.x;
261     dst_rect.y = current->target.y;
262     dst_rect.width = current->target.width;
263     dst_rect.height = current->target.height;
264
265     if (!vaapi_create_buffer (va_display, blend->va_context,
266             VAProcPipelineParameterBufferType, sizeof (*param), NULL, &id,
267             (gpointer *) & param))
268       return FALSE;
269
270     memset (param, 0, sizeof (*param));
271
272     param->surface = GST_VAAPI_SURFACE_ID (current->surface);
273     param->surface_region = &src_rect;
274     param->output_region = &dst_rect;
275     param->output_background_color = 0xff000000;
276
277 #if VA_CHECK_VERSION(1,1,0)
278     blend_state.flags = VA_BLEND_GLOBAL_ALPHA;
279     blend_state.global_alpha = current->alpha;
280     param->blend_state = &blend_state;
281 #endif
282
283     vaapi_unmap_buffer (va_display, id, NULL);
284
285     va_status = vaRenderPicture (va_display, blend->va_context, &id, 1);
286     vaapi_destroy_buffer (va_display, &id);
287     if (!vaapi_check_status (va_status, "vaRenderPicture()"))
288       return FALSE;
289   }
290
291   va_status = vaEndPicture (va_display, blend->va_context);
292   if (!vaapi_check_status (va_status, "vaEndPicture()"))
293     return FALSE;
294
295   return TRUE;
296 }
297
298 /**
299  * gst_vaapi_blend_process:
300  * @blend: a #GstVaapiBlend instance.
301  * @output: a #GstVaapiSurface to be composed.
302  * @next: a function to fetch the next #GstVaapiBlendSurface to
303  *    process.
304  * @data: state storage for @next.
305  *
306  * This function will process all the input surfaces defined through
307  * #GstVaapiBlendSurface and will blend them onto the @output surface.
308  *
309  * Returns: %TRUE if the blend process succeed; otherwise %FALSE.
310  **/
311 gboolean
312 gst_vaapi_blend_process (GstVaapiBlend * blend, GstVaapiSurface * output,
313     GstVaapiBlendSurfaceNextFunc next, gpointer user_data)
314 {
315   gboolean result;
316
317   g_return_val_if_fail (blend != NULL, FALSE);
318   g_return_val_if_fail (output != NULL, FALSE);
319   g_return_val_if_fail (next != NULL, FALSE);
320
321   GST_VAAPI_DISPLAY_LOCK (blend->display);
322   result = gst_vaapi_blend_process_unlocked (blend, output, next, user_data);
323   GST_VAAPI_DISPLAY_UNLOCK (blend->display);
324
325   return result;
326 }