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"
42 #include "gstvaapiutils_core.h"
45 #include "gstvaapidebug.h"
47 /* Define default VA surface chroma format to YUV 4:2:0 */
48 #define DEFAULT_CHROMA_TYPE (GST_VAAPI_CHROMA_TYPE_YUV420)
51 unref_surface_cb (GstVaapiSurface * surface)
53 gst_vaapi_surface_set_parent_context (surface, NULL);
54 gst_vaapi_object_unref (surface);
57 static inline gboolean
58 context_get_attribute (GstVaapiContext * context, VAConfigAttribType type,
59 guint * out_value_ptr)
61 return gst_vaapi_get_config_attribute (GST_VAAPI_OBJECT_DISPLAY (context),
62 context->va_profile, context->va_entrypoint, type, out_value_ptr);
66 context_destroy_surfaces (GstVaapiContext * context)
68 gst_vaapi_context_overlay_reset (context);
70 if (context->surfaces) {
71 g_ptr_array_unref (context->surfaces);
72 context->surfaces = NULL;
74 gst_vaapi_video_pool_replace (&context->surfaces_pool, NULL);
78 context_destroy (GstVaapiContext * context)
80 GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (context);
81 VAContextID context_id;
84 context_id = GST_VAAPI_OBJECT_ID (context);
85 GST_DEBUG ("context 0x%08x", context_id);
87 if (context_id != VA_INVALID_ID) {
88 GST_VAAPI_DISPLAY_LOCK (display);
89 status = vaDestroyContext (GST_VAAPI_DISPLAY_VADISPLAY (display),
91 GST_VAAPI_DISPLAY_UNLOCK (display);
92 if (!vaapi_check_status (status, "vaDestroyContext()"))
93 GST_WARNING ("failed to destroy context 0x%08x", context_id);
94 GST_VAAPI_OBJECT_ID (context) = VA_INVALID_ID;
97 if (context->va_config != VA_INVALID_ID) {
98 GST_VAAPI_DISPLAY_LOCK (display);
99 status = vaDestroyConfig (GST_VAAPI_DISPLAY_VADISPLAY (display),
101 GST_VAAPI_DISPLAY_UNLOCK (display);
102 if (!vaapi_check_status (status, "vaDestroyConfig()"))
103 GST_WARNING ("failed to destroy config 0x%08x", context->va_config);
104 context->va_config = VA_INVALID_ID;
109 context_create_surfaces (GstVaapiContext * context)
111 const GstVaapiContextInfo *const cip = &context->info;
113 GstVaapiSurface *surface;
114 guint i, num_surfaces;
116 /* Number of scratch surfaces beyond those used as reference */
117 const guint SCRATCH_SURFACES_COUNT = 4;
119 if (!gst_vaapi_context_overlay_reset (context))
122 num_surfaces = cip->ref_frames + SCRATCH_SURFACES_COUNT;
123 if (!context->surfaces) {
124 context->surfaces = g_ptr_array_new_full (num_surfaces,
125 (GDestroyNotify) unref_surface_cb);
126 if (!context->surfaces)
130 if (!context->surfaces_pool) {
131 gst_video_info_set_format (&vi, GST_VIDEO_FORMAT_ENCODED,
132 cip->width, cip->height);
133 context->surfaces_pool =
134 gst_vaapi_surface_pool_new (GST_VAAPI_OBJECT_DISPLAY (context), &vi);
135 if (!context->surfaces_pool)
138 gst_vaapi_video_pool_set_capacity (context->surfaces_pool, num_surfaces);
140 for (i = context->surfaces->len; i < num_surfaces; i++) {
141 surface = gst_vaapi_surface_new (GST_VAAPI_OBJECT_DISPLAY (context),
142 cip->chroma_type, cip->width, cip->height);
145 gst_vaapi_surface_set_parent_context (surface, context);
146 g_ptr_array_add (context->surfaces, surface);
147 if (!gst_vaapi_video_pool_add_object (context->surfaces_pool, surface))
154 context_create (GstVaapiContext * context)
156 const GstVaapiContextInfo *const cip = &context->info;
157 GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (context);
158 VAConfigAttrib attribs[3], *attrib = attribs;
159 VAContextID context_id;
160 VASurfaceID surface_id;
162 GArray *surfaces = NULL;
163 gboolean success = FALSE;
164 guint i, value, va_chroma_format;
166 if (!context->surfaces && !context_create_surfaces (context))
169 /* Create VA surfaces list for vaCreateContext() */
170 surfaces = g_array_sized_new (FALSE,
171 FALSE, sizeof (VASurfaceID), context->surfaces->len);
175 for (i = 0; i < context->surfaces->len; i++) {
176 GstVaapiSurface *const surface = g_ptr_array_index (context->surfaces, i);
179 surface_id = GST_VAAPI_OBJECT_ID (surface);
180 g_array_append_val (surfaces, surface_id);
182 g_assert (surfaces->len == context->surfaces->len);
184 /* Reset profile and entrypoint */
185 if (!cip->profile || !cip->entrypoint)
187 context->va_profile = gst_vaapi_profile_get_va_profile (cip->profile);
188 context->va_entrypoint =
189 gst_vaapi_entrypoint_get_va_entrypoint (cip->entrypoint);
191 /* Validate VA surface format */
192 va_chroma_format = from_GstVaapiChromaType (cip->chroma_type);
193 if (!va_chroma_format)
195 attrib->type = VAConfigAttribRTFormat;
196 if (!context_get_attribute (context, attrib->type, &value))
198 if (!(value & va_chroma_format)) {
199 GST_ERROR ("unsupported chroma format (%s)",
200 string_of_va_chroma_format (va_chroma_format));
203 attrib->value = va_chroma_format;
206 switch (cip->usage) {
208 case GST_VAAPI_CONTEXT_USAGE_ENCODE:
210 const GstVaapiConfigInfoEncoder *const config = &cip->config.encoder;
211 guint va_rate_control;
214 attrib->type = VAConfigAttribRateControl;
215 if (!context_get_attribute (context, attrib->type, &value))
218 va_rate_control = from_GstVaapiRateControl (config->rc_mode);
219 if ((value & va_rate_control) != va_rate_control) {
220 GST_ERROR ("unsupported %s rate control",
221 string_of_VARateControl (va_rate_control));
224 attrib->value = va_rate_control;
228 if (config->packed_headers) {
229 attrib->type = VAConfigAttribEncPackedHeaders;
230 if (!context_get_attribute (context, attrib->type, &value))
233 if ((value & config->packed_headers) != config->packed_headers) {
234 GST_ERROR ("unsupported packed headers 0x%08x",
235 config->packed_headers & ~(value & config->packed_headers));
238 attrib->value = config->packed_headers;
248 GST_VAAPI_DISPLAY_LOCK (display);
249 status = vaCreateConfig (GST_VAAPI_DISPLAY_VADISPLAY (display),
250 context->va_profile, context->va_entrypoint, attribs, attrib - attribs,
251 &context->va_config);
252 GST_VAAPI_DISPLAY_UNLOCK (display);
253 if (!vaapi_check_status (status, "vaCreateConfig()"))
256 GST_VAAPI_DISPLAY_LOCK (display);
257 status = vaCreateContext (GST_VAAPI_DISPLAY_VADISPLAY (display),
258 context->va_config, cip->width, cip->height, VA_PROGRESSIVE,
259 (VASurfaceID *) surfaces->data, surfaces->len, &context_id);
260 GST_VAAPI_DISPLAY_UNLOCK (display);
261 if (!vaapi_check_status (status, "vaCreateContext()"))
264 GST_DEBUG ("context 0x%08x", context_id);
265 GST_VAAPI_OBJECT_ID (context) = context_id;
270 g_array_free (surfaces, TRUE);
274 /** Updates config for encoding. Returns %TRUE if config changed */
276 context_update_config_encoder (GstVaapiContext * context,
277 const GstVaapiConfigInfoEncoder * new_config)
279 GstVaapiConfigInfoEncoder *const config = &context->info.config.encoder;
280 gboolean config_changed = FALSE;
282 g_assert (context->info.usage == GST_VAAPI_CONTEXT_USAGE_ENCODE);
284 if (config->rc_mode != new_config->rc_mode) {
285 config->rc_mode = new_config->rc_mode;
286 config_changed = TRUE;
289 if (config->packed_headers != new_config->packed_headers) {
290 config->packed_headers = new_config->packed_headers;
291 config_changed = TRUE;
293 return config_changed;
297 gst_vaapi_context_init (GstVaapiContext * context,
298 const GstVaapiContextInfo * new_cip)
300 GstVaapiContextInfo *const cip = &context->info;
303 if (!cip->chroma_type)
304 cip->chroma_type = DEFAULT_CHROMA_TYPE;
306 context->va_config = VA_INVALID_ID;
307 gst_vaapi_context_overlay_init (context);
311 gst_vaapi_context_finalize (GstVaapiContext * context)
313 context_destroy (context);
314 context_destroy_surfaces (context);
315 gst_vaapi_context_overlay_finalize (context);
318 GST_VAAPI_OBJECT_DEFINE_CLASS (GstVaapiContext, gst_vaapi_context);
321 * gst_vaapi_context_new:
322 * @display: a #GstVaapiDisplay
323 * @cip: a pointer to the #GstVaapiContextInfo
325 * Creates a new #GstVaapiContext with the configuration specified by
326 * @cip, thus including profile, entry-point, encoded size and maximum
327 * number of reference frames reported by the bitstream.
329 * Return value: the newly allocated #GstVaapiContext object
332 gst_vaapi_context_new (GstVaapiDisplay * display,
333 const GstVaapiContextInfo * cip)
335 GstVaapiContext *context;
337 g_return_val_if_fail (cip->profile, NULL);
338 g_return_val_if_fail (cip->entrypoint, NULL);
339 g_return_val_if_fail (cip->width > 0, NULL);
340 g_return_val_if_fail (cip->height > 0, NULL);
342 context = gst_vaapi_object_new (gst_vaapi_context_class (), display);
346 gst_vaapi_context_init (context, cip);
347 if (!context_create (context))
352 gst_vaapi_object_unref (context);
357 * gst_vaapi_context_reset:
358 * @context: a #GstVaapiContext
359 * @new_cip: a pointer to the new #GstVaapiContextInfo details
361 * Resets @context to the configuration specified by @new_cip, thus
362 * including profile, entry-point, encoded size and maximum number of
363 * reference frames reported by the bitstream.
365 * Return value: %TRUE on success
368 gst_vaapi_context_reset (GstVaapiContext * context,
369 const GstVaapiContextInfo * new_cip)
371 GstVaapiContextInfo *const cip = &context->info;
372 gboolean reset_surfaces = FALSE, reset_config = FALSE;
373 GstVaapiChromaType chroma_type;
375 chroma_type = new_cip->chroma_type ? new_cip->chroma_type :
377 if (cip->chroma_type != chroma_type) {
378 cip->chroma_type = chroma_type;
379 reset_surfaces = TRUE;
382 if (cip->width != new_cip->width || cip->height != new_cip->height) {
383 cip->width = new_cip->width;
384 cip->height = new_cip->height;
385 reset_surfaces = TRUE;
388 if (cip->profile != new_cip->profile ||
389 cip->entrypoint != new_cip->entrypoint) {
390 cip->profile = new_cip->profile;
391 cip->entrypoint = new_cip->entrypoint;
395 if (cip->usage != new_cip->usage) {
396 cip->usage = new_cip->usage;
398 memcpy (&cip->config, &new_cip->config, sizeof (cip->config));
399 } else if (new_cip->usage == GST_VAAPI_CONTEXT_USAGE_ENCODE) {
400 if (context_update_config_encoder (context, &new_cip->config.encoder))
402 } else if (new_cip->usage == GST_VAAPI_CONTEXT_USAGE_DECODE) {
408 context_destroy_surfaces (context);
410 context_destroy (context);
412 if (reset_surfaces && !context_create_surfaces (context))
414 if (reset_config && !context_create (context))
420 * gst_vaapi_context_get_id:
421 * @context: a #GstVaapiContext
423 * Returns the underlying VAContextID of the @context.
425 * Return value: the underlying VA context id
428 gst_vaapi_context_get_id (GstVaapiContext * context)
430 g_return_val_if_fail (context != NULL, VA_INVALID_ID);
432 return GST_VAAPI_OBJECT_ID (context);
436 * gst_vaapi_context_get_surface_proxy:
437 * @context: a #GstVaapiContext
439 * Acquires a free surface, wrapped into a #GstVaapiSurfaceProxy. The
440 * returned surface will be automatically released when the proxy is
441 * destroyed. So, it is enough to call gst_vaapi_surface_proxy_unref()
444 * This function returns %NULL if there is no free surface available
445 * in the pool. The surfaces are pre-allocated during context creation
448 * Return value: a free surface, or %NULL if none is available
450 GstVaapiSurfaceProxy *
451 gst_vaapi_context_get_surface_proxy (GstVaapiContext * context)
453 g_return_val_if_fail (context != NULL, NULL);
456 gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL
457 (context->surfaces_pool));
461 * gst_vaapi_context_get_surface_count:
462 * @context: a #GstVaapiContext
464 * Retrieves the number of free surfaces left in the pool.
466 * Return value: the number of free surfaces available in the pool
469 gst_vaapi_context_get_surface_count (GstVaapiContext * context)
471 g_return_val_if_fail (context != NULL, 0);
473 return gst_vaapi_video_pool_get_size (context->surfaces_pool);