From 95756a54134a20c5411b47d5c573c2797bdbbf55 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Sun, 8 Mar 2015 18:16:04 +1100 Subject: [PATCH] caopengllayersink: implement as a bin like glimagesink --- ext/gl/caopengllayersink.h | 3 +- ext/gl/caopengllayersink.m | 308 ++++++++++++++++++++++----------------------- ext/gl/gstopengl.c | 4 +- 3 files changed, 150 insertions(+), 165 deletions(-) diff --git a/ext/gl/caopengllayersink.h b/ext/gl/caopengllayersink.h index 16fbc09..35a4cd2 100644 --- a/ext/gl/caopengllayersink.h +++ b/ext/gl/caopengllayersink.h @@ -57,8 +57,6 @@ struct _GstCAOpenGLLayerSink GstGLContext *other_context; GstGLContext *context; - GstGLUpload *upload; - GstGLColorConvert *convert; guint next_tex; GstBuffer *next_buffer; @@ -92,6 +90,7 @@ struct _GstCAOpenGLLayerSinkClass }; GType gst_ca_opengl_layer_sink_get_type(void); +GType gst_ca_opengl_layer_sink_bin_get_type (void); G_END_DECLS diff --git a/ext/gl/caopengllayersink.m b/ext/gl/caopengllayersink.m index 3a11b8e..3656099 100644 --- a/ext/gl/caopengllayersink.m +++ b/ext/gl/caopengllayersink.m @@ -31,11 +31,92 @@ #endif #include "caopengllayersink.h" +#include "gstglsinkbin.h" #include GST_DEBUG_CATEGORY (gst_debug_ca_sink); #define GST_CAT_DEFAULT gst_debug_ca_sink +typedef GstGLSinkBin GstCAOpenGLLayerSinkBin; +typedef GstGLSinkBinClass GstCAOpenGLLayerSinkBinClass; + +G_DEFINE_TYPE (GstCAOpenGLLayerSinkBin, gst_ca_opengl_layer_sink_bin, + GST_TYPE_GL_SINK_BIN); + +enum +{ + PROP_BIN_0, + PROP_BIN_QOS, + PROP_BIN_FORCE_ASPECT_RATIO, + PROP_BIN_LAST_SAMPLE, + PROP_BIN_LAYER, +}; + +static void +_on_notify_layer (GObject * object, GParamSpec *pspec, gpointer user_data) +{ + GstCAOpenGLLayerSinkBin *self = user_data; + + g_object_notify (G_OBJECT (self), "layer"); +} + +static void +gst_ca_opengl_layer_sink_bin_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * param_spec) +{ + g_object_set_property (G_OBJECT (GST_GL_SINK_BIN (object)->sink), + param_spec->name, value); +} + +static void +gst_ca_opengl_layer_sink_bin_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * param_spec) +{ + g_object_get_property (G_OBJECT (GST_GL_SINK_BIN (object)->sink), + param_spec->name, value); +} + +static void +gst_ca_opengl_layer_sink_bin_init (GstCAOpenGLLayerSinkBin * self) +{ + GstGLCAOpenGLLayer *sink = g_object_new (GST_TYPE_CA_OPENGL_LAYER_SINK, NULL); + + g_signal_connect (sink, "notify::layer", G_CALLBACK (_on_notify_layer), self); + + gst_gl_sink_bin_finish_init_with_element (GST_GL_SINK_BIN (self), + GST_ELEMENT (sink)); +} + +static void +gst_ca_opengl_layer_sink_bin_class_init (GstCAOpenGLLayerSinkBinClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->get_property = gst_ca_opengl_layer_sink_bin_get_property; + gobject_class->set_property = gst_ca_opengl_layer_sink_bin_set_property; + + g_object_class_install_property (gobject_class, PROP_BIN_FORCE_ASPECT_RATIO, + g_param_spec_boolean ("force-aspect-ratio", + "Force aspect ratio", + "When enabled, scaling will respect original aspect ratio", TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_BIN_LAST_SAMPLE, + g_param_spec_boxed ("last-sample", "Last Sample", + "The last sample received in the sink", GST_TYPE_SAMPLE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_BIN_LAYER, + g_param_spec_pointer ("layer", "CAOpenGLLayer", + "OpenGL Core Animation layer", + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_BIN_QOS, + g_param_spec_boolean ("qos", "Quality of Service", + "Generate Quality-of-Service events upstream", TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} + #define GST_CA_OPENGL_LAYER_SINK_GET_LOCK(glsink) \ (GST_CA_OPENGL_LAYER_SINK(glsink)->drawing_lock) #define GST_CA_OPENGL_LAYER_SINK_LOCK(glsink) \ @@ -88,10 +169,7 @@ static GstStaticPadTemplate gst_ca_opengl_layer_sink_template = 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_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, - "RGBA") "; " GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS)) + "RGBA")) ); enum @@ -320,12 +398,41 @@ gst_ca_opengl_layer_sink_query (GstBaseSink * bsink, GstQuery * query) switch (GST_QUERY_TYPE (query)) { case GST_QUERY_CONTEXT: { - gboolean ret = + const gchar *context_type; + GstContext *context, *old_context; + gboolean ret; + + ret = gst_gl_handle_context_query ((GstElement *) ca_sink, query, &ca_sink->display, &ca_sink->other_context); if (ca_sink->display) gst_gl_display_filter_gl_api (ca_sink->display, SUPPORTED_GL_APIS); - return ret; + + gst_query_parse_context_type (query, &context_type); + + if (g_strcmp0 (context_type, "gst.gl.local_context") == 0) { + GstStructure *s; + + gst_query_parse_context (query, &old_context); + + if (old_context) + context = gst_context_copy (old_context); + else + context = gst_context_new ("gst.gl.local_context", FALSE); + + s = gst_context_writable_structure (context); + gst_structure_set (s, "context", GST_GL_TYPE_CONTEXT, + ca_sink->context, NULL); + gst_query_set_context (query, context); + gst_context_unref (context); + + ret = ca_sink->context != NULL; + } + GST_DEBUG_OBJECT (ca_sink, "context query of type %s %i", + context_type, ret); + + if (ret) + return ret; } case GST_QUERY_DRAIN: { @@ -341,17 +448,15 @@ gst_ca_opengl_layer_sink_query (GstBaseSink * bsink, GstQuery * query) gst_buffer_unref (buf); gst_buffer_replace (&ca_sink->next_buffer, NULL); - gst_gl_upload_release_buffer (ca_sink->upload); res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query); break; } default: - res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query); break; } - return res; + return GST_BASE_SINK_CLASS (parent_class)->query (bsink, query); } static gboolean @@ -430,16 +535,6 @@ gst_ca_opengl_layer_sink_change_state (GstElement * element, GstStateChange tran GST_CA_OPENGL_LAYER_SINK_UNLOCK (ca_sink); gst_buffer_replace (&ca_sink->next_buffer, NULL); - if (ca_sink->upload) { - gst_object_unref (ca_sink->upload); - ca_sink->upload = NULL; - } - - if (ca_sink->convert) { - gst_object_unref (ca_sink->convert); - ca_sink->convert = NULL; - } - if (ca_sink->pool) { gst_buffer_pool_set_active (ca_sink->pool, FALSE); gst_object_unref (ca_sink->pool); @@ -502,10 +597,6 @@ gst_ca_opengl_layer_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) gint display_par_n, display_par_d; guint display_ratio_num, display_ratio_den; GstVideoInfo vinfo; - GstStructure *structure; - GstBufferPool *newpool, *oldpool; - GstCapsFeatures *gl_features; - GstCaps *uploaded_caps; GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps); @@ -562,56 +653,6 @@ gst_ca_opengl_layer_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) if (!_ensure_gl_setup (ca_sink)) return FALSE; - newpool = gst_gl_buffer_pool_new (ca_sink->context); - structure = gst_buffer_pool_get_config (newpool); - gst_buffer_pool_config_set_params (structure, caps, vinfo.size, 2, 0); - gst_buffer_pool_set_config (newpool, structure); - - oldpool = ca_sink->pool; - /* we don't activate the pool yet, this will be done by downstream after it - * has configured the pool. If downstream does not want our pool we will - * activate it when we render into it */ - ca_sink->pool = newpool; - - /* unref the old sink */ - if (oldpool) { - /* we don't deactivate, some elements might still be using it, it will - * be deactivated when the last ref is gone */ - gst_object_unref (oldpool); - } - - if (ca_sink->upload) - gst_object_unref (ca_sink->upload); - ca_sink->upload = gst_gl_upload_new (ca_sink->context); - - gl_features = - gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY); - - uploaded_caps = gst_caps_copy (caps); - gst_caps_set_features (uploaded_caps, 0, - gst_caps_features_copy (gl_features)); - gst_gl_upload_set_caps (ca_sink->upload, caps, uploaded_caps); - - if (ca_sink->gl_caps) - gst_caps_unref (ca_sink->gl_caps); - ca_sink->gl_caps = gst_caps_copy (caps); - gst_caps_set_simple (ca_sink->gl_caps, "format", G_TYPE_STRING, "RGBA", - NULL); - gst_caps_set_features (ca_sink->gl_caps, 0, - gst_caps_features_copy (gl_features)); - - if (ca_sink->convert) - gst_object_unref (ca_sink->convert); - ca_sink->convert = gst_gl_color_convert_new (ca_sink->context); - if (!gst_gl_color_convert_set_caps (ca_sink->convert, uploaded_caps, - ca_sink->gl_caps)) { - gst_caps_unref (uploaded_caps); - gst_caps_features_free (gl_features); - return FALSE; - } - gst_caps_unref (uploaded_caps); - gst_caps_features_free (gl_features); - ca_sink->caps_change = TRUE; return TRUE; @@ -621,9 +662,7 @@ static GstFlowReturn gst_ca_opengl_layer_sink_prepare (GstBaseSink * bsink, GstBuffer * buf) { GstCAOpenGLLayerSink *ca_sink; - GstBuffer *uploaded_buffer, *next_buffer = NULL; GstVideoFrame gl_frame; - GstVideoInfo gl_info; ca_sink = GST_CA_OPENGL_LAYER_SINK (bsink); @@ -637,31 +676,14 @@ gst_ca_opengl_layer_sink_prepare (GstBaseSink * bsink, GstBuffer * buf) if (!_ensure_gl_setup (ca_sink)) return GST_FLOW_NOT_NEGOTIATED; - if (gst_gl_upload_perform_with_buffer (ca_sink->upload, buf, - &uploaded_buffer) != GST_GL_UPLOAD_DONE) - goto upload_failed; - - if (!(next_buffer = - gst_gl_color_convert_perform (ca_sink->convert, - uploaded_buffer))) { - gst_buffer_unref (uploaded_buffer); - goto upload_failed; - } - - gst_video_info_from_caps (&gl_info, ca_sink->gl_caps); - - if (!gst_video_frame_map (&gl_frame, &gl_info, next_buffer, + if (!gst_video_frame_map (&gl_frame, &ca_sink->info, buf, GST_MAP_READ | GST_MAP_GL)) { - gst_buffer_unref (uploaded_buffer); - gst_buffer_unref (next_buffer); goto upload_failed; } - gst_buffer_unref (uploaded_buffer); ca_sink->next_tex = *(guint *) gl_frame.data[0]; - gst_buffer_replace (&ca_sink->next_buffer, next_buffer); - gst_buffer_unref (next_buffer); + gst_buffer_replace (&ca_sink->next_buffer, buf); gst_video_frame_unmap (&gl_frame); @@ -712,7 +734,6 @@ gst_ca_opengl_layer_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf) if (g_atomic_int_get (&ca_sink->to_quit) != 0) { GST_ELEMENT_ERROR (ca_sink, RESOURCE, NOT_FOUND, ("%s", gst_gl_context_get_error ()), (NULL)); - gst_gl_upload_release_buffer (ca_sink->upload); return GST_FLOW_ERROR; } @@ -723,16 +744,10 @@ static gboolean gst_ca_opengl_layer_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) { GstCAOpenGLLayerSink *ca_sink = GST_CA_OPENGL_LAYER_SINK (bsink); - GstBufferPool *pool; GstStructure *config; GstCaps *caps; guint size; gboolean need_pool; - GstStructure *gl_context; - gchar *platform, *gl_apis; - gpointer handle; - GstAllocator *allocator = NULL; - GstAllocationParams params; if (!_ensure_gl_setup (ca_sink)) return FALSE; @@ -742,79 +757,50 @@ gst_ca_opengl_layer_sink_propose_allocation (GstBaseSink * bsink, GstQuery * que if (caps == NULL) goto no_caps; - if ((pool = ca_sink->pool)) - gst_object_ref (pool); - - if (pool != NULL) { - GstCaps *pcaps; - - /* we had a pool, check caps */ - GST_DEBUG_OBJECT (ca_sink, "check existing pool caps"); - config = gst_buffer_pool_get_config (pool); - gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL); - - if (!gst_caps_is_equal (caps, pcaps)) { - GST_DEBUG_OBJECT (ca_sink, "pool has different caps"); - /* different caps, we can't use this pool */ - gst_object_unref (pool); - pool = NULL; - } - gst_structure_free (config); - } - - if (pool == NULL && need_pool) { + if (need_pool) { GstVideoInfo info; if (!gst_video_info_from_caps (&info, caps)) goto invalid_caps; - GST_DEBUG_OBJECT (ca_sink, "create new pool"); - pool = gst_gl_buffer_pool_new (ca_sink->context); - /* the normal size of a frame */ size = info.size; - config = gst_buffer_pool_get_config (pool); - gst_buffer_pool_config_set_params (config, caps, size, 0, 0); - 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 */ - if (pool) { - gst_query_add_allocation_pool (query, pool, size, 2, 0); - gst_object_unref (pool); + if (ca_sink->pool) { + GstCaps *pcaps; + + /* we had a pool, check caps */ + GST_DEBUG_OBJECT (ca_sink, "check existing pool caps"); + config = gst_buffer_pool_get_config (ca_sink->pool); + gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL); + + if (!gst_caps_is_equal (caps, pcaps)) { + GST_DEBUG_OBJECT (ca_sink, "pool has different caps"); + /* different caps, we can't use this pool */ + gst_object_unref (ca_sink->pool); + ca_sink->pool = NULL; + } + gst_structure_free (config); + } + + if (ca_sink->pool == NULL) { + GST_DEBUG_OBJECT (ca_sink, "create new pool"); + + ca_sink->pool = gst_gl_buffer_pool_new (ca_sink->context); + config = gst_buffer_pool_get_config (ca_sink->pool); + gst_buffer_pool_config_set_params (config, caps, size, 0, 0); + + if (!gst_buffer_pool_set_config (ca_sink->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, ca_sink->pool, size, 2, 0); } - /* we also support various metadata */ - gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0); if (ca_sink->context->gl_vtable->FenceSync) gst_query_add_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, 0); - gl_apis = - gst_gl_api_to_string (gst_gl_context_get_gl_api (ca_sink->context)); - platform = - gst_gl_platform_to_string (gst_gl_context_get_gl_platform - (ca_sink->context)); - handle = (gpointer) gst_gl_context_get_gl_context (ca_sink->context); - - gl_context = - gst_structure_new ("GstVideoGLTextureUploadMeta", "gst.gl.GstGLContext", - GST_GL_TYPE_CONTEXT, ca_sink->context, "gst.gl.context.handle", - G_TYPE_POINTER, handle, "gst.gl.context.type", G_TYPE_STRING, platform, - "gst.gl.context.apis", G_TYPE_STRING, gl_apis, NULL); - gst_query_add_allocation_meta (query, - GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, gl_context); - - g_free (gl_apis); - g_free (platform); - gst_structure_free (gl_context); - - gst_allocation_params_init (¶ms); - - allocator = gst_allocator_find (GST_GL_MEMORY_ALLOCATOR); - gst_query_add_allocation_param (query, allocator, ¶ms); - gst_object_unref (allocator); - return TRUE; /* ERRORS */ diff --git a/ext/gl/gstopengl.c b/ext/gl/gstopengl.c index 3878607..452efdd 100644 --- a/ext/gl/gstopengl.c +++ b/ext/gl/gstopengl.c @@ -84,7 +84,7 @@ #if GST_GL_HAVE_WINDOW_COCOA /* avoid including Cocoa/CoreFoundation from a C file... */ -extern GType gst_ca_opengl_layer_sink_get_type (void); +extern GType gst_ca_opengl_layer_sink_bin_get_type (void); #endif #ifdef USE_EGL_RPI @@ -251,7 +251,7 @@ plugin_init (GstPlugin * plugin) #endif /* GST_GL_HAVE_OPENGL */ #if GST_GL_HAVE_WINDOW_COCOA if (!gst_element_register (plugin, "caopengllayersink", - GST_RANK_NONE, gst_ca_opengl_layer_sink_get_type ())) { + GST_RANK_NONE, gst_ca_opengl_layer_sink_bin_get_type ())) { return FALSE; } #endif -- 2.7.4