diff --git a/ext/gl/gstglmosaic.c b/ext/gl/gstglmosaic.c index 857c179931..5a5c41835e 100644 --- a/ext/gl/gstglmosaic.c +++ b/ext/gl/gstglmosaic.c @@ -197,9 +197,9 @@ gst_gl_mosaic_process_textures (GstGLMixer * mix, GPtrArray * frames, //blocking call, use a FBO gst_gl_context_use_fbo_v2 (mix->context, - GST_VIDEO_INFO_WIDTH (&mix->out_info), - GST_VIDEO_INFO_HEIGHT (&mix->out_info), mix->fbo, mix->depthbuffer, - out_tex, gst_gl_mosaic_callback, (gpointer) mosaic); + GST_VIDEO_INFO_WIDTH (&GST_VIDEO_AGGREGATOR (mix)->info), + GST_VIDEO_INFO_HEIGHT (&GST_VIDEO_AGGREGATOR (mix)->info), mix->fbo, + mix->depthbuffer, out_tex, gst_gl_mosaic_callback, (gpointer) mosaic); return TRUE; } @@ -294,8 +294,9 @@ gst_gl_mosaic_callback (gpointer stuff) continue; } in_tex = frame->texture; - width = GST_VIDEO_INFO_WIDTH (&frame->pad->in_info); - height = GST_VIDEO_INFO_HEIGHT (&frame->pad->in_info); + width = GST_VIDEO_INFO_WIDTH (&GST_VIDEO_AGGREGATOR_PAD (frame->pad)->info); + height = + GST_VIDEO_INFO_HEIGHT (&GST_VIDEO_AGGREGATOR_PAD (frame->pad)->info); if (!in_tex || width <= 0 || height <= 0) { GST_DEBUG ("skipping texture:%u frame:%p width:%u height %u", diff --git a/ext/gl/gstglvideomixer.c b/ext/gl/gstglvideomixer.c index e3d5807410..b2ff4008f9 100644 --- a/ext/gl/gstglvideomixer.c +++ b/ext/gl/gstglvideomixer.c @@ -116,7 +116,6 @@ struct _GstGLVideoMixerPad /* properties */ gint xpos, ypos; gint width, height; - guint zorder; gdouble alpha; }; @@ -134,7 +133,6 @@ static void gst_gl_video_mixer_pad_set_property (GObject * object, static void gst_gl_video_mixer_pad_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -#define DEFAULT_PAD_ZORDER 0 #define DEFAULT_PAD_XPOS 0 #define DEFAULT_PAD_YPOS 0 #define DEFAULT_PAD_WIDTH 0 @@ -143,7 +141,6 @@ static void gst_gl_video_mixer_pad_get_property (GObject * object, enum { PROP_PAD_0, - PROP_PAD_ZORDER, PROP_PAD_XPOS, PROP_PAD_YPOS, PROP_PAD_WIDTH, @@ -165,10 +162,6 @@ gst_gl_video_mixer_pad_class_init (GstGLVideoMixerPadClass * klass) gobject_class->set_property = gst_gl_video_mixer_pad_set_property; gobject_class->get_property = gst_gl_video_mixer_pad_get_property; - g_object_class_install_property (gobject_class, PROP_PAD_ZORDER, - g_param_spec_uint ("zorder", "Z-Order", "Z Order of the picture", - 0, 10000, DEFAULT_PAD_ZORDER, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_PAD_XPOS, g_param_spec_int ("xpos", "X Position", "X Position of the picture", G_MININT, G_MAXINT, DEFAULT_PAD_XPOS, @@ -198,9 +191,6 @@ gst_gl_video_mixer_pad_get_property (GObject * object, guint prop_id, GstGLVideoMixerPad *pad = GST_GL_VIDEO_MIXER_PAD (object); switch (prop_id) { - case PROP_PAD_ZORDER: - g_value_set_uint (value, pad->zorder); - break; case PROP_PAD_XPOS: g_value_set_int (value, pad->xpos); break; @@ -222,13 +212,6 @@ gst_gl_video_mixer_pad_get_property (GObject * object, guint prop_id, } } -static int -pad_zorder_compare (const GstGLVideoMixerPad * pad1, - const GstGLVideoMixerPad * pad2) -{ - return pad1->zorder - pad2->zorder; -} - static void gst_gl_video_mixer_pad_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) @@ -237,14 +220,6 @@ gst_gl_video_mixer_pad_set_property (GObject * object, guint prop_id, GstGLMixer *mix = GST_GL_MIXER (gst_pad_get_parent (GST_PAD (pad))); switch (prop_id) { - case PROP_PAD_ZORDER: - GST_GL_MIXER_LOCK (mix); - pad->zorder = g_value_get_uint (value); - - mix->sinkpads = g_slist_sort (mix->sinkpads, - (GCompareFunc) pad_zorder_compare); - GST_GL_MIXER_UNLOCK (mix); - break; case PROP_PAD_XPOS: pad->xpos = g_value_get_int (value); break; @@ -273,6 +248,7 @@ gst_gl_video_mixer_class_init (GstGLVideoMixerClass * klass) { GObjectClass *gobject_class; GstElementClass *element_class; + GstAggregatorClass *agg_class = (GstAggregatorClass *) klass; gobject_class = (GObjectClass *) klass; element_class = GST_ELEMENT_CLASS (klass); @@ -288,6 +264,9 @@ gst_gl_video_mixer_class_init (GstGLVideoMixerClass * klass) GST_GL_MIXER_CLASS (klass)->reset = gst_gl_video_mixer_reset; GST_GL_MIXER_CLASS (klass)->process_textures = gst_gl_video_mixer_process_textures; + + agg_class->sinkpads_type = GST_TYPE_GL_VIDEO_MIXER_PAD; + } static void @@ -295,9 +274,6 @@ gst_gl_video_mixer_init (GstGLVideoMixer * video_mixer) { video_mixer->shader = NULL; video_mixer->input_frames = NULL; - - gst_gl_mixer_set_pad_type (GST_GL_MIXER (video_mixer), - GST_TYPE_GL_VIDEO_MIXER_PAD); } static void @@ -352,8 +328,9 @@ gst_gl_video_mixer_process_textures (GstGLMixer * mix, GPtrArray * frames, video_mixer->input_frames = frames; gst_gl_context_use_fbo_v2 (mix->context, - GST_VIDEO_INFO_WIDTH (&mix->out_info), - GST_VIDEO_INFO_HEIGHT (&mix->out_info), mix->fbo, mix->depthbuffer, + GST_VIDEO_INFO_WIDTH (&GST_VIDEO_AGGREGATOR (mix)->info), + GST_VIDEO_INFO_HEIGHT (&GST_VIDEO_AGGREGATOR (mix)->info), + mix->fbo, mix->depthbuffer, out_tex, gst_gl_video_mixer_callback, (gpointer) video_mixer); return TRUE; @@ -378,8 +355,8 @@ gst_gl_video_mixer_callback (gpointer stuff) guint count = 0; - out_width = GST_VIDEO_INFO_WIDTH (&mixer->out_info); - out_height = GST_VIDEO_INFO_HEIGHT (&mixer->out_info); + out_width = GST_VIDEO_INFO_WIDTH (&GST_VIDEO_AGGREGATOR (stuff)->info); + out_height = GST_VIDEO_INFO_HEIGHT (&GST_VIDEO_AGGREGATOR (stuff)->info); gst_gl_context_clear_shader (mixer->context); gl->BindTexture (GL_TEXTURE_2D, 0); @@ -424,8 +401,10 @@ gst_gl_video_mixer_callback (gpointer stuff) continue; } pad = (GstGLVideoMixerPad *) frame->pad; - in_width = GST_VIDEO_INFO_WIDTH (&frame->pad->in_info); - in_height = GST_VIDEO_INFO_HEIGHT (&frame->pad->in_info); + in_width = + GST_VIDEO_INFO_WIDTH (&GST_VIDEO_AGGREGATOR_PAD (pad)->info); + in_height = + GST_VIDEO_INFO_HEIGHT (&GST_VIDEO_AGGREGATOR_PAD (pad)->info); if (!frame->texture || in_width <= 0 || in_height <= 0) { GST_DEBUG ("skipping texture:%u frame:%p width:%u height %u", diff --git a/gst-libs/gst/gl/Makefile.am b/gst-libs/gst/gl/Makefile.am index 44252a3a05..85713360fb 100644 --- a/gst-libs/gst/gl/Makefile.am +++ b/gst-libs/gst/gl/Makefile.am @@ -52,6 +52,8 @@ libgstgl_@GST_API_VERSION@include_HEADERS = \ gl.h libgstgl_@GST_API_VERSION@_la_LIBADD = \ + $(top_builddir)/gst-libs/gst/base/libgstbadbase-$(GST_API_VERSION).la \ + $(top_builddir)/gst-libs/gst/video/libgstbadvideo-$(GST_API_VERSION).la \ $(GMODULE_NO_EXPORT_LIBS) \ $(GST_PLUGINS_BASE_LIBS) \ -lgstvideo-$(GST_API_VERSION) \ diff --git a/gst-libs/gst/gl/gstglmixer.c b/gst-libs/gst/gl/gstglmixer.c index 2d88d8aa89..94ca44f7d1 100644 --- a/gst-libs/gst/gl/gstglmixer.c +++ b/gst-libs/gst/gl/gstglmixer.c @@ -36,6 +36,12 @@ #include "gstglmixer.h" +#define gst_gl_mixer_parent_class parent_class +G_DEFINE_ABSTRACT_TYPE (GstGLMixer, gst_gl_mixer, GST_TYPE_VIDEO_AGGREGATOR); +static gboolean gst_gl_mixer_do_bufferpool (GstGLMixer * mix, + GstCaps * outcaps); + + #define GST_CAT_DEFAULT gst_gl_mixer_debug GST_DEBUG_CATEGORY (gst_gl_mixer_debug); @@ -51,12 +57,6 @@ static void gst_gl_mixer_pad_get_property (GObject * object, guint prop_id, static void gst_gl_mixer_pad_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); -static gboolean gst_gl_mixer_src_event (GstPad * pad, GstObject * object, - GstEvent * event); -static gboolean gst_gl_mixer_sink_event (GstCollectPads * pads, - GstCollectData * cdata, GstEvent * event, GstGLMixer * mix); -static gboolean gst_gl_mixer_src_setcaps (GstPad * pad, GstGLMixer * mix, - GstCaps * caps); static void gst_gl_mixer_set_context (GstElement * element, GstContext * context); @@ -79,7 +79,7 @@ struct _GstGLMixerPrivate GstQuery *query; }; -G_DEFINE_TYPE (GstGLMixerPad, gst_gl_mixer_pad, GST_TYPE_PAD); +G_DEFINE_TYPE (GstGLMixerPad, gst_gl_mixer_pad, GST_TYPE_VIDEO_AGGREGATOR_PAD); static void gst_gl_mixer_pad_class_init (GstGLMixerPadClass * klass) @@ -113,203 +113,12 @@ gst_gl_mixer_pad_set_property (GObject * object, guint prop_id, } static gboolean -gst_gl_mixer_update_src_caps (GstGLMixer * mix) +_negotiated_caps (GstVideoAggregator * vagg, GstCaps * caps) { - GSList *l; - gint best_width = -1, best_height = -1; - gdouble best_fps = -1, cur_fps; - gint best_fps_n = -1, best_fps_d = -1; - gboolean ret = TRUE; + GstGLMixer *mix = GST_GL_MIXER (vagg); + gboolean ret = gst_gl_mixer_do_bufferpool (mix, caps); - GST_GL_MIXER_LOCK (mix); - - for (l = mix->sinkpads; l; l = l->next) { - GstGLMixerPad *mpad = l->data; - gint this_width, this_height; - gint fps_n, fps_d; - gint width, height; - - fps_n = GST_VIDEO_INFO_FPS_N (&mpad->in_info); - fps_d = GST_VIDEO_INFO_FPS_D (&mpad->in_info); - width = GST_VIDEO_INFO_WIDTH (&mpad->in_info); - height = GST_VIDEO_INFO_HEIGHT (&mpad->in_info); - - if (width == 0 || height == 0) - continue; - - this_width = width; - this_height = height; - - if (best_width < this_width) - best_width = this_width; - if (best_height < this_height) - best_height = this_height; - - if (fps_d == 0) - cur_fps = 0.0; - else - gst_util_fraction_to_double (fps_n, fps_d, &cur_fps); - - if (best_fps < cur_fps) { - best_fps = cur_fps; - best_fps_n = fps_n; - best_fps_d = fps_d; - } - } - - if (best_fps_n == 0 || (best_fps_n < 0 && best_fps_d <= 0)) { - best_fps_n = 25; - best_fps_d = 1; - best_fps = 25.0; - } - - if (best_width > 0 && best_height > 0 && best_fps > 0.0) { - GstCaps *caps, *peercaps; - GstStructure *s; - GstVideoInfo info; - - if (GST_VIDEO_INFO_FPS_N (&mix->out_info) != best_fps_n || - GST_VIDEO_INFO_FPS_D (&mix->out_info) != best_fps_d) { - if (mix->segment.position != -1) { - mix->ts_offset = mix->segment.position - mix->segment.start; - mix->nframes = 0; - } - } - - caps = gst_caps_new_empty_simple ("video/x-raw"); - - peercaps = gst_pad_peer_query_caps (mix->srcpad, NULL); - if (peercaps) { - GstCaps *tmp; - tmp = gst_caps_intersect (caps, peercaps); - gst_caps_unref (caps); - gst_caps_unref (peercaps); - caps = tmp; - } - - if (!gst_caps_is_fixed (caps)) { - caps = gst_caps_make_writable (caps); - - caps = gst_caps_truncate (caps); - - s = gst_caps_get_structure (caps, 0); - gst_structure_fixate_field_nearest_int (s, "width", best_width); - gst_structure_fixate_field_nearest_int (s, "height", best_height); - gst_structure_fixate_field_nearest_fraction (s, "framerate", best_fps_n, - best_fps_d); - gst_structure_fixate_field_string (s, "format", "RGBA"); - - gst_structure_get_int (s, "width", &info.width); - gst_structure_get_int (s, "height", &info.height); - gst_structure_get_fraction (s, "fraction", &info.fps_n, &info.fps_d); - GST_DEBUG_OBJECT (mix, "fixated caps to %" GST_PTR_FORMAT, caps); - } - - GST_GL_MIXER_UNLOCK (mix); - ret = gst_gl_mixer_src_setcaps (mix->srcpad, mix, caps); - } else { - GST_ERROR_OBJECT (mix, "Invalid caps"); - GST_GL_MIXER_UNLOCK (mix); - } - - return ret; -} - -static gboolean -gst_gl_mixer_pad_sink_setcaps (GstPad * pad, GstObject * parent, GstCaps * caps) -{ - GstGLMixer *mix; - GstGLMixerPad *mixpad; - GstVideoInfo info; - gboolean ret = TRUE; - - GST_INFO_OBJECT (pad, "Setting caps %" GST_PTR_FORMAT, caps); - - mix = GST_GL_MIXER (parent); - mixpad = GST_GL_MIXER_PAD (pad); - - if (!gst_video_info_from_caps (&info, caps)) { - GST_ERROR_OBJECT (pad, "Failed to parse caps"); - goto beach; - } - - GST_GL_MIXER_LOCK (mix); - - mix->out_info = info; - mixpad->in_info = info; - - GST_GL_MIXER_UNLOCK (mix); - - ret = gst_gl_mixer_update_src_caps (mix); - -beach: - return ret; -} - -static GstCaps * -gst_gl_mixer_pad_sink_getcaps (GstPad * pad, GstGLMixer * mix, GstCaps * filter) -{ - GstCaps *srccaps; - GstStructure *s; - gint i, n; - - srccaps = gst_pad_get_current_caps (GST_PAD (mix->srcpad)); - if (srccaps == NULL) - srccaps = gst_pad_get_pad_template_caps (GST_PAD (mix->srcpad)); - - srccaps = gst_caps_make_writable (srccaps); - - n = gst_caps_get_size (srccaps); - for (i = 0; i < n; i++) { - s = gst_caps_get_structure (srccaps, i); - gst_structure_set (s, "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, - "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); - if (!gst_structure_has_field (s, "pixel-aspect-ratio")) - gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, - NULL); - } - - GST_DEBUG_OBJECT (pad, "Returning %" GST_PTR_FORMAT, srccaps); - - return srccaps; -} - -static gboolean -gst_gl_mixer_pad_sink_acceptcaps (GstPad * pad, GstGLMixer * mix, - GstCaps * caps) -{ - gboolean ret; - GstCaps *accepted_caps; - gint i, n; - GstStructure *s; - - GST_DEBUG_OBJECT (pad, "%" GST_PTR_FORMAT, caps); - - accepted_caps = gst_pad_get_current_caps (GST_PAD (mix->srcpad)); - if (accepted_caps == NULL) - accepted_caps = gst_pad_get_pad_template_caps (GST_PAD (mix->srcpad)); - - accepted_caps = gst_caps_make_writable (accepted_caps); - GST_LOG_OBJECT (pad, "src caps %" GST_PTR_FORMAT, accepted_caps); - - n = gst_caps_get_size (accepted_caps); - for (i = 0; i < n; i++) { - s = gst_caps_get_structure (accepted_caps, i); - gst_structure_set (s, "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, - "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); - gst_structure_remove_field (s, "format"); - if (!gst_structure_has_field (s, "pixel-aspect-ratio")) - gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, - NULL); - } - - ret = gst_caps_can_intersect (caps, accepted_caps); - GST_INFO_OBJECT (pad, "%saccepted caps %" GST_PTR_FORMAT, (ret ? "" : "not "), - caps); - GST_INFO_OBJECT (pad, "acceptable caps are %" GST_PTR_FORMAT, accepted_caps); - gst_caps_unref (accepted_caps); + mix->priv->negotiated = ret; return ret; } @@ -440,11 +249,11 @@ context_error: } static gboolean -gst_gl_mixer_sink_query (GstCollectPads * pads, GstCollectData * data, - GstQuery * query, GstGLMixer * mix) +gst_gl_mixer_sink_query (GstAggregator * agg, GstAggregatorPad * bpad, + GstQuery * query) { - GstPad *pad = data->pad; gboolean ret = FALSE; + GstGLMixer *mix = GST_GL_MIXER (agg); GST_TRACE ("QUERY %" GST_PTR_FORMAT, query); @@ -478,27 +287,6 @@ gst_gl_mixer_sink_query (GstCollectPads * pads, GstCollectData * data, GST_DEBUG_OBJECT (mix, "ALLOCATION ret %d, %" GST_PTR_FORMAT, ret, query); break; } - case GST_QUERY_CAPS: - { - GstCaps *filter, *caps; - - gst_query_parse_caps (query, &filter); - caps = gst_gl_mixer_pad_sink_getcaps (pad, mix, filter); - gst_query_set_caps_result (query, caps); - gst_caps_unref (caps); - ret = TRUE; - break; - } - case GST_QUERY_ACCEPT_CAPS: - { - GstCaps *caps; - - gst_query_parse_accept_caps (query, &caps); - ret = gst_gl_mixer_pad_sink_acceptcaps (pad, mix, caps); - gst_query_set_accept_caps_result (query, ret); - ret = TRUE; - break; - } case GST_QUERY_CONTEXT: { ret = gst_gl_handle_context_query ((GstElement *) mix, query, @@ -506,7 +294,7 @@ gst_gl_mixer_sink_query (GstCollectPads * pads, GstCollectData * data, break; } default: - ret = gst_collect_pads_query_default (pads, data, query, FALSE); + ret = GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, bpad, query); break; } @@ -542,7 +330,7 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", "; " GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS)) ); -static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%d", +static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%u", GST_PAD_SINK, GST_PAD_REQUEST, GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES @@ -554,100 +342,45 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%d", "; " GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS)) ); -static gboolean gst_gl_mixer_src_query (GstPad * pad, GstObject * object, - GstQuery * query); -static gboolean gst_gl_mixer_src_activate_mode (GstPad * pad, - GstObject * parent, GstPadMode mode, gboolean active); -static GstFlowReturn gst_gl_mixer_sink_clip (GstCollectPads * pads, - GstCollectData * data, GstBuffer * buf, GstBuffer ** outbuf, - GstGLMixer * mix); +static gboolean gst_gl_mixer_src_query (GstAggregator * agg, GstQuery * query); +static GstFlowReturn +gst_gl_mixer_get_output_buffer (GstVideoAggregator * videoaggregator, + GstBuffer ** outbuf); +static gboolean +gst_gl_mixer_src_activate_mode (GstAggregator * aggregator, GstPadMode mode, + gboolean active); +static gboolean gst_gl_mixer_stop (GstAggregator * agg); +static gboolean gst_gl_mixer_start (GstAggregator * agg); -static GstFlowReturn gst_gl_mixer_collected (GstCollectPads * pads, - GstGLMixer * mix); -static GstPad *gst_gl_mixer_request_new_pad (GstElement * element, - GstPadTemplate * templ, const gchar * name, const GstCaps * caps); -static void gst_gl_mixer_release_pad (GstElement * element, GstPad * pad); +static GstFlowReturn +gst_gl_mixer_aggregate_frames (GstVideoAggregator * vagg, + GstBuffer * outbuffer); static void gst_gl_mixer_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_gl_mixer_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static GstStateChangeReturn gst_gl_mixer_change_state (GstElement * element, - GstStateChange transition); -static gboolean gst_gl_mixer_query_caps (GstPad * pad, GstObject * parent, - GstQuery * query); -static gboolean gst_gl_mixer_query_duration (GstGLMixer * mix, - GstQuery * query); -static gboolean gst_gl_mixer_query_latency (GstGLMixer * mix, GstQuery * query); - -static gboolean gst_gl_mixer_do_bufferpool (GstGLMixer * mix, - GstCaps * outcaps); static gboolean gst_gl_mixer_decide_allocation (GstGLMixer * mix, GstQuery * query); static gboolean gst_gl_mixer_set_allocation (GstGLMixer * mix, GstBufferPool * pool, GstAllocator * allocator, GstAllocationParams * params, GstQuery * query); -static gint64 gst_gl_mixer_do_qos (GstGLMixer * mix, GstClockTime timestamp); -static void gst_gl_mixer_update_qos (GstGLMixer * mix, gdouble proportion, - GstClockTimeDiff diff, GstClockTime timestamp); -static void gst_gl_mixer_reset_qos (GstGLMixer * mix); -static void gst_gl_mixer_read_qos (GstGLMixer * mix, gdouble * proportion, - GstClockTime * time); - -static void gst_gl_mixer_child_proxy_init (gpointer g_iface, - gpointer iface_data); - -#define gst_gl_mixer_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GstGLMixer, gst_gl_mixer, GST_TYPE_ELEMENT, - G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY, gst_gl_mixer_child_proxy_init); - GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "glmixer", 0, "opengl mixer")); static void gst_gl_mixer_finalize (GObject * object); -static GObject * -gst_gl_mixer_child_proxy_get_child_by_index (GstChildProxy * child_proxy, - guint index) -{ - GstGLMixer *mix = GST_GL_MIXER (child_proxy); - GObject *obj; - - GST_GL_MIXER_LOCK (mix); - if ((obj = g_slist_nth_data (mix->sinkpads, index))) - gst_object_ref (obj); - GST_GL_MIXER_UNLOCK (mix); - return obj; -} - -static guint -gst_gl_mixer_child_proxy_get_children_count (GstChildProxy * child_proxy) -{ - guint count = 0; - GstGLMixer *mix = GST_GL_MIXER (child_proxy); - - GST_GL_MIXER_LOCK (mix); - count = mix->numpads; - GST_GL_MIXER_UNLOCK (mix); - GST_INFO_OBJECT (mix, "Children Count: %d", count); - return count; -} - -static void -gst_gl_mixer_child_proxy_init (gpointer g_iface, gpointer iface_data) -{ - GstChildProxyInterface *iface = g_iface; - - GST_INFO ("intializing child proxy interface"); - iface->get_child_by_index = gst_gl_mixer_child_proxy_get_child_by_index; - iface->get_children_count = gst_gl_mixer_child_proxy_get_children_count; -} - static void gst_gl_mixer_class_init (GstGLMixerClass * klass) { GObjectClass *gobject_class; GstElementClass *element_class; + GstVideoAggregatorClass *videoaggregator_class = + (GstVideoAggregatorClass *) klass; + GstAggregatorClass *agg_class = (GstAggregatorClass *) klass; + + GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "glmixer", 0, "opengl mixer"); + gobject_class = (GObjectClass *) klass; element_class = GST_ELEMENT_CLASS (klass); @@ -663,56 +396,33 @@ gst_gl_mixer_class_init (GstGLMixerClass * klass) gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&sink_factory)); - element_class->request_new_pad = - GST_DEBUG_FUNCPTR (gst_gl_mixer_request_new_pad); - element_class->release_pad = GST_DEBUG_FUNCPTR (gst_gl_mixer_release_pad); - element_class->change_state = GST_DEBUG_FUNCPTR (gst_gl_mixer_change_state); element_class->set_context = GST_DEBUG_FUNCPTR (gst_gl_mixer_set_context); + agg_class->sinkpads_type = GST_TYPE_GL_MIXER_PAD; + agg_class->sink_query = gst_gl_mixer_sink_query; + agg_class->src_query = gst_gl_mixer_src_query; + agg_class->src_activate = gst_gl_mixer_src_activate_mode; + agg_class->stop = gst_gl_mixer_stop; + agg_class->start = gst_gl_mixer_start; + + videoaggregator_class->disable_frame_conversion = TRUE; + videoaggregator_class->aggregate_frames = gst_gl_mixer_aggregate_frames; + videoaggregator_class->get_output_buffer = gst_gl_mixer_get_output_buffer; + videoaggregator_class->negotiated_caps = _negotiated_caps; + + /* Register the pad class */ g_type_class_ref (GST_TYPE_GL_MIXER_PAD); klass->set_caps = NULL; -} -static void -gst_gl_mixer_collect_free (GstGLMixerCollect * mixcol) -{ - if (mixcol->buffer) { - gst_buffer_unref (mixcol->buffer); - mixcol->buffer = NULL; - } } static void gst_gl_mixer_reset (GstGLMixer * mix) { - GstGLMixerPrivate *priv = mix->priv; - GSList *l; - - gst_video_info_init (&mix->out_info); - mix->ts_offset = 0; - mix->nframes = 0; - - gst_segment_init (&mix->segment, GST_FORMAT_TIME); - mix->segment.position = -1; - /* clean up collect data */ - for (l = mix->sinkpads; l; l = l->next) { - GstGLMixerPad *p = l->data; - GstGLMixerCollect *mixcol = p->mixcol; - - gst_buffer_replace (&mixcol->buffer, NULL); - mixcol->start_time = -1; - mixcol->end_time = -1; - - gst_video_info_init (&p->in_info); - } - - mix->newseg_pending = TRUE; - mix->flush_stop_pending = FALSE; - - priv->negotiated = FALSE; + mix->priv->negotiated = FALSE; } static void @@ -724,39 +434,12 @@ _free_pad_frame_data (gpointer data) static void gst_gl_mixer_init (GstGLMixer * mix) { - GstElementClass *klass = GST_ELEMENT_GET_CLASS (mix); - mix->priv = GST_GL_MIXER_GET_PRIVATE (mix); - - mix->srcpad = - gst_pad_new_from_template (gst_element_class_get_pad_template (klass, - "src"), "src"); - gst_pad_set_query_function (GST_PAD (mix->srcpad), - GST_DEBUG_FUNCPTR (gst_gl_mixer_src_query)); - gst_pad_set_event_function (GST_PAD (mix->srcpad), - GST_DEBUG_FUNCPTR (gst_gl_mixer_src_event)); - gst_pad_set_activatemode_function (mix->srcpad, - GST_DEBUG_FUNCPTR (gst_gl_mixer_src_activate_mode)); - gst_element_add_pad (GST_ELEMENT (mix), mix->srcpad); - - mix->collect = gst_collect_pads_new (); - - gst_collect_pads_set_function (mix->collect, - (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_gl_mixer_collected), mix); - gst_collect_pads_set_event_function (mix->collect, - (GstCollectPadsEventFunction) gst_gl_mixer_sink_event, mix); - gst_collect_pads_set_query_function (mix->collect, - (GstCollectPadsQueryFunction) gst_gl_mixer_sink_query, mix); - gst_collect_pads_set_clip_function (mix->collect, - (GstCollectPadsClipFunction) gst_gl_mixer_sink_clip, mix); - g_mutex_init (&mix->lock); - mix->array_buffers = 0; mix->display = NULL; mix->fbo = 0; mix->depthbuffer = 0; - mix->pad_type = GST_TYPE_GL_MIXER_PAD; mix->frames = g_ptr_array_new_full (4, _free_pad_frame_data); mix->array_buffers = g_ptr_array_new_full (4, NULL); @@ -770,7 +453,6 @@ gst_gl_mixer_finalize (GObject * object) { GstGLMixer *mix = GST_GL_MIXER (object); - gst_object_unref (mix->collect); g_mutex_clear (&mix->lock); g_ptr_array_free (mix->frames, TRUE); @@ -779,239 +461,6 @@ gst_gl_mixer_finalize (GObject * object) G_OBJECT_CLASS (parent_class)->finalize (object); } -static gboolean -gst_gl_mixer_query_duration (GstGLMixer * mix, GstQuery * query) -{ - GValue item = { 0 }; - gint64 max; - gboolean res; - GstFormat format; - GstIterator *it; - gboolean done; - - /* parse format */ - gst_query_parse_duration (query, &format, NULL); - - max = -1; - res = TRUE; - done = FALSE; - - /* Take maximum of all durations */ - it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (mix)); - while (!done) { - GstIteratorResult ires; - - ires = gst_iterator_next (it, &item); - switch (ires) { - case GST_ITERATOR_DONE: - done = TRUE; - break; - case GST_ITERATOR_OK: - { - GstPad *pad; - gint64 duration; - - pad = g_value_get_object (&item); - - /* ask sink peer for duration */ - res &= gst_pad_peer_query_duration (pad, format, &duration); - /* take max from all valid return values */ - if (res) { - /* valid unknown length, stop searching */ - if (duration == -1) { - max = duration; - done = TRUE; - } - /* else see if bigger than current max */ - else if (duration > max) - max = duration; - } - g_value_reset (&item); - break; - } - case GST_ITERATOR_RESYNC: - max = -1; - res = TRUE; - gst_iterator_resync (it); - break; - default: - res = FALSE; - done = TRUE; - break; - } - } - g_value_reset (&item); - gst_iterator_free (it); - - if (res) { - /* and store the max */ - GST_DEBUG_OBJECT (mix, "Total duration in format %s: %" - GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (max)); - gst_query_set_duration (query, format, max); - } - - return res; -} - -static gboolean -gst_gl_mixer_query_caps (GstPad * pad, GstObject * parent, GstQuery * query) -{ - GstCaps *filter, *caps; - GstGLMixer *mix = GST_GL_MIXER (parent); - GstStructure *s; - gint n; - - gst_query_parse_caps (query, &filter); - - if (GST_VIDEO_INFO_FORMAT (&mix->out_info) != GST_VIDEO_FORMAT_UNKNOWN) { - caps = gst_pad_get_current_caps (mix->srcpad); - } else { - caps = gst_pad_get_pad_template_caps (mix->srcpad); - } - - caps = gst_caps_make_writable (caps); - - n = gst_caps_get_size (caps) - 1; - for (; n >= 0; n--) { - s = gst_caps_get_structure (caps, n); - gst_structure_set (s, "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, - "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL); - if (GST_VIDEO_INFO_FPS_D (&mix->out_info) != 0) { - gst_structure_set (s, - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); - } - } - gst_query_set_caps_result (query, caps); - - return TRUE; -} - -static gboolean -gst_gl_mixer_query_latency (GstGLMixer * mix, GstQuery * query) -{ - GValue item = { 0 }; - GstClockTime min, max; - gboolean live; - gboolean res; - GstIterator *it; - gboolean done; - - res = TRUE; - done = FALSE; - live = FALSE; - min = 0; - max = GST_CLOCK_TIME_NONE; - - /* Take maximum of all latency values */ - it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (mix)); - while (!done) { - GstIteratorResult ires; - - ires = gst_iterator_next (it, &item); - switch (ires) { - case GST_ITERATOR_DONE: - done = TRUE; - break; - case GST_ITERATOR_OK: - { - GstPad *pad; - GstQuery *peerquery; - GstClockTime min_cur, max_cur; - gboolean live_cur; - - pad = g_value_get_object (&item); - peerquery = gst_query_new_latency (); - - /* Ask peer for latency */ - res &= gst_pad_peer_query (pad, peerquery); - - /* take max from all valid return values */ - if (res) { - gst_query_parse_latency (peerquery, &live_cur, &min_cur, &max_cur); - - if (min_cur > min) - min = min_cur; - - if (max_cur != GST_CLOCK_TIME_NONE && - ((max != GST_CLOCK_TIME_NONE && max_cur > max) || - (max == GST_CLOCK_TIME_NONE))) - max = max_cur; - - live = live || live_cur; - } - - gst_query_unref (peerquery); - g_value_reset (&item); - break; - } - case GST_ITERATOR_RESYNC: - live = FALSE; - min = 0; - max = GST_CLOCK_TIME_NONE; - res = TRUE; - gst_iterator_resync (it); - break; - default: - res = FALSE; - done = TRUE; - break; - } - } - g_value_unset (&item); - gst_iterator_free (it); - - if (res) { - /* store the results */ - GST_DEBUG_OBJECT (mix, "Calculated total latency: live %s, min %" - GST_TIME_FORMAT ", max %" GST_TIME_FORMAT, - (live ? "yes" : "no"), GST_TIME_ARGS (min), GST_TIME_ARGS (max)); - gst_query_set_latency (query, live, min, max); - } - - return res; -} - -static void -gst_gl_mixer_update_qos (GstGLMixer * mix, gdouble proportion, - GstClockTimeDiff diff, GstClockTime timestamp) -{ - GST_DEBUG_OBJECT (mix, - "Updating QoS: proportion %lf, diff %s%" GST_TIME_FORMAT ", timestamp %" - GST_TIME_FORMAT, proportion, (diff < 0) ? "-" : "", - GST_TIME_ARGS (ABS (diff)), GST_TIME_ARGS (timestamp)); - - GST_OBJECT_LOCK (mix); - mix->proportion = proportion; - if (G_LIKELY (timestamp != GST_CLOCK_TIME_NONE)) { - if (G_UNLIKELY (diff > 0)) - mix->earliest_time = - timestamp + 2 * diff + gst_util_uint64_scale_int (GST_SECOND, - GST_VIDEO_INFO_FPS_D (&mix->out_info), - GST_VIDEO_INFO_FPS_N (&mix->out_info)); - else - mix->earliest_time = timestamp + diff; - } else { - mix->earliest_time = GST_CLOCK_TIME_NONE; - } - GST_OBJECT_UNLOCK (mix); -} - -static void -gst_gl_mixer_reset_qos (GstGLMixer * mix) -{ - gst_gl_mixer_update_qos (mix, 0.5, 0, GST_CLOCK_TIME_NONE); - mix->qos_processed = mix->qos_dropped = 0; -} - -static void -gst_gl_mixer_read_qos (GstGLMixer * mix, gdouble * proportion, - GstClockTime * time) -{ - GST_OBJECT_LOCK (mix); - *proportion = mix->proportion; - *time = mix->earliest_time; - GST_OBJECT_UNLOCK (mix); -} static void gst_gl_mixer_set_context (GstElement * element, GstContext * context) @@ -1035,13 +484,13 @@ gst_gl_mixer_activate (GstGLMixer * mix, gboolean active) } static gboolean -gst_gl_mixer_src_activate_mode (GstPad * pad, GstObject * parent, - GstPadMode mode, gboolean active) +gst_gl_mixer_src_activate_mode (GstAggregator * aggregator, GstPadMode mode, + gboolean active) { - gboolean result = FALSE; GstGLMixer *mix; + gboolean result = FALSE; - mix = GST_GL_MIXER (parent); + mix = GST_GL_MIXER (aggregator); switch (mode) { case GST_PAD_MODE_PUSH: @@ -1056,10 +505,44 @@ gst_gl_mixer_src_activate_mode (GstPad * pad, GstObject * parent, } static gboolean -gst_gl_mixer_src_query (GstPad * pad, GstObject * parent, GstQuery * query) +gst_gl_mixer_query_caps (GstPad * pad, GstAggregator * agg, GstQuery * query) +{ + GstCaps *filter, *caps; + GstStructure *s; + gint n; + + GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg); + + gst_query_parse_caps (query, &filter); + + if (GST_VIDEO_INFO_FORMAT (&vagg->info) != GST_VIDEO_FORMAT_UNKNOWN) { + caps = gst_video_info_to_caps (&vagg->info); + } else { + caps = gst_pad_get_pad_template_caps (agg->srcpad); + } + + caps = gst_caps_make_writable (caps); + + n = gst_caps_get_size (caps) - 1; + for (; n >= 0; n--) { + s = gst_caps_get_structure (caps, n); + gst_structure_set (s, "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, + "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL); + if (GST_VIDEO_INFO_FPS_D (&vagg->info) != 0) { + gst_structure_set (s, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); + } + } + gst_query_set_caps_result (query, caps); + + return TRUE; +} + +static gboolean +gst_gl_mixer_src_query (GstAggregator * agg, GstQuery * query) { - GstGLMixer *mix = GST_GL_MIXER (parent); gboolean res = FALSE; + GstGLMixer *mix = GST_GL_MIXER (agg); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_CONTEXT: @@ -1068,43 +551,35 @@ gst_gl_mixer_src_query (GstPad * pad, GstObject * parent, GstQuery * query) &mix->display); break; } - case GST_QUERY_POSITION: - { - GstFormat format; - - gst_query_parse_position (query, &format, NULL); - - switch (format) { - case GST_FORMAT_TIME: - gst_query_set_position (query, format, - gst_segment_to_stream_time (&mix->segment, GST_FORMAT_TIME, - mix->segment.position)); - res = TRUE; - break; - default: - break; - } - break; - } - case GST_QUERY_DURATION: - res = gst_gl_mixer_query_duration (mix, query); - break; - case GST_QUERY_LATENCY: - res = gst_gl_mixer_query_latency (mix, query); - break; case GST_QUERY_CAPS: - res = gst_gl_mixer_query_caps (pad, parent, query); + res = gst_gl_mixer_query_caps (agg->srcpad, agg, query); break; default: - /* FIXME, needs a custom query handler because we have multiple - * sinkpads, send to the master pad until then */ - res = FALSE; + res = GST_AGGREGATOR_CLASS (parent_class)->src_query (agg, query); break; } return res; } +static GstFlowReturn +gst_gl_mixer_get_output_buffer (GstVideoAggregator * videoaggregator, + GstBuffer ** outbuf) +{ + GstGLMixer *mix = GST_GL_MIXER (videoaggregator); + + if (!mix->priv->pool_active) { + if (!gst_buffer_pool_set_active (mix->priv->pool, TRUE)) { + GST_ELEMENT_ERROR (mix, RESOURCE, SETTINGS, + ("failed to activate bufferpool"), ("failed to activate bufferpool")); + return GST_FLOW_ERROR; + } + mix->priv->pool_active = TRUE; + } + + return gst_buffer_pool_acquire_buffer (mix->priv->pool, outbuf, NULL); +} + static gboolean gst_gl_mixer_decide_allocation (GstGLMixer * mix, GstQuery * query) { @@ -1118,6 +593,7 @@ gst_gl_mixer_decide_allocation (GstGLMixer * mix, GstQuery * query) guint idx; guint out_width, out_height; GstGLContext *other_context = NULL; + GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix); gst_query_parse_allocation (query, &caps, NULL); @@ -1182,8 +658,8 @@ gst_gl_mixer_decide_allocation (GstGLMixer * mix, GstQuery * query) goto context_error; } - out_width = GST_VIDEO_INFO_WIDTH (&mix->out_info); - out_height = GST_VIDEO_INFO_HEIGHT (&mix->out_info); + out_width = GST_VIDEO_INFO_WIDTH (&vagg->info); + out_height = GST_VIDEO_INFO_HEIGHT (&vagg->info); if (!gst_gl_context_gen_fbo (mix->context, out_width, out_height, &mix->fbo, &mix->depthbuffer)) @@ -1276,11 +752,12 @@ gst_gl_mixer_do_bufferpool (GstGLMixer * mix, GstCaps * outcaps) GstBufferPool *pool = NULL; GstAllocator *allocator; GstAllocationParams params; + GstAggregator *agg = GST_AGGREGATOR (mix); /* find a pool for the negotiated caps now */ GST_DEBUG_OBJECT (mix, "doing allocation query"); query = gst_query_new_allocation (outcaps, TRUE); - if (!gst_pad_peer_query (mix->srcpad, query)) { + if (!gst_pad_peer_query (agg->srcpad, query)) { /* not a problem, just debug a little */ GST_DEBUG_OBJECT (mix, "peer ALLOCATION query failed"); } @@ -1321,354 +798,23 @@ no_decide_allocation: } } -static gboolean -gst_gl_mixer_src_setcaps (GstPad * pad, GstGLMixer * mix, GstCaps * caps) -{ - GstGLMixerPrivate *priv = mix->priv; - GstVideoInfo info; - gboolean ret = TRUE; - - GST_INFO_OBJECT (mix, "set src caps: %" GST_PTR_FORMAT, caps); - - if (!gst_video_info_from_caps (&info, caps)) { - ret = FALSE; - goto done; - } - - GST_GL_MIXER_LOCK (mix); - - if (GST_VIDEO_INFO_FPS_N (&mix->out_info) != GST_VIDEO_INFO_FPS_N (&info) || - GST_VIDEO_INFO_FPS_D (&mix->out_info) != GST_VIDEO_INFO_FPS_D (&info)) { - if (mix->segment.position != -1) { - mix->ts_offset = mix->segment.position - mix->segment.start; - mix->nframes = 0; - } - gst_gl_mixer_reset_qos (mix); - } - - mix->out_info = info; - - if (mix->current_caps == NULL || - gst_caps_is_equal (caps, mix->current_caps) == FALSE) { - gst_caps_replace (&mix->current_caps, caps); - mix->send_caps = TRUE; - } - - GST_GL_MIXER_UNLOCK (mix); - - ret = gst_gl_mixer_do_bufferpool (mix, caps); - -done: - priv->negotiated = ret; - - return ret; -} - -/** - * gst_gl_mixer_set_pad_type: - * @mix: a #GstGLMixer - * @pad_type: a #GstPad type subclass - * - * Set the pad type that will be created in the request_new_pad vfunc. - * - * Intended only for derived classes of #GstGLMixer. - */ -void -gst_gl_mixer_set_pad_type (GstGLMixer * mix, GType pad_type) -{ - g_return_if_fail (GST_IS_GL_MIXER (mix)); - g_return_if_fail (g_type_is_a (pad_type, GST_TYPE_GL_MIXER_PAD)); - - GST_GL_MIXER_LOCK (mix); - mix->pad_type = pad_type; - GST_GL_MIXER_UNLOCK (mix); -} - -static GstPad * -gst_gl_mixer_request_new_pad (GstElement * element, - GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps) -{ - GstGLMixer *mix; - GstGLMixerPad *mixpad; - GstElementClass *klass = GST_ELEMENT_GET_CLASS (element); - gint serial = 0; - gchar *name = NULL; - GstGLMixerCollect *mixcol = NULL; - - mix = GST_GL_MIXER (element); - - if (templ != gst_element_class_get_pad_template (klass, "sink_%d")) - return NULL; - - GST_GL_MIXER_LOCK (mix); - if (req_name == NULL || strlen (req_name) < 6 - || !g_str_has_prefix (req_name, "sink_")) { - /* no name given when requesting the pad, use next available int */ - serial = mix->next_sinkpad++; - } else { - /* parse serial number from requested padname */ - serial = g_ascii_strtoull (&req_name[5], NULL, 10); - if (serial >= mix->next_sinkpad) - mix->next_sinkpad = serial + 1; - } - /* create new pad with the name */ - name = g_strdup_printf ("sink_%d", serial); - mixpad = g_object_new (mix->pad_type, "name", name, "direction", - templ->direction, "template", templ, NULL); - g_free (name); - - mixcol = (GstGLMixerCollect *) - gst_collect_pads_add_pad (mix->collect, GST_PAD (mixpad), - sizeof (GstGLMixerCollect), - (GstCollectDataDestroyNotify) gst_gl_mixer_collect_free, TRUE); - - /* Keep track of each other */ - mixcol->mixpad = mixpad; - mixpad->mixcol = mixcol; - - mixcol->start_time = -1; - mixcol->end_time = -1; - - /* Keep an internal list of mixpads for zordering */ - mix->sinkpads = g_slist_append (mix->sinkpads, mixpad); - mix->numpads++; - - g_ptr_array_set_size (mix->array_buffers, mix->numpads); - g_ptr_array_set_size (mix->frames, mix->numpads); - - mix->frames->pdata[mix->numpads - 1] = g_slice_new0 (GstGLMixerFrameData); - - GST_GL_MIXER_UNLOCK (mix); - - /* add the pad to the element */ - GST_DEBUG_OBJECT (element, "Adding pad %s", GST_PAD_NAME (mixpad)); - gst_element_add_pad (element, GST_PAD (mixpad)); - gst_child_proxy_child_added (GST_CHILD_PROXY (mix), G_OBJECT (mixpad), - GST_OBJECT_NAME (mixpad)); - - return GST_PAD (mixpad); -} - -static void -gst_gl_mixer_release_pad (GstElement * element, GstPad * pad) -{ - GstGLMixer *mix; - GstGLMixerPad *mixpad; - gboolean update_caps; - - mix = GST_GL_MIXER (element); - - GST_GL_MIXER_LOCK (mix); - if (G_UNLIKELY (g_slist_find (mix->sinkpads, pad) == NULL)) { - g_warning ("Unknown pad %s", GST_PAD_NAME (pad)); - goto error; - } - - mixpad = GST_GL_MIXER_PAD (pad); - - mix->sinkpads = g_slist_remove (mix->sinkpads, pad); - gst_child_proxy_child_removed (GST_CHILD_PROXY (mix), G_OBJECT (mixpad), - GST_OBJECT_NAME (mixpad)); - mix->numpads--; - - g_ptr_array_set_size (mix->array_buffers, mix->numpads); - g_ptr_array_set_size (mix->frames, mix->numpads); - - update_caps = - GST_VIDEO_INFO_FORMAT (&mix->out_info) != GST_VIDEO_FORMAT_UNKNOWN; - GST_GL_MIXER_UNLOCK (mix); - - gst_collect_pads_remove_pad (mix->collect, pad); - - if (update_caps) - gst_gl_mixer_update_src_caps (mix); - - gst_element_remove_pad (element, pad); - return; -error: - GST_GL_MIXER_UNLOCK (mix); -} - -/* try to get a buffer on all pads. As long as the queued value is - * negative, we skip buffers */ -static gint -gst_gl_mixer_fill_queues (GstGLMixer * mix, - GstClockTime output_start_time, GstClockTime output_end_time) -{ - GSList *l; - gboolean eos = TRUE; - gboolean need_more_data = FALSE; - - for (l = mix->sinkpads; l; l = l->next) { - GstGLMixerPad *pad = l->data; - GstGLMixerCollect *mixcol = pad->mixcol; - GstSegment *segment = &pad->mixcol->collect.segment; - GstBuffer *buf; - - buf = gst_collect_pads_peek (mix->collect, &mixcol->collect); - if (buf) { - GstClockTime start_time, end_time; - - start_time = GST_BUFFER_TIMESTAMP (buf); - if (start_time == -1) { - gst_buffer_unref (buf); - GST_ERROR_OBJECT (pad, "Need timestamped buffers!"); - return -2; - } - - /* FIXME: Make all this work with negative rates */ - - if ((mixcol->buffer && start_time < GST_BUFFER_TIMESTAMP (mixcol->buffer)) - || (mixcol->queued - && start_time < GST_BUFFER_TIMESTAMP (mixcol->queued))) { - GST_WARNING_OBJECT (pad, "Buffer from the past, dropping"); - gst_buffer_unref (buf); - buf = gst_collect_pads_pop (mix->collect, &mixcol->collect); - gst_buffer_unref (buf); - need_more_data = TRUE; - continue; - } - - if (mixcol->queued) { - end_time = start_time - GST_BUFFER_TIMESTAMP (mixcol->queued); - start_time = GST_BUFFER_TIMESTAMP (mixcol->queued); - gst_buffer_unref (buf); - buf = gst_buffer_ref (mixcol->queued); - } else { - end_time = GST_BUFFER_DURATION (buf); - - if (end_time == -1) { - mixcol->queued = buf; - need_more_data = TRUE; - continue; - } - } - - g_assert (start_time != -1 && end_time != -1); - end_time += start_time; /* convert from duration to position */ - - if (mixcol->end_time != -1 && mixcol->end_time > end_time) { - GST_WARNING_OBJECT (pad, "Buffer from the past, dropping"); - if (buf == mixcol->queued) { - gst_buffer_unref (buf); - gst_buffer_replace (&mixcol->queued, NULL); - } else { - gst_buffer_unref (buf); - buf = gst_collect_pads_pop (mix->collect, &mixcol->collect); - gst_buffer_unref (buf); - } - - need_more_data = TRUE; - continue; - } - - /* Check if it's inside the segment */ - if (start_time >= segment->stop || end_time < segment->start) { - GST_DEBUG_OBJECT (pad, "Buffer outside the segment"); - - if (buf == mixcol->queued) { - gst_buffer_unref (buf); - gst_buffer_replace (&mixcol->queued, NULL); - } else { - gst_buffer_unref (buf); - buf = gst_collect_pads_pop (mix->collect, &mixcol->collect); - gst_buffer_unref (buf); - } - - need_more_data = TRUE; - continue; - } - - /* Clip to segment and convert to running time */ - start_time = MAX (start_time, segment->start); - if (segment->stop != -1) - end_time = MIN (end_time, segment->stop); - start_time = - gst_segment_to_running_time (segment, GST_FORMAT_TIME, start_time); - end_time = - gst_segment_to_running_time (segment, GST_FORMAT_TIME, end_time); - g_assert (start_time != -1 && end_time != -1); - - /* Convert to the output segment rate */ - if (ABS (mix->segment.rate) != 1.0) { - start_time *= ABS (mix->segment.rate); - end_time *= ABS (mix->segment.rate); - } - - if (end_time >= output_start_time && start_time < output_end_time) { - GST_DEBUG_OBJECT (pad, - "Taking new buffer with start time %" GST_TIME_FORMAT, - GST_TIME_ARGS (start_time)); - gst_buffer_replace (&mixcol->buffer, buf); - mixcol->start_time = start_time; - mixcol->end_time = end_time; - - if (buf == mixcol->queued) { - gst_buffer_unref (buf); - gst_buffer_replace (&mixcol->queued, NULL); - } else { - gst_buffer_unref (buf); - buf = gst_collect_pads_pop (mix->collect, &mixcol->collect); - gst_buffer_unref (buf); - } - eos = FALSE; - } else if (start_time >= output_end_time) { - GST_DEBUG_OBJECT (pad, "Keeping buffer until %" GST_TIME_FORMAT, - GST_TIME_ARGS (start_time)); - gst_buffer_unref (buf); - eos = FALSE; - } else { - GST_DEBUG_OBJECT (pad, "Too old buffer -- dropping"); - if (buf == mixcol->queued) { - gst_buffer_unref (buf); - gst_buffer_replace (&mixcol->queued, NULL); - } else { - gst_buffer_unref (buf); - buf = gst_collect_pads_pop (mix->collect, &mixcol->collect); - gst_buffer_unref (buf); - } - - need_more_data = TRUE; - continue; - } - } else { - if (mixcol->end_time != -1) { - if (mixcol->end_time <= output_start_time) { - gst_buffer_replace (&mixcol->buffer, NULL); - mixcol->start_time = mixcol->end_time = -1; - if (!GST_COLLECT_PADS_STATE_IS_SET (mixcol, - GST_COLLECT_PADS_STATE_EOS)) - need_more_data = TRUE; - } else { - eos = FALSE; - } - } - } - } - - if (need_more_data) - return 0; - if (eos) - return -1; - - return 1; -} - gboolean gst_gl_mixer_process_textures (GstGLMixer * mix, GstBuffer * outbuf) { - GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix); - GSList *walk = mix->sinkpads; + guint i; + GList *walk; + guint out_tex; + gboolean res = TRUE; + guint array_index = 0; GstVideoFrame out_frame; gboolean out_gl_wrapped = FALSE; - guint out_tex; - guint array_index = 0; - guint i; - gboolean res = TRUE; + GstElement *element = GST_ELEMENT (mix); + GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix); + GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix); GST_TRACE ("Processing buffers"); - if (!gst_video_frame_map (&out_frame, &mix->out_info, outbuf, + if (!gst_video_frame_map (&out_frame, &vagg->info, outbuf, GST_MAP_WRITE | GST_MAP_GL)) { return FALSE; } @@ -1688,42 +834,35 @@ gst_gl_mixer_process_textures (GstGLMixer * mix, GstBuffer * outbuf) out_gl_wrapped = TRUE; } - while (walk) { /* We walk with this list because it's ordered */ + GST_OBJECT_LOCK (mix); + walk = element->sinkpads; + + i = mix->frames->len; + g_ptr_array_set_size (mix->frames, element->numsinkpads); + for (; i < element->numsinkpads; i++) + mix->frames->pdata[i] = g_slice_new0 (GstGLMixerFrameData); + while (walk) { GstGLMixerPad *pad = GST_GL_MIXER_PAD (walk->data); - GstGLMixerCollect *mixcol = pad->mixcol; + GstVideoAggregatorPad *vaggpad = walk->data; GstGLMixerFrameData *frame; frame = g_ptr_array_index (mix->frames, array_index); frame->pad = pad; frame->texture = 0; - walk = g_slist_next (walk); + walk = g_list_next (walk); - if (mixcol->buffer != NULL) { - GstClockTime timestamp; - gint64 stream_time; - GstSegment *seg; + if (vaggpad->buffer != NULL) { guint in_tex; - seg = &mixcol->collect.segment; - - timestamp = GST_BUFFER_TIMESTAMP (mixcol->buffer); - - stream_time = - gst_segment_to_stream_time (seg, GST_FORMAT_TIME, timestamp); - - /* sync object properties on stream time */ - if (GST_CLOCK_TIME_IS_VALID (stream_time)) - gst_object_sync_values (GST_OBJECT (pad), stream_time); - if (!pad->upload) { pad->upload = gst_gl_upload_new (mix->context); - gst_gl_upload_set_format (pad->upload, &pad->in_info); + gst_gl_upload_set_format (pad->upload, &vaggpad->info); } - if (!gst_gl_upload_perform_with_buffer (pad->upload, mixcol->buffer, - &in_tex)) { + if (!gst_gl_upload_perform_with_buffer (pad->upload, + vaggpad->buffer, &in_tex)) { ++array_index; pad->mapped = FALSE; continue; @@ -1749,7 +888,7 @@ gst_gl_mixer_process_textures (GstGLMixer * mix, GstBuffer * outbuf) out: i = 0; - walk = mix->sinkpads; + walk = GST_ELEMENT (mix)->sinkpads; while (walk) { GstGLMixerPad *pad = GST_GL_MIXER_PAD (walk->data); @@ -1757,548 +896,61 @@ out: gst_gl_upload_release_buffer (pad->upload); pad->mapped = FALSE; - walk = g_slist_next (walk); + walk = g_list_next (walk); i++; } + GST_OBJECT_UNLOCK (mix); gst_video_frame_unmap (&out_frame); return res; } -static void +static gboolean gst_gl_mixer_process_buffers (GstGLMixer * mix, GstBuffer * outbuf) { + GList *walk; + guint i, array_index = 0; + GstElement *element = GST_ELEMENT (mix); GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix); - GSList *walk = mix->sinkpads; - guint array_index = 0; + GST_OBJECT_LOCK (mix); + walk = GST_ELEMENT (mix)->sinkpads; + i = mix->frames->len; + g_ptr_array_set_size (mix->frames, element->numsinkpads); + for (; i < element->numsinkpads; i++) + mix->frames->pdata[i] = g_slice_new0 (GstGLMixerFrameData); while (walk) { /* We walk with this list because it's ordered */ - GstGLMixerPad *pad = GST_GL_MIXER_PAD (walk->data); - GstGLMixerCollect *mixcol = pad->mixcol; + GstVideoAggregatorPad *vaggpad = walk->data; - walk = g_slist_next (walk); - - if (mixcol->buffer != NULL) { - GstClockTime timestamp; - gint64 stream_time; - GstSegment *seg; - - seg = &mixcol->collect.segment; - - timestamp = GST_BUFFER_TIMESTAMP (mixcol->buffer); - - stream_time = - gst_segment_to_stream_time (seg, GST_FORMAT_TIME, timestamp); - - /* sync object properties on stream time */ - if (GST_CLOCK_TIME_IS_VALID (stream_time)) - gst_object_sync_values (GST_OBJECT (pad), stream_time); + walk = g_list_next (walk); + if (vaggpad->buffer != NULL) { /* put buffer into array */ - mix->array_buffers->pdata[array_index] = mixcol->buffer; + mix->array_buffers->pdata[array_index] = vaggpad->buffer; } ++array_index; } + GST_OBJECT_UNLOCK (mix); - mix_class->process_buffers (mix, mix->array_buffers, outbuf); + return mix_class->process_buffers (mix, mix->array_buffers, outbuf); } -/* Perform qos calculations before processing the next frame. Returns TRUE if - * the frame should be processed, FALSE if the frame can be dropped entirely */ -static gint64 -gst_gl_mixer_do_qos (GstGLMixer * mix, GstClockTime timestamp) -{ - GstClockTime qostime, earliest_time; - gdouble proportion; - gint64 jitter; - /* no timestamp, can't do QoS => process frame */ - if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) { - GST_LOG_OBJECT (mix, "invalid timestamp, can't do QoS, process frame"); - return -1; - } - - /* get latest QoS observation values */ - gst_gl_mixer_read_qos (mix, &proportion, &earliest_time); - - /* skip qos if we have no observation (yet) => process frame */ - if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) { - GST_LOG_OBJECT (mix, "no observation yet, process frame"); - return -1; - } - - /* qos is done on running time */ - qostime = - gst_segment_to_running_time (&mix->segment, GST_FORMAT_TIME, timestamp); - - /* see how our next timestamp relates to the latest qos timestamp */ - GST_LOG_OBJECT (mix, "qostime %" GST_TIME_FORMAT ", earliest %" - GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time)); - - jitter = GST_CLOCK_DIFF (qostime, earliest_time); - if (qostime != GST_CLOCK_TIME_NONE && jitter > 0) { - GST_DEBUG_OBJECT (mix, "we are late, drop frame"); - return jitter; - } - - GST_LOG_OBJECT (mix, "process frame"); - return jitter; -} static GstFlowReturn -gst_gl_mixer_collected (GstCollectPads * pads, GstGLMixer * mix) +gst_gl_mixer_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf) { - GstGLMixerClass *mix_class; - GstFlowReturn ret; - GstClockTime output_start_time, output_end_time; - GstBuffer *outbuf = NULL; - gint res; - gint64 jitter; + gboolean res = FALSE; + GstGLMixer *mix = GST_GL_MIXER (vagg); + GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (vagg); - g_return_val_if_fail (GST_IS_GL_MIXER (mix), GST_FLOW_ERROR); + if (mix_class->process_buffers) + res = gst_gl_mixer_process_buffers (mix, outbuf); + else if (mix_class->process_textures) + res = gst_gl_mixer_process_textures (mix, outbuf); - mix_class = GST_GL_MIXER_GET_CLASS (mix); - - /* If we're not negotiated yet... */ - if (GST_VIDEO_INFO_FORMAT (&mix->out_info) == GST_VIDEO_FORMAT_UNKNOWN) { - GST_ELEMENT_ERROR (mix, CORE, NEGOTIATION, ("not negotiated"), (NULL)); - return GST_FLOW_NOT_NEGOTIATED; - } - - if (g_atomic_int_compare_and_exchange (&mix->flush_stop_pending, TRUE, FALSE)) { - GST_DEBUG_OBJECT (mix, "pending flush stop"); - gst_pad_push_event (mix->srcpad, gst_event_new_flush_stop (TRUE)); - } - - if (mix->send_stream_start) { - gchar s_id[32]; - - /* stream-start (FIXME: create id based on input ids) */ - g_snprintf (s_id, sizeof (s_id), "mix-%08x", g_random_int ()); - if (!gst_pad_push_event (mix->srcpad, gst_event_new_stream_start (s_id))) { - GST_WARNING_OBJECT (mix->srcpad, "Sending stream start event failed"); - } - mix->send_stream_start = FALSE; - } - - if (gst_pad_check_reconfigure (mix->srcpad)) - gst_gl_mixer_update_src_caps (mix); - - if (mix->send_caps) { - if (!gst_pad_push_event (mix->srcpad, - gst_event_new_caps (mix->current_caps))) { - GST_WARNING_OBJECT (mix->srcpad, "Sending caps event failed"); - } - mix->send_caps = FALSE; - } - - GST_GL_MIXER_LOCK (mix); - - if (mix->newseg_pending) { - GST_DEBUG_OBJECT (mix, "Sending NEWSEGMENT event"); - if (!gst_pad_push_event (mix->srcpad, - gst_event_new_segment (&mix->segment))) { - ret = GST_FLOW_ERROR; - goto error; - } - mix->newseg_pending = FALSE; - } - - if (mix->segment.position == -1) - output_start_time = mix->segment.start; - else - output_start_time = mix->segment.position; - - if (output_start_time >= mix->segment.stop) { - GST_DEBUG_OBJECT (mix, "Segment done"); - gst_pad_push_event (mix->srcpad, gst_event_new_eos ()); - ret = GST_FLOW_EOS; - goto error; - } - - output_end_time = - mix->ts_offset + gst_util_uint64_scale (mix->nframes + 1, - GST_SECOND * GST_VIDEO_INFO_FPS_D (&mix->out_info), - GST_VIDEO_INFO_FPS_N (&mix->out_info)); - if (mix->segment.stop != -1) - output_end_time = MIN (output_end_time, mix->segment.stop); - - GST_LOG ("got output times start:%" GST_TIME_FORMAT " end:%" GST_TIME_FORMAT, - GST_TIME_ARGS (output_start_time), GST_TIME_ARGS (output_end_time)); - - res = gst_gl_mixer_fill_queues (mix, output_start_time, output_end_time); - - if (res == 0) { - GST_DEBUG_OBJECT (mix, "Need more data for decisions"); - ret = GST_FLOW_OK; - goto error; - } else if (res == -1) { - GST_DEBUG_OBJECT (mix, "All sinkpads are EOS -- forwarding"); - gst_pad_push_event (mix->srcpad, gst_event_new_eos ()); - ret = GST_FLOW_EOS; - goto error; - } else if (res == -2) { - GST_ERROR_OBJECT (mix, "Error collecting buffers"); - ret = GST_FLOW_ERROR; - goto error; - } - - jitter = gst_gl_mixer_do_qos (mix, output_start_time); - if (jitter <= 0) { - - if (!mix->priv->pool_active) { - if (!gst_buffer_pool_set_active (mix->priv->pool, TRUE)) { - GST_ELEMENT_ERROR (mix, RESOURCE, SETTINGS, - ("failed to activate bufferpool"), - ("failed to activate bufferpool")); - ret = GST_FLOW_ERROR; - goto error; - } - mix->priv->pool_active = TRUE; - } - - ret = gst_buffer_pool_acquire_buffer (mix->priv->pool, &outbuf, NULL); - if (ret != GST_FLOW_OK) - goto error; - - GST_BUFFER_TIMESTAMP (outbuf) = output_start_time; - GST_BUFFER_DURATION (outbuf) = output_end_time - output_start_time; - - if (!mix_class->process_buffers && !mix_class->process_textures) { - ret = GST_FLOW_ERROR; - g_assert_not_reached (); - goto error; - } - - if (mix_class->process_buffers) - gst_gl_mixer_process_buffers (mix, outbuf); - else if (mix_class->process_textures) - gst_gl_mixer_process_textures (mix, outbuf); - - mix->qos_processed++; - } else { - GstMessage *msg; - - mix->qos_dropped++; - - /* TODO: live */ - msg = - gst_message_new_qos (GST_OBJECT_CAST (mix), FALSE, - gst_segment_to_running_time (&mix->segment, GST_FORMAT_TIME, - output_start_time), gst_segment_to_stream_time (&mix->segment, - GST_FORMAT_TIME, output_start_time), output_start_time, - output_end_time - output_start_time); - gst_message_set_qos_values (msg, jitter, mix->proportion, 1000000); - gst_message_set_qos_stats (msg, GST_FORMAT_BUFFERS, mix->qos_processed, - mix->qos_dropped); - gst_element_post_message (GST_ELEMENT_CAST (mix), msg); - - ret = GST_FLOW_OK; - } - - mix->segment.position = output_end_time; - mix->nframes++; - - GST_GL_MIXER_UNLOCK (mix); - if (outbuf) { - GST_LOG_OBJECT (mix, - "Pushing buffer with ts %" GST_TIME_FORMAT " and duration %" - GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf))); - ret = gst_pad_push (mix->srcpad, outbuf); - } - -done: - return ret; - - /* ERRORS */ -error: - { - GST_GL_MIXER_UNLOCK (mix); - goto done; - } -} - -static gboolean -forward_event_func (GValue * item, GValue * ret, GstEvent * event) -{ - GstPad *pad = g_value_get_object (item); - gst_event_ref (event); - GST_LOG_OBJECT (pad, "About to send event %s", GST_EVENT_TYPE_NAME (event)); - if (!gst_pad_push_event (pad, event)) { - g_value_set_boolean (ret, FALSE); - GST_WARNING_OBJECT (pad, "Sending event %p (%s) failed.", - event, GST_EVENT_TYPE_NAME (event)); - } else { - GST_LOG_OBJECT (pad, "Sent event %p (%s).", - event, GST_EVENT_TYPE_NAME (event)); - } - return TRUE; -} - -/* forwards the event to all sinkpads, takes ownership of the - * event - * - * Returns: TRUE if the event could be forwarded on all - * sinkpads. - */ -static gboolean -gst_gl_mixer_push_sink_event (GstGLMixer * mix, GstEvent * event) -{ - GstIterator *it; - GValue vret = { 0 }; - - GST_LOG_OBJECT (mix, "Forwarding event %p (%s)", event, - GST_EVENT_TYPE_NAME (event)); - - g_value_init (&vret, G_TYPE_BOOLEAN); - g_value_set_boolean (&vret, TRUE); - it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (mix)); - gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func, &vret, - event); - gst_iterator_free (it); - gst_event_unref (event); - - return g_value_get_boolean (&vret); -} - -static GstFlowReturn -gst_gl_mixer_sink_clip (GstCollectPads * pads, - GstCollectData * data, GstBuffer * buf, GstBuffer ** outbuf, - GstGLMixer * mix) -{ - GstGLMixerPad *pad = GST_GL_MIXER_PAD (data->pad); - GstGLMixerCollect *mixcol = pad->mixcol; - GstClockTime start_time, end_time; - - start_time = GST_BUFFER_TIMESTAMP (buf); - if (start_time == -1) { - GST_ERROR_OBJECT (pad, "Timestamped buffers required!"); - gst_buffer_unref (buf); - return GST_FLOW_ERROR; - } - - end_time = GST_BUFFER_DURATION (buf); - if (end_time == -1) - end_time = - gst_util_uint64_scale_int (GST_SECOND, - GST_VIDEO_INFO_FPS_D (&pad->in_info), - GST_VIDEO_INFO_FPS_N (&pad->in_info)); - if (end_time == -1) { - *outbuf = buf; - return GST_FLOW_OK; - } - - start_time = MAX (start_time, mixcol->collect.segment.start); - start_time = - gst_segment_to_running_time (&mixcol->collect.segment, - GST_FORMAT_TIME, start_time); - - end_time += GST_BUFFER_TIMESTAMP (buf); - if (mixcol->collect.segment.stop != -1) - end_time = MIN (end_time, mixcol->collect.segment.stop); - end_time = - gst_segment_to_running_time (&mixcol->collect.segment, - GST_FORMAT_TIME, end_time); - - /* Convert to the output segment rate */ - if (ABS (mix->segment.rate) != 1.0) { - start_time *= ABS (mix->segment.rate); - end_time *= ABS (mix->segment.rate); - } - - if (mixcol->buffer != NULL && end_time < mixcol->end_time) { - gst_buffer_unref (buf); - *outbuf = NULL; - return GST_FLOW_OK; - } - - *outbuf = buf; - return GST_FLOW_OK; -} - -static gboolean -gst_gl_mixer_src_event (GstPad * pad, GstObject * parent, GstEvent * event) -{ - GstGLMixer *mix = GST_GL_MIXER (parent); - gboolean result; - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_QOS: - { - GstQOSType type; - GstClockTimeDiff diff; - GstClockTime timestamp; - gdouble proportion; - - gst_event_parse_qos (event, &type, &proportion, &diff, ×tamp); - - gst_gl_mixer_update_qos (mix, proportion, diff, timestamp); - - result = gst_gl_mixer_push_sink_event (mix, event); - break; - } - case GST_EVENT_SEEK: - { - gdouble rate; - GstFormat fmt; - GstSeekFlags flags; - GstSeekType start_type, stop_type; - gint64 start, stop; - GSList *l; - gdouble abs_rate; - - /* parse the seek parameters */ - gst_event_parse_seek (event, &rate, &fmt, &flags, &start_type, - &start, &stop_type, &stop); - - if (rate <= 0.0) { - GST_ERROR_OBJECT (mix, "Negative rates not supported yet"); - result = FALSE; - gst_event_unref (event); - break; - } - - GST_DEBUG_OBJECT (mix, "Handling SEEK event"); - - /* check if we are flushing */ - if (flags & GST_SEEK_FLAG_FLUSH) { - /* flushing seek, start flush downstream, the flush will be done - * when all pads received a FLUSH_STOP. */ - gst_pad_push_event (mix->srcpad, gst_event_new_flush_start ()); - - /* make sure we accept nothing anymore and return WRONG_STATE */ - gst_collect_pads_set_flushing (mix->collect, TRUE); - } - - /* now wait for the collected to be finished and mark a new - * segment */ - GST_COLLECT_PADS_STREAM_LOCK (mix->collect); - - abs_rate = ABS (rate); - - GST_GL_MIXER_LOCK (mix); - for (l = mix->sinkpads; l; l = l->next) { - GstGLMixerPad *p = l->data; - - if (flags & GST_SEEK_FLAG_FLUSH) { - gst_buffer_replace (&p->mixcol->buffer, NULL); - p->mixcol->start_time = p->mixcol->end_time = -1; - continue; - } - - /* Convert to the output segment rate */ - if (ABS (mix->segment.rate) != abs_rate) { - if (ABS (mix->segment.rate) != 1.0 && p->mixcol->buffer) { - p->mixcol->start_time /= ABS (mix->segment.rate); - p->mixcol->end_time /= ABS (mix->segment.rate); - } - if (abs_rate != 1.0 && p->mixcol->buffer) { - p->mixcol->start_time *= abs_rate; - p->mixcol->end_time *= abs_rate; - } - } - } - GST_GL_MIXER_UNLOCK (mix); - - gst_segment_do_seek (&mix->segment, rate, fmt, flags, start_type, start, - stop_type, stop, NULL); - mix->segment.position = -1; - mix->ts_offset = 0; - mix->nframes = 0; - mix->newseg_pending = TRUE; - - if (flags & GST_SEEK_FLAG_FLUSH) { - gst_collect_pads_set_flushing (mix->collect, FALSE); - - /* we can't send FLUSH_STOP here since upstream could start pushing data - * after we unlock mix->collect. - * We set flush_stop_pending to TRUE instead and send FLUSH_STOP after - * forwarding the seek upstream or from gst_gl_mixer_collected, - * whichever happens first. - */ - mix->flush_stop_pending = TRUE; - } - - GST_COLLECT_PADS_STREAM_UNLOCK (mix->collect); - - gst_gl_mixer_reset_qos (mix); - - result = gst_gl_mixer_push_sink_event (mix, event); - - if (g_atomic_int_compare_and_exchange (&mix->flush_stop_pending, TRUE, - FALSE)) { - GST_DEBUG_OBJECT (mix, "pending flush stop"); - gst_pad_push_event (mix->srcpad, gst_event_new_flush_stop (TRUE)); - } - - break; - } - case GST_EVENT_NAVIGATION: - /* navigation is rather pointless. */ - result = FALSE; - gst_event_unref (event); - break; - default: - /* just forward the rest for now */ - result = gst_gl_mixer_push_sink_event (mix, event); - break; - } - - return result; -} - -static gboolean -gst_gl_mixer_sink_event (GstCollectPads * pads, GstCollectData * cdata, - GstEvent * event, GstGLMixer * mix) -{ - GstGLMixerPad *pad = GST_GL_MIXER_PAD (cdata->pad); - gboolean ret = TRUE; - - GST_DEBUG_OBJECT (pad, "Got %s event on pad %s:%s", - GST_EVENT_TYPE_NAME (event), GST_DEBUG_PAD_NAME (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_CAPS: - { - GstCaps *caps; - - gst_event_parse_caps (event, &caps); - ret = - gst_gl_mixer_pad_sink_setcaps (GST_PAD (pad), GST_OBJECT (mix), caps); - gst_event_unref (event); - event = NULL; - break; - } - case GST_EVENT_SEGMENT:{ - GstSegment seg; - gst_event_copy_segment (event, &seg); - - g_assert (seg.format == GST_FORMAT_TIME); - break; - } - case GST_EVENT_FLUSH_STOP: - mix->newseg_pending = TRUE; - mix->flush_stop_pending = FALSE; - gst_gl_mixer_reset_qos (mix); - gst_buffer_replace (&pad->mixcol->buffer, NULL); - pad->mixcol->start_time = -1; - pad->mixcol->end_time = -1; - - gst_segment_init (&mix->segment, GST_FORMAT_TIME); - mix->segment.position = -1; - mix->ts_offset = 0; - mix->nframes = 0; - break; - default: - break; - } - - if (event != NULL) - return gst_collect_pads_event_default (pads, cdata, event, FALSE); - - return ret; + return res ? GST_FLOW_OK : GST_FLOW_ERROR; } static void @@ -2323,92 +975,101 @@ gst_gl_mixer_set_property (GObject * object, } } -static GstStateChangeReturn -gst_gl_mixer_change_state (GstElement * element, GstStateChange transition) +static gboolean +_clean_upload (GstAggregator * agg, GstPad * aggpad, gpointer udata) { - GstGLMixer *mix; - GstStateChangeReturn ret; - GstGLMixerClass *mixer_class; + GstGLMixerPad *pad = GST_GL_MIXER_PAD (aggpad); - g_return_val_if_fail (GST_IS_GL_MIXER (element), GST_STATE_CHANGE_FAILURE); - - mix = GST_GL_MIXER (element); - mixer_class = GST_GL_MIXER_GET_CLASS (mix); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - { - mix->send_stream_start = TRUE; - mix->send_caps = TRUE; - gst_caps_replace (&mix->current_caps, NULL); - GST_LOG_OBJECT (mix, "starting collectpads"); - gst_collect_pads_start (mix->collect); - break; - } - case GST_STATE_CHANGE_PAUSED_TO_READY: - { - GSList *walk = mix->sinkpads; - - GST_LOG_OBJECT (mix, "stopping collectpads"); - gst_collect_pads_stop (mix->collect); - - if (mixer_class->reset) - mixer_class->reset (mix); - if (mix->fbo) { - gst_gl_context_del_fbo (mix->context, mix->fbo, mix->depthbuffer); - mix->fbo = 0; - mix->depthbuffer = 0; - } - if (mix->download) { - gst_object_unref (mix->download); - mix->download = NULL; - } - - while (walk) { - GstGLMixerPad *pad = (GstGLMixerPad *) (walk->data); - - if (pad->upload) { - gst_object_unref (pad->upload); - pad->upload = NULL; - } - - walk = walk->next; - } - - if (mix->priv->query) { - gst_query_unref (mix->priv->query); - mix->priv->query = NULL; - } - - if (mix->priv->pool) { - gst_object_unref (mix->priv->pool); - mix->priv->pool = NULL; - } - - if (mix->display) { - gst_object_unref (mix->display); - mix->display = NULL; - } - - if (mix->context) { - gst_object_unref (mix->context); - mix->context = NULL; - } - break; - } - default: - break; + if (pad->upload) { + gst_object_unref (pad->upload); + pad->upload = NULL; } - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_gl_mixer_reset (mix); - break; - default: - break; - } - - return ret; + return TRUE; +} + +static void +_free_glmixer_frame_data (GstGLMixerFrameData * frame) +{ + g_slice_free1 (sizeof (GstGLMixerFrameData), frame); +} + +static gboolean +gst_gl_mixer_start (GstAggregator * agg) +{ + guint i; + GstGLMixer *mix = GST_GL_MIXER (agg); + GstElement *element = GST_ELEMENT (agg); + + if (!GST_AGGREGATOR_CLASS (parent_class)->start (agg)) + return FALSE; + + GST_OBJECT_LOCK (mix); + mix->array_buffers = g_ptr_array_new_full (element->numsinkpads, + (GDestroyNotify) _free_glmixer_frame_data); + mix->frames = g_ptr_array_new_full (element->numsinkpads, NULL); + + g_ptr_array_set_size (mix->array_buffers, element->numsinkpads); + g_ptr_array_set_size (mix->frames, element->numsinkpads); + + for (i = 0; i < element->numsinkpads; i++) + mix->frames->pdata[i] = g_slice_new0 (GstGLMixerFrameData); + + GST_OBJECT_UNLOCK (mix); + + return TRUE; +} + +static gboolean +gst_gl_mixer_stop (GstAggregator * agg) +{ + guint i; + GstGLMixer *mix = GST_GL_MIXER (agg); + GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix); + + if (!GST_AGGREGATOR_CLASS (parent_class)->stop (agg)) + return FALSE; + + GST_OBJECT_LOCK (agg); + for (i = 0; i < GST_ELEMENT (agg)->numsinkpads; i++) { + g_slice_free1 (sizeof (GstGLMixerFrameData), mix->frames->pdata[i]); + } + GST_OBJECT_UNLOCK (agg); + + if (mixer_class->reset) + mixer_class->reset (mix); + if (mix->fbo) { + gst_gl_context_del_fbo (mix->context, mix->fbo, mix->depthbuffer); + mix->fbo = 0; + mix->depthbuffer = 0; + } + if (mix->download) { + gst_object_unref (mix->download); + mix->download = NULL; + } + + gst_aggregator_iterate_sinkpads (GST_AGGREGATOR (mix), _clean_upload, NULL); + + if (mix->priv->query) { + gst_query_unref (mix->priv->query); + mix->priv->query = NULL; + } + + if (mix->priv->pool) { + gst_object_unref (mix->priv->pool); + mix->priv->pool = NULL; + } + + if (mix->display) { + gst_object_unref (mix->display); + mix->display = NULL; + } + + if (mix->context) { + gst_object_unref (mix->context); + mix->context = NULL; + } + gst_gl_mixer_reset (mix); + + return TRUE; } diff --git a/gst-libs/gst/gl/gstglmixer.h b/gst-libs/gst/gl/gstglmixer.h index 3716eb15fe..c056e6a86c 100644 --- a/gst-libs/gst/gl/gstglmixer.h +++ b/gst-libs/gst/gl/gstglmixer.h @@ -40,10 +40,6 @@ G_BEGIN_DECLS #define GST_GL_MIXER_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_GL_MIXER,GstGLMixerClass)) -#define GST_GL_MIXER_GET_LOCK(mix) (GST_GL_MIXER(mix)->lock) -#define GST_GL_MIXER_LOCK(mix) (g_mutex_lock(&GST_GL_MIXER_GET_LOCK (mix))) -#define GST_GL_MIXER_UNLOCK(mix) (g_mutex_unlock(&GST_GL_MIXER_GET_LOCK (mix))) - typedef struct _GstGLMixer GstGLMixer; typedef struct _GstGLMixerClass GstGLMixerClass; typedef struct _GstGLMixerPrivate GstGLMixerPrivate; @@ -59,57 +55,28 @@ typedef gboolean (*GstGLMixerProcessTextures) (GstGLMixer *mix, struct _GstGLMixer { - GstElement element; + GstVideoAggregator vaggregator; GstGLMixerPrivate *priv; - /* pad */ - GstPad *srcpad; - /* Lock to prevent the state to change while blending */ GMutex lock; - /* Sink pads using Collect Pads from core's base library */ - GstCollectPads *collect; - - /* sinkpads, a GSList of GstGLMixerPads */ - GSList *sinkpads; - gint numpads; - /* Next available sinkpad index */ - gint next_sinkpad; GPtrArray *array_buffers; GPtrArray *frames; - GstCaps *current_caps; - GstVideoInfo out_info; GLuint out_tex_id; GstGLDownload *download; - gboolean newseg_pending; - gboolean flush_stop_pending; - gboolean send_stream_start; - gboolean send_caps; - - GstSegment segment; - GstClockTime ts_offset; - guint64 nframes; - - /* sink event handling */ - gdouble proportion; - GstClockTime earliest_time; - guint64 qos_processed, qos_dropped; - GstGLDisplay *display; GstGLContext *context; GLuint fbo; GLuint depthbuffer; - - GType pad_type; }; struct _GstGLMixerClass { - GstElementClass parent_class; + GstVideoAggregatorClass parent_class; GstGLMixerSetCaps set_caps; GstGLMixerReset reset; @@ -127,7 +94,5 @@ GType gst_gl_mixer_get_type(void); gboolean gst_gl_mixer_process_textures (GstGLMixer * mix, GstBuffer * outbuf); -void gst_gl_mixer_set_pad_type (GstGLMixer * mix, GType pad_type); - G_END_DECLS #endif /* __GST_GL_MIXER_H__ */ diff --git a/gst-libs/gst/gl/gstglmixerpad.h b/gst-libs/gst/gl/gstglmixerpad.h index 31f1d99a47..d2fb8290c3 100644 --- a/gst-libs/gst/gl/gstglmixerpad.h +++ b/gst-libs/gst/gl/gstglmixerpad.h @@ -22,7 +22,7 @@ #define __GST_GL_MIXER_PAD_H__ #include -#include +#include #include #include @@ -41,38 +41,21 @@ G_BEGIN_DECLS typedef struct _GstGLMixerPad GstGLMixerPad; typedef struct _GstGLMixerPadClass GstGLMixerPadClass; -typedef struct _GstGLMixerCollect GstGLMixerCollect; - -struct _GstGLMixerCollect -{ - GstCollectData collect; /* we extend the CollectData */ - - GstBuffer *queued; - - GstBuffer *buffer; /* the queued buffer for this pad */ - GstClockTime start_time; - GstClockTime end_time; - - GstGLMixerPad *mixpad; -}; /* all information needed for one video stream */ struct _GstGLMixerPad { - GstPad parent; /* subclass the pad */ + GstVideoAggregatorPad parent; /* subclass the pad */ /* */ GstGLUpload *upload; - GstVideoInfo in_info; guint in_tex_id; gboolean mapped; - - GstGLMixerCollect *mixcol; }; struct _GstGLMixerPadClass { - GstPadClass parent_class; + GstVideoAggregatorPadClass parent_class; }; GType gst_gl_mixer_pad_get_type (void);