mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-30 07:42:23 +02:00
Sink: merge gstsink into single class
Clapper only uses single video sink. No need for subclassing it.
This commit is contained in:
@@ -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);
|
||||||
|
|
||||||
|
@@ -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 (>k_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);
|
||||||
|
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -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);
|
|
||||||
}
|
|
@@ -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__ */
|
|
@@ -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 = [
|
||||||
|
Reference in New Issue
Block a user