From 19724f6ece1a29ce155a2b5a1ada1050f945b6b9 Mon Sep 17 00:00:00 2001 From: Matthieu Bouron Date: Sun, 16 Mar 2014 16:36:06 +0000 Subject: [PATCH] dvbsuboverlay: handle video/x-raw(ANY) if downstream supports the GstVideoOverlayCompositionMeta API https://bugzilla.gnome.org/show_bug.cgi?id=726463 --- gst/dvbsuboverlay/gstdvbsuboverlay.c | 276 ++++++++++++++++++++++++--- 1 file changed, 246 insertions(+), 30 deletions(-) diff --git a/gst/dvbsuboverlay/gstdvbsuboverlay.c b/gst/dvbsuboverlay/gstdvbsuboverlay.c index 59bf9e5095..67f8a3fa64 100644 --- a/gst/dvbsuboverlay/gstdvbsuboverlay.c +++ b/gst/dvbsuboverlay/gstdvbsuboverlay.c @@ -68,17 +68,24 @@ enum #define VIDEO_FORMATS GST_VIDEO_OVERLAY_COMPOSITION_BLEND_FORMATS +#define DVBSUB_OVERLAY_CAPS GST_VIDEO_CAPS_MAKE(VIDEO_FORMATS) + +#define DVBSUB_OVERLAY_ALL_CAPS DVBSUB_OVERLAY_CAPS ";" \ + GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY", GST_VIDEO_FORMATS_ALL) + +static GstStaticCaps sw_template_caps = GST_STATIC_CAPS (DVBSUB_OVERLAY_CAPS); + static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (VIDEO_FORMATS)) + GST_STATIC_CAPS (DVBSUB_OVERLAY_ALL_CAPS) ); static GstStaticPadTemplate video_sink_factory = GST_STATIC_PAD_TEMPLATE ("video_sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (VIDEO_FORMATS)) + GST_STATIC_CAPS (DVBSUB_OVERLAY_ALL_CAPS) ); static GstStaticPadTemplate text_sink_factory = @@ -101,7 +108,9 @@ static GstStateChangeReturn gst_dvbsub_overlay_change_state (GstElement * #define gst_dvbsub_overlay_parent_class parent_class G_DEFINE_TYPE (GstDVBSubOverlay, gst_dvbsub_overlay, GST_TYPE_ELEMENT); -static GstCaps *gst_dvbsub_overlay_getcaps (GstDVBSubOverlay * render, +static GstCaps *gst_dvbsub_overlay_get_videosink_caps (GstDVBSubOverlay * + render, GstPad * pad, GstCaps * filter); +static GstCaps *gst_dvbsub_overlay_get_src_caps (GstDVBSubOverlay * render, GstPad * pad, GstCaps * filter); static GstFlowReturn gst_dvbsub_overlay_chain_video (GstPad * pad, @@ -373,7 +382,7 @@ gst_dvbsub_overlay_query_src (GstPad * pad, GstObject * parent, GstCaps *filter, *caps; gst_query_parse_caps (query, &filter); - caps = gst_dvbsub_overlay_getcaps (render, pad, filter); + caps = gst_dvbsub_overlay_get_src_caps (render, pad, filter); gst_query_set_caps_result (query, caps); gst_caps_unref (caps); ret = TRUE; @@ -428,39 +437,236 @@ gst_dvbsub_overlay_event_src (GstPad * pad, GstObject * parent, return ret; } +/** + * gst_dvbsub_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_dvbsub_overlay_getcaps (GstDVBSubOverlay * render, GstPad * pad, - GstCaps * filter) +gst_dvbsub_overlay_add_feature_and_intersect (GstCaps * caps, + const gchar * feature, GstCaps * filter) { - GstPad *otherpad; - GstCaps *caps, *templ; + int i, caps_size; + GstCaps *new_caps; - if (pad == render->srcpad) - otherpad = render->video_sinkpad; - else - otherpad = render->srcpad; + new_caps = gst_caps_copy (caps); - templ = gst_pad_get_pad_template_caps (otherpad); - - /* we can do what the peer can */ - caps = gst_pad_peer_query_caps (otherpad, filter); - if (caps) { - GstCaps *temp; - - /* filtered against our padtemplate */ - temp = gst_caps_intersect (caps, templ); - gst_caps_unref (templ); - gst_caps_unref (caps); - /* this is what we can do */ - caps = temp; - } else { - /* no peer, our padtemplate is enough then */ - caps = templ; + caps_size = gst_caps_get_size (new_caps); + for (i = 0; i < caps_size; i++) { + GstCapsFeatures *features = gst_caps_get_features (new_caps, i); + 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_dvbsub_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_dvbsub_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_dvbsub_overlay_get_videosink_caps (GstDVBSubOverlay * render, GstPad * pad, + GstCaps * filter) +{ + GstPad *srcpad = render->srcpad; + GstCaps *peer_caps = NULL, *caps = NULL, *dvdsub_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); + dvdsub_overlay_filter = + gst_dvbsub_overlay_add_feature_and_intersect (filter, + GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION, sw_caps); + gst_caps_unref (sw_caps); + + GST_DEBUG_OBJECT (render, "dvdsub_overlay filter %" GST_PTR_FORMAT, + dvdsub_overlay_filter); + } + + peer_caps = gst_pad_peer_query_caps (srcpad, dvdsub_overlay_filter); + + if (dvdsub_overlay_filter) + gst_caps_unref (dvdsub_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)); + if (filter) { + GstCaps *intersection = gst_caps_intersect_full (filter, caps, + GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (caps); + caps = intersection; + } + + } 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_dvbsub_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; + + intersection = + gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (caps); + caps = intersection; + } + } + + GST_DEBUG_OBJECT (render, "returning %" GST_PTR_FORMAT, caps); + return caps; } +static GstCaps * +gst_dvbsub_overlay_get_src_caps (GstDVBSubOverlay * render, GstPad * pad, + GstCaps * filter) +{ + GstPad *sinkpad = render->video_sinkpad; + GstCaps *peer_caps = NULL, *caps = NULL, *dvdsub_overlay_filter = NULL; + + if (filter) { + /* duplicate filter 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); + dvdsub_overlay_filter = + gst_dvbsub_overlay_intersect_by_feature (filter, + GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION, sw_caps); + gst_caps_unref (sw_caps); + } + + peer_caps = gst_pad_peer_query_caps (sinkpad, dvdsub_overlay_filter); + + if (dvdsub_overlay_filter) + gst_caps_unref (dvdsub_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 sink pad template caps */ + caps = gst_caps_copy (gst_pad_get_pad_template_caps (sinkpad)); + if (filter) { + GstCaps *intersection = gst_caps_intersect_full (filter, caps, + GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (caps); + caps = intersection; + } + + } else { + + /* return upstream caps + composition feature + upstream caps + * filtered by the software caps. */ + GstCaps *sw_caps = gst_static_caps_get (&sw_template_caps); + caps = gst_dvbsub_overlay_add_feature_and_intersect (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; + + intersection = + gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (caps); + caps = intersection; + } + } + + GST_DEBUG_OBJECT (render, "returning %" GST_PTR_FORMAT, caps); + + return caps; +} + +static gboolean +gst_dvbsub_overlay_can_handle_caps (GstCaps * incaps) +{ + gboolean ret; + GstCaps *caps; + GstStaticCaps static_caps = GST_STATIC_CAPS (DVBSUB_OVERLAY_CAPS); + + caps = gst_static_caps_get (&static_caps); + ret = gst_caps_is_subset (incaps, caps); + gst_caps_unref (caps); + + return ret; +} + /* only negotiate/query video overlay composition support for now */ static gboolean gst_dvbsub_overlay_negotiate (GstDVBSubOverlay * overlay) @@ -521,7 +727,11 @@ gst_dvbsub_overlay_setcaps_video (GstPad * pad, GstCaps * caps) gst_dvbsub_overlay_negotiate (render); - GST_DEBUG_OBJECT (render, "ass renderer setup complete"); + if (!render->attach_compo_to_buffer && + !gst_dvbsub_overlay_can_handle_caps (caps)) + goto unsupported_caps; + + GST_DEBUG_OBJECT (render, "dvbsub overlay renderer setup complete"); out: gst_object_unref (render); @@ -535,6 +745,12 @@ invalid_caps: ret = FALSE; goto out; } +unsupported_caps: + { + GST_ERROR_OBJECT (render, "Unsupported caps: %" GST_PTR_FORMAT, caps); + ret = FALSE; + goto out; + } } static void @@ -933,7 +1149,7 @@ gst_dvbsub_overlay_query_video (GstPad * pad, GstObject * parent, GstCaps *filter, *caps; gst_query_parse_caps (query, &filter); - caps = gst_dvbsub_overlay_getcaps (render, pad, filter); + caps = gst_dvbsub_overlay_get_videosink_caps (render, pad, filter); gst_query_set_caps_result (query, caps); gst_caps_unref (caps); ret = TRUE;