7524b518ff63807f60fc99206661ed62960511f7
[platform/upstream/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapicontext.c
1 /*
2  *  gstvaapicontext.c - VA context abstraction
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6  *  Copyright (C) 2011-2014 Intel Corporation
7  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public License
11  *  as published by the Free Software Foundation; either version 2.1
12  *  of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this library; if not, write to the Free
21  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  *  Boston, MA 02110-1301 USA
23  */
24
25 /**
26  * SECTION:gstvaapicontext
27  * @short_description: VA context abstraction
28  */
29
30 #include "sysdeps.h"
31 #include "gstvaapicompat.h"
32 #include "gstvaapicontext.h"
33 #include "gstvaapicontext_overlay.h"
34 #include "gstvaapidisplay_priv.h"
35 #include "gstvaapiobject_priv.h"
36 #include "gstvaapisurface.h"
37 #include "gstvaapisurface_priv.h"
38 #include "gstvaapisurfacepool.h"
39 #include "gstvaapisurfaceproxy.h"
40 #include "gstvaapivideopool_priv.h"
41 #include "gstvaapiutils.h"
42
43 #define DEBUG 1
44 #include "gstvaapidebug.h"
45
46 static void
47 unref_surface_cb (GstVaapiSurface * surface)
48 {
49   gst_vaapi_surface_set_parent_context (surface, NULL);
50   gst_vaapi_object_unref (surface);
51 }
52
53 static void
54 context_destroy_surfaces (GstVaapiContext * context)
55 {
56   gst_vaapi_context_overlay_reset (context);
57
58   if (context->surfaces) {
59     g_ptr_array_unref (context->surfaces);
60     context->surfaces = NULL;
61   }
62   gst_vaapi_video_pool_replace (&context->surfaces_pool, NULL);
63 }
64
65 static void
66 context_destroy (GstVaapiContext * context)
67 {
68   GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (context);
69   VAContextID context_id;
70   VAStatus status;
71
72   context_id = GST_VAAPI_OBJECT_ID (context);
73   GST_DEBUG ("context 0x%08x", context_id);
74
75   if (context_id != VA_INVALID_ID) {
76     GST_VAAPI_DISPLAY_LOCK (display);
77     status = vaDestroyContext (GST_VAAPI_DISPLAY_VADISPLAY (display),
78         context_id);
79     GST_VAAPI_DISPLAY_UNLOCK (display);
80     if (!vaapi_check_status (status, "vaDestroyContext()"))
81       GST_WARNING ("failed to destroy context 0x%08x", context_id);
82     GST_VAAPI_OBJECT_ID (context) = VA_INVALID_ID;
83   }
84
85   if (context->va_config != VA_INVALID_ID) {
86     GST_VAAPI_DISPLAY_LOCK (display);
87     status = vaDestroyConfig (GST_VAAPI_DISPLAY_VADISPLAY (display),
88         context->va_config);
89     GST_VAAPI_DISPLAY_UNLOCK (display);
90     if (!vaapi_check_status (status, "vaDestroyConfig()"))
91       GST_WARNING ("failed to destroy config 0x%08x", context->va_config);
92     context->va_config = VA_INVALID_ID;
93   }
94 }
95
96 static gboolean
97 context_create_surfaces (GstVaapiContext * context)
98 {
99   const GstVaapiContextInfo *const cip = &context->info;
100   GstVideoInfo vi;
101   GstVaapiSurface *surface;
102   guint i, num_surfaces;
103
104   /* Number of scratch surfaces beyond those used as reference */
105   const guint SCRATCH_SURFACES_COUNT = 4;
106
107   if (!gst_vaapi_context_overlay_reset (context))
108     return FALSE;
109
110   num_surfaces = cip->ref_frames + SCRATCH_SURFACES_COUNT;
111   if (!context->surfaces) {
112     context->surfaces = g_ptr_array_new_full (num_surfaces,
113         (GDestroyNotify) unref_surface_cb);
114     if (!context->surfaces)
115       return FALSE;
116   }
117
118   if (!context->surfaces_pool) {
119     gst_video_info_set_format (&vi, GST_VIDEO_FORMAT_ENCODED,
120         cip->width, cip->height);
121     context->surfaces_pool =
122         gst_vaapi_surface_pool_new (GST_VAAPI_OBJECT_DISPLAY (context), &vi);
123     if (!context->surfaces_pool)
124       return FALSE;
125   }
126   gst_vaapi_video_pool_set_capacity (context->surfaces_pool, num_surfaces);
127
128   for (i = context->surfaces->len; i < num_surfaces; i++) {
129     surface = gst_vaapi_surface_new (GST_VAAPI_OBJECT_DISPLAY (context),
130         GST_VAAPI_CHROMA_TYPE_YUV420, cip->width, cip->height);
131     if (!surface)
132       return FALSE;
133     gst_vaapi_surface_set_parent_context (surface, context);
134     g_ptr_array_add (context->surfaces, surface);
135     if (!gst_vaapi_video_pool_add_object (context->surfaces_pool, surface))
136       return FALSE;
137   }
138   return TRUE;
139 }
140
141 static gboolean
142 context_create (GstVaapiContext * context)
143 {
144   const GstVaapiContextInfo *const cip = &context->info;
145   GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (context);
146   guint va_rate_control;
147   VAConfigAttrib attribs[2];
148   guint num_attribs;
149   VAContextID context_id;
150   VASurfaceID surface_id;
151   VAStatus status;
152   GArray *surfaces = NULL;
153   gboolean success = FALSE;
154   guint i;
155
156   if (!context->surfaces && !context_create_surfaces (context))
157     goto cleanup;
158
159   surfaces = g_array_sized_new (FALSE,
160       FALSE, sizeof (VASurfaceID), context->surfaces->len);
161   if (!surfaces)
162     goto cleanup;
163
164   for (i = 0; i < context->surfaces->len; i++) {
165     GstVaapiSurface *const surface = g_ptr_array_index (context->surfaces, i);
166     if (!surface)
167       goto cleanup;
168     surface_id = GST_VAAPI_OBJECT_ID (surface);
169     g_array_append_val (surfaces, surface_id);
170   }
171   g_assert (surfaces->len == context->surfaces->len);
172
173   if (!cip->profile || !cip->entrypoint)
174     goto cleanup;
175   context->va_profile = gst_vaapi_profile_get_va_profile (cip->profile);
176   context->va_entrypoint =
177       gst_vaapi_entrypoint_get_va_entrypoint (cip->entrypoint);
178
179   num_attribs = 0;
180   attribs[num_attribs++].type = VAConfigAttribRTFormat;
181   if (cip->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE)
182     attribs[num_attribs++].type = VAConfigAttribRateControl;
183
184   GST_VAAPI_DISPLAY_LOCK (display);
185   status = vaGetConfigAttributes (GST_VAAPI_DISPLAY_VADISPLAY (display),
186       context->va_profile, context->va_entrypoint, attribs, num_attribs);
187   GST_VAAPI_DISPLAY_UNLOCK (display);
188   if (!vaapi_check_status (status, "vaGetConfigAttributes()"))
189     goto cleanup;
190   if (!(attribs[0].value & VA_RT_FORMAT_YUV420))
191     goto cleanup;
192
193   if (cip->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE) {
194     va_rate_control = from_GstVaapiRateControl (cip->rc_mode);
195     if (va_rate_control == VA_RC_NONE)
196       attribs[1].value = VA_RC_NONE;
197     if ((attribs[1].value & va_rate_control) != va_rate_control) {
198       GST_ERROR ("unsupported %s rate control",
199           string_of_VARateControl (va_rate_control));
200       goto cleanup;
201     }
202     attribs[1].value = va_rate_control;
203   }
204
205   GST_VAAPI_DISPLAY_LOCK (display);
206   status = vaCreateConfig (GST_VAAPI_DISPLAY_VADISPLAY (display),
207       context->va_profile, context->va_entrypoint, attribs, num_attribs,
208       &context->va_config);
209   GST_VAAPI_DISPLAY_UNLOCK (display);
210   if (!vaapi_check_status (status, "vaCreateConfig()"))
211     goto cleanup;
212
213   GST_VAAPI_DISPLAY_LOCK (display);
214   status = vaCreateContext (GST_VAAPI_DISPLAY_VADISPLAY (display),
215       context->va_config, cip->width, cip->height, VA_PROGRESSIVE,
216       (VASurfaceID *) surfaces->data, surfaces->len, &context_id);
217   GST_VAAPI_DISPLAY_UNLOCK (display);
218   if (!vaapi_check_status (status, "vaCreateContext()"))
219     goto cleanup;
220
221   GST_DEBUG ("context 0x%08x", context_id);
222   GST_VAAPI_OBJECT_ID (context) = context_id;
223   success = TRUE;
224
225 cleanup:
226   if (surfaces)
227     g_array_free (surfaces, TRUE);
228   return success;
229 }
230
231 static inline void
232 gst_vaapi_context_init (GstVaapiContext * context,
233     const GstVaapiContextInfo * cip)
234 {
235   context->info = *cip;
236   context->va_config = VA_INVALID_ID;
237   gst_vaapi_context_overlay_init (context);
238 }
239
240 static void
241 gst_vaapi_context_finalize (GstVaapiContext * context)
242 {
243   context_destroy (context);
244   context_destroy_surfaces (context);
245   gst_vaapi_context_overlay_finalize (context);
246 }
247
248 GST_VAAPI_OBJECT_DEFINE_CLASS (GstVaapiContext, gst_vaapi_context);
249
250 /**
251  * gst_vaapi_context_new:
252  * @display: a #GstVaapiDisplay
253  * @cip: a pointer to the #GstVaapiContextInfo
254  *
255  * Creates a new #GstVaapiContext with the configuration specified by
256  * @cip, thus including profile, entry-point, encoded size and maximum
257  * number of reference frames reported by the bitstream.
258  *
259  * Return value: the newly allocated #GstVaapiContext object
260  */
261 GstVaapiContext *
262 gst_vaapi_context_new (GstVaapiDisplay * display,
263     const GstVaapiContextInfo * cip)
264 {
265   GstVaapiContext *context;
266
267   g_return_val_if_fail (cip->profile, NULL);
268   g_return_val_if_fail (cip->entrypoint, NULL);
269   g_return_val_if_fail (cip->width > 0, NULL);
270   g_return_val_if_fail (cip->height > 0, NULL);
271
272   context = gst_vaapi_object_new (gst_vaapi_context_class (), display);
273   if (!context)
274     return NULL;
275
276   gst_vaapi_context_init (context, cip);
277   if (!context_create (context))
278     goto error;
279   return context;
280
281 error:
282   gst_vaapi_object_unref (context);
283   return NULL;
284 }
285
286 /**
287  * gst_vaapi_context_reset:
288  * @context: a #GstVaapiContext
289  * @new_cip: a pointer to the new #GstVaapiContextInfo details
290  *
291  * Resets @context to the configuration specified by @new_cip, thus
292  * including profile, entry-point, encoded size and maximum number of
293  * reference frames reported by the bitstream.
294  *
295  * Return value: %TRUE on success
296  */
297 gboolean
298 gst_vaapi_context_reset (GstVaapiContext * context,
299     const GstVaapiContextInfo * new_cip)
300 {
301   GstVaapiContextInfo *const cip = &context->info;
302   gboolean size_changed, config_changed;
303
304   size_changed = cip->width != new_cip->width || cip->height != new_cip->height;
305   if (size_changed) {
306     cip->width = new_cip->width;
307     cip->height = new_cip->height;
308   }
309
310   config_changed = cip->profile != new_cip->profile ||
311       cip->entrypoint != new_cip->entrypoint;
312   if (config_changed) {
313     cip->profile = new_cip->profile;
314     cip->entrypoint = new_cip->entrypoint;
315   }
316
317   switch (new_cip->entrypoint) {
318     case GST_VAAPI_ENTRYPOINT_SLICE_ENCODE:
319       if (cip->rc_mode != new_cip->rc_mode) {
320         cip->rc_mode = new_cip->rc_mode;
321         config_changed = TRUE;
322       }
323       break;
324     default:
325       break;
326   }
327
328   if (size_changed)
329     context_destroy_surfaces (context);
330   if (config_changed)
331     context_destroy (context);
332
333   if (size_changed && !context_create_surfaces (context))
334     return FALSE;
335   if (config_changed && !context_create (context))
336     return FALSE;
337   return TRUE;
338 }
339
340 /**
341  * gst_vaapi_context_get_id:
342  * @context: a #GstVaapiContext
343  *
344  * Returns the underlying VAContextID of the @context.
345  *
346  * Return value: the underlying VA context id
347  */
348 GstVaapiID
349 gst_vaapi_context_get_id (GstVaapiContext * context)
350 {
351   g_return_val_if_fail (context != NULL, VA_INVALID_ID);
352
353   return GST_VAAPI_OBJECT_ID (context);
354 }
355
356 /**
357  * gst_vaapi_context_get_surface_proxy:
358  * @context: a #GstVaapiContext
359  *
360  * Acquires a free surface, wrapped into a #GstVaapiSurfaceProxy. The
361  * returned surface will be automatically released when the proxy is
362  * destroyed. So, it is enough to call gst_vaapi_surface_proxy_unref()
363  * after usage.
364  *
365  * This function returns %NULL if there is no free surface available
366  * in the pool. The surfaces are pre-allocated during context creation
367  * though.
368  *
369  * Return value: a free surface, or %NULL if none is available
370  */
371 GstVaapiSurfaceProxy *
372 gst_vaapi_context_get_surface_proxy (GstVaapiContext * context)
373 {
374   g_return_val_if_fail (context != NULL, NULL);
375
376   return
377       gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL
378       (context->surfaces_pool));
379 }
380
381 /**
382  * gst_vaapi_context_get_surface_count:
383  * @context: a #GstVaapiContext
384  *
385  * Retrieves the number of free surfaces left in the pool.
386  *
387  * Return value: the number of free surfaces available in the pool
388  */
389 guint
390 gst_vaapi_context_get_surface_count (GstVaapiContext * context)
391 {
392   g_return_val_if_fail (context != NULL, 0);
393
394   return gst_vaapi_video_pool_get_size (context->surfaces_pool);
395 }
396
397 /**
398  * gst_vaapi_context_get_attribute:
399  * @context: a #GstVaapiContext
400  * @type: a VA config attribute type
401  * @out_value_ptr: return location for the config attribute value
402  *
403  * Determines the value for the VA config attribute @type.
404  *
405  * Note: this function only returns success if the VA driver does
406  * actually know about this config attribute type and that it returned
407  * a valid value for it.
408  *
409  * Return value: %TRUE if the VA driver knows about the requested
410  *   config attribute and returned a valid value, %FALSE otherwise
411  */
412 gboolean
413 gst_vaapi_context_get_attribute (GstVaapiContext * context,
414     VAConfigAttribType type, guint * out_value_ptr)
415 {
416   VAConfigAttrib attrib;
417   VAStatus status;
418
419   g_return_val_if_fail (context != NULL, FALSE);
420
421   GST_VAAPI_OBJECT_LOCK_DISPLAY (context);
422   attrib.type = type;
423   status = vaGetConfigAttributes (GST_VAAPI_OBJECT_VADISPLAY (context),
424       context->va_profile, context->va_entrypoint, &attrib, 1);
425   GST_VAAPI_OBJECT_UNLOCK_DISPLAY (context);
426   if (!vaapi_check_status (status, "vaGetConfigAttributes()"))
427     return FALSE;
428   if (attrib.value == VA_ATTRIB_NOT_SUPPORTED)
429     return FALSE;
430
431   if (out_value_ptr)
432     *out_value_ptr = attrib.value;
433   return TRUE;
434 }