diff --git a/gst-libs/gst/gl/Makefile.am b/gst-libs/gst/gl/Makefile.am index 942638f506..b6aab1de36 100644 --- a/gst-libs/gst/gl/Makefile.am +++ b/gst-libs/gst/gl/Makefile.am @@ -29,7 +29,8 @@ libgstgl_@GST_API_VERSION@_la_SOURCES = \ gstglframebuffer.c \ gstglsyncmeta.c \ gstglviewconvert.c \ - gstglcompositionoverlay.c + gstglcompositionoverlay.c \ + gstgloverlaycompositor.c libgstgl_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/gl libgstgl_@GST_API_VERSION@include_HEADERS = \ @@ -54,6 +55,7 @@ libgstgl_@GST_API_VERSION@include_HEADERS = \ gstglsyncmeta.h \ gstglviewconvert.h \ gstglcompositionoverlay.h \ + gstgloverlaycompositor.c \ gstgl_fwd.h \ gl.h diff --git a/gst-libs/gst/gl/gl.h b/gst-libs/gst/gl/gl.h index d6dcb51010..4b1e8ef43f 100644 --- a/gst-libs/gst/gl/gl.h +++ b/gst-libs/gst/gl/gl.h @@ -48,5 +48,6 @@ #include #include #include +#include #endif /* __GST_GL_H__ */ diff --git a/gst-libs/gst/gl/gstgl_fwd.h b/gst-libs/gst/gl/gstgl_fwd.h index 7c2bd34c5f..aac40b75e6 100644 --- a/gst-libs/gst/gl/gstgl_fwd.h +++ b/gst-libs/gst/gl/gstgl_fwd.h @@ -81,6 +81,9 @@ typedef struct _GstGLViewConvertPrivate GstGLViewConvertPrivate; typedef struct _GstGLCompositionOverlay GstGLCompositionOverlay; typedef struct _GstGLCompositionOverlayClass GstGLCompositionOverlayClass; +typedef struct _GstGLOverlayCompositor GstGLOverlayCompositor; +typedef struct _GstGLOverlayCompositorClass GstGLOverlayCompositorClass; + G_END_DECLS #endif /* __GST_GL_FWD_H__ */ diff --git a/gst-libs/gst/gl/gstgloverlaycompositor.c b/gst-libs/gst/gl/gstgloverlaycompositor.c new file mode 100644 index 0000000000..4fd9be9aa4 --- /dev/null +++ b/gst-libs/gst/gl/gstgloverlaycompositor.c @@ -0,0 +1,216 @@ +/* + * GStreamer + * Copyright (C) 2015 Lubosz Sarnecki + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "gl.h" +#include "gstgloverlaycompositor.h" + +GST_DEBUG_CATEGORY_STATIC (gst_gl_overlay_compositor_debug); +#define GST_CAT_DEFAULT gst_gl_overlay_compositor_debug + +#define DEBUG_INIT \ + GST_DEBUG_CATEGORY_INIT (gst_gl_overlay_compositor_debug, \ + "gloverlaycompositor", 0, "overlaycompositor"); + +G_DEFINE_TYPE_WITH_CODE (GstGLOverlayCompositor, gst_gl_overlay_compositor, + GST_TYPE_OBJECT, DEBUG_INIT); + +static void gst_gl_overlay_compositor_finalize (GObject * object); +static gboolean _is_rectangle_in_overlays (GList * overlays, + GstVideoOverlayRectangle * rectangle); +static gboolean _is_overlay_in_rectangles (GstVideoOverlayComposition * + composition, GstGLCompositionOverlay * overlay); + +static void +gst_gl_overlay_compositor_class_init (GstGLOverlayCompositorClass * klass) +{ + G_OBJECT_CLASS (klass)->finalize = gst_gl_overlay_compositor_finalize; +} + +static void +gst_gl_overlay_compositor_init (GstGLOverlayCompositor * compositor) +{ +} + +GstGLOverlayCompositor * +gst_gl_overlay_compositor_new (GstGLContext * context) +{ + GstGLOverlayCompositor *compositor = + g_object_new (GST_TYPE_GL_OVERLAY_COMPOSITOR, NULL); + + compositor->context = gst_object_ref (context); + + GST_DEBUG_OBJECT (compositor, "Created new GstGLOverlayCompositor"); + + return compositor; +} + +static void +gst_gl_overlay_compositor_finalize (GObject * object) +{ + GstGLOverlayCompositor *compositor; + + compositor = GST_GL_OVERLAY_COMPOSITOR (object); + + gst_gl_overlay_compositor_free_overlays (compositor); + + if (compositor->context) + gst_object_unref (compositor->context); + + G_OBJECT_CLASS (gst_gl_overlay_compositor_parent_class)->finalize (object); +} + +static gboolean +_is_rectangle_in_overlays (GList * overlays, + GstVideoOverlayRectangle * rectangle) +{ + for (GList * l = overlays; l != NULL; l = l->next) { + GstGLCompositionOverlay *overlay = (GstGLCompositionOverlay *) l->data; + if (overlay->rectangle == rectangle) + return TRUE; + } + return FALSE; +} + +static gboolean +_is_overlay_in_rectangles (GstVideoOverlayComposition * composition, + GstGLCompositionOverlay * overlay) +{ + for (guint i = 0; + i < gst_video_overlay_composition_n_rectangles (composition); i++) { + GstVideoOverlayRectangle *rectangle = + gst_video_overlay_composition_get_rectangle (composition, i); + if (overlay->rectangle == rectangle) + return TRUE; + } + return FALSE; +} + + +void +gst_gl_overlay_compositor_free_overlays (GstGLOverlayCompositor * compositor) +{ + GList *l = compositor->overlays; + while (l != NULL) { + GList *next = l->next; + GstGLCompositionOverlay *overlay = (GstGLCompositionOverlay *) l->data; + compositor->overlays = g_list_delete_link (compositor->overlays, l); + gst_object_unref (overlay); + l = next; + } + g_list_free (compositor->overlays); + compositor->overlays = NULL; +} + +void +gst_gl_overlay_compositor_upload_overlays (GstGLOverlayCompositor * compositor, + GstBuffer * buf, GLint position_attrib, GLint texcoord_attrib, + guint window_width, guint window_height) +{ + GstVideoOverlayCompositionMeta *composition_meta; + + if (compositor->last_window_width != window_width || + compositor->last_window_height != window_height) { + gst_gl_overlay_compositor_free_overlays (compositor); + compositor->last_window_width = window_width; + compositor->last_window_height = window_height; + GST_DEBUG ("window size changed, freeing overlays"); + } + + composition_meta = gst_buffer_get_video_overlay_composition_meta (buf); + if (composition_meta) { + GstVideoOverlayComposition *composition = NULL; + guint num_overlays; + GList *l = compositor->overlays; + + GST_DEBUG ("GstVideoOverlayCompositionMeta found."); + + composition = composition_meta->overlay; + num_overlays = gst_video_overlay_composition_n_rectangles (composition); + + /* add new overlays to list */ + for (guint i = 0; i < num_overlays; i++) { + GstVideoOverlayRectangle *rectangle = + gst_video_overlay_composition_get_rectangle (composition, i); + + if (!_is_rectangle_in_overlays (compositor->overlays, rectangle)) { + GstGLCompositionOverlay *overlay = + gst_gl_composition_overlay_new (compositor->context, rectangle, + position_attrib, texcoord_attrib); + + gst_gl_composition_overlay_upload (overlay, buf, + window_width, window_height); + compositor->overlays = g_list_append (compositor->overlays, overlay); + } + } + + /* remove old overlays from list */ + while (l != NULL) { + GList *next = l->next; + GstGLCompositionOverlay *overlay = (GstGLCompositionOverlay *) l->data; + if (!_is_overlay_in_rectangles (composition, overlay)) { + compositor->overlays = g_list_delete_link (compositor->overlays, l); + gst_object_unref (overlay); + } + l = next; + } + } else { + gst_gl_overlay_compositor_free_overlays (compositor); + } +} + +void +gst_gl_overlay_compositor_draw_overlays (GstGLOverlayCompositor * compositor, + GstGLShader * shader) +{ + const GstGLFuncs *gl = compositor->context->gl_vtable; + if (compositor->overlays != NULL) { + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + for (GList * l = compositor->overlays; l != NULL; l = l->next) { + GstGLCompositionOverlay *overlay = (GstGLCompositionOverlay *) l->data; + gst_gl_composition_overlay_draw (overlay, shader); + } + gl->BindTexture (GL_TEXTURE_2D, 0); + } +} + +GstCaps * +gst_gl_overlay_compositor_add_caps (GstCaps * caps) +{ + GstCaps *composition_caps; + + composition_caps = gst_caps_copy (caps); + + for (int i = 0; i < gst_caps_get_size (composition_caps); i++) { + GstCapsFeatures *f = gst_caps_get_features (composition_caps, i); + gst_caps_features_add (f, + GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION); + } + + caps = gst_caps_merge (composition_caps, caps); + + return caps; +} diff --git a/gst-libs/gst/gl/gstgloverlaycompositor.h b/gst-libs/gst/gl/gstgloverlaycompositor.h new file mode 100644 index 0000000000..c0675b42af --- /dev/null +++ b/gst-libs/gst/gl/gstgloverlaycompositor.h @@ -0,0 +1,77 @@ +/* + * GStreamer + * Copyright (C) 2015 Lubosz Sarnecki + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_GL_OVERLAY_COMPOSITOR_H__ +#define __GST_GL_OVERLAY_COMPOSITOR_H__ + +#include +#include +#include + +#define GST_TYPE_GL_OVERLAY_COMPOSITOR (gst_gl_overlay_compositor_get_type()) +#define GST_GL_OVERLAY_COMPOSITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_OVERLAY_COMPOSITOR,GstGLOverlayCompositor)) +#define GST_GL_OVERLAY_COMPOSITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_OVERLAY_COMPOSITOR,GstGLOverlayCompositorClass)) +#define GST_IS_GL_OVERLAY_COMPOSITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_OVERLAY_COMPOSITOR)) +#define GST_IS_GL_OVERLAY_COMPOSITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_OVERLAY_COMPOSITOR)) +#define GST_GL_OVERLAY_COMPOSITOR_CAST(obj) ((GstGLOverlayCompositor*)(obj)) + +G_BEGIN_DECLS + +GType gst_gl_overlay_compositor_get_type (void); + +/** + * GstGLOverlayCompositor + * + * Opaque #GstGLOverlayCompositor object + */ +struct _GstGLOverlayCompositor +{ + GstObject parent; + GstGLContext *context; + guint last_window_width; + guint last_window_height; + + GList * overlays; +}; + +/** + * GstGLOverlayCompositorClass: + * + */ +struct _GstGLOverlayCompositorClass +{ + GstObjectClass object_class; +}; + +GstGLOverlayCompositor *gst_gl_overlay_compositor_new (GstGLContext * context); + +void gst_gl_overlay_compositor_free_overlays (GstGLOverlayCompositor * compositor); + +void gst_gl_overlay_compositor_upload_overlays (GstGLOverlayCompositor * compositor, + GstBuffer * buf, GLint position_attrib, GLint texcoord_attrib, + guint window_width, guint window_height); + +void gst_gl_overlay_compositor_draw_overlays (GstGLOverlayCompositor * compositor, + GstGLShader *shader); + +GstCaps * gst_gl_overlay_compositor_add_caps(GstCaps * caps); + +G_END_DECLS +#endif /* __GST_GL_OVERLAY_COMPOSITOR_H__ */