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
/* 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);
}
#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);
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;
}
/* 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);
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);
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;
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;
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);
}
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) {
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;
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;
}
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);
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)
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);
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;
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)) {
|| 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;
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);
* @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
* 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
{
/*< 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);
GstVideoInfo * best_info,
gboolean * at_least_one_alpha);
- gboolean preserve_update_caps_result;
-
GstCaps *sink_non_alpha_caps;
/* < private > */
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;
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);
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)
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;
* 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 */
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;
}
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) {
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;
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;
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,