2 * gstvaapicontext.c - VA context abstraction
4 * Copyright (C) 2010-2011 Splitted-Desktop Systems
5 * Copyright (C) 2011-2012 Intel Corporation
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.
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.
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
24 * SECTION:gstvaapicontext
25 * @short_description: VA context abstraction
30 #include "gstvaapicompat.h"
31 #include "gstvaapicontext.h"
32 #include "gstvaapisurface.h"
33 #include "gstvaapisurface_priv.h"
34 #include "gstvaapisurfacepool.h"
35 #include "gstvaapiimage.h"
36 #include "gstvaapisubpicture.h"
37 #include "gstvaapiutils.h"
38 #include "gstvaapi_priv.h"
41 #include "gstvaapidebug.h"
43 G_DEFINE_TYPE(GstVaapiContext, gst_vaapi_context, GST_VAAPI_TYPE_OBJECT)
45 #define GST_VAAPI_CONTEXT_GET_PRIVATE(obj) \
46 (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
47 GST_VAAPI_TYPE_CONTEXT, \
48 GstVaapiContextPrivate))
50 typedef struct _GstVaapiOverlayRectangle GstVaapiOverlayRectangle;
51 struct _GstVaapiOverlayRectangle {
52 GstVaapiContext *context;
53 GstVaapiSubpicture *subpicture;
54 GstVaapiRectangle rect;
58 /* XXX: optimize for the effective number of reference frames */
59 struct _GstVaapiContextPrivate {
62 GstVaapiVideoPool *surfaces_pool;
64 GstVaapiProfile profile;
65 GstVaapiEntrypoint entrypoint;
69 guint is_constructed : 1;
83 get_max_ref_frames(GstVaapiProfile profile)
87 switch (gst_vaapi_profile_get_codec(profile)) {
88 case GST_VAAPI_CODEC_H264: ref_frames = 16; break;
89 case GST_VAAPI_CODEC_JPEG: ref_frames = 0; break;
90 default: ref_frames = 2; break;
95 static GstVaapiOverlayRectangle *
96 overlay_rectangle_new(GstVaapiContext *context)
98 GstVaapiOverlayRectangle *overlay;
100 overlay = g_slice_new0(GstVaapiOverlayRectangle);
104 overlay->context = context;
109 overlay_rectangle_destroy(GstVaapiOverlayRectangle *overlay)
111 GstVaapiContextPrivate *priv;
116 priv = overlay->context->priv;
118 if (overlay->subpicture) {
119 if (priv->surfaces) {
120 GstVaapiSubpicture * const subpicture = overlay->subpicture;
121 for (i = 0; i < priv->surfaces->len; i++) {
122 GstVaapiSurface * const surface =
123 g_ptr_array_index(priv->surfaces, i);
124 gst_vaapi_surface_deassociate_subpicture(surface, subpicture);
127 g_object_unref(overlay->subpicture);
128 overlay->subpicture = NULL;
130 g_slice_free(GstVaapiOverlayRectangle, overlay);
134 destroy_overlay_cb(gpointer data, gpointer user_data)
136 GstVaapiOverlayRectangle * const overlay = data;
138 overlay_rectangle_destroy(overlay);
142 gst_vaapi_context_destroy_overlay(GstVaapiContext *context)
144 GstVaapiContextPrivate * const priv = context->priv;
149 g_ptr_array_foreach(priv->overlay, destroy_overlay_cb, priv);
150 g_ptr_array_free(priv->overlay, TRUE);
151 priv->overlay = NULL;
155 unref_surface_cb(gpointer data, gpointer user_data)
157 GstVaapiSurface * const surface = GST_VAAPI_SURFACE(data);
159 gst_vaapi_surface_set_parent_context(surface, NULL);
160 g_object_unref(surface);
164 gst_vaapi_context_destroy_surfaces(GstVaapiContext *context)
166 GstVaapiContextPrivate * const priv = context->priv;
168 gst_vaapi_context_destroy_overlay(context);
170 if (priv->surfaces) {
171 g_ptr_array_foreach(priv->surfaces, unref_surface_cb, NULL);
172 g_ptr_array_free(priv->surfaces, TRUE);
173 priv->surfaces = NULL;
176 g_clear_object(&priv->surfaces_pool);
180 gst_vaapi_context_destroy(GstVaapiContext *context)
182 GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(context);
183 GstVaapiContextPrivate * const priv = context->priv;
184 VAContextID context_id;
187 context_id = GST_VAAPI_OBJECT_ID(context);
188 GST_DEBUG("context %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(context_id));
190 if (context_id != VA_INVALID_ID) {
191 GST_VAAPI_DISPLAY_LOCK(display);
192 status = vaDestroyContext(
193 GST_VAAPI_DISPLAY_VADISPLAY(display),
196 GST_VAAPI_DISPLAY_UNLOCK(display);
197 if (!vaapi_check_status(status, "vaDestroyContext()"))
198 g_warning("failed to destroy context %" GST_VAAPI_ID_FORMAT,
199 GST_VAAPI_ID_ARGS(context_id));
200 GST_VAAPI_OBJECT_ID(context) = VA_INVALID_ID;
203 if (priv->config_id != VA_INVALID_ID) {
204 GST_VAAPI_DISPLAY_LOCK(display);
205 status = vaDestroyConfig(
206 GST_VAAPI_DISPLAY_VADISPLAY(display),
209 GST_VAAPI_DISPLAY_UNLOCK(display);
210 if (!vaapi_check_status(status, "vaDestroyConfig()"))
211 g_warning("failed to destroy config %" GST_VAAPI_ID_FORMAT,
212 GST_VAAPI_ID_ARGS(priv->config_id));
213 priv->config_id = VA_INVALID_ID;
218 gst_vaapi_context_create_overlay(GstVaapiContext *context)
220 GstVaapiContextPrivate * const priv = context->priv;
222 if (!priv->overlay) {
223 priv->overlay = g_ptr_array_new();
231 gst_vaapi_context_create_surfaces(GstVaapiContext *context)
233 GstVaapiContextPrivate * const priv = context->priv;
235 GstVaapiSurface *surface;
236 guint i, num_surfaces;
238 /* Number of scratch surfaces beyond those used as reference */
239 const guint SCRATCH_SURFACES_COUNT = 4;
241 if (!gst_vaapi_context_create_overlay(context))
244 if (!priv->surfaces) {
245 priv->surfaces = g_ptr_array_new();
250 if (!priv->surfaces_pool) {
251 caps = gst_caps_new_simple(
252 GST_VAAPI_SURFACE_CAPS_NAME,
253 "type", G_TYPE_STRING, "vaapi",
254 "width", G_TYPE_INT, priv->width,
255 "height", G_TYPE_INT, priv->height,
260 priv->surfaces_pool = gst_vaapi_surface_pool_new(
261 GST_VAAPI_OBJECT_DISPLAY(context),
264 gst_caps_unref(caps);
265 if (!priv->surfaces_pool)
269 num_surfaces = priv->ref_frames + SCRATCH_SURFACES_COUNT;
270 gst_vaapi_video_pool_set_capacity(priv->surfaces_pool, num_surfaces);
272 for (i = priv->surfaces->len; i < num_surfaces; i++) {
273 surface = gst_vaapi_surface_new(
274 GST_VAAPI_OBJECT_DISPLAY(context),
275 GST_VAAPI_CHROMA_TYPE_YUV420,
276 priv->width, priv->height
280 g_ptr_array_add(priv->surfaces, surface);
281 if (!gst_vaapi_video_pool_add_object(priv->surfaces_pool, surface))
288 gst_vaapi_context_create(GstVaapiContext *context)
290 GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(context);
291 GstVaapiContextPrivate * const priv = context->priv;
292 VAProfile va_profile;
293 VAEntrypoint va_entrypoint;
294 VAConfigAttrib attribs[2];
296 VAContextID context_id;
297 VASurfaceID surface_id;
299 GArray *surfaces = NULL;
300 gboolean success = FALSE;
303 if (!priv->surfaces && !gst_vaapi_context_create_surfaces(context))
306 surfaces = g_array_sized_new(
315 for (i = 0; i < priv->surfaces->len; i++) {
316 GstVaapiSurface * const surface = g_ptr_array_index(priv->surfaces, i);
319 surface_id = GST_VAAPI_OBJECT_ID(surface);
320 g_array_append_val(surfaces, surface_id);
322 assert(surfaces->len == priv->surfaces->len);
324 if (!priv->profile || !priv->entrypoint)
326 va_profile = gst_vaapi_profile_get_va_profile(priv->profile);
327 va_entrypoint = gst_vaapi_entrypoint_get_va_entrypoint(priv->entrypoint);
329 GST_VAAPI_DISPLAY_LOCK(display);
330 attribs[0].type = VAConfigAttribRTFormat;
331 attribs[1].type = VAConfigAttribRateControl;
332 if (VAEntrypointEncSlice == va_entrypoint)
337 status = vaGetConfigAttributes(
338 GST_VAAPI_DISPLAY_VADISPLAY(display),
343 GST_VAAPI_DISPLAY_UNLOCK(display);
344 if (!vaapi_check_status(status, "vaGetConfigAttributes()"))
346 if (!(attribs[0].value & VA_RT_FORMAT_YUV420))
348 if (attribs_num > 1 && !(attribs[1].value & VA_RC_NONE)
349 && !(attribs[1].value & VA_RC_CBR)
350 && !(attribs[1].value & VA_RC_VBR))
353 GST_VAAPI_DISPLAY_LOCK(display);
354 status = vaCreateConfig(
355 GST_VAAPI_DISPLAY_VADISPLAY(display),
358 attribs, attribs_num,
361 GST_VAAPI_DISPLAY_UNLOCK(display);
362 if (!vaapi_check_status(status, "vaCreateConfig()"))
365 VASurfaceID *surface_ids = (VASurfaceID*)surfaces->data;
366 int surface_num = surfaces->len;
368 if (VAEntrypointEncSlice == va_entrypoint) {
373 GST_VAAPI_DISPLAY_LOCK(display);
374 status = vaCreateContext(
375 GST_VAAPI_DISPLAY_VADISPLAY(display),
377 priv->width, priv->height,
379 (VASurfaceID *)surface_ids, surface_num,
382 GST_VAAPI_DISPLAY_UNLOCK(display);
383 if (!vaapi_check_status(status, "vaCreateContext()"))
386 GST_DEBUG("context %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(context_id));
387 GST_VAAPI_OBJECT_ID(context) = context_id;
391 g_array_free(surfaces, TRUE);
396 gst_vaapi_context_finalize(GObject *object)
398 GstVaapiContext * const context = GST_VAAPI_CONTEXT(object);
400 gst_vaapi_context_destroy(context);
401 gst_vaapi_context_destroy_surfaces(context);
403 G_OBJECT_CLASS(gst_vaapi_context_parent_class)->finalize(object);
407 gst_vaapi_context_set_property(
414 GstVaapiContext * const context = GST_VAAPI_CONTEXT(object);
415 GstVaapiContextPrivate * const priv = context->priv;
419 gst_vaapi_context_set_profile(context, g_value_get_uint(value));
421 case PROP_ENTRYPOINT:
422 priv->entrypoint = g_value_get_uint(value);
425 priv->width = g_value_get_uint(value);
428 priv->height = g_value_get_uint(value);
430 case PROP_REF_FRAMES:
431 priv->ref_frames = g_value_get_uint(value);
434 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
440 gst_vaapi_context_get_property(
447 GstVaapiContext * const context = GST_VAAPI_CONTEXT(object);
448 GstVaapiContextPrivate * const priv = context->priv;
452 g_value_set_uint(value, gst_vaapi_context_get_profile(context));
454 case PROP_ENTRYPOINT:
455 g_value_set_uint(value, gst_vaapi_context_get_entrypoint(context));
458 g_value_set_uint(value, priv->width);
461 g_value_set_uint(value, priv->height);
463 case PROP_REF_FRAMES:
464 g_value_set_uint(value, priv->ref_frames);
467 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
473 gst_vaapi_context_class_init(GstVaapiContextClass *klass)
475 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
477 g_type_class_add_private(klass, sizeof(GstVaapiContextPrivate));
479 object_class->finalize = gst_vaapi_context_finalize;
480 object_class->set_property = gst_vaapi_context_set_property;
481 object_class->get_property = gst_vaapi_context_get_property;
483 g_object_class_install_property
486 g_param_spec_uint("profile",
488 "The profile used for decoding",
492 g_object_class_install_property
495 g_param_spec_uint("entrypoint",
497 "The decoder entrypoint",
499 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
501 g_object_class_install_property
504 g_param_spec_uint("width",
506 "The width of decoded surfaces",
508 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
510 g_object_class_install_property
513 g_param_spec_uint("height",
515 "The height of the decoded surfaces",
517 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
519 g_object_class_install_property
522 g_param_spec_uint("ref-frames",
524 "The number of reference frames",
526 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
530 gst_vaapi_context_init(GstVaapiContext *context)
532 GstVaapiContextPrivate *priv = GST_VAAPI_CONTEXT_GET_PRIVATE(context);
534 context->priv = priv;
535 priv->config_id = VA_INVALID_ID;
536 priv->surfaces = NULL;
537 priv->surfaces_pool = NULL;
538 priv->overlay = NULL;
540 priv->entrypoint = 0;
543 priv->ref_frames = 0;
547 * gst_vaapi_context_new:
548 * @display: a #GstVaapiDisplay
549 * @profile: a #GstVaapiProfile
550 * @entrypoint: a #GstVaapiEntrypoint
551 * @width: coded width from the bitstream
552 * @height: coded height from the bitstream
554 * Creates a new #GstVaapiContext with the specified codec @profile
557 * Return value: the newly allocated #GstVaapiContext object
560 gst_vaapi_context_new(
561 GstVaapiDisplay *display,
562 GstVaapiProfile profile,
563 GstVaapiEntrypoint entrypoint,
568 GstVaapiContextInfo info;
570 info.profile = profile;
571 info.entrypoint = entrypoint;
573 info.height = height;
574 info.ref_frames = get_max_ref_frames(profile);
575 return gst_vaapi_context_new_full(display, &info);
579 * gst_vaapi_context_new_full:
580 * @display: a #GstVaapiDisplay
581 * @cip: a pointer to the #GstVaapiContextInfo
583 * Creates a new #GstVaapiContext with the configuration specified by
584 * @cip, thus including profile, entry-point, encoded size and maximum
585 * number of reference frames reported by the bitstream.
587 * Return value: the newly allocated #GstVaapiContext object
590 gst_vaapi_context_new_full(GstVaapiDisplay *display, GstVaapiContextInfo *cip)
592 GstVaapiContext *context;
594 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
595 g_return_val_if_fail(cip->profile, NULL);
596 g_return_val_if_fail(cip->entrypoint, NULL);
597 g_return_val_if_fail(cip->width > 0, NULL);
598 g_return_val_if_fail(cip->height > 0, NULL);
600 context = g_object_new(
601 GST_VAAPI_TYPE_CONTEXT,
603 "id", GST_VAAPI_ID(VA_INVALID_ID),
604 "profile", cip->profile,
605 "entrypoint", cip->entrypoint,
607 "height", cip->height,
608 "ref-frames", cip->ref_frames,
611 if (!context->priv->is_constructed) {
612 g_object_unref(context);
619 * gst_vaapi_context_reset:
620 * @context: a #GstVaapiContext
621 * @profile: a #GstVaapiProfile
622 * @entrypoint: a #GstVaapiEntrypoint
623 * @width: coded width from the bitstream
624 * @height: coded height from the bitstream
626 * Resets @context to the specified codec @profile and @entrypoint.
627 * The surfaces will be reallocated if the coded size changed.
629 * Return value: %TRUE on success
632 gst_vaapi_context_reset(
633 GstVaapiContext *context,
634 GstVaapiProfile profile,
635 GstVaapiEntrypoint entrypoint,
640 GstVaapiContextPrivate * const priv = context->priv;
641 GstVaapiContextInfo info;
643 info.profile = profile;
644 info.entrypoint = entrypoint;
646 info.height = height;
647 info.ref_frames = priv->ref_frames;
649 return gst_vaapi_context_reset_full(context, &info);
653 * gst_vaapi_context_reset_full:
654 * @context: a #GstVaapiContext
655 * @cip: a pointer to the new #GstVaapiContextInfo details
657 * Resets @context to the configuration specified by @cip, thus
658 * including profile, entry-point, encoded size and maximum number of
659 * reference frames reported by the bitstream.
661 * Return value: %TRUE on success
664 gst_vaapi_context_reset_full(GstVaapiContext *context, GstVaapiContextInfo *cip)
666 GstVaapiContextPrivate * const priv = context->priv;
667 gboolean size_changed, codec_changed;
669 size_changed = priv->width != cip->width || priv->height != cip->height;
671 gst_vaapi_context_destroy_surfaces(context);
672 priv->width = cip->width;
673 priv->height = cip->height;
676 codec_changed = priv->profile != cip->profile || priv->entrypoint != cip->entrypoint;
678 gst_vaapi_context_destroy(context);
679 priv->profile = cip->profile;
680 priv->entrypoint = cip->entrypoint;
683 if (size_changed && !gst_vaapi_context_create_surfaces(context))
686 if (codec_changed && !gst_vaapi_context_create(context))
689 priv->is_constructed = TRUE;
694 * gst_vaapi_context_get_id:
695 * @context: a #GstVaapiContext
697 * Returns the underlying VAContextID of the @context.
699 * Return value: the underlying VA context id
702 gst_vaapi_context_get_id(GstVaapiContext *context)
704 g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), VA_INVALID_ID);
706 return GST_VAAPI_OBJECT_ID(context);
710 * gst_vaapi_context_get_profile:
711 * @context: a #GstVaapiContext
713 * Returns the VA profile used by the @context.
715 * Return value: the VA profile used by the @context
718 gst_vaapi_context_get_profile(GstVaapiContext *context)
720 g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), 0);
722 return context->priv->profile;
726 * gst_vaapi_context_set_profile:
727 * @context: a #GstVaapiContext
728 * @profile: the new #GstVaapiProfile to use
730 * Sets the new @profile to use with the @context. If @profile matches
731 * the previous profile, this call has no effect. Otherwise, the
732 * underlying VA context is recreated, while keeping the previously
733 * allocated surfaces.
735 * Return value: %TRUE on success
738 gst_vaapi_context_set_profile(GstVaapiContext *context, GstVaapiProfile profile)
740 g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), FALSE);
741 g_return_val_if_fail(profile, FALSE);
743 return gst_vaapi_context_reset(context,
745 context->priv->entrypoint,
746 context->priv->width,
747 context->priv->height);
751 * gst_vaapi_context_get_entrypoint:
752 * @context: a #GstVaapiContext
754 * Returns the VA entrypoint used by the @context
756 * Return value: the VA entrypoint used by the @context
759 gst_vaapi_context_get_entrypoint(GstVaapiContext *context)
761 g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), 0);
763 return context->priv->entrypoint;
767 * gst_vaapi_context_get_size:
768 * @context: a #GstVaapiContext
769 * @pwidth: return location for the width, or %NULL
770 * @pheight: return location for the height, or %NULL
772 * Retrieves the size of the surfaces attached to @context.
775 gst_vaapi_context_get_size(
776 GstVaapiContext *context,
781 g_return_if_fail(GST_VAAPI_IS_CONTEXT(context));
784 *pwidth = context->priv->width;
787 *pheight = context->priv->height;
791 * gst_vaapi_context_get_surface:
792 * @context: a #GstVaapiContext
794 * Acquires a free surface. The returned surface but be released with
795 * gst_vaapi_context_put_surface(). This function returns %NULL if
796 * there is no free surface available in the pool. The surfaces are
797 * pre-allocated during context creation though.
799 * Return value: a free surface, or %NULL if none is available
802 gst_vaapi_context_get_surface(GstVaapiContext *context)
804 GstVaapiSurface *surface;
806 g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), NULL);
808 surface = gst_vaapi_video_pool_get_object(context->priv->surfaces_pool);
812 gst_vaapi_surface_set_parent_context(surface, context);
817 * gst_vaapi_context_get_surface_pool:
818 * @context: a #GstVaapiContext
820 * Reference the surface pool. The returned surface pool should be released with
821 * g_object_unref(). This function returns %NULL if
822 * there is the surface pool is empty. The surface pool is
823 * created during context creation though.
825 * Return value: surface pool, or %NULL if it is not created.
828 GstVaapiSurfacePool *
829 gst_vaapi_context_get_surface_pool(GstVaapiContext *context)
831 g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), NULL);
832 return (GstVaapiSurfacePool*)g_object_ref(context->priv->surfaces_pool);
837 * gst_vaapi_context_get_surface_count:
838 * @context: a #GstVaapiContext
840 * Retrieves the number of free surfaces left in the pool.
842 * Return value: the number of free surfaces available in the pool
845 gst_vaapi_context_get_surface_count(GstVaapiContext *context)
847 g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), 0);
849 return gst_vaapi_video_pool_get_size(context->priv->surfaces_pool);
853 * gst_vaapi_context_put_surface:
854 * @context: a #GstVaapiContext
855 * @surface: the #GstVaapiSurface to release
857 * Releases a surface acquired by gst_vaapi_context_get_surface().
860 gst_vaapi_context_put_surface(GstVaapiContext *context, GstVaapiSurface *surface)
862 g_return_if_fail(GST_VAAPI_IS_CONTEXT(context));
863 g_return_if_fail(GST_VAAPI_IS_SURFACE(surface));
865 gst_vaapi_surface_set_parent_context(surface, NULL);
866 gst_vaapi_video_pool_put_object(context->priv->surfaces_pool, surface);
870 * gst_vaapi_context_find_surface_by_id:
871 * @context: a #GstVaapiContext
872 * @id: the VA surface id to find
874 * Finds VA surface by @id in the list of surfaces attached to the @context.
876 * Return value: the matching #GstVaapiSurface object, or %NULL if
880 gst_vaapi_context_find_surface_by_id(GstVaapiContext *context, GstVaapiID id)
882 GstVaapiContextPrivate *priv;
883 GstVaapiSurface *surface;
886 g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), NULL);
888 priv = context->priv;
889 g_return_val_if_fail(priv->surfaces, NULL);
891 for (i = 0; i < priv->surfaces->len; i++) {
892 surface = g_ptr_array_index(priv->surfaces, i);
893 if (GST_VAAPI_OBJECT_ID(surface) == id)
899 /* Check if composition changed */
901 gst_vaapi_context_composition_changed(
902 GstVaapiContext *context,
903 GstVideoOverlayComposition *composition
906 GstVaapiContextPrivate * const priv = context->priv;
907 GstVaapiOverlayRectangle *overlay;
908 GstVideoOverlayRectangle *rect;
909 guint i, n_rectangles;
911 if (!priv->overlay || !composition)
914 n_rectangles = gst_video_overlay_composition_n_rectangles(composition);
915 if (priv->overlay->len != n_rectangles)
918 for (i = 0; i < n_rectangles; i++) {
919 rect = gst_video_overlay_composition_get_rectangle(composition, i);
920 g_return_val_if_fail(rect, TRUE);
921 overlay = g_ptr_array_index(priv->overlay, i);
922 g_return_val_if_fail(overlay, TRUE);
923 if (overlay->seq_num != gst_video_overlay_rectangle_get_seqnum(rect))
930 * gst_vaapi_context_apply_composition:
931 * @context: a #GstVaapiContext
932 * @composition: a #GstVideoOverlayComposition
934 * Applies video composition planes to all surfaces bound to @context.
935 * This helper function resets any additional subpictures the user may
936 * have associated himself. A %NULL @composition will also clear all
937 * the existing subpictures.
939 * Return value: %TRUE if all composition planes could be applied,
943 gst_vaapi_context_apply_composition(
944 GstVaapiContext *context,
945 GstVideoOverlayComposition *composition
948 GstVaapiContextPrivate *priv;
949 GstVideoOverlayRectangle *rect;
950 GstVaapiOverlayRectangle *overlay = NULL;
951 GstVaapiDisplay *display;
952 guint i, j, n_rectangles;
954 g_return_val_if_fail(GST_VAAPI_IS_CONTEXT(context), FALSE);
956 priv = context->priv;
960 display = GST_VAAPI_OBJECT_DISPLAY(context);
964 if (!gst_vaapi_context_composition_changed(context, composition))
966 gst_vaapi_context_destroy_overlay(context);
970 if (!gst_vaapi_context_create_overlay(context))
973 n_rectangles = gst_video_overlay_composition_n_rectangles(composition);
974 for (i = 0; i < n_rectangles; i++) {
975 rect = gst_video_overlay_composition_get_rectangle(composition, i);
977 overlay = overlay_rectangle_new(context);
979 GST_WARNING("could not create VA overlay rectangle");
982 overlay->seq_num = gst_video_overlay_rectangle_get_seqnum(rect);
984 overlay->subpicture = gst_vaapi_subpicture_new_from_overlay_rectangle(
988 if (!overlay->subpicture) {
989 overlay_rectangle_destroy(overlay);
993 gst_video_overlay_rectangle_get_render_rectangle(
995 (gint *)&overlay->rect.x,
996 (gint *)&overlay->rect.y,
997 &overlay->rect.width,
998 &overlay->rect.height
1001 for (j = 0; j < priv->surfaces->len; j++) {
1002 GstVaapiSurface * const surface =
1003 g_ptr_array_index(priv->surfaces, j);
1004 if (!gst_vaapi_surface_associate_subpicture(surface,
1005 overlay->subpicture, NULL, &overlay->rect)) {
1006 GST_WARNING("could not render overlay rectangle %p", rect);
1007 overlay_rectangle_destroy(overlay);
1011 g_ptr_array_add(priv->overlay, overlay);