diff --git a/subprojects/gst-plugins-base/gst/playback/gstsubtitleoverlay.c b/subprojects/gst-plugins-base/gst/playback/gstsubtitleoverlay.c index cc2ee06cd9..75f6ad8fa8 100644 --- a/subprojects/gst-plugins-base/gst/playback/gstsubtitleoverlay.c +++ b/subprojects/gst-plugins-base/gst/playback/gstsubtitleoverlay.c @@ -55,6 +55,10 @@ GST_DEBUG_CATEGORY_STATIC (subtitle_overlay_debug); #define IS_VIDEO_CHAIN_IGNORE_ERROR(flow) \ G_UNLIKELY (flow == GST_FLOW_ERROR) +/* We have colorspace conversions so we can accept any known video formats */ +#define SUBTITLE_OVERLAY_CAPS GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL) +static GstStaticCaps sw_template_caps = GST_STATIC_CAPS (SUBTITLE_OVERLAY_CAPS); + static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, @@ -1796,6 +1800,186 @@ done: return ret; } +/** + * gst_subtitle_overlay_add_feature_and_intersect: + * + * Creates a new #GstCaps containing the (given caps + + * given caps feature) + (given caps intersected by the + * given filter). + * + * Returns: the new #GstCaps + */ +static GstCaps * +gst_subtitle_overlay_add_feature_and_intersect (GstCaps * caps, + const gchar * feature, GstCaps * filter) +{ + int i, caps_size; + GstCaps *new_caps; + + new_caps = gst_caps_copy (caps); + + caps_size = gst_caps_get_size (new_caps); + for (i = 0; i < caps_size; i++) { + GstCapsFeatures *features = gst_caps_get_features (new_caps, i); + if (!gst_caps_features_is_any (features)) { + gst_caps_features_add (features, feature); + } + } + + gst_caps_append (new_caps, gst_caps_intersect_full (caps, + filter, GST_CAPS_INTERSECT_FIRST)); + + return new_caps; +} + +/** + * gst_subtitle_overlay_intersect_by_feature: + * + * Creates a new #GstCaps based on the following filtering rule. + * + * For each individual caps contained in given caps, if the + * caps uses the given caps feature, keep a version of the caps + * with the feature and an another one without. Otherwise, intersect + * the caps with the given filter. + * + * Returns: the new #GstCaps + */ +static GstCaps * +gst_subtitle_overlay_intersect_by_feature (GstCaps * caps, + const gchar * feature, GstCaps * filter) +{ + int i, caps_size; + GstCaps *new_caps; + + new_caps = gst_caps_new_empty (); + + caps_size = gst_caps_get_size (caps); + for (i = 0; i < caps_size; i++) { + GstStructure *caps_structure = gst_caps_get_structure (caps, i); + GstCapsFeatures *caps_features = + gst_caps_features_copy (gst_caps_get_features (caps, i)); + GstCaps *filtered_caps; + GstCaps *simple_caps = + gst_caps_new_full (gst_structure_copy (caps_structure), NULL); + gst_caps_set_features (simple_caps, 0, caps_features); + + if (gst_caps_features_contains (caps_features, feature)) { + gst_caps_append (new_caps, gst_caps_copy (simple_caps)); + + gst_caps_features_remove (caps_features, feature); + filtered_caps = gst_caps_ref (simple_caps); + } else { + filtered_caps = gst_caps_intersect_full (simple_caps, filter, + GST_CAPS_INTERSECT_FIRST); + } + + gst_caps_unref (simple_caps); + gst_caps_append (new_caps, filtered_caps); + } + + return new_caps; +} + +static GstCaps * +gst_subtitle_overlay_get_videosink_caps (GstSubtitleOverlay * overlay, + GstPad * pad, GstCaps * filter) +{ + GstPad *srcpad = overlay->srcpad; + GstCaps *peer_caps = NULL, *caps = NULL, *overlay_filter = NULL; + + if (filter) { + /* filter caps + composition feature + filter caps + * filtered by the software caps. */ + GstCaps *sw_caps = gst_static_caps_get (&sw_template_caps); + overlay_filter = gst_subtitle_overlay_add_feature_and_intersect (filter, + GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION, sw_caps); + gst_caps_unref (sw_caps); + + GST_DEBUG_OBJECT (overlay, "overlay filter %" GST_PTR_FORMAT, + overlay_filter); + } + + peer_caps = gst_pad_peer_query_caps (srcpad, overlay_filter); + + if (overlay_filter) + gst_caps_unref (overlay_filter); + + if (peer_caps) { + + GST_DEBUG_OBJECT (pad, "peer caps %" GST_PTR_FORMAT, peer_caps); + + if (gst_caps_is_any (peer_caps)) { + + /* if peer returns ANY caps, return filtered src pad template caps */ + caps = gst_caps_copy (gst_pad_get_pad_template_caps (srcpad)); + } else { + + /* duplicate caps which contains the composition into one version with + * the meta and one without. Filter the other caps by the software caps */ + GstCaps *sw_caps = gst_static_caps_get (&sw_template_caps); + caps = gst_subtitle_overlay_intersect_by_feature (peer_caps, + GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION, sw_caps); + gst_caps_unref (sw_caps); + } + + gst_caps_unref (peer_caps); + + } else { + /* no peer, our padtemplate is enough then */ + caps = gst_pad_get_pad_template_caps (pad); + } + + if (filter) { + GstCaps *intersection = gst_caps_intersect_full (filter, caps, + GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (caps); + caps = intersection; + } + + GST_DEBUG_OBJECT (overlay, "returning %" GST_PTR_FORMAT, caps); + + return caps; +} + + + +static gboolean +gst_subtitle_overlay_video_sink_query (GstPad * pad, GstObject * parent, + GstQuery * query) +{ + GstSubtitleOverlay *overlay = (GstSubtitleOverlay *) parent; + gboolean res = FALSE; + + GST_DEBUG_OBJECT (pad, "query %" GST_PTR_FORMAT, query); + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_CAPS: + { + GstPad *target = gst_ghost_pad_get_target (GST_GHOST_PAD_CAST (pad)); + + if (target) { + /* If we have a peer, we let the default handler take care of it */ + res = gst_pad_query_default (pad, parent, query); + gst_object_unref (target); + } else { + GstCaps *filter, *caps; + /* We haven't instantiated the internal elements yet, we handle it ourselves */ + gst_query_parse_caps (query, &filter); + caps = gst_subtitle_overlay_get_videosink_caps (overlay, pad, filter); + gst_query_set_caps_result (query, caps); + gst_caps_unref (caps); + res = TRUE; + } + break; + } + default: + res = gst_pad_query_default (pad, parent, query); + break; + } + + return res; +} + static GstFlowReturn gst_subtitle_overlay_video_sink_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) @@ -2023,6 +2207,8 @@ gst_subtitle_overlay_subtitle_sink_query (GstPad * pad, GstObject * parent, { gboolean ret; + GST_DEBUG_OBJECT (pad, "got query %" GST_PTR_FORMAT, query); + switch (GST_QUERY_TYPE (query)) { case GST_QUERY_ACCEPT_CAPS: { @@ -2078,6 +2264,8 @@ gst_subtitle_overlay_init (GstSubtitleOverlay * self) gst_object_unref (templ); gst_pad_set_event_function (self->video_sinkpad, GST_DEBUG_FUNCPTR (gst_subtitle_overlay_video_sink_event)); + gst_pad_set_query_function (self->video_sinkpad, + GST_DEBUG_FUNCPTR (gst_subtitle_overlay_video_sink_query)); gst_pad_set_chain_function (self->video_sinkpad, GST_DEBUG_FUNCPTR (gst_subtitle_overlay_video_sink_chain));