Sink: merge gstsink into single class

Clapper only uses single video sink. No need for subclassing it.
This commit is contained in:
Rafał Dzięgiel
2021-03-05 21:06:03 +01:00
parent 93549a67af
commit 95c3845398
6 changed files with 246 additions and 420 deletions

View File

@@ -30,7 +30,7 @@
#endif #endif
#include "gstclapper-gtk4-plugin.h" #include "gstclapper-gtk4-plugin.h"
#include "gtk4/gstgtkglsink.h" #include "gtk4/gstgtkbasesink.h"
enum enum
{ {
@@ -78,7 +78,7 @@ gst_clapper_gtk4_plugin_constructed (GObject * object)
GstClapperGtk4Plugin *self = GST_CLAPPER_GTK4_PLUGIN (object); GstClapperGtk4Plugin *self = GST_CLAPPER_GTK4_PLUGIN (object);
if (!self->video_sink) if (!self->video_sink)
self->video_sink = g_object_new (GST_TYPE_GTK_GL_SINK, NULL); self->video_sink = g_object_new (GST_TYPE_GTK_BASE_SINK, NULL);
gst_object_ref_sink (self->video_sink); gst_object_ref_sink (self->video_sink);

View File

@@ -29,8 +29,12 @@
#include "config.h" #include "config.h"
#endif #endif
#include <gst/gl/gstglfuncs.h>
#include "gtkconfig.h"
#include "gstgtkbasesink.h" #include "gstgtkbasesink.h"
#include "gstgtkutils.h" #include "gstgtkutils.h"
#include "gtkgstglwidget.h"
GST_DEBUG_CATEGORY (gst_debug_gtk_base_sink); GST_DEBUG_CATEGORY (gst_debug_gtk_base_sink);
#define GST_CAT_DEFAULT gst_debug_gtk_base_sink #define GST_CAT_DEFAULT gst_debug_gtk_base_sink
@@ -40,12 +44,25 @@ GST_DEBUG_CATEGORY (gst_debug_gtk_base_sink);
#define DEFAULT_PAR_D 1 #define DEFAULT_PAR_D 1
#define DEFAULT_IGNORE_TEXTURES FALSE #define DEFAULT_IGNORE_TEXTURES FALSE
static GstStaticPadTemplate gst_gtk_base_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_MEMORY_GL_MEMORY, "RGBA") "; "
GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_MEMORY_GL_MEMORY ", "
GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION, "RGBA")));
static void gst_gtk_base_sink_finalize (GObject * object); static void gst_gtk_base_sink_finalize (GObject * object);
static void gst_gtk_base_sink_set_property (GObject * object, guint prop_id, static void gst_gtk_base_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * param_spec); const GValue * value, GParamSpec * param_spec);
static void gst_gtk_base_sink_get_property (GObject * object, guint prop_id, static void gst_gtk_base_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * param_spec); GValue * value, GParamSpec * param_spec);
static gboolean gst_gtk_base_sink_propose_allocation (GstBaseSink * bsink,
GstQuery * query);
static gboolean gst_gtk_base_sink_query (GstBaseSink * bsink, GstQuery * query);
static gboolean gst_gtk_base_sink_start (GstBaseSink * bsink); static gboolean gst_gtk_base_sink_start (GstBaseSink * bsink);
static gboolean gst_gtk_base_sink_stop (GstBaseSink * bsink); static gboolean gst_gtk_base_sink_stop (GstBaseSink * bsink);
@@ -55,6 +72,8 @@ gst_gtk_base_sink_change_state (GstElement * element,
static void gst_gtk_base_sink_get_times (GstBaseSink * bsink, GstBuffer * buf, static void gst_gtk_base_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
GstClockTime * start, GstClockTime * end); GstClockTime * start, GstClockTime * end);
static GstCaps *gst_gtk_base_sink_get_caps (GstBaseSink * bsink,
GstCaps * filter);
static gboolean gst_gtk_base_sink_set_caps (GstBaseSink * bsink, static gboolean gst_gtk_base_sink_set_caps (GstBaseSink * bsink,
GstCaps * caps); GstCaps * caps);
static GstFlowReturn gst_gtk_base_sink_show_frame (GstVideoSink * bsink, static GstFlowReturn gst_gtk_base_sink_show_frame (GstVideoSink * bsink,
@@ -73,14 +92,13 @@ enum
}; };
#define gst_gtk_base_sink_parent_class parent_class #define gst_gtk_base_sink_parent_class parent_class
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstGtkBaseSink, gst_gtk_base_sink, G_DEFINE_TYPE_WITH_CODE (GstGtkBaseSink, gst_gtk_base_sink,
GST_TYPE_VIDEO_SINK, GST_TYPE_VIDEO_SINK,
G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION, G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION,
gst_gtk_base_sink_navigation_interface_init); gst_gtk_base_sink_navigation_interface_init);
GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_base_sink, GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_base_sink,
"gtkbasesink", 0, "GTK Video Sink base class")); "gtkbasesink", 0, "GTK Video Sink base class"));
static void static void
gst_gtk_base_sink_class_init (GstGtkBaseSinkClass * klass) gst_gtk_base_sink_class_init (GstGtkBaseSinkClass * klass)
{ {
@@ -88,11 +106,13 @@ gst_gtk_base_sink_class_init (GstGtkBaseSinkClass * klass)
GstElementClass *gstelement_class; GstElementClass *gstelement_class;
GstBaseSinkClass *gstbasesink_class; GstBaseSinkClass *gstbasesink_class;
GstVideoSinkClass *gstvideosink_class; GstVideoSinkClass *gstvideosink_class;
GstGtkBaseSinkClass *gstgtkbasesink_class;
gobject_class = (GObjectClass *) klass; gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass; gstelement_class = (GstElementClass *) klass;
gstbasesink_class = (GstBaseSinkClass *) klass; gstbasesink_class = (GstBaseSinkClass *) klass;
gstvideosink_class = (GstVideoSinkClass *) klass; gstvideosink_class = (GstVideoSinkClass *) klass;
gstgtkbasesink_class = (GstGtkBaseSinkClass *) klass;
gobject_class->set_property = gst_gtk_base_sink_set_property; gobject_class->set_property = gst_gtk_base_sink_set_property;
gobject_class->get_property = gst_gtk_base_sink_get_property; gobject_class->get_property = gst_gtk_base_sink_get_property;
@@ -123,13 +143,29 @@ gst_gtk_base_sink_class_init (GstGtkBaseSinkClass * klass)
gobject_class->finalize = gst_gtk_base_sink_finalize; gobject_class->finalize = gst_gtk_base_sink_finalize;
gstelement_class->change_state = gst_gtk_base_sink_change_state; gstelement_class->change_state = gst_gtk_base_sink_change_state;
gstbasesink_class->get_caps = gst_gtk_base_sink_get_caps;
gstbasesink_class->set_caps = gst_gtk_base_sink_set_caps; gstbasesink_class->set_caps = gst_gtk_base_sink_set_caps;
gstbasesink_class->get_times = gst_gtk_base_sink_get_times; gstbasesink_class->get_times = gst_gtk_base_sink_get_times;
gstbasesink_class->propose_allocation = gst_gtk_base_sink_propose_allocation;
gstbasesink_class->query = gst_gtk_base_sink_query;
gstbasesink_class->start = gst_gtk_base_sink_start; gstbasesink_class->start = gst_gtk_base_sink_start;
gstbasesink_class->stop = gst_gtk_base_sink_stop; gstbasesink_class->stop = gst_gtk_base_sink_stop;
gstvideosink_class->show_frame = gst_gtk_base_sink_show_frame; gstvideosink_class->show_frame = gst_gtk_base_sink_show_frame;
gstgtkbasesink_class->create_widget = gtk_gst_gl_widget_new;
gstgtkbasesink_class->window_title = GTKCONFIG_NAME " GL Renderer";
gst_element_class_set_metadata (gstelement_class,
GTKCONFIG_NAME " GL Video Sink",
"Sink/Video", "A video sink that renders to a GtkWidget using OpenGL",
"Matthew Waters <matthew@centricular.com>, "
"Rafał Dzięgiel <rafostar.github@gmail.com>");
gst_element_class_add_static_pad_template (gstelement_class,
&gst_gtk_base_sink_template);
gst_type_mark_as_plugin_api (GST_TYPE_GTK_BASE_SINK, 0); gst_type_mark_as_plugin_api (GST_TYPE_GTK_BASE_SINK, 0);
} }
@@ -145,18 +181,18 @@ gst_gtk_base_sink_init (GstGtkBaseSink * gtk_sink)
static void static void
gst_gtk_base_sink_finalize (GObject * object) gst_gtk_base_sink_finalize (GObject * object)
{ {
GstGtkBaseSink *gtk_sink = GST_GTK_BASE_SINK (object); GstGtkBaseSink *base_sink = GST_GTK_BASE_SINK (object);
GST_DEBUG ("finalizing base sink"); GST_DEBUG ("finalizing base sink");
GST_OBJECT_LOCK (gtk_sink); GST_OBJECT_LOCK (base_sink);
if (gtk_sink->window && gtk_sink->window_destroy_id) if (base_sink->window && base_sink->window_destroy_id)
g_signal_handler_disconnect (gtk_sink->window, gtk_sink->window_destroy_id); g_signal_handler_disconnect (base_sink->window, base_sink->window_destroy_id);
if (gtk_sink->widget && gtk_sink->widget_destroy_id) if (base_sink->widget && base_sink->widget_destroy_id)
g_signal_handler_disconnect (gtk_sink->widget, gtk_sink->widget_destroy_id); g_signal_handler_disconnect (base_sink->widget, base_sink->widget_destroy_id);
g_clear_object (&gtk_sink->widget); g_clear_object (&base_sink->widget);
GST_OBJECT_UNLOCK (gtk_sink); GST_OBJECT_UNLOCK (base_sink);
G_OBJECT_CLASS (parent_class)->finalize (object); G_OBJECT_CLASS (parent_class)->finalize (object);
} }
@@ -319,6 +355,118 @@ gst_gtk_base_sink_navigation_interface_init (GstNavigationInterface * iface)
iface->send_event = gst_gtk_base_sink_navigation_send_event; iface->send_event = gst_gtk_base_sink_navigation_send_event;
} }
static gboolean
gst_gtk_base_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
{
GstGtkBaseSink *base_sink = GST_GTK_BASE_SINK (bsink);
GstBufferPool *pool = NULL;
GstStructure *config;
GstCaps *caps;
GstVideoInfo info;
guint size;
gboolean need_pool;
GstStructure *allocation_meta = NULL;
gint display_width, display_height;
if (!base_sink->display || !base_sink->context)
return FALSE;
gst_query_parse_allocation (query, &caps, &need_pool);
if (caps == NULL)
goto no_caps;
if (!gst_video_info_from_caps (&info, caps))
goto invalid_caps;
/* the normal size of a frame */
size = info.size;
if (need_pool) {
GST_DEBUG_OBJECT (base_sink, "create new pool");
pool = gst_gl_buffer_pool_new (base_sink->context);
config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
gst_buffer_pool_config_add_option (config,
GST_BUFFER_POOL_OPTION_GL_SYNC_META);
if (!gst_buffer_pool_set_config (pool, config))
goto config_failed;
}
/* we need at least 2 buffer because we hold on to the last one */
gst_query_add_allocation_pool (query, pool, size, 2, 0);
if (pool)
gst_object_unref (pool);
GST_OBJECT_LOCK (base_sink);
display_width = base_sink->display_width;
display_height = base_sink->display_height;
GST_OBJECT_UNLOCK (base_sink);
if (display_width != 0 && display_height != 0) {
GST_DEBUG_OBJECT (base_sink, "sending alloc query with size %dx%d",
display_width, display_height);
allocation_meta = gst_structure_new ("GstVideoOverlayCompositionMeta",
"width", G_TYPE_UINT, display_width,
"height", G_TYPE_UINT, display_height, NULL);
}
gst_query_add_allocation_meta (query,
GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, allocation_meta);
if (allocation_meta)
gst_structure_free (allocation_meta);
/* we also support various metadata */
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0);
if (base_sink->context->gl_vtable->FenceSync)
gst_query_add_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, 0);
return TRUE;
/* ERRORS */
no_caps:
{
GST_DEBUG_OBJECT (bsink, "no caps specified");
return FALSE;
}
invalid_caps:
{
GST_DEBUG_OBJECT (bsink, "invalid caps specified");
return FALSE;
}
config_failed:
{
GST_DEBUG_OBJECT (bsink, "failed setting config");
return FALSE;
}
}
static gboolean
gst_gtk_base_sink_query (GstBaseSink * bsink, GstQuery * query)
{
GstGtkBaseSink *base_sink = GST_GTK_BASE_SINK (bsink);
gboolean res = FALSE;
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CONTEXT:
{
if (gst_gl_handle_context_query ((GstElement *) base_sink, query,
base_sink->display, base_sink->context, base_sink->gtk_context))
return TRUE;
break;
}
default:
res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query);
break;
}
return res;
}
static gboolean static gboolean
gst_gtk_base_sink_start_on_main (GstBaseSink * bsink) gst_gtk_base_sink_start_on_main (GstBaseSink * bsink)
{ {
@@ -330,7 +478,7 @@ gst_gtk_base_sink_start_on_main (GstBaseSink * bsink)
if (gst_gtk_base_sink_get_widget (gst_sink) == NULL) if (gst_gtk_base_sink_get_widget (gst_sink) == NULL)
return FALSE; return FALSE;
/* After this point, gtk_sink->widget will always be set */ /* After this point, base_sink->widget will always be set */
root = gtk_widget_get_root (GTK_WIDGET (gst_sink->widget)); root = gtk_widget_get_root (GTK_WIDGET (gst_sink->widget));
if (!GTK_IS_ROOT (root)) { if (!GTK_IS_ROOT (root)) {
@@ -363,8 +511,39 @@ gst_gtk_base_sink_start_on_main (GstBaseSink * bsink)
static gboolean static gboolean
gst_gtk_base_sink_start (GstBaseSink * bsink) gst_gtk_base_sink_start (GstBaseSink * bsink)
{ {
return ! !gst_gtk_invoke_on_main ((GThreadFunc) (GCallback) GstGtkBaseSink *base_sink = GST_GTK_BASE_SINK (bsink);
gst_gtk_base_sink_start_on_main, bsink); GtkGstGLWidget *gst_widget;
if (!(! !gst_gtk_invoke_on_main ((GThreadFunc) (GCallback)
gst_gtk_base_sink_start_on_main, bsink)))
return FALSE;
/* After this point, base_sink->widget will always be set */
gst_widget = GTK_GST_GL_WIDGET (base_sink->widget);
if (!gtk_gst_gl_widget_init_winsys (gst_widget)) {
GST_ELEMENT_ERROR (bsink, RESOURCE, NOT_FOUND, ("%s",
"Failed to initialize OpenGL with GTK"), (NULL));
return FALSE;
}
if (!base_sink->display)
base_sink->display = gtk_gst_gl_widget_get_display (gst_widget);
if (!base_sink->context)
base_sink->context = gtk_gst_gl_widget_get_context (gst_widget);
if (!base_sink->gtk_context)
base_sink->gtk_context = gtk_gst_gl_widget_get_gtk_context (gst_widget);
if (!base_sink->display || !base_sink->context || !base_sink->gtk_context) {
GST_ELEMENT_ERROR (bsink, RESOURCE, NOT_FOUND, ("%s",
"Failed to retrieve OpenGL context from GTK"), (NULL));
return FALSE;
}
gst_gl_element_propagate_display_context (GST_ELEMENT (bsink),
base_sink->display);
return TRUE;
} }
static gboolean static gboolean
@@ -384,9 +563,21 @@ gst_gtk_base_sink_stop_on_main (GstBaseSink * bsink)
static gboolean static gboolean
gst_gtk_base_sink_stop (GstBaseSink * bsink) gst_gtk_base_sink_stop (GstBaseSink * bsink)
{ {
GstGtkBaseSink *gst_sink = GST_GTK_BASE_SINK (bsink); GstGtkBaseSink *base_sink = GST_GTK_BASE_SINK (bsink);
if (gst_sink->window) if (base_sink->display) {
gst_object_unref (base_sink->display);
base_sink->display = NULL;
}
if (base_sink->context) {
gst_object_unref (base_sink->context);
base_sink->context = NULL;
}
if (base_sink->gtk_context) {
gst_object_unref (base_sink->gtk_context);
base_sink->gtk_context = NULL;
}
if (base_sink->window)
return ! !gst_gtk_invoke_on_main ((GThreadFunc) (GCallback) return ! !gst_gtk_invoke_on_main ((GThreadFunc) (GCallback)
gst_gtk_base_sink_stop_on_main, bsink); gst_gtk_base_sink_stop_on_main, bsink);
@@ -466,7 +657,32 @@ gst_gtk_base_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
} }
} }
gboolean static GstCaps *
gst_gtk_base_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
{
GstCaps *tmp = NULL;
GstCaps *result = NULL;
tmp = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink));
if (filter) {
GST_DEBUG_OBJECT (bsink, "intersecting with filter caps %" GST_PTR_FORMAT,
filter);
result = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (tmp);
} else {
result = tmp;
}
result = gst_gl_overlay_compositor_add_caps (result);
GST_DEBUG_OBJECT (bsink, "returning caps: %" GST_PTR_FORMAT, result);
return result;
}
static gboolean
gst_gtk_base_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) gst_gtk_base_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
{ {
GstGtkBaseSink *gtk_sink = GST_GTK_BASE_SINK (bsink); GstGtkBaseSink *gtk_sink = GST_GTK_BASE_SINK (bsink);

View File

@@ -25,6 +25,7 @@
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/video/gstvideosink.h> #include <gst/video/gstvideosink.h>
#include <gst/video/video.h> #include <gst/video/video.h>
#include <gst/gl/gl.h>
#include "gtkgstbasewidget.h" #include "gtkgstbasewidget.h"
@@ -37,7 +38,6 @@
#define GST_GTK_BASE_SINK_CAST(obj) ((GstGtkBaseSink*)(obj)) #define GST_GTK_BASE_SINK_CAST(obj) ((GstGtkBaseSink*)(obj))
G_BEGIN_DECLS G_BEGIN_DECLS
typedef struct _GstGtkBaseSink GstGtkBaseSink; typedef struct _GstGtkBaseSink GstGtkBaseSink;
typedef struct _GstGtkBaseSinkClass GstGtkBaseSinkClass; typedef struct _GstGtkBaseSinkClass GstGtkBaseSinkClass;
@@ -71,6 +71,17 @@ struct _GstGtkBaseSink
GtkWidget *window; GtkWidget *window;
gulong widget_destroy_id; gulong widget_destroy_id;
gulong window_destroy_id; gulong window_destroy_id;
GstGLDisplay *display;
GstGLContext *context;
GstGLContext *gtk_context;
GstGLUpload *upload;
GstBuffer *uploaded_buffer;
/* read/write with object lock */
gint display_width;
gint display_height;
}; };
/** /**

View File

@@ -1,336 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
* Copyright (C) 2020 Rafał Dzięgiel <rafostar.github@gmail.com>
*
* 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.
*/
/**
* SECTION:element-gtkglsink
* @title: gtkglsink
*/
/**
* SECTION:element-gtk4glsink
* @title: gtk4glsink
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gl/gstglfuncs.h>
#include "gtkconfig.h"
#include "gstgtkglsink.h"
#include "gtkgstglwidget.h"
GST_DEBUG_CATEGORY (gst_debug_gtk_gl_sink);
#define GST_CAT_DEFAULT gst_debug_gtk_gl_sink
static gboolean gst_gtk_gl_sink_start (GstBaseSink * bsink);
static gboolean gst_gtk_gl_sink_stop (GstBaseSink * bsink);
static gboolean gst_gtk_gl_sink_query (GstBaseSink * bsink, GstQuery * query);
static gboolean gst_gtk_gl_sink_propose_allocation (GstBaseSink * bsink,
GstQuery * query);
static GstCaps *gst_gtk_gl_sink_get_caps (GstBaseSink * bsink,
GstCaps * filter);
static void gst_gtk_gl_sink_finalize (GObject * object);
static GstStaticPadTemplate gst_gtk_gl_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_MEMORY_GL_MEMORY, "RGBA") "; "
GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_MEMORY_GL_MEMORY ", "
GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION, "RGBA")));
#define gst_gtk_gl_sink_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstGtkGLSink, gst_gtk_gl_sink,
GST_TYPE_GTK_BASE_SINK, GST_DEBUG_CATEGORY_INIT (gst_debug_gtk_gl_sink,
GTKCONFIG_GLSINK, 0, GTKCONFIG_NAME " GL Video Sink"));
static void
gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstBaseSinkClass *gstbasesink_class;
GstGtkBaseSinkClass *gstgtkbasesink_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gstbasesink_class = (GstBaseSinkClass *) klass;
gstgtkbasesink_class = (GstGtkBaseSinkClass *) klass;
gobject_class->finalize = gst_gtk_gl_sink_finalize;
gstbasesink_class->query = gst_gtk_gl_sink_query;
gstbasesink_class->propose_allocation = gst_gtk_gl_sink_propose_allocation;
gstbasesink_class->start = gst_gtk_gl_sink_start;
gstbasesink_class->stop = gst_gtk_gl_sink_stop;
gstbasesink_class->get_caps = gst_gtk_gl_sink_get_caps;
gstgtkbasesink_class->create_widget = gtk_gst_gl_widget_new;
gstgtkbasesink_class->window_title = GTKCONFIG_NAME " GL Renderer";
gst_element_class_set_metadata (gstelement_class,
GTKCONFIG_NAME " GL Video Sink",
"Sink/Video", "A video sink that renders to a GtkWidget using OpenGL",
"Matthew Waters <matthew@centricular.com>, "
"Rafał Dzięgiel <rafostar.github@gmail.com>");
gst_element_class_add_static_pad_template (gstelement_class,
&gst_gtk_gl_sink_template);
}
static void
gst_gtk_gl_sink_init (GstGtkGLSink * gtk_sink)
{
}
static gboolean
gst_gtk_gl_sink_query (GstBaseSink * bsink, GstQuery * query)
{
GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (bsink);
gboolean res = FALSE;
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CONTEXT:
{
if (gst_gl_handle_context_query ((GstElement *) gtk_sink, query,
gtk_sink->display, gtk_sink->context, gtk_sink->gtk_context))
return TRUE;
break;
}
default:
res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query);
break;
}
return res;
}
static void
destroy_cb (GtkWidget * widget, GstGtkGLSink * gtk_sink)
{
if (gtk_sink->widget_destroy_sig_handler) {
g_signal_handler_disconnect (widget, gtk_sink->widget_destroy_sig_handler);
gtk_sink->widget_destroy_sig_handler = 0;
}
}
static gboolean
gst_gtk_gl_sink_start (GstBaseSink * bsink)
{
GstGtkBaseSink *base_sink = GST_GTK_BASE_SINK (bsink);
GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (bsink);
GtkGstGLWidget *gst_widget;
if (!GST_BASE_SINK_CLASS (parent_class)->start (bsink))
return FALSE;
/* After this point, gtk_sink->widget will always be set */
gst_widget = GTK_GST_GL_WIDGET (base_sink->widget);
if (!gtk_sink->widget_destroy_sig_handler) {
gtk_sink->widget_destroy_sig_handler =
g_signal_connect (gst_widget, "destroy", G_CALLBACK (destroy_cb),
gtk_sink);
}
if (!gtk_gst_gl_widget_init_winsys (gst_widget)) {
GST_ELEMENT_ERROR (bsink, RESOURCE, NOT_FOUND, ("%s",
"Failed to initialize OpenGL with GTK"), (NULL));
return FALSE;
}
if (!gtk_sink->display)
gtk_sink->display = gtk_gst_gl_widget_get_display (gst_widget);
if (!gtk_sink->context)
gtk_sink->context = gtk_gst_gl_widget_get_context (gst_widget);
if (!gtk_sink->gtk_context)
gtk_sink->gtk_context = gtk_gst_gl_widget_get_gtk_context (gst_widget);
if (!gtk_sink->display || !gtk_sink->context || !gtk_sink->gtk_context) {
GST_ELEMENT_ERROR (bsink, RESOURCE, NOT_FOUND, ("%s",
"Failed to retrieve OpenGL context from GTK"), (NULL));
return FALSE;
}
gst_gl_element_propagate_display_context (GST_ELEMENT (bsink),
gtk_sink->display);
return TRUE;
}
static gboolean
gst_gtk_gl_sink_stop (GstBaseSink * bsink)
{
GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (bsink);
GstGtkBaseSink *base_sink = GST_GTK_BASE_SINK (bsink);
if (gtk_sink->display) {
gst_object_unref (gtk_sink->display);
gtk_sink->display = NULL;
}
if (gtk_sink->context) {
gst_object_unref (gtk_sink->context);
gtk_sink->context = NULL;
}
if (gtk_sink->gtk_context) {
gst_object_unref (gtk_sink->gtk_context);
gtk_sink->gtk_context = NULL;
}
return GST_BASE_SINK_CLASS (parent_class)->stop (bsink);
}
static gboolean
gst_gtk_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
{
GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (bsink);
GstBufferPool *pool = NULL;
GstStructure *config;
GstCaps *caps;
GstVideoInfo info;
guint size;
gboolean need_pool;
GstStructure *allocation_meta = NULL;
gint display_width, display_height;
if (!gtk_sink->display || !gtk_sink->context)
return FALSE;
gst_query_parse_allocation (query, &caps, &need_pool);
if (caps == NULL)
goto no_caps;
if (!gst_video_info_from_caps (&info, caps))
goto invalid_caps;
/* the normal size of a frame */
size = info.size;
if (need_pool) {
GST_DEBUG_OBJECT (gtk_sink, "create new pool");
pool = gst_gl_buffer_pool_new (gtk_sink->context);
config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
gst_buffer_pool_config_add_option (config,
GST_BUFFER_POOL_OPTION_GL_SYNC_META);
if (!gst_buffer_pool_set_config (pool, config))
goto config_failed;
}
/* we need at least 2 buffer because we hold on to the last one */
gst_query_add_allocation_pool (query, pool, size, 2, 0);
if (pool)
gst_object_unref (pool);
GST_OBJECT_LOCK (gtk_sink);
display_width = gtk_sink->display_width;
display_height = gtk_sink->display_height;
GST_OBJECT_UNLOCK (gtk_sink);
if (display_width != 0 && display_height != 0) {
GST_DEBUG_OBJECT (gtk_sink, "sending alloc query with size %dx%d",
display_width, display_height);
allocation_meta = gst_structure_new ("GstVideoOverlayCompositionMeta",
"width", G_TYPE_UINT, display_width,
"height", G_TYPE_UINT, display_height, NULL);
}
gst_query_add_allocation_meta (query,
GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, allocation_meta);
if (allocation_meta)
gst_structure_free (allocation_meta);
/* we also support various metadata */
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0);
if (gtk_sink->context->gl_vtable->FenceSync)
gst_query_add_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, 0);
return TRUE;
/* ERRORS */
no_caps:
{
GST_DEBUG_OBJECT (bsink, "no caps specified");
return FALSE;
}
invalid_caps:
{
GST_DEBUG_OBJECT (bsink, "invalid caps specified");
return FALSE;
}
config_failed:
{
GST_DEBUG_OBJECT (bsink, "failed setting config");
return FALSE;
}
}
static GstCaps *
gst_gtk_gl_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
{
GstCaps *tmp = NULL;
GstCaps *result = NULL;
tmp = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink));
if (filter) {
GST_DEBUG_OBJECT (bsink, "intersecting with filter caps %" GST_PTR_FORMAT,
filter);
result = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (tmp);
} else {
result = tmp;
}
result = gst_gl_overlay_compositor_add_caps (result);
GST_DEBUG_OBJECT (bsink, "returning caps: %" GST_PTR_FORMAT, result);
return result;
}
static void
gst_gtk_gl_sink_finalize (GObject * object)
{
GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (object);
GstGtkBaseSink *base_sink = GST_GTK_BASE_SINK (object);
if (gtk_sink->widget_destroy_sig_handler) {
g_signal_handler_disconnect (base_sink->widget,
gtk_sink->widget_destroy_sig_handler);
gtk_sink->widget_destroy_sig_handler = 0;
}
G_OBJECT_CLASS (parent_class)->finalize (object);
}

View File

@@ -1,64 +0,0 @@
/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
*
* 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_GTK_GL_SINK_H__
#define __GST_GTK_GL_SINK_H__
#include <gtk/gtk.h>
#include <gst/gst.h>
#include <gst/video/gstvideosink.h>
#include <gst/video/video.h>
#include <gst/gl/gl.h>
#include "gstgtkbasesink.h"
G_BEGIN_DECLS
#define GST_TYPE_GTK_GL_SINK (gst_gtk_gl_sink_get_type ())
G_DECLARE_FINAL_TYPE (GstGtkGLSink, gst_gtk_gl_sink, GST, GTK_GL_SINK,
GstGtkBaseSink);
/**
* GstGtkGLSink:
*
* Opaque #GstGtkGLSink object
*/
struct _GstGtkGLSink
{
/* <private> */
GstGtkBaseSink parent;
GstGLDisplay *display;
GstGLContext *context;
GstGLContext *gtk_context;
GstGLUpload *upload;
GstBuffer *uploaded_buffer;
/* read/write with object lock */
gint display_width;
gint display_height;
gulong widget_destroy_sig_handler;
};
G_END_DECLS
#endif /* __GST_GTK_GL_SINK_H__ */

View File

@@ -11,7 +11,6 @@ gstclapper_sources = [
'gtk4/gstgtkbasesink.c', 'gtk4/gstgtkbasesink.c',
'gtk4/gstgtkutils.c', 'gtk4/gstgtkutils.c',
'gtk4/gtkgstbasewidget.c', 'gtk4/gtkgstbasewidget.c',
'gtk4/gstgtkglsink.c',
'gtk4/gtkgstglwidget.c', 'gtk4/gtkgstglwidget.c',
] ]
gstclapper_headers = [ gstclapper_headers = [