dvbsuboverlay: handle video/x-raw(ANY) if downstream supports the GstVideoOverlayCompositionMeta API

https://bugzilla.gnome.org/show_bug.cgi?id=726463
This commit is contained in:
Matthieu Bouron 2014-03-16 16:36:06 +00:00 committed by Sebastian Dröge
parent 6da1c48970
commit 19724f6ece

View file

@ -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;