static GstCaps * gst_video_rate_transform_caps (GstBaseTransform * trans, GstPadDirection direction, GstCaps * caps, GstCaps * filter) { GstVideoRate *videorate = GST_VIDEO_RATE (trans); GstCaps *ret; GstStructure *s, *s1, *s2, *s3 = NULL; int maxrate = g_atomic_int_get (&videorate->max_rate); gint i; ret = gst_caps_new_empty (); for (i = 0; i < gst_caps_get_size (caps); i++) { s = gst_caps_get_structure (caps, i); s1 = gst_structure_copy (s); if (videorate->updating_caps && direction == GST_PAD_SINK) { GST_INFO_OBJECT (trans, "Only updating caps %" GST_PTR_FORMAT " with framerate" " %d/%d", caps, videorate->to_rate_numerator, videorate->to_rate_denominator); gst_structure_set (s1, "framerate", GST_TYPE_FRACTION, videorate->to_rate_numerator, videorate->to_rate_denominator, NULL); ret = gst_caps_merge_structure (ret, s1); continue; } s2 = gst_structure_copy (s); s3 = NULL; if (videorate->drop_only) { gint min_num = 0, min_denom = 1; gint max_num = G_MAXINT, max_denom = 1; /* Clamp the caps to our maximum rate as the first caps if possible */ if (!gst_video_max_rate_clamp_structure (s1, maxrate, &min_num, &min_denom, &max_num, &max_denom)) { min_num = 0; min_denom = 1; max_num = maxrate; max_denom = 1; /* clamp wouldn't be a real subset of 1..maxrate, in this case the sink * caps should become [1..maxrate], [1..maxint] and the src caps just * [1..maxrate]. In case there was a caps incompatibility things will * explode later as appropriate :) * * In case [X..maxrate] == [X..maxint], skip as we'll set it later */ if (direction == GST_PAD_SRC && maxrate != G_MAXINT) gst_structure_set (s1, "framerate", GST_TYPE_FRACTION_RANGE, min_num, min_denom, maxrate, 1, NULL); else { gst_structure_free (s1); s1 = NULL; } } if (direction == GST_PAD_SRC) { /* We can accept anything as long as it's at least the minimal framerate * the the sink needs */ gst_structure_set (s2, "framerate", GST_TYPE_FRACTION_RANGE, min_num, min_denom, G_MAXINT, 1, NULL); /* Also allow unknown framerate, if it isn't already */ if (min_num != 0 || min_denom != 1) { s3 = gst_structure_copy (s); gst_structure_set (s3, "framerate", GST_TYPE_FRACTION, 0, 1, NULL); } } else if (max_num != 0 || max_denom != 1) { /* We can provide everything upto the maximum framerate at the src */ gst_structure_set (s2, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, max_num, max_denom, NULL); } } else if (direction == GST_PAD_SINK) { gint min_num = 0, min_denom = 1; gint max_num = G_MAXINT, max_denom = 1; if (!gst_video_max_rate_clamp_structure (s1, maxrate, &min_num, &min_denom, &max_num, &max_denom)) { gst_structure_free (s1); s1 = NULL; } gst_structure_set (s2, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, maxrate, 1, NULL); } else { /* set the framerate as a range */ gst_structure_set (s2, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); } if (s1 != NULL) ret = gst_caps_merge_structure_full (ret, s1, gst_caps_features_copy (gst_caps_get_features (caps, i))); ret = gst_caps_merge_structure_full (ret, s2, gst_caps_features_copy (gst_caps_get_features (caps, i))); if (s3 != NULL) ret = gst_caps_merge_structure_full (ret, s3, gst_caps_features_copy (gst_caps_get_features (caps, i))); } if (filter) { GstCaps *intersection; intersection = gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST); gst_caps_unref (ret); ret = intersection; } return ret; }
static GstCaps * gst_play_sink_convert_bin_getcaps (GstPad * pad, GstCaps * filter) { GstPlaySinkConvertBin *self = GST_PLAY_SINK_CONVERT_BIN (gst_pad_get_parent (pad)); GstCaps *ret; GstPad *otherpad, *peer; GST_PLAY_SINK_CONVERT_BIN_LOCK (self); if (pad == self->srcpad) { otherpad = self->sinkpad; } else if (pad == self->sinkpad) { otherpad = self->srcpad; } else { GST_ERROR_OBJECT (pad, "Not one of our pads"); otherpad = NULL; } if (otherpad) { peer = gst_pad_get_peer (otherpad); if (peer) { GstCaps *peer_caps; GstCaps *downstream_filter = NULL; /* Add all the caps that we can convert to to the filter caps, * otherwise downstream might just return EMPTY caps because * it doesn't handle the filter caps but we could still convert * to these caps */ if (filter) { guint i, n; downstream_filter = gst_caps_new_empty (); /* Intersect raw video caps in the filter caps with the converter * caps. This makes sure that we don't accept raw video that we * can't handle, e.g. because of caps features */ n = gst_caps_get_size (filter); for (i = 0; i < n; i++) { GstStructure *s; GstCaps *tmp, *tmp2; s = gst_structure_copy (gst_caps_get_structure (filter, i)); if (gst_structure_has_name (s, self->audio ? "audio/x-raw" : "video/x-raw")) { tmp = gst_caps_new_full (s, NULL); tmp2 = gst_caps_intersect (tmp, self->converter_caps); gst_caps_append (downstream_filter, tmp2); gst_caps_unref (tmp); } else { gst_caps_append_structure (downstream_filter, s); } } downstream_filter = gst_caps_merge (downstream_filter, gst_caps_ref (self->converter_caps)); } peer_caps = gst_pad_query_caps (peer, downstream_filter); if (downstream_filter) gst_caps_unref (downstream_filter); gst_object_unref (peer); if (self->converter_caps && is_raw_caps (peer_caps, self->audio)) { GstCaps *converter_caps = gst_caps_ref (self->converter_caps); GstCapsFeatures *cf; GstStructure *s; guint i, n; ret = gst_caps_make_writable (peer_caps); /* Filter out ANY capsfeatures from the converter caps. We can't * convert to ANY capsfeatures, they are only there so that we * can passthrough whatever downstream can support... but we * definitely don't want to return them here */ n = gst_caps_get_size (converter_caps); for (i = 0; i < n; i++) { s = gst_caps_get_structure (converter_caps, i); cf = gst_caps_get_features (converter_caps, i); if (cf && gst_caps_features_is_any (cf)) continue; ret = gst_caps_merge_structure_full (ret, gst_structure_copy (s), (cf ? gst_caps_features_copy (cf) : NULL)); } gst_caps_unref (converter_caps); } else { ret = peer_caps; } } else { ret = gst_caps_ref (self->converter_caps); } GST_PLAY_SINK_CONVERT_BIN_FILTER_CAPS (filter, ret); } else { ret = filter ? gst_caps_ref (filter) : gst_caps_new_any (); } GST_PLAY_SINK_CONVERT_BIN_UNLOCK (self); gst_object_unref (self); GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret); return ret; }