aggregator: add simple support for caps handling
authorMatthew Waters <matthew@centricular.com>
Sat, 20 May 2017 12:24:57 +0000 (14:24 +0200)
committerOlivier CrĂȘte <olivier.crete@collabora.com>
Sat, 20 May 2017 14:21:17 +0000 (16:21 +0200)
Modelled off the videoaggregator caps handling as that seems the most
mature aggregtor-using implementation that has caps handling there is.

https://bugzilla.gnome.org/show_bug.cgi?id=776931

15 files changed:
ext/gl/gstglbasemixer.c
ext/gl/gstglmixer.c
ext/gl/gstglstereomix.c
ext/gl/gstglvideomixer.c
gst-libs/gst/audio/gstaudioaggregator.c
gst-libs/gst/audio/gstaudioaggregator.h
gst-libs/gst/base/gstaggregator.c
gst-libs/gst/base/gstaggregator.h
gst-libs/gst/video/gstvideoaggregator.c
gst-libs/gst/video/gstvideoaggregator.h
gst/audiomixer/gstaudiointerleave.c
gst/audiomixer/gstaudiointerleave.h
gst/audiomixer/gstaudiomixer.c
gst/compositor/compositor.c
tests/check/elements/audiointerleave.c

index 6e6e949..317d339 100644 (file)
@@ -108,11 +108,14 @@ gst_gl_base_mixer_pad_set_property (GObject * object, guint prop_id,
 }
 
 static gboolean
-_negotiated_caps (GstVideoAggregator * vagg, GstCaps * caps)
+_negotiated_caps (GstAggregator * agg, GstCaps * caps)
 {
-  GstGLBaseMixer *mix = GST_GL_BASE_MIXER (vagg);
+  GstGLBaseMixer *mix = GST_GL_BASE_MIXER (agg);
+
+  if (!gst_gl_base_mixer_do_bufferpool (mix, caps))
+    return FALSE;
 
-  return gst_gl_base_mixer_do_bufferpool (mix, caps);
+  return GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps (agg, caps);
 }
 
 static gboolean
@@ -324,9 +327,6 @@ gst_gl_base_mixer_class_init (GstGLBaseMixerClass * 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");
@@ -350,8 +350,7 @@ gst_gl_base_mixer_class_init (GstGLBaseMixerClass * klass)
   agg_class->src_activate = gst_gl_base_mixer_src_activate_mode;
   agg_class->stop = gst_gl_base_mixer_stop;
   agg_class->start = gst_gl_base_mixer_start;
-
-  videoaggregator_class->negotiated_caps = _negotiated_caps;
+  agg_class->negotiated_src_caps = _negotiated_caps;
 
   klass->propose_allocation = _default_propose_allocation;
 
index b8f4da0..d2ce49d 100644 (file)
@@ -96,16 +96,16 @@ gst_gl_mixer_pad_set_property (GObject * object, guint prop_id,
 }
 
 static gboolean
-_negotiated_caps (GstVideoAggregator * vagg, GstCaps * caps)
+_negotiated_caps (GstAggregator * agg, GstCaps * caps)
 {
-  GstGLMixer *mix = GST_GL_MIXER (vagg);
+  GstGLMixer *mix = GST_GL_MIXER (agg);
   gboolean ret;
 
   mix->priv->negotiated = TRUE;
 
   gst_caps_replace (&mix->out_caps, caps);
 
-  ret = GST_VIDEO_AGGREGATOR_CLASS (parent_class)->negotiated_caps (vagg, caps);
+  ret = GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps (agg, caps);
 
   return ret;
 }
@@ -215,29 +215,6 @@ gst_gl_mixer_pad_sink_acceptcaps (GstPad * pad, GstGLMixer * mix,
   return ret;
 }
 
-/* copies the given caps */
-static GstCaps *
-_update_caps (GstVideoAggregator * vagg, GstCaps * caps, GstCaps * filter)
-{
-  GstCaps *tmp;
-  guint i, n;
-
-  if (filter) {
-    tmp = gst_caps_intersect (caps, filter);
-    tmp = gst_caps_make_writable (tmp);
-  } else {
-    tmp = gst_caps_copy (caps);
-  }
-
-  n = gst_caps_get_size (tmp);
-  for (i = 0; i < n; i++) {
-    gst_caps_set_features (tmp, i,
-        gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY));
-  }
-
-  return tmp;
-}
-
 static GstCaps *
 gst_gl_mixer_pad_sink_getcaps (GstPad * pad, GstGLMixer * mix, GstCaps * filter)
 {
@@ -391,11 +368,10 @@ gst_gl_mixer_class_init (GstGLMixerClass * klass)
   agg_class->src_query = gst_gl_mixer_src_query;
   agg_class->stop = gst_gl_mixer_stop;
   agg_class->start = gst_gl_mixer_start;
+  agg_class->negotiated_src_caps = _negotiated_caps;
 
   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;
-  videoaggregator_class->update_caps = _update_caps;
   videoaggregator_class->find_best_format = _find_best_format;
 
   mix_class->propose_allocation = gst_gl_mixer_propose_allocation;
index 78a2934..9e42b23 100644 (file)
@@ -81,10 +81,8 @@ gst_gl_stereo_mix_pad_init (GstGLStereoMixPad * pad)
 #define gst_gl_stereo_mix_parent_class parent_class
 G_DEFINE_TYPE (GstGLStereoMix, gst_gl_stereo_mix, GST_TYPE_GL_MIXER);
 
-static GstCaps *_update_caps (GstVideoAggregator * vagg, GstCaps * caps,
-    GstCaps * filter);
-static gboolean _negotiated_caps (GstVideoAggregator * videoaggregator,
-    GstCaps * caps);
+static GstCaps *_update_caps (GstVideoAggregator * vagg, GstCaps * caps);
+static gboolean _negotiated_caps (GstAggregator * aggregator, GstCaps * caps);
 gboolean gst_gl_stereo_mix_make_output (GstGLStereoMix * mix);
 static gboolean gst_gl_stereo_mix_process_frames (GstGLStereoMix * mixer);
 
@@ -188,10 +186,10 @@ gst_gl_stereo_mix_class_init (GstGLStereoMixClass * klass)
   agg_class->stop = gst_gl_stereo_mix_stop;
   agg_class->start = gst_gl_stereo_mix_start;
   agg_class->src_query = gst_gl_stereo_mix_src_query;
+  agg_class->negotiated_src_caps = _negotiated_caps;
 
   videoaggregator_class->aggregate_frames = gst_gl_stereo_mix_aggregate_frames;
   videoaggregator_class->update_caps = _update_caps;
-  videoaggregator_class->negotiated_caps = _negotiated_caps;
   videoaggregator_class->get_output_buffer =
       gst_gl_stereo_mix_get_output_buffer;
 
@@ -470,7 +468,7 @@ get_converted_caps (GstGLStereoMix * mix, GstCaps * caps)
 
 /* Return the possible output caps based on inputs and downstream prefs */
 static GstCaps *
-_update_caps (GstVideoAggregator * vagg, GstCaps * caps, GstCaps * filter)
+_update_caps (GstVideoAggregator * vagg, GstCaps * caps)
 {
   GstGLStereoMix *mix = GST_GL_STEREO_MIX (vagg);
   GList *l;
@@ -563,16 +561,16 @@ _update_caps (GstVideoAggregator * vagg, GstCaps * caps, GstCaps * filter)
 
 /* Called after videoaggregator fixates our caps */
 static gboolean
-_negotiated_caps (GstVideoAggregator * vagg, GstCaps * caps)
+_negotiated_caps (GstAggregator * agg, GstCaps * caps)
 {
+  GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
   GstGLStereoMix *mix = GST_GL_STEREO_MIX (vagg);
   GstCaps *in_caps;
 
   GST_LOG_OBJECT (mix, "Configured output caps %" GST_PTR_FORMAT, caps);
 
-  if (GST_VIDEO_AGGREGATOR_CLASS (parent_class)->negotiated_caps)
-    if (!GST_VIDEO_AGGREGATOR_CLASS (parent_class)->negotiated_caps (vagg,
-            caps))
+  if (GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps)
+    if (!GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps (agg, caps))
       return FALSE;
 
   /* Update the glview_convert output */
index 06bdf3e..10251e6 100644 (file)
@@ -453,9 +453,8 @@ static void gst_gl_video_mixer_set_property (GObject * object, guint prop_id,
 static void gst_gl_video_mixer_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 
-static GstCaps *_update_caps (GstVideoAggregator * vagg, GstCaps * caps,
-    GstCaps * filter);
-static GstCaps *_fixate_caps (GstVideoAggregator * vagg, GstCaps * caps);
+static GstCaps *_update_caps (GstVideoAggregator * vagg, GstCaps * caps);
+static GstCaps *_fixate_caps (GstAggregator * agg, GstCaps * caps);
 static gboolean gst_gl_video_mixer_propose_allocation (GstGLBaseMixer *
     base_mix, GstGLBaseMixerPad * base_pad, GstQuery * decide_query,
     GstQuery * query);
@@ -874,9 +873,9 @@ gst_gl_video_mixer_class_init (GstGLVideoMixerClass * klass)
       gst_gl_video_mixer_process_textures;
 
   vagg_class->update_caps = _update_caps;
-  vagg_class->fixate_caps = _fixate_caps;
 
   agg_class->sinkpads_type = GST_TYPE_GL_VIDEO_MIXER_PAD;
+  agg_class->fixate_src_caps = _fixate_caps;
 
   mix_class->propose_allocation = gst_gl_video_mixer_propose_allocation;
 
@@ -986,7 +985,7 @@ _mixer_pad_get_output_size (GstGLVideoMixer * mix,
 }
 
 static GstCaps *
-_update_caps (GstVideoAggregator * vagg, GstCaps * caps, GstCaps * filter)
+_update_caps (GstVideoAggregator * vagg, GstCaps * caps)
 {
   GstCaps *ret;
   GList *l;
@@ -1014,18 +1013,15 @@ _update_caps (GstVideoAggregator * vagg, GstCaps * caps, GstCaps * filter)
 
   GST_OBJECT_UNLOCK (vagg);
 
-  if (filter) {
-    ret = gst_caps_intersect (caps, filter);
-  } else {
-    ret = gst_caps_ref (caps);
-  }
+  ret = gst_caps_ref (caps);
 
   return ret;
 }
 
 static GstCaps *
-_fixate_caps (GstVideoAggregator * vagg, GstCaps * caps)
+_fixate_caps (GstAggregator * agg, GstCaps * caps)
 {
+  GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
   GstGLVideoMixer *mix = GST_GL_VIDEO_MIXER (vagg);
   gint best_width = 0, best_height = 0;
   gint best_fps_n = 0, best_fps_d = 0;
index 2eb8a84..f5c6c2b 100644 (file)
@@ -144,8 +144,6 @@ struct _GstAudioAggregatorPrivate
 {
   GMutex mutex;
 
-  gboolean send_caps;           /* aagg lock */
-
   /* All three properties are unprotected, can't be modified while streaming */
   /* Size in frames that is output per buffer */
   GstClockTime output_buffer_duration;
@@ -189,6 +187,8 @@ static GstFlowReturn gst_audio_aggregator_aggregate (GstAggregator * agg,
     gboolean timeout);
 static gboolean sync_pad_values (GstAudioAggregator * aagg,
     GstAudioAggregatorPad * pad);
+static gboolean gst_audio_aggregator_negotiated_src_caps (GstAggregator * agg,
+    GstCaps * caps);
 
 #define DEFAULT_OUTPUT_BUFFER_DURATION (10 * GST_MSECOND)
 #define DEFAULT_ALIGNMENT_THRESHOLD   (40 * GST_MSECOND)
@@ -251,6 +251,8 @@ gst_audio_aggregator_class_init (GstAudioAggregatorClass * klass)
       GST_DEBUG_FUNCPTR (gst_audio_aggregator_aggregate);
   gstaggregator_class->clip = GST_DEBUG_FUNCPTR (gst_audio_aggregator_do_clip);
   gstaggregator_class->get_next_time = gst_audio_aggregator_get_next_time;
+  gstaggregator_class->negotiated_src_caps =
+      gst_audio_aggregator_negotiated_src_caps;
 
   klass->create_output_buffer = gst_audio_aggregator_create_output_buffer;
 
@@ -656,9 +658,10 @@ gst_audio_aggregator_set_sink_caps (GstAudioAggregator * aagg,
 }
 
 
-gboolean
-gst_audio_aggregator_set_src_caps (GstAudioAggregator * aagg, GstCaps * caps)
+static gboolean
+gst_audio_aggregator_negotiated_src_caps (GstAggregator * agg, GstCaps * caps)
 {
+  GstAudioAggregator *aagg = GST_AUDIO_AGGREGATOR (agg);
   GstAudioInfo info;
 
   if (!gst_audio_info_from_caps (&info, caps)) {
@@ -674,8 +677,6 @@ gst_audio_aggregator_set_src_caps (GstAudioAggregator * aagg, GstCaps * caps)
     gst_caps_replace (&aagg->current_caps, caps);
 
     memcpy (&aagg->info, &info, sizeof (info));
-    aagg->priv->send_caps = TRUE;
-
   }
 
   GST_OBJECT_UNLOCK (aagg);
@@ -683,7 +684,9 @@ gst_audio_aggregator_set_src_caps (GstAudioAggregator * aagg, GstCaps * caps)
 
   /* send caps event later, after stream-start event */
 
-  return TRUE;
+  return
+      GST_AGGREGATOR_CLASS
+      (gst_audio_aggregator_parent_class)->negotiated_src_caps (agg, caps);
 }
 
 
@@ -1132,21 +1135,13 @@ gst_audio_aggregator_aggregate (GstAggregator * agg, gboolean timeout)
 
       GST_OBJECT_UNLOCK (agg);
       GST_AUDIO_AGGREGATOR_UNLOCK (aagg);
-      return GST_FLOW_OK;
+      return GST_AGGREGATOR_FLOW_NEED_DATA;
     } else {
       GST_OBJECT_UNLOCK (agg);
       goto not_negotiated;
     }
   }
 
-  if (aagg->priv->send_caps) {
-    GST_OBJECT_UNLOCK (agg);
-    gst_aggregator_set_src_caps (agg, aagg->current_caps);
-    GST_OBJECT_LOCK (agg);
-
-    aagg->priv->send_caps = FALSE;
-  }
-
   rate = GST_AUDIO_INFO_RATE (&aagg->info);
   bpf = GST_AUDIO_INFO_BPF (&aagg->info);
 
@@ -1296,7 +1291,7 @@ gst_audio_aggregator_aggregate (GstAggregator * agg, gboolean timeout)
     /* We dropped a buffer, retry */
     GST_LOG_OBJECT (aagg, "A pad dropped a buffer, wait for the next one");
     GST_AUDIO_AGGREGATOR_UNLOCK (aagg);
-    return GST_FLOW_OK;
+    return GST_AGGREGATOR_FLOW_NEED_DATA;
   }
 
   if (!is_done && !is_eos) {
@@ -1304,7 +1299,7 @@ gst_audio_aggregator_aggregate (GstAggregator * agg, gboolean timeout)
     GST_LOG_OBJECT (aagg,
         "We're not done yet for the current offset, waiting for more data");
     GST_AUDIO_AGGREGATOR_UNLOCK (aagg);
-    return GST_FLOW_OK;
+    return GST_AGGREGATOR_FLOW_NEED_DATA;
   }
 
   if (is_eos) {
index 304bad2..be76349 100644 (file)
@@ -162,9 +162,6 @@ void
 gst_audio_aggregator_set_sink_caps (GstAudioAggregator * aagg,
     GstAudioAggregatorPad * pad, GstCaps * caps);
 
-gboolean
-gst_audio_aggregator_set_src_caps (GstAudioAggregator * aagg, GstCaps * caps);
-
 
 G_END_DECLS
 
index 46b3c5d..3d64903 100644 (file)
@@ -809,6 +809,116 @@ gst_aggregator_pad_set_flushing (GstAggregatorPad * aggpad,
   PAD_UNLOCK (aggpad);
 }
 
+static GstFlowReturn
+gst_aggregator_default_update_src_caps (GstAggregator * agg, GstCaps * caps,
+    GstCaps ** ret)
+{
+  *ret = gst_caps_ref (caps);
+
+  return GST_FLOW_OK;
+}
+
+static GstCaps *
+gst_aggregator_default_fixate_src_caps (GstAggregator * agg, GstCaps * caps)
+{
+  caps = gst_caps_fixate (caps);
+
+  return caps;
+}
+
+static gboolean
+gst_aggregator_default_negotiated_src_caps (GstAggregator * agg, GstCaps * caps)
+{
+  return TRUE;
+}
+
+/* WITH SRC_LOCK held */
+static GstFlowReturn
+gst_aggregator_update_src_caps (GstAggregator * self)
+{
+  GstAggregatorClass *agg_klass = GST_AGGREGATOR_GET_CLASS (self);
+  GstCaps *downstream_caps, *template_caps, *caps = NULL;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  template_caps = gst_pad_get_pad_template_caps (self->srcpad);
+  downstream_caps = gst_pad_peer_query_caps (self->srcpad, template_caps);
+
+  if (gst_caps_is_empty (downstream_caps)) {
+    GST_INFO_OBJECT (self, "Downstream caps (%"
+        GST_PTR_FORMAT ") not compatible with pad template caps (%"
+        GST_PTR_FORMAT ")", downstream_caps, template_caps);
+    ret = GST_FLOW_NOT_NEGOTIATED;
+    goto done;
+  }
+
+  g_assert (agg_klass->update_src_caps);
+  GST_DEBUG_OBJECT (self, "updating caps from %" GST_PTR_FORMAT,
+      downstream_caps);
+  ret = agg_klass->update_src_caps (self, downstream_caps, &caps);
+  if (ret < GST_FLOW_OK) {
+    GST_WARNING_OBJECT (self, "Subclass failed to update provided caps");
+    goto done;
+  }
+  if ((caps == NULL || gst_caps_is_empty (caps)) && ret >= GST_FLOW_OK) {
+    ret = GST_FLOW_NOT_NEGOTIATED;
+    goto done;
+  }
+  GST_DEBUG_OBJECT (self, "               to %" GST_PTR_FORMAT, caps);
+
+#ifdef GST_ENABLE_EXTRA_CHECKS
+  if (!gst_caps_is_subset (caps, template_caps)) {
+    GstCaps *intersection;
+
+    GST_ERROR_OBJECT (self,
+        "update_src_caps returned caps %" GST_PTR_FORMAT
+        " which are not a real subset of the template caps %"
+        GST_PTR_FORMAT, caps, template_caps);
+    g_warning ("%s: update_src_caps returned caps which are not a real "
+        "subset of the filter caps", GST_ELEMENT_NAME (self));
+
+    intersection =
+        gst_caps_intersect_full (template_caps, caps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (caps);
+    caps = intersection;
+  }
+#endif
+
+  if (gst_caps_is_any (caps)) {
+    goto done;
+  }
+
+  if (!gst_caps_is_fixed (caps)) {
+    g_assert (agg_klass->fixate_src_caps);
+
+    GST_DEBUG_OBJECT (self, "fixate caps from %" GST_PTR_FORMAT, caps);
+    if (!(caps = agg_klass->fixate_src_caps (self, caps))) {
+      GST_WARNING_OBJECT (self, "Subclass failed to fixate provided caps");
+      ret = GST_FLOW_NOT_NEGOTIATED;
+      goto done;
+    }
+    GST_DEBUG_OBJECT (self, "             to %" GST_PTR_FORMAT, caps);
+  }
+
+  if (agg_klass->negotiated_src_caps) {
+    if (!agg_klass->negotiated_src_caps (self, caps)) {
+      GST_WARNING_OBJECT (self, "Subclass failed to accept negotiated caps");
+      ret = GST_FLOW_NOT_NEGOTIATED;
+      goto done;
+    }
+  }
+
+  gst_aggregator_set_src_caps (self, caps);
+
+done:
+  gst_caps_unref (downstream_caps);
+  gst_caps_unref (template_caps);
+
+  if (caps)
+    gst_caps_unref (caps);
+
+  return ret;
+}
+
 static void
 gst_aggregator_aggregate_func (GstAggregator * self)
 {
@@ -823,7 +933,7 @@ gst_aggregator_aggregate_func (GstAggregator * self)
 
   GST_LOG_OBJECT (self, "Checking aggregate");
   while (priv->send_eos && priv->running) {
-    GstFlowReturn flow_return;
+    GstFlowReturn flow_return = GST_FLOW_OK;
     gboolean processed_event = FALSE;
 
     gst_aggregator_iterate_sinkpads (self, check_events, NULL);
@@ -835,8 +945,19 @@ gst_aggregator_aggregate_func (GstAggregator * self)
     if (processed_event)
       continue;
 
-    GST_TRACE_OBJECT (self, "Actually aggregating!");
-    flow_return = klass->aggregate (self, timeout);
+    if (gst_pad_check_reconfigure (GST_AGGREGATOR_SRC_PAD (self))) {
+      flow_return = gst_aggregator_update_src_caps (self);
+      if (flow_return != GST_FLOW_OK)
+        gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (self));
+    }
+
+    if (timeout || flow_return >= GST_FLOW_OK) {
+      GST_TRACE_OBJECT (self, "Actually aggregating!");
+      flow_return = klass->aggregate (self, timeout);
+    }
+
+    if (flow_return == GST_AGGREGATOR_FLOW_NEED_DATA)
+      continue;
 
     GST_OBJECT_LOCK (self);
     if (flow_return == GST_FLOW_FLUSHING && priv->flush_seeking) {
@@ -1979,6 +2100,9 @@ gst_aggregator_class_init (GstAggregatorClass * klass)
   klass->src_query = gst_aggregator_default_src_query;
 
   klass->create_new_pad = gst_aggregator_default_create_new_pad;
+  klass->update_src_caps = gst_aggregator_default_update_src_caps;
+  klass->fixate_src_caps = gst_aggregator_default_fixate_src_caps;
+  klass->negotiated_src_caps = gst_aggregator_default_negotiated_src_caps;
 
   gstelement_class->request_new_pad =
       GST_DEBUG_FUNCPTR (gst_aggregator_request_new_pad);
index 38d2605..be989ad 100644 (file)
@@ -120,6 +120,7 @@ gboolean    gst_aggregator_pad_is_eos       (GstAggregatorPad *  pad);
 #define GST_IS_AGGREGATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AGGREGATOR))
 
 #define GST_FLOW_NOT_HANDLED           GST_FLOW_CUSTOM_SUCCESS
+#define GST_AGGREGATOR_FLOW_NEED_DATA             GST_FLOW_CUSTOM_ERROR
 
 /**
  * GstAggregator:
@@ -195,6 +196,18 @@ struct _GstAggregator
  *                  based aggregation to occur. Defaults to returning
  *                  GST_CLOCK_TIME_NONE causing the element to wait for buffers
  *                  on all sink pads before aggregating.
+ * @update_src_caps: Lets subclasses update the #GstCaps representing
+ *                   the src pad caps before usage.  The result should end up
+ *                   in @ret. Return %GST_AGGREGATOR_FLOW_NEED_DATA to indicate that the
+ *                   element needs more information (caps, a buffer, etc) to
+ *                   choose the correct caps. Should return ANY caps if the
+ *                   stream has not caps at all.
+ * @fixate_src_caps: Optional.
+ *                   Fixate and return the src pad caps provided.  The function takes
+ *                   ownership of @caps and returns a fixated version of
+ *                   @caps. @caps is not guaranteed to be writable.
+ * @negotiated_src_caps: Optional.
+ *                       Notifies subclasses what caps format has been negotiated
  *
  * The aggregator base class will handle in a thread-safe way all manners of
  * concurrent flushes, seeks, pad additions and removals, leaving to the
@@ -250,6 +263,13 @@ struct _GstAggregatorClass {
                                         GstPadTemplate * templ,
                                         const gchar    * req_name,
                                         const GstCaps  * caps);
+  GstFlowReturn     (*update_src_caps) (GstAggregator *  self,
+                                        GstCaps       *  caps,
+                                        GstCaps       ** ret);
+  GstCaps *         (*fixate_src_caps) (GstAggregator *  self,
+                                        GstCaps       *  caps);
+  gboolean          (*negotiated_src_caps) (GstAggregator *  self,
+                                            GstCaps      *  caps);
 
   /*< private >*/
   gpointer          _gst_reserved[GST_PADDING_LARGE];
index 8310fd2..7cdce00 100644 (file)
@@ -535,60 +535,11 @@ gst_video_aggregator_find_best_format (GstVideoAggregator * vagg,
   g_hash_table_unref (formats_table);
 }
 
-/* WITH GST_VIDEO_AGGREGATOR_LOCK TAKEN */
-static gboolean
-gst_video_aggregator_src_setcaps (GstVideoAggregator * vagg, GstCaps * caps)
-{
-  GstAggregator *agg = GST_AGGREGATOR (vagg);
-  gboolean ret = FALSE;
-  GstVideoInfo info;
-
-  GstPad *pad = GST_AGGREGATOR (vagg)->srcpad;
-
-  GST_INFO_OBJECT (pad, "set src caps: %" GST_PTR_FORMAT, caps);
-
-  if (!gst_video_info_from_caps (&info, caps))
-    goto done;
-
-  ret = TRUE;
-
-  if (GST_VIDEO_INFO_FPS_N (&vagg->info) != GST_VIDEO_INFO_FPS_N (&info) ||
-      GST_VIDEO_INFO_FPS_D (&vagg->info) != GST_VIDEO_INFO_FPS_D (&info)) {
-    if (agg->segment.position != -1) {
-      vagg->priv->nframes = 0;
-      /* The timestamp offset will be updated based on the
-       * segment position the next time we aggregate */
-      GST_DEBUG_OBJECT (vagg,
-          "Resetting frame counter because of framerate change");
-    }
-    gst_video_aggregator_reset_qos (vagg);
-  }
-
-  vagg->info = info;
-
-  if (vagg->priv->current_caps == NULL ||
-      gst_caps_is_equal (caps, vagg->priv->current_caps) == FALSE) {
-    GstClockTime latency;
-
-    gst_caps_replace (&vagg->priv->current_caps, caps);
-    GST_VIDEO_AGGREGATOR_UNLOCK (vagg);
-
-    gst_aggregator_set_src_caps (agg, caps);
-    latency = gst_util_uint64_scale (GST_SECOND,
-        GST_VIDEO_INFO_FPS_D (&info), GST_VIDEO_INFO_FPS_N (&info));
-    gst_aggregator_set_latency (agg, latency, latency);
-
-    GST_VIDEO_AGGREGATOR_LOCK (vagg);
-  }
-
-done:
-  return ret;
-}
-
 static GstCaps *
-gst_video_aggregator_default_fixate_caps (GstVideoAggregator * vagg,
+gst_video_aggregator_default_fixate_src_caps (GstAggregator * agg,
     GstCaps * caps)
 {
+  GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
   gint best_width = -1, best_height = -1;
   gint best_fps_n = -1, best_fps_d = -1;
   gdouble best_fps = -1.;
@@ -634,6 +585,7 @@ gst_video_aggregator_default_fixate_caps (GstVideoAggregator * vagg,
     best_fps = 25.0;
   }
 
+  caps = gst_caps_make_writable (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);
@@ -648,7 +600,7 @@ gst_video_aggregator_default_fixate_caps (GstVideoAggregator * vagg,
 
 static GstCaps *
 gst_video_aggregator_default_update_caps (GstVideoAggregator * vagg,
-    GstCaps * caps, GstCaps * filter)
+    GstCaps * caps)
 {
   GstVideoAggregatorClass *vagg_klass = GST_VIDEO_AGGREGATOR_GET_CLASS (vagg);
   GstCaps *ret, *best_format_caps;
@@ -682,38 +634,59 @@ gst_video_aggregator_default_update_caps (GstVideoAggregator * vagg,
       gst_video_chroma_to_string (best_info.chroma_site), NULL);
   ret = gst_caps_merge (best_format_caps, gst_caps_ref (caps));
 
-  if (filter) {
-    GstCaps *tmp;
-    tmp = gst_caps_intersect (ret, filter);
-    gst_caps_unref (ret);
-    ret = tmp;
+  return ret;
+}
+
+static GstFlowReturn
+gst_video_aggregator_default_update_src_caps (GstAggregator * agg,
+    GstCaps * caps, GstCaps ** ret)
+{
+  GstVideoAggregatorClass *vagg_klass = GST_VIDEO_AGGREGATOR_GET_CLASS (agg);
+  GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
+  gboolean at_least_one_pad_configured = FALSE;
+  GList *l;
+
+  GST_OBJECT_LOCK (vagg);
+  for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
+    GstVideoAggregatorPad *mpad = l->data;
+
+    if (GST_VIDEO_INFO_WIDTH (&mpad->info) == 0
+        || GST_VIDEO_INFO_HEIGHT (&mpad->info) == 0)
+      continue;
+
+    at_least_one_pad_configured = TRUE;
+  }
+  GST_OBJECT_UNLOCK (vagg);
+
+  if (!at_least_one_pad_configured) {
+    /* We couldn't decide the output video info because the sinkpads don't have
+     * all the caps yet, so we mark the pad as needing a reconfigure. This
+     * allows aggregate() to skip ahead a bit and try again later. */
+    GST_DEBUG_OBJECT (vagg, "Couldn't decide output video info");
+    gst_pad_mark_reconfigure (agg->srcpad);
+    return GST_AGGREGATOR_FLOW_NEED_DATA;
   }
 
-  return ret;
+  g_assert (vagg_klass->update_caps);
+
+  *ret = vagg_klass->update_caps (vagg, caps);
+
+  return GST_FLOW_OK;
 }
 
-/* WITH GST_VIDEO_AGGREGATOR_LOCK TAKEN */
 static gboolean
-gst_video_aggregator_update_src_caps (GstVideoAggregator * vagg)
+gst_video_aggregator_default_negotiated_src_caps (GstAggregator * agg,
+    GstCaps * caps)
 {
-  GstVideoAggregatorClass *vagg_klass = GST_VIDEO_AGGREGATOR_GET_CLASS (vagg);
   GstVideoAggregatorPadClass *vaggpad_klass = g_type_class_peek
-      (GST_AGGREGATOR_GET_CLASS (vagg)->sinkpads_type);
-  GstAggregator *agg = GST_AGGREGATOR (vagg);
-  gboolean ret = TRUE, at_least_one_pad_configured = FALSE;
+      (GST_AGGREGATOR_GET_CLASS (agg)->sinkpads_type);
+  GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
   gboolean at_least_one_alpha = FALSE;
-  GstCaps *downstream_caps;
+  const GstVideoFormatInfo *finfo;
+  GstVideoInfo info;
   GList *l;
 
-  downstream_caps = gst_pad_get_allowed_caps (agg->srcpad);
-
-  if (!downstream_caps || gst_caps_is_empty (downstream_caps)) {
-    GST_INFO_OBJECT (vagg, "No downstream caps found %"
-        GST_PTR_FORMAT, downstream_caps);
-    if (downstream_caps)
-      gst_caps_unref (downstream_caps);
-    return FALSE;
-  }
+  GST_INFO_OBJECT (agg->srcpad, "set src caps: %" GST_PTR_FORMAT, caps);
 
   GST_OBJECT_LOCK (vagg);
   for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
@@ -725,101 +698,59 @@ gst_video_aggregator_update_src_caps (GstVideoAggregator * vagg)
 
     if (mpad->info.finfo->flags & GST_VIDEO_FORMAT_FLAG_ALPHA)
       at_least_one_alpha = TRUE;
-
-    at_least_one_pad_configured = TRUE;
   }
   GST_OBJECT_UNLOCK (vagg);
 
-  if (at_least_one_pad_configured) {
-    GstCaps *caps, *peercaps;
-
-    peercaps = gst_pad_peer_query_caps (agg->srcpad, NULL);
-
-    g_assert (vagg_klass->update_caps);
-    GST_DEBUG_OBJECT (vagg, "updating caps from %" GST_PTR_FORMAT,
-        downstream_caps);
-    GST_DEBUG_OBJECT (vagg, "       with filter %" GST_PTR_FORMAT, peercaps);
-    if (!(caps = vagg_klass->update_caps (vagg, downstream_caps, peercaps)) ||
-        gst_caps_is_empty (caps)) {
-      GST_WARNING_OBJECT (vagg, "Subclass failed to update provided caps");
-      gst_caps_unref (downstream_caps);
-      if (peercaps)
-        gst_caps_unref (peercaps);
-      ret = FALSE;
-      goto done;
+  if (!gst_video_info_from_caps (&info, caps))
+    return FALSE;
+
+  if (GST_VIDEO_INFO_FPS_N (&vagg->info) != GST_VIDEO_INFO_FPS_N (&info) ||
+      GST_VIDEO_INFO_FPS_D (&vagg->info) != GST_VIDEO_INFO_FPS_D (&info)) {
+    if (agg->segment.position != -1) {
+      vagg->priv->nframes = 0;
+      /* The timestamp offset will be updated based on the
+       * segment position the next time we aggregate */
+      GST_DEBUG_OBJECT (vagg,
+          "Resetting frame counter because of framerate change");
     }
-    GST_DEBUG_OBJECT (vagg, "               to %" GST_PTR_FORMAT, caps);
+    gst_video_aggregator_reset_qos (vagg);
+  }
+
+  vagg->info = info;
 
-    gst_caps_unref (downstream_caps);
-    if (peercaps)
-      gst_caps_unref (peercaps);
+  finfo = vagg->info.finfo;
 
-    if (!gst_caps_is_fixed (caps)) {
-      g_assert (vagg_klass->fixate_caps);
+  if (at_least_one_alpha && !(finfo->flags & GST_VIDEO_FORMAT_FLAG_ALPHA)) {
+    GST_ELEMENT_ERROR (vagg, CORE, NEGOTIATION,
+        ("At least one of the input pads contains alpha, but configured caps don't support alpha."),
+        ("Either convert your inputs to not contain alpha or add a videoconvert after the aggregator"));
+    return FALSE;
+  }
 
-      caps = gst_caps_make_writable (caps);
-      GST_DEBUG_OBJECT (vagg, "fixate caps from %" GST_PTR_FORMAT, caps);
-      if (!(caps = vagg_klass->fixate_caps (vagg, caps))) {
-        GST_WARNING_OBJECT (vagg, "Subclass failed to fixate provided caps");
-        ret = FALSE;
-        goto done;
-      }
-      GST_DEBUG_OBJECT (vagg, "             to %" GST_PTR_FORMAT, caps);
-    }
+  if (vaggpad_klass->set_info) {
+    /* Then browse the sinks once more, setting or unsetting conversion if needed */
+    for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
+      GstVideoAggregatorPad *pad = GST_VIDEO_AGGREGATOR_PAD (l->data);
 
-    {
-      const GstVideoFormatInfo *finfo;
-      const gchar *v_format_str;
-      GstVideoFormat v_format;
-      GstStructure *s;
-
-      s = gst_caps_get_structure (caps, 0);
-      v_format_str = gst_structure_get_string (s, "format");
-      g_return_val_if_fail (v_format_str != NULL, FALSE);
-      v_format = gst_video_format_from_string (v_format_str);
-      g_return_val_if_fail (v_format != GST_VIDEO_FORMAT_UNKNOWN, FALSE);
-      finfo = gst_video_format_get_info (v_format);
-      g_return_val_if_fail (finfo != NULL, FALSE);
-
-      if (at_least_one_alpha && !(finfo->flags & GST_VIDEO_FORMAT_FLAG_ALPHA)) {
-        GST_ELEMENT_ERROR (vagg, CORE, NEGOTIATION,
-            ("At least one of the input pads contains alpha, but configured caps don't support alpha."),
-            ("Either convert your inputs to not contain alpha or add a videoconvert after the aggregator"));
-        ret = FALSE;
-        goto done;
+      if (!vaggpad_klass->set_info (pad, vagg, &pad->info, &vagg->info)) {
+        return FALSE;
       }
     }
+  }
 
-    gst_video_info_from_caps (&vagg->info, caps);
-
-    if (vaggpad_klass->set_info) {
-      /* Then browse the sinks once more, setting or unsetting conversion if needed */
-      for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
-        GstVideoAggregatorPad *pad = GST_VIDEO_AGGREGATOR_PAD (l->data);
+  if (vagg->priv->current_caps == NULL ||
+      gst_caps_is_equal (caps, vagg->priv->current_caps) == FALSE) {
+    GstClockTime latency;
 
-        if (!vaggpad_klass->set_info (pad, vagg, &pad->info, &vagg->info)) {
-          return FALSE;
-        }
-      }
-    }
+    gst_caps_replace (&vagg->priv->current_caps, caps);
 
-    if (gst_video_aggregator_src_setcaps (vagg, caps)) {
-      if (vagg_klass->negotiated_caps)
-        ret =
-            GST_VIDEO_AGGREGATOR_GET_CLASS (vagg)->negotiated_caps (vagg, caps);
-    }
-    gst_caps_unref (caps);
-  } else {
-    /* We couldn't decide the output video info because the sinkpads don't have
-     * all the caps yet, so we mark the pad as needing a reconfigure. This
-     * allows aggregate() to skip ahead a bit and try again later. */
-    GST_DEBUG_OBJECT (vagg, "Couldn't decide output video info");
-    gst_pad_mark_reconfigure (agg->srcpad);
-    ret = FALSE;
+    gst_aggregator_set_src_caps (agg, caps);
+    latency = gst_util_uint64_scale (GST_SECOND,
+        GST_VIDEO_INFO_FPS_D (&vagg->info), GST_VIDEO_INFO_FPS_N (&vagg->info));
+    gst_aggregator_set_latency (agg, latency, latency);
   }
 
-done:
-  return ret;
+  return TRUE;
 }
 
 static gboolean
@@ -1101,7 +1032,6 @@ gst_video_aggregator_reset (GstVideoAggregator * vagg)
   GST_OBJECT_UNLOCK (vagg);
 }
 
-#define GST_FLOW_NEEDS_DATA GST_FLOW_CUSTOM_ERROR
 static gint
 gst_video_aggregator_fill_queues (GstVideoAggregator * vagg,
     GstClockTime output_start_running_time,
@@ -1309,7 +1239,7 @@ gst_video_aggregator_fill_queues (GstVideoAggregator * vagg,
     gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (vagg));
 
   if (need_more_data)
-    return GST_FLOW_NEEDS_DATA;
+    return GST_AGGREGATOR_FLOW_NEED_DATA;
   if (eos)
     return GST_FLOW_EOS;
 
@@ -1471,66 +1401,36 @@ gst_video_aggregator_get_next_time (GstAggregator * agg)
   return next_time;
 }
 
-static GstFlowReturn
-gst_video_aggregator_check_reconfigure (GstVideoAggregator * vagg,
-    gboolean timeout)
+static void
+gst_video_aggregator_advance_on_timeout (GstVideoAggregator * vagg)
 {
-  GstAggregator *agg = (GstAggregator *) vagg;
-
-  if (GST_VIDEO_INFO_FORMAT (&vagg->info) == GST_VIDEO_FORMAT_UNKNOWN
-      || gst_pad_check_reconfigure (GST_AGGREGATOR_SRC_PAD (vagg))) {
-    gboolean ret;
-
-  restart:
-    ret = gst_video_aggregator_update_src_caps (vagg);
-    if (!ret) {
-      gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (vagg));
-      if (timeout) {
-        guint64 frame_duration;
-        gint fps_d, fps_n;
-
-        GST_DEBUG_OBJECT (vagg,
-            "Got timeout before receiving any caps, don't output anything");
-
-        if (agg->segment.position == -1) {
-          if (agg->segment.rate > 0.0)
-            agg->segment.position = agg->segment.start;
-          else
-            agg->segment.position = agg->segment.stop;
-        }
+  GstAggregator *agg = GST_AGGREGATOR (vagg);
+  guint64 frame_duration;
+  gint fps_d, fps_n;
 
-        /* Advance position */
-        fps_d = GST_VIDEO_INFO_FPS_D (&vagg->info) ?
-            GST_VIDEO_INFO_FPS_D (&vagg->info) : 1;
-        fps_n = GST_VIDEO_INFO_FPS_N (&vagg->info) ?
-            GST_VIDEO_INFO_FPS_N (&vagg->info) : 25;
-        /* Default to 25/1 if no "best fps" is known */
-        frame_duration = gst_util_uint64_scale (GST_SECOND, fps_d, fps_n);
-        if (agg->segment.rate > 0.0)
-          agg->segment.position += frame_duration;
-        else if (agg->segment.position > frame_duration)
-          agg->segment.position -= frame_duration;
-        else
-          agg->segment.position = 0;
-        vagg->priv->nframes++;
-        return GST_FLOW_NEEDS_DATA;
-      } else {
-        if (GST_PAD_IS_FLUSHING (GST_AGGREGATOR_SRC_PAD (vagg)))
-          return GST_FLOW_FLUSHING;
-        else
-          return GST_FLOW_NOT_NEGOTIATED;
-      }
-    } else {
-      /* It is possible that during gst_video_aggregator_update_src_caps()
-       * we got a caps change on one of the sink pads, in which case we need
-       * to redo the negotiation
-       * - https://bugzilla.gnome.org/show_bug.cgi?id=755782 */
-      if (gst_pad_check_reconfigure (GST_AGGREGATOR_SRC_PAD (vagg)))
-        goto restart;
-    }
+  GST_OBJECT_LOCK (agg);
+  if (agg->segment.position == -1) {
+    if (agg->segment.rate > 0.0)
+      agg->segment.position = agg->segment.start;
+    else
+      agg->segment.position = agg->segment.stop;
   }
 
-  return GST_FLOW_OK;
+  /* Advance position */
+  fps_d = GST_VIDEO_INFO_FPS_D (&vagg->info) ?
+      GST_VIDEO_INFO_FPS_D (&vagg->info) : 1;
+  fps_n = GST_VIDEO_INFO_FPS_N (&vagg->info) ?
+      GST_VIDEO_INFO_FPS_N (&vagg->info) : 25;
+  /* Default to 25/1 if no "best fps" is known */
+  frame_duration = gst_util_uint64_scale (GST_SECOND, fps_d, fps_n);
+  if (agg->segment.rate > 0.0)
+    agg->segment.position += frame_duration;
+  else if (agg->segment.position > frame_duration)
+    agg->segment.position -= frame_duration;
+  else
+    agg->segment.position = 0;
+  vagg->priv->nframes++;
+  GST_OBJECT_UNLOCK (agg);
 }
 
 static GstFlowReturn
@@ -1546,10 +1446,10 @@ gst_video_aggregator_aggregate (GstAggregator * agg, gboolean timeout)
   GST_VIDEO_AGGREGATOR_LOCK (vagg);
 
 restart:
-  flow_ret = gst_video_aggregator_check_reconfigure (vagg, timeout);
-  if (flow_ret != GST_FLOW_OK) {
-    if (flow_ret == GST_FLOW_NEEDS_DATA)
-      flow_ret = GST_FLOW_OK;
+  if (GST_VIDEO_INFO_FORMAT (&vagg->info) == GST_VIDEO_FORMAT_UNKNOWN) {
+    if (timeout)
+      gst_video_aggregator_advance_on_timeout (vagg);
+    flow_ret = GST_AGGREGATOR_FLOW_NEED_DATA;
     goto unlock_and_return;
   }
 
@@ -1591,9 +1491,8 @@ restart:
         output_end_running_time);
   }
 
-  if (flow_ret == GST_FLOW_NEEDS_DATA && !timeout) {
+  if (flow_ret == GST_AGGREGATOR_FLOW_NEED_DATA && !timeout) {
     GST_DEBUG_OBJECT (vagg, "Need more data for decisions");
-    flow_ret = GST_FLOW_OK;
     goto unlock_and_return;
   } else if (flow_ret == GST_FLOW_EOS) {
     GST_DEBUG_OBJECT (vagg, "All sinkpads are EOS -- forwarding");
@@ -2187,11 +2086,14 @@ gst_video_aggregator_class_init (GstVideoAggregatorClass * klass)
   agg_class->src_event = gst_video_aggregator_src_event;
   agg_class->src_query = gst_video_aggregator_src_query;
   agg_class->get_next_time = gst_video_aggregator_get_next_time;
+  agg_class->update_src_caps = gst_video_aggregator_default_update_src_caps;
+  agg_class->fixate_src_caps = gst_video_aggregator_default_fixate_src_caps;
+  agg_class->negotiated_src_caps =
+      gst_video_aggregator_default_negotiated_src_caps;
 
   klass->find_best_format = gst_video_aggregator_find_best_format;
   klass->get_output_buffer = gst_video_aggregator_get_output_buffer;
   klass->update_caps = gst_video_aggregator_default_update_caps;
-  klass->fixate_caps = gst_video_aggregator_default_fixate_caps;
 
   /* Register the pad class */
   g_type_class_ref (GST_TYPE_VIDEO_AGGREGATOR_PAD);
index 6204bdd..ced6124 100644 (file)
@@ -73,9 +73,6 @@ struct _GstVideoAggregator
  * @update_caps:              Optional.
  *                            Lets subclasses update the #GstCaps representing
  *                            the src pad caps before usage.  Return %NULL to indicate failure.
- * @fixate_caps:              Fixate and return the src pad caps provided.  The function takes
- *                            ownership of @caps and returns a fixated version of
- *                            @caps. @caps is not guaranteed to be writable.
  * @aggregate_frames:         Lets subclasses aggregate frames that are ready. Subclasses
  *                            should iterate the GstElement.sinkpads and use the already
  *                            mapped #GstVideoFrame from GstVideoAggregatorPad.aggregated_frame
@@ -97,16 +94,11 @@ struct _GstVideoAggregatorClass
 
   /*< public >*/
   GstCaps *          (*update_caps)               (GstVideoAggregator *  videoaggregator,
-                                                   GstCaps            *  caps,
-                                                   GstCaps            *  filter_caps);
-  GstCaps *          (*fixate_caps)               (GstVideoAggregator *  videoaggregator,
                                                    GstCaps            *  caps);
   GstFlowReturn      (*aggregate_frames)          (GstVideoAggregator *  videoaggregator,
                                                    GstBuffer          *  outbuffer);
   GstFlowReturn      (*get_output_buffer)         (GstVideoAggregator *  videoaggregator,
                                                    GstBuffer          ** outbuffer);
-  gboolean           (*negotiated_caps)           (GstVideoAggregator *  videoaggregator,
-                                                   GstCaps            *  caps);
   void               (*find_best_format)          (GstVideoAggregator *  vagg,
                                                    GstCaps            *  downstream_caps,
                                                    GstVideoInfo       *  best_info,
index 8d99b3c..dfae4a5 100644 (file)
@@ -432,10 +432,10 @@ gst_audio_interleave_setcaps (GstAudioInterleave * self, GstPad * pad,
     GST_DEBUG_OBJECT (self, "setting sinkcaps %" GST_PTR_FORMAT, sinkcaps);
 
     gst_caps_replace (&self->sinkcaps, sinkcaps);
+    gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (aagg));
 
     gst_caps_unref (sinkcaps);
     new = TRUE;
-    self->new_caps = TRUE;
   }
 
   if (self->channel_positions_from_input
@@ -504,52 +504,40 @@ gst_audio_interleave_sink_event (GstAggregator * agg, GstAggregatorPad * aggpad,
 }
 
 static GstFlowReturn
-gst_audio_interleave_aggregate (GstAggregator * aggregator, gboolean timeout)
+gst_audio_interleave_update_src_caps (GstAggregator * agg, GstCaps * caps,
+    GstCaps ** ret)
 {
-  GstAudioInterleave *self = GST_AUDIO_INTERLEAVE (aggregator);
-  GstAudioAggregator *aagg = GST_AUDIO_AGGREGATOR (aggregator);
-
-  GST_OBJECT_LOCK (aggregator);
-  if (self->new_caps) {
-    GstCaps *srccaps;
-    GstStructure *s;
-    gboolean ret;
-
-    if (self->sinkcaps == NULL || self->channels == 0) {
-      /* In this case, let the base class handle it */
-      goto not_negotiated;
-    }
-
-    srccaps = gst_caps_copy (self->sinkcaps);
-    s = gst_caps_get_structure (srccaps, 0);
-
-    gst_structure_set (s, "channels", G_TYPE_INT, self->channels, "layout",
-        G_TYPE_STRING, "interleaved", "channel-mask", GST_TYPE_BITMASK,
-        gst_audio_interleave_get_channel_mask (self), NULL);
-
+  GstAudioInterleave *self = GST_AUDIO_INTERLEAVE (agg);
+  GstStructure *s;
 
-    GST_OBJECT_UNLOCK (aggregator);
-    ret = gst_audio_aggregator_set_src_caps (aagg, srccaps);
-    gst_caps_unref (srccaps);
+  /* This means that either no caps have been set on the sink pad (if
+   * sinkcaps is NULL) or that there is no sink pad (if channels == 0).
+   */
+  if (self->sinkcaps == NULL || self->channels == 0)
+    return GST_FLOW_NOT_NEGOTIATED;
 
-    if (!ret)
-      goto src_did_not_accept;
+  *ret = gst_caps_copy (self->sinkcaps);
+  s = gst_caps_get_structure (*ret, 0);
 
-    GST_OBJECT_LOCK (aggregator);
+  gst_structure_set (s, "channels", G_TYPE_INT, self->channels, "layout",
+      G_TYPE_STRING, "interleaved", "channel-mask", GST_TYPE_BITMASK,
+      gst_audio_interleave_get_channel_mask (self), NULL);
 
-    gst_audio_interleave_set_process_function (self, &aagg->info);
+  return GST_FLOW_OK;
+}
 
-    self->new_caps = FALSE;
-  }
+static gboolean
+gst_audio_interleave_negotiated_src_caps (GstAggregator * agg, GstCaps * caps)
+{
+  GstAudioInterleave *self = GST_AUDIO_INTERLEAVE (agg);
+  GstAudioAggregator *aagg = GST_AUDIO_AGGREGATOR (self);
 
-not_negotiated:
-  GST_OBJECT_UNLOCK (aggregator);
+  if (!GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps (agg, caps))
+    return FALSE;
 
-  return GST_AGGREGATOR_CLASS (parent_class)->aggregate (aggregator, timeout);
+  gst_audio_interleave_set_process_function (self, &aagg->info);
 
-src_did_not_accept:
-  GST_WARNING_OBJECT (self, "src did not accept setcaps()");
-  return GST_FLOW_NOT_NEGOTIATED;;
+  return TRUE;
 }
 
 static void
@@ -586,7 +574,8 @@ gst_audio_interleave_class_init (GstAudioInterleaveClass * klass)
   agg_class->sink_query = GST_DEBUG_FUNCPTR (gst_audio_interleave_sink_query);
   agg_class->sink_event = GST_DEBUG_FUNCPTR (gst_audio_interleave_sink_event);
   agg_class->stop = gst_audio_interleave_stop;
-  agg_class->aggregate = gst_audio_interleave_aggregate;
+  agg_class->update_src_caps = gst_audio_interleave_update_src_caps;
+  agg_class->negotiated_src_caps = gst_audio_interleave_negotiated_src_caps;
 
   aagg_class->aggregate_one_buffer = gst_audio_interleave_aggregate_one_buffer;
 
@@ -720,7 +709,6 @@ gst_audio_interleave_stop (GstAggregator * agg)
   if (!GST_AGGREGATOR_CLASS (parent_class)->stop (agg))
     return FALSE;
 
-  self->new_caps = FALSE;
   gst_caps_replace (&self->sinkcaps, NULL);
 
   return TRUE;
@@ -765,9 +753,7 @@ gst_audio_interleave_request_new_pad (GstElement * element,
   g_value_unset (&val);
 
   /* Update the src caps if we already have them */
-  GST_OBJECT_LOCK (self);
-  self->new_caps = TRUE;
-  GST_OBJECT_UNLOCK (self);
+  gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (self));
 
   return GST_PAD_CAST (newpad);
 
@@ -804,7 +790,7 @@ gst_audio_interleave_release_pad (GstElement * element, GstPad * pad)
       ipad->channel--;
   }
 
-  self->new_caps = TRUE;
+  gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (self));
   GST_OBJECT_UNLOCK (self);
 
 
index 6dd82d3..ef959ce 100644 (file)
@@ -58,7 +58,6 @@ struct _GstAudioInterleave {
   gint padcounter;
   guint channels;
 
-  gboolean new_caps;
   GstCaps *sinkcaps;
 
   GValueArray *channel_positions;
index ac2f49c..2233b82 100644 (file)
@@ -348,7 +348,6 @@ gst_audiomixer_setcaps (GstAudioMixer * audiomixer, GstPad * pad,
   GstAudioInfo info;
   GstStructure *s;
   gint channels = 0;
-  gboolean ret;
 
   caps = gst_caps_copy (orig_caps);
 
@@ -405,20 +404,21 @@ gst_audiomixer_setcaps (GstAudioMixer * audiomixer, GstPad * pad,
       gst_caps_unref (caps);
       return FALSE;
     }
+  } else {
+    gst_caps_replace (&aagg->current_caps, caps);
+    aagg->info = info;
+    gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (agg));
   }
   GST_OBJECT_UNLOCK (audiomixer);
 
-  ret = gst_audio_aggregator_set_src_caps (aagg, caps);
-
-  if (ret)
-    gst_audio_aggregator_set_sink_caps (aagg, GST_AUDIO_AGGREGATOR_PAD (pad),
-        orig_caps);
+  gst_audio_aggregator_set_sink_caps (aagg, GST_AUDIO_AGGREGATOR_PAD (pad),
+      orig_caps);
 
   GST_INFO_OBJECT (pad, "handle caps change to %" GST_PTR_FORMAT, caps);
 
   gst_caps_unref (caps);
 
-  return ret;
+  return TRUE;
 
   /* ERRORS */
 invalid_format:
@@ -429,6 +429,20 @@ invalid_format:
   }
 }
 
+static GstFlowReturn
+gst_audiomixer_update_src_caps (GstAggregator * agg, GstCaps * caps,
+    GstCaps ** ret)
+{
+  GstAudioAggregator *aagg = GST_AUDIO_AGGREGATOR (agg);
+
+  if (aagg->current_caps == NULL)
+    return GST_AGGREGATOR_FLOW_NEED_DATA;
+
+  *ret = gst_caps_ref (aagg->current_caps);
+
+  return GST_FLOW_OK;
+}
+
 static gboolean
 gst_audiomixer_sink_event (GstAggregator * agg, GstAggregatorPad * aggpad,
     GstEvent * event)
@@ -495,6 +509,8 @@ gst_audiomixer_class_init (GstAudioMixerClass * klass)
 
   agg_class->sink_query = GST_DEBUG_FUNCPTR (gst_audiomixer_sink_query);
   agg_class->sink_event = GST_DEBUG_FUNCPTR (gst_audiomixer_sink_event);
+  agg_class->update_src_caps =
+      GST_DEBUG_FUNCPTR (gst_audiomixer_update_src_caps);
 
   aagg_class->aggregate_one_buffer = gst_audiomixer_aggregate_one_buffer;
 }
index de3bf22..23dc20c 100644 (file)
@@ -870,8 +870,9 @@ set_functions (GstCompositor * self, GstVideoInfo * info)
 }
 
 static GstCaps *
-_fixate_caps (GstVideoAggregator * vagg, GstCaps * caps)
+_fixate_caps (GstAggregator * agg, GstCaps * caps)
 {
+  GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
   GList *l;
   gint best_width = -1, best_height = -1;
   gint best_fps_n = -1, best_fps_d = -1;
@@ -945,21 +946,21 @@ _fixate_caps (GstVideoAggregator * vagg, GstCaps * caps)
 }
 
 static gboolean
-_negotiated_caps (GstVideoAggregator * vagg, GstCaps * caps)
+_negotiated_caps (GstAggregator * agg, GstCaps * caps)
 {
   GstVideoInfo v_info;
 
-  GST_DEBUG_OBJECT (vagg, "Negotiated caps %" GST_PTR_FORMAT, caps);
+  GST_DEBUG_OBJECT (agg, "Negotiated caps %" GST_PTR_FORMAT, caps);
 
   if (!gst_video_info_from_caps (&v_info, caps))
     return FALSE;
 
-  if (!set_functions (GST_COMPOSITOR (vagg), &v_info)) {
-    GST_ERROR_OBJECT (vagg, "Failed to setup vfuncs");
+  if (!set_functions (GST_COMPOSITOR (agg), &v_info)) {
+    GST_ERROR_OBJECT (agg, "Failed to setup vfuncs");
     return FALSE;
   }
 
-  return TRUE;
+  return GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps (agg, caps);
 }
 
 static GstFlowReturn
@@ -1090,8 +1091,8 @@ gst_compositor_class_init (GstCompositorClass * klass)
 
   agg_class->sinkpads_type = GST_TYPE_COMPOSITOR_PAD;
   agg_class->sink_query = _sink_query;
-  videoaggregator_class->fixate_caps = _fixate_caps;
-  videoaggregator_class->negotiated_caps = _negotiated_caps;
+  agg_class->fixate_src_caps = _fixate_caps;
+  agg_class->negotiated_src_caps = _negotiated_caps;
   videoaggregator_class->aggregate_frames = gst_compositor_aggregate_frames;
 
   g_object_class_install_property (gobject_class, PROP_BACKGROUND,
index cb992f3..f2e820b 100644 (file)
@@ -1043,7 +1043,9 @@ GST_START_TEST (test_audiointerleave_2ch_smallbuf)
   gst_caps_unref (caps);
   gst_event_unref (ev);
 
-  for (i = 0; i < 24; i++)
+  /* eat the caps processing */
+  gst_harness_crank_single_clock_wait (h);
+  for (i = 0; i < 23; i++)
     gst_harness_crank_single_clock_wait (h);
   fail_unless_equals_uint64 (gst_clock_get_time (GST_ELEMENT_CLOCK
           (h->element)), 750 * GST_MSECOND);