mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
dvdspu: negotiate overlay composition meta with downstream
This allows attaching the overlay composition as a meta on the video buffer instead of blending with the video. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5827>
This commit is contained in:
parent
85081cbef7
commit
5919bfec5e
2 changed files with 372 additions and 29 deletions
|
@ -58,17 +58,23 @@ enum
|
||||||
|
|
||||||
#define VIDEO_FORMATS GST_VIDEO_OVERLAY_COMPOSITION_BLEND_FORMATS
|
#define VIDEO_FORMATS GST_VIDEO_OVERLAY_COMPOSITION_BLEND_FORMATS
|
||||||
|
|
||||||
|
#define DVDSPU_CAPS GST_VIDEO_CAPS_MAKE (VIDEO_FORMATS)
|
||||||
|
#define DVDSPU_ALL_CAPS DVDSPU_CAPS ";" \
|
||||||
|
GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY", GST_VIDEO_FORMATS_ALL)
|
||||||
|
|
||||||
|
static GstStaticCaps sw_template_caps = GST_STATIC_CAPS (DVDSPU_CAPS);
|
||||||
|
|
||||||
static GstStaticPadTemplate video_sink_factory =
|
static GstStaticPadTemplate video_sink_factory =
|
||||||
GST_STATIC_PAD_TEMPLATE ("video",
|
GST_STATIC_PAD_TEMPLATE ("video",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (VIDEO_FORMATS))
|
GST_STATIC_CAPS (DVDSPU_ALL_CAPS)
|
||||||
);
|
);
|
||||||
|
|
||||||
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (VIDEO_FORMATS))
|
GST_STATIC_CAPS (DVDSPU_ALL_CAPS)
|
||||||
);
|
);
|
||||||
|
|
||||||
static GstStaticPadTemplate subpic_sink_factory =
|
static GstStaticPadTemplate subpic_sink_factory =
|
||||||
|
@ -93,8 +99,10 @@ static gboolean gst_dvd_spu_src_event (GstPad * pad, GstObject * parent,
|
||||||
GstEvent * event);
|
GstEvent * event);
|
||||||
static gboolean gst_dvd_spu_src_query (GstPad * pad, GstObject * parent,
|
static gboolean gst_dvd_spu_src_query (GstPad * pad, GstObject * parent,
|
||||||
GstQuery * query);
|
GstQuery * query);
|
||||||
|
static GstCaps *gst_dvd_spu_src_get_caps (GstDVDSpu * dvdspu, GstPad * pad,
|
||||||
|
GstCaps * filter);
|
||||||
|
|
||||||
static GstCaps *gst_dvd_spu_video_proxy_getcaps (GstPad * pad,
|
static GstCaps *gst_dvd_spu_video_get_caps (GstDVDSpu * dvdspu, GstPad * pad,
|
||||||
GstCaps * filter);
|
GstCaps * filter);
|
||||||
static gboolean gst_dvd_spu_video_set_caps (GstDVDSpu * dvdspu, GstPad * pad,
|
static gboolean gst_dvd_spu_video_set_caps (GstDVDSpu * dvdspu, GstPad * pad,
|
||||||
GstCaps * caps);
|
GstCaps * caps);
|
||||||
|
@ -113,6 +121,7 @@ static gboolean gst_dvd_spu_subpic_event (GstPad * pad, GstObject * parent,
|
||||||
GstEvent * event);
|
GstEvent * event);
|
||||||
static gboolean gst_dvd_spu_subpic_set_caps (GstDVDSpu * dvdspu, GstPad * pad,
|
static gboolean gst_dvd_spu_subpic_set_caps (GstDVDSpu * dvdspu, GstPad * pad,
|
||||||
GstCaps * caps);
|
GstCaps * caps);
|
||||||
|
static gboolean gst_dvd_spu_negotiate (GstDVDSpu * dvdspu, GstCaps * caps);
|
||||||
|
|
||||||
static void gst_dvd_spu_clear (GstDVDSpu * dvdspu);
|
static void gst_dvd_spu_clear (GstDVDSpu * dvdspu);
|
||||||
static void gst_dvd_spu_flush_spu_info (GstDVDSpu * dvdspu,
|
static void gst_dvd_spu_flush_spu_info (GstDVDSpu * dvdspu,
|
||||||
|
@ -292,6 +301,7 @@ gst_dvd_spu_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_dvd_spu_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
|
gst_dvd_spu_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
|
||||||
{
|
{
|
||||||
|
GstDVDSpu *dvdspu = GST_DVD_SPU (parent);
|
||||||
gboolean res = FALSE;
|
gboolean res = FALSE;
|
||||||
|
|
||||||
switch (GST_QUERY_TYPE (query)) {
|
switch (GST_QUERY_TYPE (query)) {
|
||||||
|
@ -300,7 +310,7 @@ gst_dvd_spu_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
|
||||||
GstCaps *filter, *caps;
|
GstCaps *filter, *caps;
|
||||||
|
|
||||||
gst_query_parse_caps (query, &filter);
|
gst_query_parse_caps (query, &filter);
|
||||||
caps = gst_dvd_spu_video_proxy_getcaps (pad, filter);
|
caps = gst_dvd_spu_src_get_caps (dvdspu, pad, filter);
|
||||||
gst_query_set_caps_result (query, caps);
|
gst_query_set_caps_result (query, caps);
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
|
@ -314,51 +324,239 @@ gst_dvd_spu_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_dvd_spu_can_handle_caps (GstCaps * caps)
|
||||||
|
{
|
||||||
|
GstCaps *sw_caps;
|
||||||
|
gboolean ret;
|
||||||
|
|
||||||
|
sw_caps = gst_static_caps_get (&sw_template_caps);
|
||||||
|
ret = gst_caps_is_subset (caps, sw_caps);
|
||||||
|
gst_caps_unref (sw_caps);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_dvd_spu_video_set_caps (GstDVDSpu * dvdspu, GstPad * pad, GstCaps * caps)
|
gst_dvd_spu_video_set_caps (GstDVDSpu * dvdspu, GstPad * pad, GstCaps * caps)
|
||||||
{
|
{
|
||||||
gboolean res = FALSE;
|
|
||||||
GstVideoInfo info;
|
GstVideoInfo info;
|
||||||
SpuState *state;
|
gboolean ret = FALSE;
|
||||||
|
|
||||||
if (!gst_video_info_from_caps (&info, caps))
|
if (!gst_video_info_from_caps (&info, caps))
|
||||||
goto done;
|
goto invalid_caps;
|
||||||
|
|
||||||
|
dvdspu->spu_state.info = info;
|
||||||
|
|
||||||
|
ret = gst_dvd_spu_negotiate (dvdspu, caps);
|
||||||
|
|
||||||
DVD_SPU_LOCK (dvdspu);
|
DVD_SPU_LOCK (dvdspu);
|
||||||
state = &dvdspu->spu_state;
|
if (!dvdspu->attach_compo_to_buffer && !gst_dvd_spu_can_handle_caps (caps)) {
|
||||||
state->info = info;
|
GST_DEBUG_OBJECT (dvdspu, "unsupported caps %" GST_PTR_FORMAT, caps);
|
||||||
|
ret = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
DVD_SPU_UNLOCK (dvdspu);
|
DVD_SPU_UNLOCK (dvdspu);
|
||||||
|
|
||||||
res = TRUE;
|
return ret;
|
||||||
done:
|
|
||||||
return res;
|
/* ERRORS */
|
||||||
|
invalid_caps:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (dvdspu, "could not parse caps");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_dvd_spu_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_dvd_spu_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_dvd_spu_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_dvd_spu_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 *
|
static GstCaps *
|
||||||
gst_dvd_spu_video_proxy_getcaps (GstPad * pad, GstCaps * filter)
|
gst_dvd_spu_video_get_caps (GstDVDSpu * dvdspu, GstPad * pad, GstCaps * filter)
|
||||||
{
|
{
|
||||||
GstDVDSpu *dvdspu = GST_DVD_SPU (gst_pad_get_parent (pad));
|
GstPad *srcpad = dvdspu->srcpad;
|
||||||
GstCaps *caps;
|
GstCaps *peer_caps = NULL, *caps = NULL, *dvdspu_filter = NULL;
|
||||||
GstPad *otherpad;
|
|
||||||
|
|
||||||
/* Proxy the getcaps between videosink and the srcpad, ignoring the
|
if (filter) {
|
||||||
* subpicture sink pad */
|
/* filter caps + composition feature + filter caps
|
||||||
otherpad = (pad == dvdspu->srcpad) ? dvdspu->videosinkpad : dvdspu->srcpad;
|
* filtered by the software caps. */
|
||||||
|
GstCaps *sw_caps = gst_static_caps_get (&sw_template_caps);
|
||||||
|
dvdspu_filter = gst_dvd_spu_add_feature_and_intersect (filter,
|
||||||
|
GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION, sw_caps);
|
||||||
|
gst_caps_unref (sw_caps);
|
||||||
|
|
||||||
caps = gst_pad_peer_query_caps (otherpad, filter);
|
GST_DEBUG_OBJECT (dvdspu, "dvdspu filter %" GST_PTR_FORMAT, dvdspu_filter);
|
||||||
if (caps) {
|
}
|
||||||
GstCaps *temp, *templ;
|
|
||||||
|
peer_caps = gst_pad_peer_query_caps (srcpad, dvdspu_filter);
|
||||||
|
|
||||||
|
if (dvdspu_filter)
|
||||||
|
gst_caps_unref (dvdspu_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_dvd_spu_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);
|
||||||
|
|
||||||
templ = gst_pad_get_pad_template_caps (otherpad);
|
|
||||||
temp = gst_caps_intersect (caps, templ);
|
|
||||||
gst_caps_unref (templ);
|
|
||||||
gst_caps_unref (caps);
|
|
||||||
caps = temp;
|
|
||||||
} else {
|
} else {
|
||||||
|
/* no peer, our padtemplate is enough then */
|
||||||
caps = gst_pad_get_pad_template_caps (pad);
|
caps = gst_pad_get_pad_template_caps (pad);
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_object_unref (dvdspu);
|
if (filter) {
|
||||||
|
GstCaps *intersection = gst_caps_intersect_full (filter, caps,
|
||||||
|
GST_CAPS_INTERSECT_FIRST);
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
caps = intersection;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dvdspu, "returning %" GST_PTR_FORMAT, caps);
|
||||||
|
|
||||||
|
return caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstCaps *
|
||||||
|
gst_dvd_spu_src_get_caps (GstDVDSpu * dvdspu, GstPad * pad, GstCaps * filter)
|
||||||
|
{
|
||||||
|
GstPad *sinkpad = dvdspu->videosinkpad;
|
||||||
|
GstCaps *peer_caps = NULL, *caps = NULL, *dvdspu_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);
|
||||||
|
dvdspu_filter = gst_dvd_spu_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, dvdspu_filter);
|
||||||
|
|
||||||
|
if (dvdspu_filter)
|
||||||
|
gst_caps_unref (dvdspu_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));
|
||||||
|
} 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_dvd_spu_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 = gst_caps_intersect_full (filter, caps,
|
||||||
|
GST_CAPS_INTERSECT_FIRST);
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
caps = intersection;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dvdspu, "returning %" GST_PTR_FORMAT, caps);
|
||||||
|
|
||||||
return caps;
|
return caps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,12 +685,16 @@ gst_dvd_spu_video_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GST_EVENT_FLUSH_START:
|
case GST_EVENT_FLUSH_START:
|
||||||
|
DVD_SPU_LOCK (dvdspu);
|
||||||
|
dvdspu->video_flushing = TRUE;
|
||||||
|
DVD_SPU_UNLOCK (dvdspu);
|
||||||
res = gst_pad_event_default (pad, parent, event);
|
res = gst_pad_event_default (pad, parent, event);
|
||||||
goto done;
|
goto done;
|
||||||
case GST_EVENT_FLUSH_STOP:
|
case GST_EVENT_FLUSH_STOP:
|
||||||
res = gst_pad_event_default (pad, parent, event);
|
res = gst_pad_event_default (pad, parent, event);
|
||||||
|
|
||||||
DVD_SPU_LOCK (dvdspu);
|
DVD_SPU_LOCK (dvdspu);
|
||||||
|
dvdspu->video_flushing = FALSE;
|
||||||
gst_segment_init (&dvdspu->video_seg, GST_FORMAT_UNDEFINED);
|
gst_segment_init (&dvdspu->video_seg, GST_FORMAT_UNDEFINED);
|
||||||
gst_buffer_replace (&dvdspu->ref_frame, NULL);
|
gst_buffer_replace (&dvdspu->ref_frame, NULL);
|
||||||
gst_buffer_replace (&dvdspu->pending_frame, NULL);
|
gst_buffer_replace (&dvdspu->pending_frame, NULL);
|
||||||
|
@ -516,6 +718,7 @@ error:
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_dvd_spu_video_query (GstPad * pad, GstObject * parent, GstQuery * query)
|
gst_dvd_spu_video_query (GstPad * pad, GstObject * parent, GstQuery * query)
|
||||||
{
|
{
|
||||||
|
GstDVDSpu *dvdspu = GST_DVD_SPU (parent);
|
||||||
gboolean res = FALSE;
|
gboolean res = FALSE;
|
||||||
|
|
||||||
switch (GST_QUERY_TYPE (query)) {
|
switch (GST_QUERY_TYPE (query)) {
|
||||||
|
@ -524,7 +727,7 @@ gst_dvd_spu_video_query (GstPad * pad, GstObject * parent, GstQuery * query)
|
||||||
GstCaps *filter, *caps;
|
GstCaps *filter, *caps;
|
||||||
|
|
||||||
gst_query_parse_caps (query, &filter);
|
gst_query_parse_caps (query, &filter);
|
||||||
caps = gst_dvd_spu_video_proxy_getcaps (pad, filter);
|
caps = gst_dvd_spu_video_get_caps (dvdspu, pad, filter);
|
||||||
gst_query_set_caps_result (query, caps);
|
gst_query_set_caps_result (query, caps);
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
|
@ -546,6 +749,9 @@ gst_dvd_spu_video_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||||||
|
|
||||||
g_return_val_if_fail (dvdspu != NULL, GST_FLOW_ERROR);
|
g_return_val_if_fail (dvdspu != NULL, GST_FLOW_ERROR);
|
||||||
|
|
||||||
|
if (gst_pad_check_reconfigure (dvdspu->srcpad))
|
||||||
|
gst_dvd_spu_negotiate (dvdspu, NULL);
|
||||||
|
|
||||||
GST_LOG_OBJECT (dvdspu, "video buffer %p with TS %" GST_TIME_FORMAT,
|
GST_LOG_OBJECT (dvdspu, "video buffer %p with TS %" GST_TIME_FORMAT,
|
||||||
buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
|
buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
|
||||||
|
|
||||||
|
@ -827,6 +1033,11 @@ gstspu_render (GstDVDSpu * dvdspu, GstBuffer * buf)
|
||||||
if (!composition)
|
if (!composition)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (dvdspu->attach_compo_to_buffer) {
|
||||||
|
gst_buffer_add_video_overlay_composition_meta (buf, composition);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
if (!gst_video_frame_map (&frame, &dvdspu->spu_state.info, buf,
|
if (!gst_video_frame_map (&frame, &dvdspu->spu_state.info, buf,
|
||||||
GST_MAP_READWRITE)) {
|
GST_MAP_READWRITE)) {
|
||||||
GST_WARNING_OBJECT (dvdspu, "failed to map video frame for blending");
|
GST_WARNING_OBJECT (dvdspu, "failed to map video frame for blending");
|
||||||
|
@ -1063,6 +1274,134 @@ submit_new_spu_packet (GstDVDSpu * dvdspu, GstBuffer * buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_dvd_spu_negotiate (GstDVDSpu * dvdspu, GstCaps * caps)
|
||||||
|
{
|
||||||
|
gboolean upstream_has_meta = FALSE;
|
||||||
|
gboolean caps_has_meta = FALSE;
|
||||||
|
gboolean alloc_has_meta = FALSE;
|
||||||
|
gboolean attach = FALSE;
|
||||||
|
gboolean ret = TRUE;
|
||||||
|
GstCapsFeatures *f;
|
||||||
|
GstCaps *overlay_caps;
|
||||||
|
GstQuery *query;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (dvdspu, "performing negotiation");
|
||||||
|
|
||||||
|
/* Clear any pending reconfigure to avoid negotiating twice */
|
||||||
|
gst_pad_check_reconfigure (dvdspu->srcpad);
|
||||||
|
|
||||||
|
if (!caps)
|
||||||
|
caps = gst_pad_get_current_caps (dvdspu->videosinkpad);
|
||||||
|
else
|
||||||
|
gst_caps_ref (caps);
|
||||||
|
|
||||||
|
if (!caps || gst_caps_is_empty (caps))
|
||||||
|
goto no_format;
|
||||||
|
|
||||||
|
/* Check if upstream caps have meta */
|
||||||
|
if ((f = gst_caps_get_features (caps, 0))) {
|
||||||
|
upstream_has_meta = gst_caps_features_contains (f,
|
||||||
|
GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (upstream_has_meta) {
|
||||||
|
overlay_caps = gst_caps_ref (caps);
|
||||||
|
} else {
|
||||||
|
GstCaps *peercaps;
|
||||||
|
|
||||||
|
/* BaseTransform requires caps for the allocation query to work */
|
||||||
|
overlay_caps = gst_caps_copy (caps);
|
||||||
|
f = gst_caps_get_features (overlay_caps, 0);
|
||||||
|
gst_caps_features_add (f,
|
||||||
|
GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION);
|
||||||
|
|
||||||
|
/* Then check if downstream accept dvdspu composition in caps */
|
||||||
|
/* FIXME: We should probably check if downstream *prefers* the
|
||||||
|
* dvdspu meta, and only enforce usage of it if we can't handle
|
||||||
|
* the format ourselves and thus would have to drop the overlays.
|
||||||
|
* Otherwise we should prefer what downstream wants here.
|
||||||
|
*/
|
||||||
|
peercaps = gst_pad_peer_query_caps (dvdspu->srcpad, NULL);
|
||||||
|
caps_has_meta = gst_caps_can_intersect (peercaps, overlay_caps);
|
||||||
|
gst_caps_unref (peercaps);
|
||||||
|
|
||||||
|
GST_DEBUG ("caps have dvdspu meta %d", caps_has_meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (upstream_has_meta || caps_has_meta) {
|
||||||
|
/* Send caps immediatly, it's needed by GstBaseTransform to get a reply
|
||||||
|
* from allocation query */
|
||||||
|
ret = gst_pad_set_caps (dvdspu->srcpad, overlay_caps);
|
||||||
|
|
||||||
|
/* First check if the allocation meta has compositon */
|
||||||
|
query = gst_query_new_allocation (overlay_caps, FALSE);
|
||||||
|
|
||||||
|
if (!gst_pad_peer_query (dvdspu->srcpad, query)) {
|
||||||
|
/* no problem, we use the query defaults */
|
||||||
|
GST_DEBUG_OBJECT (dvdspu, "ALLOCATION query failed");
|
||||||
|
|
||||||
|
/* In case we were flushing, mark reconfigure and fail this method,
|
||||||
|
* will make it retry */
|
||||||
|
if (dvdspu->video_flushing)
|
||||||
|
ret = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
alloc_has_meta = gst_query_find_allocation_meta (query,
|
||||||
|
GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL);
|
||||||
|
|
||||||
|
GST_DEBUG ("sink alloc has dvdspu meta %d", alloc_has_meta);
|
||||||
|
|
||||||
|
gst_query_unref (query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For backward compatbility, we will prefer bliting if downstream
|
||||||
|
* allocation does not support the meta. In other case we will prefer
|
||||||
|
* attaching, and will fail the negotiation in the unlikely case we are
|
||||||
|
* force to blit, but format isn't supported. */
|
||||||
|
|
||||||
|
if (upstream_has_meta) {
|
||||||
|
attach = TRUE;
|
||||||
|
} else if (caps_has_meta) {
|
||||||
|
if (alloc_has_meta) {
|
||||||
|
attach = TRUE;
|
||||||
|
} else {
|
||||||
|
/* Don't attach unless we cannot handle the format */
|
||||||
|
attach = !gst_dvd_spu_can_handle_caps (caps);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = gst_dvd_spu_can_handle_caps (caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we attach, then pick the dvdspu caps */
|
||||||
|
if (attach) {
|
||||||
|
GST_DEBUG_OBJECT (dvdspu, "Using caps %" GST_PTR_FORMAT, overlay_caps);
|
||||||
|
/* Caps where already sent */
|
||||||
|
} else if (ret) {
|
||||||
|
GST_DEBUG_OBJECT (dvdspu, "Using caps %" GST_PTR_FORMAT, caps);
|
||||||
|
ret = gst_pad_set_caps (dvdspu->srcpad, caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
dvdspu->attach_compo_to_buffer = attach;
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
GST_DEBUG_OBJECT (dvdspu, "negotiation failed, schedule reconfigure");
|
||||||
|
gst_pad_mark_reconfigure (dvdspu->srcpad);
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_caps_unref (overlay_caps);
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
no_format:
|
||||||
|
{
|
||||||
|
if (caps)
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_dvd_spu_subpic_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
gst_dvd_spu_subpic_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
|
|
|
@ -94,6 +94,7 @@ struct _GstDVDSpu {
|
||||||
/* Mutex to protect state we access from different chain funcs */
|
/* Mutex to protect state we access from different chain funcs */
|
||||||
GMutex spu_lock;
|
GMutex spu_lock;
|
||||||
|
|
||||||
|
gboolean video_flushing;
|
||||||
GstSegment video_seg;
|
GstSegment video_seg;
|
||||||
GstSegment subp_seg;
|
GstSegment subp_seg;
|
||||||
|
|
||||||
|
@ -112,6 +113,9 @@ struct _GstDVDSpu {
|
||||||
|
|
||||||
/* Buffer to push after handling a DVD event, if any */
|
/* Buffer to push after handling a DVD event, if any */
|
||||||
GstBuffer *pending_frame;
|
GstBuffer *pending_frame;
|
||||||
|
|
||||||
|
/* Overlay composition */
|
||||||
|
gboolean attach_compo_to_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstDVDSpuClass {
|
struct _GstDVDSpuClass {
|
||||||
|
|
Loading…
Reference in a new issue