videoaggregator: don't do caps processing that is not overridable
authorMatthew Waters <matthew@centricular.com>
Wed, 14 Oct 2015 10:13:57 +0000 (21:13 +1100)
committerMatthew Waters <matthew@centricular.com>
Wed, 27 Jan 2016 09:36:25 +0000 (20:36 +1100)
Allows the subclass to completely override the chosen src caps.

This is needed as videoaggregator generally has no idea exactly
what operation is being performed.

- Adds a fixate_caps vfunc for fixation
- Merges gst_video_aggregator_update_converters() into
  gst_videoaggregator_update_src_caps() as we need some of its info
  for proper caps handling.
- Pass the downstream caps to the update_caps vfunc

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

ext/gl/gstglmixer.c
ext/gl/gstglstereomix.c
ext/gl/gstglvideomixer.c
gst-libs/gst/video/gstvideoaggregator.c
gst-libs/gst/video/gstvideoaggregator.h
gst/compositor/compositor.c

index 401e4ed6c9b9ee77e90c6d807a74f71842766552..a9daf894acf81fd9eac1114cc4013f37ec7be233 100644 (file)
@@ -221,9 +221,17 @@ gst_gl_mixer_pad_sink_acceptcaps (GstPad * pad, GstGLMixer * mix,
 
 /* copies the given caps */
 static GstCaps *
-_update_caps (GstVideoAggregator * vagg, GstCaps * caps)
+_update_caps (GstVideoAggregator * vagg, GstCaps * caps, GstCaps * filter)
 {
-  return gst_gl_caps_replace_all_caps_features (caps,
+  GstCaps *tmp;
+
+  if (filter) {
+    tmp = gst_caps_intersect (caps, filter);
+  } else {
+    tmp = caps;
+  }
+
+  return gst_gl_caps_replace_all_caps_features (tmp,
       GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
 }
 
index c342a234132f505213e85d76f2d7c15b43151150..6768ff010608ca3722fc09b32a9b629360161378 100644 (file)
@@ -33,7 +33,8 @@ GST_DEBUG_CATEGORY (gst_gl_stereo_mix_debug);
 #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);
+static GstCaps *_update_caps (GstVideoAggregator * vagg, GstCaps * caps,
+    GstCaps * filter);
 static gboolean _negotiated_caps (GstVideoAggregator * videoaggregator,
     GstCaps * caps);
 gboolean gst_gl_stereo_mix_make_output (GstGLStereoMix * mix);
@@ -153,7 +154,6 @@ gst_gl_stereo_mix_class_init (GstGLStereoMixClass * klass)
   videoaggregator_class->get_output_buffer =
       gst_gl_stereo_mix_get_output_buffer;
   videoaggregator_class->find_best_format = gst_gl_stereo_mix_find_best_format;
-  videoaggregator_class->preserve_update_caps_result = TRUE;
 
   base_mix_class->supported_gl_api = GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
 }
@@ -471,7 +471,7 @@ get_converted_caps (GstGLStereoMix * mix, GstCaps * caps)
 
 /* Return the possible output caps we decided in find_best_format() */
 static GstCaps *
-_update_caps (GstVideoAggregator * vagg, GstCaps * caps)
+_update_caps (GstVideoAggregator * vagg, GstCaps * caps, GstCaps * filter)
 {
   GstGLStereoMix *mix = GST_GL_STEREO_MIX (vagg);
 
index 9bce937065cd09e6f79cd47f62691f38603f316a..a3e22b25d898ed123170134e8e6a8a901e86424d 100644 (file)
@@ -460,7 +460,9 @@ 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);
+static GstCaps *_update_caps (GstVideoAggregator * vagg, GstCaps * caps,
+    GstCaps * filter);
+static GstCaps *_fixate_caps (GstVideoAggregator * vagg, GstCaps * caps);
 static void gst_gl_video_mixer_reset (GstGLMixer * mixer);
 static gboolean gst_gl_video_mixer_init_shader (GstGLMixer * mixer,
     GstCaps * outcaps);
@@ -863,6 +865,7 @@ 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;
 
@@ -912,9 +915,9 @@ gst_gl_video_mixer_get_property (GObject * object, guint prop_id,
 
 static void
 _mixer_pad_get_output_size (GstGLVideoMixer * mix,
-    GstGLVideoMixerPad * mix_pad, gint * width, gint * height)
+    GstGLVideoMixerPad * mix_pad, gint out_par_n, gint out_par_d, gint * width,
+    gint * height)
 {
-  GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix);
   GstVideoAggregatorPad *vagg_pad = GST_VIDEO_AGGREGATOR_PAD (mix_pad);
   gint pad_width, pad_height;
   guint dar_n, dar_d;
@@ -937,13 +940,10 @@ _mixer_pad_get_output_size (GstGLVideoMixer * mix,
 
   gst_video_calculate_display_ratio (&dar_n, &dar_d, pad_width, pad_height,
       GST_VIDEO_INFO_PAR_N (&vagg_pad->info),
-      GST_VIDEO_INFO_PAR_D (&vagg_pad->info),
-      GST_VIDEO_INFO_PAR_N (&vagg->info), GST_VIDEO_INFO_PAR_D (&vagg->info)
-      );
+      GST_VIDEO_INFO_PAR_D (&vagg_pad->info), out_par_n, out_par_d);
   GST_LOG_OBJECT (mix_pad, "scaling %ux%u by %u/%u (%u/%u / %u/%u)", pad_width,
       pad_height, dar_n, dar_d, GST_VIDEO_INFO_PAR_N (&vagg_pad->info),
-      GST_VIDEO_INFO_PAR_D (&vagg_pad->info),
-      GST_VIDEO_INFO_PAR_N (&vagg->info), GST_VIDEO_INFO_PAR_D (&vagg->info));
+      GST_VIDEO_INFO_PAR_D (&vagg_pad->info), out_par_n, out_par_d);
 
   if (pad_height % dar_n == 0) {
     pad_width = gst_util_uint64_scale_int (pad_height, dar_n, dar_d);
@@ -960,17 +960,45 @@ _mixer_pad_get_output_size (GstGLVideoMixer * mix,
 }
 
 static GstCaps *
-_update_caps (GstVideoAggregator * vagg, GstCaps * caps)
+_update_caps (GstVideoAggregator * vagg, GstCaps * caps, GstCaps * filter)
+{
+  GstCaps *ret;
+
+  ret =
+      GST_VIDEO_AGGREGATOR_CLASS (gst_gl_video_mixer_parent_class)->update_caps
+      (vagg, caps, NULL);
+
+  if (filter) {
+    GstCaps *tmp = gst_caps_intersect (ret, filter);
+    gst_caps_unref (ret);
+    ret = tmp;
+  }
+
+  return ret;
+}
+
+static GstCaps *
+_fixate_caps (GstVideoAggregator * vagg, GstCaps * caps)
 {
   GstGLVideoMixer *mix = GST_GL_VIDEO_MIXER (vagg);
-  GList *l;
-  gint best_width = -1, best_height = -1;
-  GstVideoInfo info;
+  gint best_width = 0, best_height = 0;
+  gint best_fps_n = 0, best_fps_d = 0;
+  gint par_n, par_d;
+  gdouble best_fps = 0.;
   GstCaps *ret = NULL;
-  int i;
+  GstStructure *s;
+  GList *l;
+
+  ret = gst_caps_make_writable (caps);
 
-  caps = gst_caps_make_writable (caps);
-  gst_video_info_from_caps (&info, caps);
+  /* we need this to calculate how large to make the output frame */
+  s = gst_caps_get_structure (ret, 0);
+  if (gst_structure_has_field (s, "pixel-aspect-ratio")) {
+    gst_structure_fixate_field_nearest_fraction (s, "pixel-aspect-ratio", 1, 1);
+    gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
+  } else {
+    par_n = par_d = 1;
+  }
 
   GST_OBJECT_LOCK (vagg);
   for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
@@ -978,8 +1006,12 @@ _update_caps (GstVideoAggregator * vagg, GstCaps * caps)
     GstGLVideoMixerPad *mixer_pad = GST_GL_VIDEO_MIXER_PAD (vaggpad);
     gint this_width, this_height;
     gint width, height;
+    gint fps_n, fps_d;
+    gdouble cur_fps;
 
-    _mixer_pad_get_output_size (mix, mixer_pad, &width, &height);
+    fps_n = GST_VIDEO_INFO_FPS_N (&vaggpad->info);
+    fps_d = GST_VIDEO_INFO_FPS_D (&vaggpad->info);
+    _mixer_pad_get_output_size (mix, mixer_pad, par_n, par_d, &width, &height);
 
     if (width == 0 || height == 0)
       continue;
@@ -991,20 +1023,34 @@ _update_caps (GstVideoAggregator * vagg, GstCaps * caps)
       best_width = this_width;
     if (best_height < this_height)
       best_height = this_height;
-  }
-  GST_OBJECT_UNLOCK (vagg);
 
-  ret =
-      GST_VIDEO_AGGREGATOR_CLASS (gst_gl_video_mixer_parent_class)->update_caps
-      (vagg, caps);
+    if (fps_d == 0)
+      cur_fps = 0.0;
+    else
+      gst_util_fraction_to_double (fps_n, fps_d, &cur_fps);
 
-  for (i = 0; i < gst_caps_get_size (ret); i++) {
-    GstStructure *s = gst_caps_get_structure (ret, i);
+    if (best_fps < cur_fps) {
+      best_fps = cur_fps;
+      best_fps_n = fps_n;
+      best_fps_d = fps_d;
+    }
+  }
+  GST_OBJECT_UNLOCK (vagg);
 
-    gst_structure_set (s, "width", G_TYPE_INT, best_width, "height", G_TYPE_INT,
-        best_height, NULL);
+  if (best_fps_n <= 0 || best_fps_d <= 0 || best_fps == 0.0) {
+    best_fps_n = 25;
+    best_fps_d = 1;
+    best_fps = 25.0;
   }
 
+  s = gst_caps_get_structure (ret, 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_nearest_fraction (s, "pixel-aspect-ratio", 1, 1);
+  ret = gst_caps_fixate (ret);
+
   return ret;
 }
 
@@ -1397,7 +1443,9 @@ gst_gl_video_mixer_callback (gpointer stuff)
       gint pad_width, pad_height;
       gfloat w, h;
 
-      _mixer_pad_get_output_size (video_mixer, pad, &pad_width, &pad_height);
+      _mixer_pad_get_output_size (video_mixer, pad,
+          GST_VIDEO_INFO_PAR_N (&vagg->info),
+          GST_VIDEO_INFO_PAR_D (&vagg->info), &pad_width, &pad_height);
 
       w = ((gfloat) pad_width / (gfloat) out_width);
       h = ((gfloat) pad_height / (gfloat) out_height);
index d3a9ca96dc564f65dc35dde6755ee10062a20c68..2b0c87630e08ed92292c8f976179b73dd9303eb6 100644 (file)
@@ -532,86 +532,6 @@ gst_videoaggreagator_find_best_format (GstVideoAggregator * vagg,
   g_hash_table_unref (formats_table);
 }
 
-/* WITH GST_VIDEO_AGGREGATOR_LOCK TAKEN
- * NOTE: After calling that method you **have to** call
- *       gst_videoaggregator_update_src_caps (without releasing
- *       the GST_VIDEO_AGGREGATOR_LOCK in between)
- */
-static gboolean
-gst_videoaggregator_update_converters (GstVideoAggregator * vagg)
-{
-  GList *tmp;
-  GstVideoFormat best_format;
-  GstVideoInfo best_info;
-  gboolean at_least_one_alpha = FALSE;
-  GstCaps *downstream_caps;
-  GstAggregator *agg = GST_AGGREGATOR (vagg);
-
-  GstVideoAggregatorClass *vagg_class = GST_VIDEO_AGGREGATOR_GET_CLASS (vagg);
-  GstVideoAggregatorPadClass *vaggpad_class = g_type_class_peek
-      (GST_AGGREGATOR_GET_CLASS (vagg)->sinkpads_type);
-
-  best_format = GST_VIDEO_FORMAT_UNKNOWN;
-  gst_video_info_init (&best_info);
-
-  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;
-  }
-
-
-  if (vagg_class->find_best_format) {
-    vagg_class->find_best_format (vagg, downstream_caps, &best_info,
-        &at_least_one_alpha);
-
-    best_format = GST_VIDEO_INFO_FORMAT (&best_info);
-  }
-
-  if (best_format == GST_VIDEO_FORMAT_UNKNOWN) {
-    downstream_caps = gst_caps_fixate (downstream_caps);
-    gst_video_info_from_caps (&best_info, downstream_caps);
-    best_format = GST_VIDEO_INFO_FORMAT (&best_info);
-  }
-
-  gst_caps_unref (downstream_caps);
-
-  if (at_least_one_alpha
-      && !(best_info.finfo->flags & GST_VIDEO_FORMAT_FLAG_ALPHA)) {
-    GST_ELEMENT_ERROR (vagg, CORE, NEGOTIATION,
-        ("At least one of the input pads contains alpha, but downstream can't support alpha."),
-        ("Either convert your inputs to not contain alpha or add a videoconvert after the aggregator"));
-    return FALSE;
-  }
-
-  vagg->info = best_info;
-
-  GST_DEBUG_OBJECT (vagg,
-      "The output format will now be : %d with chroma : %s",
-      best_format, gst_video_chroma_to_string (best_info.chroma_site));
-
-  if (vaggpad_class->set_info) {
-    GST_OBJECT_LOCK (vagg);
-    /* Then browse the sinks once more, setting or unsetting conversion if needed */
-    for (tmp = GST_ELEMENT (vagg)->sinkpads; tmp; tmp = tmp->next) {
-      GstVideoAggregatorPad *pad = GST_VIDEO_AGGREGATOR_PAD (tmp->data);
-
-      if (!vaggpad_class->set_info (pad, vagg, &pad->info, &best_info)) {
-        GST_OBJECT_UNLOCK (vagg);
-
-        return FALSE;
-      }
-    }
-    GST_OBJECT_UNLOCK (vagg);
-  }
-
-  return TRUE;
-}
-
 /* WITH GST_VIDEO_AGGREGATOR_LOCK TAKEN */
 static gboolean
 gst_videoaggregator_src_setcaps (GstVideoAggregator * vagg, GstCaps * caps)
@@ -662,25 +582,22 @@ done:
   return ret;
 }
 
-/* WITH GST_VIDEO_AGGREGATOR_LOCK TAKEN */
-static gboolean
-gst_videoaggregator_update_src_caps (GstVideoAggregator * vagg)
+static GstCaps *
+gst_videoaggregator_default_fixate_caps (GstVideoAggregator * vagg,
+    GstCaps * caps)
 {
-  GList *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;
-  GstElementClass *klass = GST_ELEMENT_GET_CLASS (vagg);
-  GstVideoAggregatorClass *vagg_klass = (GstVideoAggregatorClass *) klass;
-  GstAggregator *agg = GST_AGGREGATOR (vagg);
+  gdouble best_fps = -1.;
+  GstStructure *s;
+  GList *l;
 
   GST_OBJECT_LOCK (vagg);
   for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
     GstVideoAggregatorPad *mpad = l->data;
-    gint this_width, this_height;
     gint fps_n, fps_d;
     gint width, height;
+    gdouble cur_fps;
 
     fps_n = GST_VIDEO_INFO_FPS_N (&mpad->info);
     fps_d = GST_VIDEO_INFO_FPS_D (&mpad->info);
@@ -690,13 +607,10 @@ gst_videoaggregator_update_src_caps (GstVideoAggregator * vagg)
     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 (best_width < width)
+      best_width = width;
+    if (best_height < height)
+      best_height = height;
 
     if (fps_d == 0)
       cur_fps = 0.0;
@@ -717,88 +631,142 @@ gst_videoaggregator_update_src_caps (GstVideoAggregator * vagg)
     best_fps = 25.0;
   }
 
-  if (best_width > 0 && best_height > 0 && best_fps > 0) {
-    GstCaps *caps, *peercaps, *info_caps;
-    GstStructure *s;
-    GstVideoInfo info;
-    int i;
+  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);
+  if (gst_structure_has_field (s, "pixel-aspect-ratio"))
+    gst_structure_fixate_field_nearest_fraction (s, "pixel-aspect-ratio", 1, 1);
+  caps = gst_caps_fixate (caps);
 
-    /* Initialize the video info with our target format and
-     * the best width and height and framerate. Then copy over
-     * all other fields as we negotiated them before
-     */
-    gst_video_info_set_format (&info, GST_VIDEO_INFO_FORMAT (&vagg->info),
-        best_width, best_height);
-    info.fps_n = best_fps_n;
-    info.fps_d = best_fps_d;
-    info.chroma_site = vagg->info.chroma_site;
-    info.par_n = vagg->info.par_n;
-    info.par_d = vagg->info.par_d;
-    info.colorimetry = vagg->info.colorimetry;
-    info.flags = vagg->info.flags;
-    info.interlace_mode = vagg->info.interlace_mode;
-
-    info_caps = gst_video_info_to_caps (&info);
-
-    if (vagg_klass->update_caps) {
-      if (!(caps = vagg_klass->update_caps (vagg, info_caps))) {
-        gst_caps_unref (info_caps);
-        ret = FALSE;
-        goto done;
-      }
-      gst_caps_unref (info_caps);
-    } else {
-      caps = info_caps;
-    }
+  return caps;
+}
 
-    /* If the sub-class allows it, allow size/framerate changes */
-    if (!vagg_klass->preserve_update_caps_result) {
-      s = gst_caps_get_structure (caps, 0);
-      gst_structure_get (s, "width", G_TYPE_INT, &best_width, "height",
-          G_TYPE_INT, &best_height, NULL);
-
-      for (i = 0; i < gst_caps_get_size (caps); i++) {
-        s = gst_caps_get_structure (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);
-      }
-    }
+static GstCaps *
+gst_videoaggregator_default_update_caps (GstVideoAggregator * vagg,
+    GstCaps * caps, GstCaps * filter)
+{
+  GstCaps *ret;
 
-    peercaps = gst_pad_peer_query_caps (agg->srcpad, caps);
-    if (peercaps) {
-      GstCaps *tmp;
+  if (filter) {
+    ret = gst_caps_intersect (caps, filter);
+  } else {
+    ret = gst_caps_ref (caps);
+  }
 
-      tmp = gst_caps_intersect (caps, peercaps);
-      GST_DEBUG_OBJECT (vagg, "intersecting %" GST_PTR_FORMAT
-          " with peer caps %" GST_PTR_FORMAT " result %" GST_PTR_FORMAT, caps,
-          peercaps, tmp);
+  return ret;
+}
 
-      gst_caps_unref (caps);
+/* WITH GST_VIDEO_AGGREGATOR_LOCK TAKEN */
+static gboolean
+gst_videoaggregator_update_src_caps (GstVideoAggregator * vagg)
+{
+  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;
+  GstVideoFormat best_format;
+  GstVideoInfo best_info;
+  gboolean at_least_one_alpha = FALSE;
+  GstCaps *downstream_caps;
+  GList *l;
+
+  best_format = GST_VIDEO_FORMAT_UNKNOWN;
+  gst_video_info_init (&best_info);
+
+  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;
+  }
+
+  if (vagg_klass->find_best_format) {
+    vagg_klass->find_best_format (vagg, downstream_caps, &best_info,
+        &at_least_one_alpha);
+
+    best_format = GST_VIDEO_INFO_FORMAT (&best_info);
+  }
+
+  if (best_format == GST_VIDEO_FORMAT_UNKNOWN) {
+    GstCaps *tmp = gst_caps_fixate (gst_caps_ref (downstream_caps));
+    gst_video_info_from_caps (&best_info, tmp);
+    best_format = GST_VIDEO_INFO_FORMAT (&best_info);
+    gst_caps_unref (tmp);
+  }
+
+  if (at_least_one_alpha
+      && !(best_info.finfo->flags & GST_VIDEO_FORMAT_FLAG_ALPHA)) {
+    GST_ELEMENT_ERROR (vagg, CORE, NEGOTIATION,
+        ("At least one of the input pads contains alpha, but downstream can't support alpha."),
+        ("Either convert your inputs to not contain alpha or add a videoconvert after the aggregator"));
+    return FALSE;
+  }
+
+  GST_DEBUG_OBJECT (vagg,
+      "The output format will now be : %d with chroma : %s",
+      best_format, gst_video_chroma_to_string (best_info.chroma_site));
+
+  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;
+    break;
+  }
+  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);
+    if (!(caps = vagg_klass->update_caps (vagg, downstream_caps, peercaps))) {
+      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;
+    }
+    gst_caps_unref (downstream_caps);
+    if (peercaps)
       gst_caps_unref (peercaps);
-      caps = tmp;               /* pass ownership */
-      if (gst_caps_is_empty (caps)) {
-        GST_DEBUG_OBJECT (vagg, "empty caps");
+
+    if (!gst_caps_is_fixed (caps)) {
+      g_assert (vagg_klass->fixate_caps);
+
+      caps = gst_caps_make_writable (caps);
+      if (!(caps = vagg_klass->fixate_caps (vagg, caps))) {
+        GST_WARNING_OBJECT (vagg, "Subclass failed to fixate provided caps");
         ret = FALSE;
-        gst_caps_unref (caps);
         goto done;
       }
+    }
+
+    gst_video_info_from_caps (&vagg->info, 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_nearest_fraction (s, "pixel-aspect-ratio", 1,
-          1);
-
-      /* fixate the the rest of the fields */
-      caps = gst_caps_fixate (caps);
-
-      gst_structure_get_int (s, "width", &info.width);
-      gst_structure_get_int (s, "height", &info.height);
-      gst_structure_get_fraction (s, "framerate", &info.fps_n, &info.fps_d);
+    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 (!vaggpad_klass->set_info (pad, vagg, &pad->info, &vagg->info)) {
+          GST_OBJECT_UNLOCK (vagg);
+
+          return FALSE;
+        }
+      }
     }
 
     if (gst_videoaggregator_src_setcaps (vagg, caps)) {
@@ -1414,10 +1382,7 @@ gst_videoaggregator_check_reconfigure (GstVideoAggregator * vagg,
       || gst_pad_check_reconfigure (GST_AGGREGATOR_SRC_PAD (vagg))) {
     gboolean ret;
 
-    ret = gst_videoaggregator_update_converters (vagg);
-    if (ret)
-      ret = gst_videoaggregator_update_src_caps (vagg);
-
+    ret = gst_videoaggregator_update_src_caps (vagg);
     if (!ret) {
       if (timeout && gst_pad_needs_reconfigure (GST_AGGREGATOR_SRC_PAD (vagg))) {
         guint64 frame_duration;
@@ -2099,6 +2064,8 @@ gst_videoaggregator_class_init (GstVideoAggregatorClass * klass)
 
   klass->find_best_format = gst_videoaggreagator_find_best_format;
   klass->get_output_buffer = gst_videoaggregator_get_output_buffer;
+  klass->update_caps = gst_videoaggregator_default_update_caps;
+  klass->fixate_caps = gst_videoaggregator_default_fixate_caps;
 
   /* Register the pad class */
   g_type_class_ref (GST_TYPE_VIDEO_AGGREGATOR_PAD);
index f95d0d26746be1e4d9439eb42e5330fbb9e8f094..86df0b62948311a78f0753bd3749c8fe40019712 100644 (file)
@@ -73,6 +73,9 @@ 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
@@ -86,9 +89,6 @@ struct _GstVideoAggregator
  *                            Notifies subclasses what caps format has been negotiated
  * @find_best_format:         Optional.
  *                            Lets subclasses decide of the best common format to use.
- * @preserve_update_caps_result: Sub-classes should set this to true if the return result
- *                               of the update_caps() method should not be further modified
- *                               by GstVideoAggregator by removing fields.
  **/
 struct _GstVideoAggregatorClass
 {
@@ -97,6 +97,9 @@ 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);
@@ -109,8 +112,6 @@ struct _GstVideoAggregatorClass
                                                    GstVideoInfo       *  best_info,
                                                    gboolean           *  at_least_one_alpha);
 
-  gboolean           preserve_update_caps_result;
-
   GstCaps           *sink_non_alpha_caps;
 
   /* < private > */
index d015d85e1054217fda626877391c278dbbee9029..c5b1a9abf4b29e2909a5f4d85325cad541d286c0 100644 (file)
@@ -216,9 +216,9 @@ gst_compositor_pad_set_property (GObject * object, guint prop_id,
 
 static void
 _mixer_pad_get_output_size (GstCompositor * comp,
-    GstCompositorPad * comp_pad, gint * width, gint * height)
+    GstCompositorPad * comp_pad, gint out_par_n, gint out_par_d, gint * width,
+    gint * height)
 {
-  GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (comp);
   GstVideoAggregatorPad *vagg_pad = GST_VIDEO_AGGREGATOR_PAD (comp_pad);
   gint pad_width, pad_height;
   guint dar_n, dar_d;
@@ -241,13 +241,10 @@ _mixer_pad_get_output_size (GstCompositor * comp,
 
   gst_video_calculate_display_ratio (&dar_n, &dar_d, pad_width, pad_height,
       GST_VIDEO_INFO_PAR_N (&vagg_pad->info),
-      GST_VIDEO_INFO_PAR_D (&vagg_pad->info),
-      GST_VIDEO_INFO_PAR_N (&vagg->info), GST_VIDEO_INFO_PAR_D (&vagg->info)
-      );
+      GST_VIDEO_INFO_PAR_D (&vagg_pad->info), out_par_n, out_par_d);
   GST_LOG_OBJECT (comp_pad, "scaling %ux%u by %u/%u (%u/%u / %u/%u)", pad_width,
       pad_height, dar_n, dar_d, GST_VIDEO_INFO_PAR_N (&vagg_pad->info),
-      GST_VIDEO_INFO_PAR_D (&vagg_pad->info),
-      GST_VIDEO_INFO_PAR_N (&vagg->info), GST_VIDEO_INFO_PAR_D (&vagg->info));
+      GST_VIDEO_INFO_PAR_D (&vagg_pad->info), out_par_n, out_par_d);
 
   if (pad_height % dar_n == 0) {
     pad_width = gst_util_uint64_scale_int (pad_height, dar_n, dar_d);
@@ -292,7 +289,8 @@ gst_compositor_pad_set_info (GstVideoAggregatorPad * pad,
       gst_video_colorimetry_to_string (&(wanted_info->colorimetry));
   best_chroma = gst_video_chroma_to_string (wanted_info->chroma_site);
 
-  _mixer_pad_get_output_size (comp, cpad, &width, &height);
+  _mixer_pad_get_output_size (comp, cpad, GST_VIDEO_INFO_PAR_N (&vagg->info),
+      GST_VIDEO_INFO_PAR_D (&vagg->info), &width, &height);
 
   if (GST_VIDEO_INFO_FORMAT (wanted_info) !=
       GST_VIDEO_INFO_FORMAT (current_info)
@@ -310,8 +308,8 @@ gst_compositor_pad_set_info (GstVideoAggregatorPad * pad,
         width, height);
     tmp_info.chroma_site = wanted_info->chroma_site;
     tmp_info.colorimetry = wanted_info->colorimetry;
-    tmp_info.par_n = vagg->info.par_n;
-    tmp_info.par_d = vagg->info.par_d;
+    tmp_info.par_n = wanted_info->par_n;
+    tmp_info.par_d = wanted_info->par_d;
     tmp_info.fps_n = current_info->fps_n;
     tmp_info.fps_d = current_info->fps_d;
     tmp_info.flags = current_info->flags;
@@ -403,7 +401,8 @@ gst_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad,
    *     width/height. See ->set_info()
    * */
 
-  _mixer_pad_get_output_size (comp, cpad, &width, &height);
+  _mixer_pad_get_output_size (comp, cpad, GST_VIDEO_INFO_PAR_N (&vagg->info),
+      GST_VIDEO_INFO_PAR_D (&vagg->info), &width, &height);
 
   /* The only thing that can change here is the width
    * and height, otherwise set_info would've been called */
@@ -498,7 +497,8 @@ gst_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad,
     GstCompositorPad *cpad2 = GST_COMPOSITOR_PAD (pad2);
     gint pad2_width, pad2_height;
 
-    _mixer_pad_get_output_size (comp, cpad2, &pad2_width, &pad2_height);
+    _mixer_pad_get_output_size (comp, cpad2, GST_VIDEO_INFO_PAR_N (&vagg->info),
+        GST_VIDEO_INFO_PAR_D (&vagg->info), &pad2_width, &pad2_height);
 
     /* We don't need to clamp the coords of the second rectangle */
     frame2_rect.x = cpad2->xpos;
@@ -883,17 +883,26 @@ set_functions (GstCompositor * self, GstVideoInfo * info)
 }
 
 static GstCaps *
-_update_caps (GstVideoAggregator * vagg, GstCaps * caps)
+_fixate_caps (GstVideoAggregator * vagg, GstCaps * caps)
 {
   GList *l;
   gint best_width = -1, best_height = -1;
-  GstVideoInfo info;
+  gint best_fps_n = -1, best_fps_d = -1;
+  gint par_n, par_d;
+  gdouble best_fps = 0.;
   GstCaps *ret = NULL;
+  GstStructure *s;
 
-  gst_video_info_from_caps (&info, caps);
+  ret = gst_caps_make_writable (caps);
 
-  /* FIXME: this doesn't work for non 1/1 output par's as we don't have that
-   * information available at this time */
+  /* we need this to calculate how large to make the output frame */
+  s = gst_caps_get_structure (ret, 0);
+  if (gst_structure_has_field (s, "pixel-aspect-ratio")) {
+    gst_structure_fixate_field_nearest_fraction (s, "pixel-aspect-ratio", 1, 1);
+    gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
+  } else {
+    par_n = par_d = 1;
+  }
 
   GST_OBJECT_LOCK (vagg);
   for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
@@ -901,9 +910,13 @@ _update_caps (GstVideoAggregator * vagg, GstCaps * caps)
     GstCompositorPad *compositor_pad = GST_COMPOSITOR_PAD (vaggpad);
     gint this_width, this_height;
     gint width, height;
+    gint fps_n, fps_d;
+    gdouble cur_fps;
 
-    _mixer_pad_get_output_size (GST_COMPOSITOR (vagg), compositor_pad, &width,
-        &height);
+    fps_n = GST_VIDEO_INFO_FPS_N (&vaggpad->info);
+    fps_d = GST_VIDEO_INFO_FPS_D (&vaggpad->info);
+    _mixer_pad_get_output_size (GST_COMPOSITOR (vagg), compositor_pad, par_n,
+        par_d, &width, &height);
 
     if (width == 0 || height == 0)
       continue;
@@ -915,17 +928,40 @@ _update_caps (GstVideoAggregator * vagg, GstCaps * caps)
       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;
+    }
   }
   GST_OBJECT_UNLOCK (vagg);
 
+  if (best_fps_n <= 0 || best_fps_d <= 0 || best_fps == 0.0) {
+    best_fps_n = 25;
+    best_fps_d = 1;
+    best_fps = 25.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);
+  ret = gst_caps_fixate (ret);
+
   if (best_width > 0 && best_height > 0) {
-    info.width = best_width;
-    info.height = best_height;
-    if (set_functions (GST_COMPOSITOR (vagg), &info))
-      ret = gst_video_info_to_caps (&info);
+    GstVideoInfo v_info;
 
-    gst_caps_set_simple (ret, "pixel-aspect-ratio", GST_TYPE_FRACTION_RANGE,
-        1, G_MAXINT, G_MAXINT, 1, NULL);
+    gst_video_info_from_caps (&v_info, ret);
+    if (!set_functions (GST_COMPOSITOR (vagg), &v_info)) {
+      GST_ERROR_OBJECT (vagg, "Failed to setup vfuncs");
+      return NULL;
+    }
   }
 
   return ret;
@@ -1059,7 +1095,7 @@ gst_compositor_class_init (GstCompositorClass * klass)
 
   agg_class->sinkpads_type = GST_TYPE_COMPOSITOR_PAD;
   agg_class->sink_query = _sink_query;
-  videoaggregator_class->update_caps = _update_caps;
+  videoaggregator_class->fixate_caps = _fixate_caps;
   videoaggregator_class->aggregate_frames = gst_compositor_aggregate_frames;
 
   g_object_class_install_property (gobject_class, PROP_BACKGROUND,