caopengllayersink: implement as a bin like glimagesink

This commit is contained in:
Matthew Waters 2015-03-08 18:16:04 +11:00
parent 66ccdab09a
commit dbe8ae4d98
3 changed files with 150 additions and 165 deletions

View file

@ -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

View file

@ -31,11 +31,92 @@
#endif
#include "caopengllayersink.h"
#include "gstglsinkbin.h"
#include <QuartzCore/QuartzCore.h>
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 (&params);
allocator = gst_allocator_find (GST_GL_MEMORY_ALLOCATOR);
gst_query_add_allocation_param (query, allocator, &params);
gst_object_unref (allocator);
return TRUE;
/* ERRORS */

View file

@ -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