2 * gstvaapicontext.c - VA context abstraction
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>
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.
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.
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
26 * SECTION:gstvaapicontext
27 * @short_description: VA context abstraction
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"
44 #include "gstvaapidebug.h"
47 unref_surface_cb (GstVaapiSurface * surface)
49 gst_vaapi_surface_set_parent_context (surface, NULL);
50 gst_vaapi_object_unref (surface);
54 context_destroy_surfaces (GstVaapiContext * context)
56 gst_vaapi_context_overlay_reset (context);
58 if (context->surfaces) {
59 g_ptr_array_unref (context->surfaces);
60 context->surfaces = NULL;
62 gst_vaapi_video_pool_replace (&context->surfaces_pool, NULL);
66 context_destroy (GstVaapiContext * context)
68 GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (context);
69 VAContextID context_id;
72 context_id = GST_VAAPI_OBJECT_ID (context);
73 GST_DEBUG ("context 0x%08x", context_id);
75 if (context_id != VA_INVALID_ID) {
76 GST_VAAPI_DISPLAY_LOCK (display);
77 status = vaDestroyContext (GST_VAAPI_DISPLAY_VADISPLAY (display),
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;
85 if (context->va_config != VA_INVALID_ID) {
86 GST_VAAPI_DISPLAY_LOCK (display);
87 status = vaDestroyConfig (GST_VAAPI_DISPLAY_VADISPLAY (display),
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;
97 context_create_surfaces (GstVaapiContext * context)
99 const GstVaapiContextInfo *const cip = &context->info;
101 GstVaapiSurface *surface;
102 guint i, num_surfaces;
104 /* Number of scratch surfaces beyond those used as reference */
105 const guint SCRATCH_SURFACES_COUNT = 4;
107 if (!gst_vaapi_context_overlay_reset (context))
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)
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)
126 gst_vaapi_video_pool_set_capacity (context->surfaces_pool, num_surfaces);
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);
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))
142 context_create (GstVaapiContext * context)
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];
149 VAContextID context_id;
150 VASurfaceID surface_id;
152 GArray *surfaces = NULL;
153 gboolean success = FALSE;
156 if (!context->surfaces && !context_create_surfaces (context))
159 surfaces = g_array_sized_new (FALSE,
160 FALSE, sizeof (VASurfaceID), context->surfaces->len);
164 for (i = 0; i < context->surfaces->len; i++) {
165 GstVaapiSurface *const surface = g_ptr_array_index (context->surfaces, i);
168 surface_id = GST_VAAPI_OBJECT_ID (surface);
169 g_array_append_val (surfaces, surface_id);
171 g_assert (surfaces->len == context->surfaces->len);
173 if (!cip->profile || !cip->entrypoint)
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);
180 attribs[num_attribs++].type = VAConfigAttribRTFormat;
181 if (cip->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE)
182 attribs[num_attribs++].type = VAConfigAttribRateControl;
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()"))
190 if (!(attribs[0].value & VA_RT_FORMAT_YUV420))
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));
202 attribs[1].value = va_rate_control;
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()"))
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()"))
221 GST_DEBUG ("context 0x%08x", context_id);
222 GST_VAAPI_OBJECT_ID (context) = context_id;
227 g_array_free (surfaces, TRUE);
232 gst_vaapi_context_init (GstVaapiContext * context,
233 const GstVaapiContextInfo * cip)
235 context->info = *cip;
236 context->va_config = VA_INVALID_ID;
237 gst_vaapi_context_overlay_init (context);
241 gst_vaapi_context_finalize (GstVaapiContext * context)
243 context_destroy (context);
244 context_destroy_surfaces (context);
245 gst_vaapi_context_overlay_finalize (context);
248 GST_VAAPI_OBJECT_DEFINE_CLASS (GstVaapiContext, gst_vaapi_context);
251 * gst_vaapi_context_new:
252 * @display: a #GstVaapiDisplay
253 * @cip: a pointer to the #GstVaapiContextInfo
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.
259 * Return value: the newly allocated #GstVaapiContext object
262 gst_vaapi_context_new (GstVaapiDisplay * display,
263 const GstVaapiContextInfo * cip)
265 GstVaapiContext *context;
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);
272 context = gst_vaapi_object_new (gst_vaapi_context_class (), display);
276 gst_vaapi_context_init (context, cip);
277 if (!context_create (context))
282 gst_vaapi_object_unref (context);
287 * gst_vaapi_context_reset:
288 * @context: a #GstVaapiContext
289 * @new_cip: a pointer to the new #GstVaapiContextInfo details
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.
295 * Return value: %TRUE on success
298 gst_vaapi_context_reset (GstVaapiContext * context,
299 const GstVaapiContextInfo * new_cip)
301 GstVaapiContextInfo *const cip = &context->info;
302 gboolean size_changed, config_changed;
304 size_changed = cip->width != new_cip->width || cip->height != new_cip->height;
306 cip->width = new_cip->width;
307 cip->height = new_cip->height;
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;
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;
329 context_destroy_surfaces (context);
331 context_destroy (context);
333 if (size_changed && !context_create_surfaces (context))
335 if (config_changed && !context_create (context))
341 * gst_vaapi_context_get_id:
342 * @context: a #GstVaapiContext
344 * Returns the underlying VAContextID of the @context.
346 * Return value: the underlying VA context id
349 gst_vaapi_context_get_id (GstVaapiContext * context)
351 g_return_val_if_fail (context != NULL, VA_INVALID_ID);
353 return GST_VAAPI_OBJECT_ID (context);
357 * gst_vaapi_context_get_surface_proxy:
358 * @context: a #GstVaapiContext
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()
365 * This function returns %NULL if there is no free surface available
366 * in the pool. The surfaces are pre-allocated during context creation
369 * Return value: a free surface, or %NULL if none is available
371 GstVaapiSurfaceProxy *
372 gst_vaapi_context_get_surface_proxy (GstVaapiContext * context)
374 g_return_val_if_fail (context != NULL, NULL);
377 gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL
378 (context->surfaces_pool));
382 * gst_vaapi_context_get_surface_count:
383 * @context: a #GstVaapiContext
385 * Retrieves the number of free surfaces left in the pool.
387 * Return value: the number of free surfaces available in the pool
390 gst_vaapi_context_get_surface_count (GstVaapiContext * context)
392 g_return_val_if_fail (context != NULL, 0);
394 return gst_vaapi_video_pool_get_size (context->surfaces_pool);
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
403 * Determines the value for the VA config attribute @type.
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.
409 * Return value: %TRUE if the VA driver knows about the requested
410 * config attribute and returned a valid value, %FALSE otherwise
413 gst_vaapi_context_get_attribute (GstVaapiContext * context,
414 VAConfigAttribType type, guint * out_value_ptr)
416 VAConfigAttrib attrib;
419 g_return_val_if_fail (context != NULL, FALSE);
421 GST_VAAPI_OBJECT_LOCK_DISPLAY (context);
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()"))
428 if (attrib.value == VA_ATTRIB_NOT_SUPPORTED)
432 *out_value_ptr = attrib.value;