diff --git a/ext/gl/gstglmixer.c b/ext/gl/gstglmixer.c index 401e4ed6c9..a9daf894ac 100644 --- a/ext/gl/gstglmixer.c +++ b/ext/gl/gstglmixer.c @@ -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); } diff --git a/ext/gl/gstglstereomix.c b/ext/gl/gstglstereomix.c index c342a23413..6768ff0106 100644 --- a/ext/gl/gstglstereomix.c +++ b/ext/gl/gstglstereomix.c @@ -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); diff --git a/ext/gl/gstglvideomixer.c b/ext/gl/gstglvideomixer.c index 9bce937065..a3e22b25d8 100644 --- a/ext/gl/gstglvideomixer.c +++ b/ext/gl/gstglvideomixer.c @@ -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; - caps = gst_caps_make_writable (caps); - gst_video_info_from_caps (&info, caps); + ret = gst_caps_make_writable (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; + + 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); - ret = - GST_VIDEO_AGGREGATOR_CLASS (gst_gl_video_mixer_parent_class)->update_caps - (vagg, caps); - - for (i = 0; i < gst_caps_get_size (ret); i++) { - GstStructure *s = gst_caps_get_structure (ret, i); - - 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); diff --git a/gst-libs/gst/video/gstvideoaggregator.c b/gst-libs/gst/video/gstvideoaggregator.c index d3a9ca96dc..2b0c87630e 100644 --- a/gst-libs/gst/video/gstvideoaggregator.c +++ b/gst-libs/gst/video/gstvideoaggregator.c @@ -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; + return caps; +} - info_caps = gst_video_info_to_caps (&info); +static GstCaps * +gst_videoaggregator_default_update_caps (GstVideoAggregator * vagg, + GstCaps * caps, GstCaps * filter) +{ + GstCaps *ret; - 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; + if (filter) { + ret = gst_caps_intersect (caps, filter); + } else { + ret = gst_caps_ref (caps); + } + + return ret; +} + +/* 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; } - - /* 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); - } - } - - peercaps = gst_pad_peer_query_caps (agg->srcpad, caps); - if (peercaps) { - GstCaps *tmp; - - 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); - - gst_caps_unref (caps); + 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; } + } - 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); + gst_video_info_from_caps (&vagg->info, caps); - /* fixate the the rest of the fields */ - caps = gst_caps_fixate (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); - 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 (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); diff --git a/gst-libs/gst/video/gstvideoaggregator.h b/gst-libs/gst/video/gstvideoaggregator.h index f95d0d2674..86df0b6294 100644 --- a/gst-libs/gst/video/gstvideoaggregator.h +++ b/gst-libs/gst/video/gstvideoaggregator.h @@ -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 > */ diff --git a/gst/compositor/compositor.c b/gst/compositor/compositor.c index d015d85e10..c5b1a9abf4 100644 --- a/gst/compositor/compositor.c +++ b/gst/compositor/compositor.c @@ -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_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); + 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_caps_set_simple (ret, "pixel-aspect-ratio", GST_TYPE_FRACTION_RANGE, - 1, G_MAXINT, G_MAXINT, 1, NULL); + 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) { + GstVideoInfo v_info; + + 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,