From 3b714c8913ff43370f7d7bd6ec0fdb85ef72328d Mon Sep 17 00:00:00 2001 From: Gwenole Beauchesne Date: Thu, 23 Jan 2014 10:59:20 +0100 Subject: [PATCH] context: move overlay composition to separate files. Move GstVideoOverlayComposition handling to separate source files. This helps keeing GstVaapiContext core implementation to the bare minimal, i.e. simpy helpers to create a VA context and handle pool of associated VA surfaces. --- gst-libs/gst/vaapi/Makefile.am | 2 + gst-libs/gst/vaapi/gstvaapicontext.c | 403 +---------------- gst-libs/gst/vaapi/gstvaapicontext.h | 6 - gst-libs/gst/vaapi/gstvaapicontext_overlay.c | 451 +++++++++++++++++++ gst-libs/gst/vaapi/gstvaapicontext_overlay.h | 52 +++ gst-libs/gst/vaapi/gstvaapisurface.c | 1 + 6 files changed, 511 insertions(+), 404 deletions(-) create mode 100644 gst-libs/gst/vaapi/gstvaapicontext_overlay.c create mode 100644 gst-libs/gst/vaapi/gstvaapicontext_overlay.h diff --git a/gst-libs/gst/vaapi/Makefile.am b/gst-libs/gst/vaapi/Makefile.am index 11efb4b63e..92b875aaa6 100644 --- a/gst-libs/gst/vaapi/Makefile.am +++ b/gst-libs/gst/vaapi/Makefile.am @@ -47,6 +47,7 @@ libgstvaapi_libs = \ libgstvaapi_source_c = \ gstvaapicodec_objects.c \ gstvaapicontext.c \ + gstvaapicontext_overlay.c \ gstvaapidecoder.c \ gstvaapidecoder_dpb.c \ gstvaapidecoder_h264.c \ @@ -110,6 +111,7 @@ libgstvaapi_source_priv_h = \ gstvaapicodec_objects.h \ gstvaapicompat.h \ gstvaapicontext.h \ + gstvaapicontext_overlay.h \ gstvaapidebug.h \ gstvaapidecoder_dpb.h \ gstvaapidecoder_objects.h \ diff --git a/gst-libs/gst/vaapi/gstvaapicontext.c b/gst-libs/gst/vaapi/gstvaapicontext.c index a4cc1fb841..8651e90ad6 100644 --- a/gst-libs/gst/vaapi/gstvaapicontext.c +++ b/gst-libs/gst/vaapi/gstvaapicontext.c @@ -30,6 +30,7 @@ #include "sysdeps.h" #include "gstvaapicompat.h" #include "gstvaapicontext.h" +#include "gstvaapicontext_overlay.h" #include "gstvaapidisplay_priv.h" #include "gstvaapiobject_priv.h" #include "gstvaapisurface.h" @@ -37,324 +38,11 @@ #include "gstvaapisurfacepool.h" #include "gstvaapisurfaceproxy.h" #include "gstvaapivideopool_priv.h" -#include "gstvaapiimage.h" -#include "gstvaapisubpicture.h" #include "gstvaapiutils.h" #define DEBUG 1 #include "gstvaapidebug.h" -typedef struct _GstVaapiOverlayRectangle GstVaapiOverlayRectangle; -struct _GstVaapiOverlayRectangle -{ - GstVaapiContext *context; - GstVaapiSubpicture *subpicture; - GstVaapiRectangle render_rect; - guint seq_num; - guint layer_id; - GstBuffer *rect_buffer; - GstVideoOverlayRectangle *rect; - guint is_associated:1; -}; - -static inline void -gst_video_overlay_rectangle_replace (GstVideoOverlayRectangle ** old_rect_ptr, - GstVideoOverlayRectangle * new_rect) -{ - gst_mini_object_replace ((GstMiniObject **) old_rect_ptr, - GST_MINI_OBJECT_CAST (new_rect)); -} - -#define overlay_rectangle_ref(overlay) \ - gst_vaapi_mini_object_ref(GST_VAAPI_MINI_OBJECT(overlay)) - -#define overlay_rectangle_unref(overlay) \ - gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(overlay)) - -#define overlay_rectangle_replace(old_overlay_ptr, new_overlay) \ - gst_vaapi_mini_object_replace((GstVaapiMiniObject **)(old_overlay_ptr), \ - (GstVaapiMiniObject *)(new_overlay)) - -static void overlay_rectangle_finalize (GstVaapiOverlayRectangle * overlay); - -static gboolean -overlay_rectangle_associate (GstVaapiOverlayRectangle * overlay); - -static gboolean -overlay_rectangle_deassociate (GstVaapiOverlayRectangle * overlay); - -static inline const GstVaapiMiniObjectClass * -overlay_rectangle_class (void) -{ - static const GstVaapiMiniObjectClass GstVaapiOverlayRectangleClass = { - sizeof (GstVaapiOverlayRectangle), - (GDestroyNotify) overlay_rectangle_finalize - }; - return &GstVaapiOverlayRectangleClass; -} - -static GstVaapiOverlayRectangle * -overlay_rectangle_new (GstVideoOverlayRectangle * rect, - GstVaapiContext * context, guint layer_id) -{ - GstVaapiOverlayRectangle *overlay; - GstVaapiRectangle *render_rect; - guint width, height, flags; - gint x, y; - - overlay = (GstVaapiOverlayRectangle *) - gst_vaapi_mini_object_new0 (overlay_rectangle_class ()); - if (!overlay) - return NULL; - - overlay->context = context; - overlay->seq_num = gst_video_overlay_rectangle_get_seqnum (rect); - overlay->layer_id = layer_id; - overlay->rect = gst_video_overlay_rectangle_ref (rect); - - flags = gst_video_overlay_rectangle_get_flags (rect); - gst_buffer_replace (&overlay->rect_buffer, - gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect, flags)); - if (!overlay->rect_buffer) - goto error; - - overlay->subpicture = - gst_vaapi_subpicture_new_from_overlay_rectangle (GST_VAAPI_OBJECT_DISPLAY - (context), rect); - if (!overlay->subpicture) - goto error; - - gst_video_overlay_rectangle_get_render_rectangle (rect, - &x, &y, &width, &height); - render_rect = &overlay->render_rect; - render_rect->x = x; - render_rect->y = y; - render_rect->width = width; - render_rect->height = height; - return overlay; - -error: - overlay_rectangle_unref (overlay); - return NULL; -} - -static void -overlay_rectangle_finalize (GstVaapiOverlayRectangle * overlay) -{ - gst_buffer_replace (&overlay->rect_buffer, NULL); - gst_video_overlay_rectangle_unref (overlay->rect); - - if (overlay->subpicture) { - overlay_rectangle_deassociate (overlay); - gst_vaapi_object_unref (overlay->subpicture); - overlay->subpicture = NULL; - } -} - -static gboolean -overlay_rectangle_associate (GstVaapiOverlayRectangle * overlay) -{ - GstVaapiSubpicture *const subpicture = overlay->subpicture; - GPtrArray *const surfaces = overlay->context->surfaces; - guint i, n_associated; - - if (overlay->is_associated) - return TRUE; - - n_associated = 0; - for (i = 0; i < surfaces->len; i++) { - GstVaapiSurface *const surface = g_ptr_array_index (surfaces, i); - if (gst_vaapi_surface_associate_subpicture (surface, subpicture, - NULL, &overlay->render_rect)) - n_associated++; - } - - overlay->is_associated = TRUE; - return n_associated == surfaces->len; -} - -static gboolean -overlay_rectangle_deassociate (GstVaapiOverlayRectangle * overlay) -{ - GstVaapiSubpicture *const subpicture = overlay->subpicture; - GPtrArray *const surfaces = overlay->context->surfaces; - guint i, n_associated; - - if (!overlay->is_associated) - return TRUE; - - n_associated = surfaces->len; - for (i = 0; i < surfaces->len; i++) { - GstVaapiSurface *const surface = g_ptr_array_index (surfaces, i); - if (gst_vaapi_surface_deassociate_subpicture (surface, subpicture)) - n_associated--; - } - - overlay->is_associated = FALSE; - return n_associated == 0; -} - -static gboolean -overlay_rectangle_changed_pixels (GstVaapiOverlayRectangle * overlay, - GstVideoOverlayRectangle * rect) -{ - guint flags; - GstBuffer *buffer; - - if (overlay->seq_num == gst_video_overlay_rectangle_get_seqnum (rect)) - return FALSE; - - flags = - to_GstVideoOverlayFormatFlags (gst_vaapi_subpicture_get_flags - (overlay->subpicture)); - - buffer = gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect, flags); - if (!buffer) - return FALSE; -#if GST_CHECK_VERSION(1,0,0) - { - const guint n_blocks = gst_buffer_n_memory (buffer); - gsize ofs; - guint i; - - if (buffer == overlay->rect_buffer) - return TRUE; - - if (n_blocks != gst_buffer_n_memory (overlay->rect_buffer)) - return FALSE; - - for (i = 0; i < n_blocks; i++) { - GstMemory *const mem1 = gst_buffer_peek_memory (buffer, i); - GstMemory *const mem2 = gst_buffer_peek_memory (overlay->rect_buffer, i); - if (!gst_memory_is_span (mem1, mem2, &ofs)) - return FALSE; - } - } -#else - if (GST_BUFFER_DATA (overlay->rect_buffer) != GST_BUFFER_DATA (buffer)) - return FALSE; -#endif - return TRUE; -} - -static gboolean -overlay_rectangle_changed_render_rect (GstVaapiOverlayRectangle * overlay, - GstVideoOverlayRectangle * rect) -{ - GstVaapiRectangle *const render_rect = &overlay->render_rect; - guint width, height; - gint x, y; - - gst_video_overlay_rectangle_get_render_rectangle (rect, - &x, &y, &width, &height); - - if (x == render_rect->x && - y == render_rect->y && - width == render_rect->width && height == render_rect->height) - return FALSE; - - render_rect->x = x; - render_rect->y = y; - render_rect->width = width; - render_rect->height = height; - return TRUE; -} - -static inline gboolean -overlay_rectangle_update_global_alpha (GstVaapiOverlayRectangle * overlay, - GstVideoOverlayRectangle * rect) -{ -#ifdef HAVE_GST_VIDEO_OVERLAY_HWCAPS - const guint flags = gst_video_overlay_rectangle_get_flags (rect); - if (!(flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA)) - return TRUE; -#endif - return gst_vaapi_subpicture_set_global_alpha (overlay->subpicture, - gst_video_overlay_rectangle_get_global_alpha (rect)); -} - -static gboolean -overlay_rectangle_update (GstVaapiOverlayRectangle * overlay, - GstVideoOverlayRectangle * rect, gboolean * reassociate_ptr) -{ - if (overlay_rectangle_changed_pixels (overlay, rect)) - return FALSE; - if (overlay_rectangle_changed_render_rect (overlay, rect)) - *reassociate_ptr = TRUE; - if (!overlay_rectangle_update_global_alpha (overlay, rect)) - return FALSE; - gst_video_overlay_rectangle_replace (&overlay->rect, rect); - return TRUE; -} - -static inline GPtrArray * -overlay_new (void) -{ - return g_ptr_array_new_with_free_func ( - (GDestroyNotify) gst_vaapi_mini_object_unref); -} - -static void -overlay_destroy (GPtrArray ** overlay_ptr) -{ - GPtrArray *const overlay = *overlay_ptr; - - if (!overlay) - return; - g_ptr_array_unref (overlay); - *overlay_ptr = NULL; -} - -static void -overlay_clear (GPtrArray * overlay) -{ - if (overlay && overlay->len > 0) - g_ptr_array_remove_range (overlay, 0, overlay->len); -} - -static GstVaapiOverlayRectangle * -overlay_lookup (GPtrArray * overlays, GstVideoOverlayRectangle * rect) -{ - guint i; - - for (i = 0; i < overlays->len; i++) { - GstVaapiOverlayRectangle *const overlay = g_ptr_array_index (overlays, i); - - if (overlay->rect == rect) - return overlay; - } - return NULL; -} - -static gboolean -overlay_reassociate (GPtrArray * overlays) -{ - guint i; - - for (i = 0; i < overlays->len; i++) - overlay_rectangle_deassociate (g_ptr_array_index (overlays, i)); - - for (i = 0; i < overlays->len; i++) { - if (!overlay_rectangle_associate (g_ptr_array_index (overlays, i))) - return FALSE; - } - return TRUE; -} - -static void -context_clear_overlay (GstVaapiContext * context) -{ - overlay_clear (context->overlays[0]); - overlay_clear (context->overlays[1]); - context->overlay_id = 0; -} - -static inline void -context_destroy_overlay (GstVaapiContext * context) -{ - context_clear_overlay (context); -} - static void unref_surface_cb (GstVaapiSurface * surface) { @@ -365,7 +53,7 @@ unref_surface_cb (GstVaapiSurface * surface) static void context_destroy_surfaces (GstVaapiContext * context) { - context_destroy_overlay (context); + gst_vaapi_context_overlay_reset (context); if (context->surfaces) { g_ptr_array_unref (context->surfaces); @@ -405,16 +93,6 @@ context_destroy (GstVaapiContext * context) } } -static gboolean -context_create_overlay (GstVaapiContext * context) -{ - if (!context->overlays[0] || !context->overlays[1]) - return FALSE; - - context_clear_overlay (context); - return TRUE; -} - static gboolean context_create_surfaces (GstVaapiContext * context) { @@ -426,7 +104,7 @@ context_create_surfaces (GstVaapiContext * context) /* Number of scratch surfaces beyond those used as reference */ const guint SCRATCH_SURFACES_COUNT = 4; - if (!context_create_overlay (context)) + if (!gst_vaapi_context_overlay_reset (context)) return FALSE; num_surfaces = cip->ref_frames + SCRATCH_SURFACES_COUNT; @@ -556,17 +234,15 @@ gst_vaapi_context_init (GstVaapiContext * context, { context->info = *cip; context->va_config = VA_INVALID_ID; - context->overlays[0] = overlay_new (); - context->overlays[1] = overlay_new (); + gst_vaapi_context_overlay_init (context); } static void gst_vaapi_context_finalize (GstVaapiContext * context) { - overlay_destroy (&context->overlays[0]); - overlay_destroy (&context->overlays[1]); context_destroy (context); context_destroy_surfaces (context); + gst_vaapi_context_overlay_finalize (context); } GST_VAAPI_OBJECT_DEFINE_CLASS (GstVaapiContext, gst_vaapi_context); @@ -718,75 +394,6 @@ gst_vaapi_context_get_surface_count (GstVaapiContext * context) return gst_vaapi_video_pool_get_size (context->surfaces_pool); } -/** - * gst_vaapi_context_apply_composition: - * @context: a #GstVaapiContext - * @composition: a #GstVideoOverlayComposition - * - * Applies video composition planes to all surfaces bound to @context. - * This helper function resets any additional subpictures the user may - * have associated himself. A %NULL @composition will also clear all - * the existing subpictures. - * - * Return value: %TRUE if all composition planes could be applied, - * %FALSE otherwise - */ -gboolean -gst_vaapi_context_apply_composition (GstVaapiContext * context, - GstVideoOverlayComposition * composition) -{ - GPtrArray *curr_overlay, *next_overlay; - guint i, n_rectangles; - gboolean reassociate = FALSE; - - g_return_val_if_fail (context != NULL, FALSE); - - if (!context->surfaces) - return FALSE; - - if (!composition) { - context_clear_overlay (context); - return TRUE; - } - - curr_overlay = context->overlays[context->overlay_id]; - next_overlay = context->overlays[context->overlay_id ^ 1]; - overlay_clear (next_overlay); - - n_rectangles = gst_video_overlay_composition_n_rectangles (composition); - for (i = 0; i < n_rectangles; i++) { - GstVideoOverlayRectangle *const rect = - gst_video_overlay_composition_get_rectangle (composition, i); - GstVaapiOverlayRectangle *overlay; - - overlay = overlay_lookup (curr_overlay, rect); - if (overlay && overlay_rectangle_update (overlay, rect, &reassociate)) { - overlay_rectangle_ref (overlay); - if (overlay->layer_id != i) - reassociate = TRUE; - } else { - overlay = overlay_rectangle_new (rect, context, i); - if (!overlay) { - GST_WARNING ("could not create VA overlay rectangle"); - goto error; - } - reassociate = TRUE; - } - g_ptr_array_add (next_overlay, overlay); - } - - overlay_clear (curr_overlay); - context->overlay_id ^= 1; - - if (reassociate && !overlay_reassociate (next_overlay)) - return FALSE; - return TRUE; - -error: - context_clear_overlay (context); - return FALSE; -} - /** * gst_vaapi_context_get_attribute: * @context: a #GstVaapiContext diff --git a/gst-libs/gst/vaapi/gstvaapicontext.h b/gst-libs/gst/vaapi/gstvaapicontext.h index 4888a837b6..8112fd4948 100644 --- a/gst-libs/gst/vaapi/gstvaapicontext.h +++ b/gst-libs/gst/vaapi/gstvaapicontext.h @@ -25,7 +25,6 @@ #ifndef GST_VAAPI_CONTEXT_H #define GST_VAAPI_CONTEXT_H -#include #include "gstvaapiobject.h" #include "gstvaapiobject_priv.h" #include "gstvaapiprofile.h" @@ -115,11 +114,6 @@ G_GNUC_INTERNAL guint gst_vaapi_context_get_surface_count (GstVaapiContext * context); -G_GNUC_INTERNAL -gboolean -gst_vaapi_context_apply_composition (GstVaapiContext * context, - GstVideoOverlayComposition * composition); - G_GNUC_INTERNAL gboolean gst_vaapi_context_get_attribute (GstVaapiContext * context, diff --git a/gst-libs/gst/vaapi/gstvaapicontext_overlay.c b/gst-libs/gst/vaapi/gstvaapicontext_overlay.c new file mode 100644 index 0000000000..b38e62e795 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicontext_overlay.c @@ -0,0 +1,451 @@ +/* + * gstvaapicontext_overlay.c - VA context abstraction (overlay composition) + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "sysdeps.h" +#include "gstvaapicontext_overlay.h" +#include "gstvaapiutils.h" +#include "gstvaapiimage.h" +#include "gstvaapisubpicture.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +typedef struct _GstVaapiOverlayRectangle GstVaapiOverlayRectangle; +struct _GstVaapiOverlayRectangle +{ + GstVaapiContext *context; + GstVaapiSubpicture *subpicture; + GstVaapiRectangle render_rect; + guint seq_num; + guint layer_id; + GstBuffer *rect_buffer; + GstVideoOverlayRectangle *rect; + guint is_associated:1; +}; + +static inline void +gst_video_overlay_rectangle_replace (GstVideoOverlayRectangle ** old_rect_ptr, + GstVideoOverlayRectangle * new_rect) +{ + gst_mini_object_replace ((GstMiniObject **) old_rect_ptr, + GST_MINI_OBJECT_CAST (new_rect)); +} + +#define overlay_rectangle_ref(overlay) \ + gst_vaapi_mini_object_ref(GST_VAAPI_MINI_OBJECT(overlay)) + +#define overlay_rectangle_unref(overlay) \ + gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(overlay)) + +#define overlay_rectangle_replace(old_overlay_ptr, new_overlay) \ + gst_vaapi_mini_object_replace((GstVaapiMiniObject **)(old_overlay_ptr), \ + (GstVaapiMiniObject *)(new_overlay)) + +static void overlay_rectangle_finalize (GstVaapiOverlayRectangle * overlay); + +static gboolean +overlay_rectangle_associate (GstVaapiOverlayRectangle * overlay); + +static gboolean +overlay_rectangle_deassociate (GstVaapiOverlayRectangle * overlay); + +static inline const GstVaapiMiniObjectClass * +overlay_rectangle_class (void) +{ + static const GstVaapiMiniObjectClass GstVaapiOverlayRectangleClass = { + sizeof (GstVaapiOverlayRectangle), + (GDestroyNotify) overlay_rectangle_finalize + }; + return &GstVaapiOverlayRectangleClass; +} + +static GstVaapiOverlayRectangle * +overlay_rectangle_new (GstVideoOverlayRectangle * rect, + GstVaapiContext * context, guint layer_id) +{ + GstVaapiOverlayRectangle *overlay; + GstVaapiRectangle *render_rect; + guint width, height, flags; + gint x, y; + + overlay = (GstVaapiOverlayRectangle *) + gst_vaapi_mini_object_new0 (overlay_rectangle_class ()); + if (!overlay) + return NULL; + + overlay->context = context; + overlay->seq_num = gst_video_overlay_rectangle_get_seqnum (rect); + overlay->layer_id = layer_id; + overlay->rect = gst_video_overlay_rectangle_ref (rect); + + flags = gst_video_overlay_rectangle_get_flags (rect); + gst_buffer_replace (&overlay->rect_buffer, + gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect, flags)); + if (!overlay->rect_buffer) + goto error; + + overlay->subpicture = + gst_vaapi_subpicture_new_from_overlay_rectangle (GST_VAAPI_OBJECT_DISPLAY + (context), rect); + if (!overlay->subpicture) + goto error; + + gst_video_overlay_rectangle_get_render_rectangle (rect, + &x, &y, &width, &height); + render_rect = &overlay->render_rect; + render_rect->x = x; + render_rect->y = y; + render_rect->width = width; + render_rect->height = height; + return overlay; + +error: + overlay_rectangle_unref (overlay); + return NULL; +} + +static void +overlay_rectangle_finalize (GstVaapiOverlayRectangle * overlay) +{ + gst_buffer_replace (&overlay->rect_buffer, NULL); + gst_video_overlay_rectangle_unref (overlay->rect); + + if (overlay->subpicture) { + overlay_rectangle_deassociate (overlay); + gst_vaapi_object_unref (overlay->subpicture); + overlay->subpicture = NULL; + } +} + +static gboolean +overlay_rectangle_associate (GstVaapiOverlayRectangle * overlay) +{ + GstVaapiSubpicture *const subpicture = overlay->subpicture; + GPtrArray *const surfaces = overlay->context->surfaces; + guint i, n_associated; + + if (overlay->is_associated) + return TRUE; + + n_associated = 0; + for (i = 0; i < surfaces->len; i++) { + GstVaapiSurface *const surface = g_ptr_array_index (surfaces, i); + if (gst_vaapi_surface_associate_subpicture (surface, subpicture, + NULL, &overlay->render_rect)) + n_associated++; + } + + overlay->is_associated = TRUE; + return n_associated == surfaces->len; +} + +static gboolean +overlay_rectangle_deassociate (GstVaapiOverlayRectangle * overlay) +{ + GstVaapiSubpicture *const subpicture = overlay->subpicture; + GPtrArray *const surfaces = overlay->context->surfaces; + guint i, n_associated; + + if (!overlay->is_associated) + return TRUE; + + n_associated = surfaces->len; + for (i = 0; i < surfaces->len; i++) { + GstVaapiSurface *const surface = g_ptr_array_index (surfaces, i); + if (gst_vaapi_surface_deassociate_subpicture (surface, subpicture)) + n_associated--; + } + + overlay->is_associated = FALSE; + return n_associated == 0; +} + +static gboolean +overlay_rectangle_changed_pixels (GstVaapiOverlayRectangle * overlay, + GstVideoOverlayRectangle * rect) +{ + guint flags; + GstBuffer *buffer; + + if (overlay->seq_num == gst_video_overlay_rectangle_get_seqnum (rect)) + return FALSE; + + flags = + to_GstVideoOverlayFormatFlags (gst_vaapi_subpicture_get_flags + (overlay->subpicture)); + + buffer = gst_video_overlay_rectangle_get_pixels_unscaled_raw (rect, flags); + if (!buffer) + return FALSE; +#if GST_CHECK_VERSION(1,0,0) + { + const guint n_blocks = gst_buffer_n_memory (buffer); + gsize ofs; + guint i; + + if (buffer == overlay->rect_buffer) + return TRUE; + + if (n_blocks != gst_buffer_n_memory (overlay->rect_buffer)) + return FALSE; + + for (i = 0; i < n_blocks; i++) { + GstMemory *const mem1 = gst_buffer_peek_memory (buffer, i); + GstMemory *const mem2 = gst_buffer_peek_memory (overlay->rect_buffer, i); + if (!gst_memory_is_span (mem1, mem2, &ofs)) + return FALSE; + } + } +#else + if (GST_BUFFER_DATA (overlay->rect_buffer) != GST_BUFFER_DATA (buffer)) + return FALSE; +#endif + return TRUE; +} + +static gboolean +overlay_rectangle_changed_render_rect (GstVaapiOverlayRectangle * overlay, + GstVideoOverlayRectangle * rect) +{ + GstVaapiRectangle *const render_rect = &overlay->render_rect; + guint width, height; + gint x, y; + + gst_video_overlay_rectangle_get_render_rectangle (rect, + &x, &y, &width, &height); + + if (x == render_rect->x && + y == render_rect->y && + width == render_rect->width && height == render_rect->height) + return FALSE; + + render_rect->x = x; + render_rect->y = y; + render_rect->width = width; + render_rect->height = height; + return TRUE; +} + +static inline gboolean +overlay_rectangle_update_global_alpha (GstVaapiOverlayRectangle * overlay, + GstVideoOverlayRectangle * rect) +{ +#ifdef HAVE_GST_VIDEO_OVERLAY_HWCAPS + const guint flags = gst_video_overlay_rectangle_get_flags (rect); + if (!(flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA)) + return TRUE; +#endif + return gst_vaapi_subpicture_set_global_alpha (overlay->subpicture, + gst_video_overlay_rectangle_get_global_alpha (rect)); +} + +static gboolean +overlay_rectangle_update (GstVaapiOverlayRectangle * overlay, + GstVideoOverlayRectangle * rect, gboolean * reassociate_ptr) +{ + if (overlay_rectangle_changed_pixels (overlay, rect)) + return FALSE; + if (overlay_rectangle_changed_render_rect (overlay, rect)) + *reassociate_ptr = TRUE; + if (!overlay_rectangle_update_global_alpha (overlay, rect)) + return FALSE; + gst_video_overlay_rectangle_replace (&overlay->rect, rect); + return TRUE; +} + +static inline GPtrArray * +overlay_new (void) +{ + return g_ptr_array_new_with_free_func ( + (GDestroyNotify) gst_vaapi_mini_object_unref); +} + +static void +overlay_destroy (GPtrArray ** overlay_ptr) +{ + GPtrArray *const overlay = *overlay_ptr; + + if (!overlay) + return; + g_ptr_array_unref (overlay); + *overlay_ptr = NULL; +} + +static void +overlay_clear (GPtrArray * overlay) +{ + if (overlay && overlay->len > 0) + g_ptr_array_remove_range (overlay, 0, overlay->len); +} + +static GstVaapiOverlayRectangle * +overlay_lookup (GPtrArray * overlays, GstVideoOverlayRectangle * rect) +{ + guint i; + + for (i = 0; i < overlays->len; i++) { + GstVaapiOverlayRectangle *const overlay = g_ptr_array_index (overlays, i); + + if (overlay->rect == rect) + return overlay; + } + return NULL; +} + +static gboolean +overlay_reassociate (GPtrArray * overlays) +{ + guint i; + + for (i = 0; i < overlays->len; i++) + overlay_rectangle_deassociate (g_ptr_array_index (overlays, i)); + + for (i = 0; i < overlays->len; i++) { + if (!overlay_rectangle_associate (g_ptr_array_index (overlays, i))) + return FALSE; + } + return TRUE; +} + +static gboolean +overlay_ensure (GPtrArray ** overlay_ptr) +{ + GPtrArray *overlay = *overlay_ptr; + + if (!overlay) { + overlay = overlay_new (); + if (!overlay) + return FALSE; + *overlay_ptr = overlay; + } + return TRUE; +} + +/** Initializes overlay resources */ +gboolean +gst_vaapi_context_overlay_init (GstVaapiContext * context) +{ + if (!overlay_ensure (&context->overlays[0])) + return FALSE; + if (!overlay_ensure (&context->overlays[1])) + return FALSE; + return TRUE; +} + +/** Destroys overlay resources */ +void +gst_vaapi_context_overlay_finalize (GstVaapiContext * context) +{ + overlay_destroy (&context->overlays[0]); + overlay_destroy (&context->overlays[1]); +} + +/** Resets overlay resources to a clean state */ +gboolean +gst_vaapi_context_overlay_reset (GstVaapiContext * context) +{ + guint num_errors = 0; + + if (overlay_ensure (&context->overlays[0])) + overlay_clear (context->overlays[0]); + else + num_errors++; + + if (overlay_ensure (&context->overlays[1])) + overlay_clear (context->overlays[1]); + else + num_errors++; + + context->overlay_id = 0; + return num_errors == 0; +} + +/** + * gst_vaapi_context_apply_composition: + * @context: a #GstVaapiContext + * @composition: a #GstVideoOverlayComposition + * + * Applies video composition planes to all surfaces bound to @context. + * This helper function resets any additional subpictures the user may + * have associated himself. A %NULL @composition will also clear all + * the existing subpictures. + * + * Return value: %TRUE if all composition planes could be applied, + * %FALSE otherwise + */ +gboolean +gst_vaapi_context_apply_composition (GstVaapiContext * context, + GstVideoOverlayComposition * composition) +{ + GPtrArray *curr_overlay, *next_overlay; + guint i, n_rectangles; + gboolean reassociate = FALSE; + + g_return_val_if_fail (context != NULL, FALSE); + + if (!context->surfaces) + return FALSE; + + if (!composition) { + gst_vaapi_context_overlay_reset (context); + return TRUE; + } + + curr_overlay = context->overlays[context->overlay_id]; + next_overlay = context->overlays[context->overlay_id ^ 1]; + overlay_clear (next_overlay); + + n_rectangles = gst_video_overlay_composition_n_rectangles (composition); + for (i = 0; i < n_rectangles; i++) { + GstVideoOverlayRectangle *const rect = + gst_video_overlay_composition_get_rectangle (composition, i); + GstVaapiOverlayRectangle *overlay; + + overlay = overlay_lookup (curr_overlay, rect); + if (overlay && overlay_rectangle_update (overlay, rect, &reassociate)) { + overlay_rectangle_ref (overlay); + if (overlay->layer_id != i) + reassociate = TRUE; + } else { + overlay = overlay_rectangle_new (rect, context, i); + if (!overlay) { + GST_WARNING ("could not create VA overlay rectangle"); + goto error; + } + reassociate = TRUE; + } + g_ptr_array_add (next_overlay, overlay); + } + + overlay_clear (curr_overlay); + context->overlay_id ^= 1; + + if (reassociate && !overlay_reassociate (next_overlay)) + return FALSE; + return TRUE; + +error: + gst_vaapi_context_overlay_reset (context); + return FALSE; +} diff --git a/gst-libs/gst/vaapi/gstvaapicontext_overlay.h b/gst-libs/gst/vaapi/gstvaapicontext_overlay.h new file mode 100644 index 0000000000..85440e9d4c --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapicontext_overlay.h @@ -0,0 +1,52 @@ +/* + * gstvaapicontext_overlay.h - VA context abstraction (overlay composition) + * + * Copyright (C) 2010-2011 Splitted-Desktop Systems + * Author: Gwenole Beauchesne + * Copyright (C) 2011-2014 Intel Corporation + * Author: Gwenole Beauchesne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef GST_VAAPI_CONTEXT_OVERLAY_H +#define GST_VAAPI_CONTEXT_OVERLAY_H + +#include +#include "gstvaapicontext.h" + +G_BEGIN_DECLS + +G_GNUC_INTERNAL +gboolean +gst_vaapi_context_overlay_init (GstVaapiContext * context); + +G_GNUC_INTERNAL +void +gst_vaapi_context_overlay_finalize (GstVaapiContext * context); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_context_overlay_reset (GstVaapiContext * context); + +G_GNUC_INTERNAL +gboolean +gst_vaapi_context_apply_composition (GstVaapiContext * context, + GstVideoOverlayComposition * composition); + +G_END_DECLS + +#endif /* GST_VAAPI_CONTEXT_OVERLAY_H */ diff --git a/gst-libs/gst/vaapi/gstvaapisurface.c b/gst-libs/gst/vaapi/gstvaapisurface.c index 40745ba429..ba848cb774 100644 --- a/gst-libs/gst/vaapi/gstvaapisurface.c +++ b/gst-libs/gst/vaapi/gstvaapisurface.c @@ -35,6 +35,7 @@ #include "gstvaapicontext.h" #include "gstvaapiimage.h" #include "gstvaapiimage_priv.h" +#include "gstvaapicontext_overlay.h" #define DEBUG 1 #include "gstvaapidebug.h"