mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
assrender: handle video/x-raw(ANY) if downstream supports the GstVideoOverlayCompositionMeta API
https://bugzilla.gnome.org/show_bug.cgi?id=721950
This commit is contained in:
parent
2129b4739b
commit
4da4dfc4bf
2 changed files with 242 additions and 25 deletions
|
@ -70,17 +70,24 @@ enum
|
||||||
I420, YV12, AYUV, YUY2, UYVY, v308, Y41B, Y42B, Y444, \
|
I420, YV12, AYUV, YUY2, UYVY, v308, Y41B, Y42B, Y444, \
|
||||||
NV12, NV21, A420, YUV9, YVU9, IYU1, GRAY8 }"
|
NV12, NV21, A420, YUV9, YVU9, IYU1, GRAY8 }"
|
||||||
|
|
||||||
|
#define ASSRENDER_CAPS GST_VIDEO_CAPS_MAKE(FORMATS)
|
||||||
|
|
||||||
|
#define ASSRENDER_ALL_CAPS ASSRENDER_CAPS ";" \
|
||||||
|
GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY", GST_VIDEO_FORMATS_ALL)
|
||||||
|
|
||||||
|
static GstStaticCaps sw_template_caps = GST_STATIC_CAPS (ASSRENDER_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 (FORMATS))
|
GST_STATIC_CAPS (ASSRENDER_ALL_CAPS)
|
||||||
);
|
);
|
||||||
|
|
||||||
static GstStaticPadTemplate video_sink_factory =
|
static GstStaticPadTemplate video_sink_factory =
|
||||||
GST_STATIC_PAD_TEMPLATE ("video_sink",
|
GST_STATIC_PAD_TEMPLATE ("video_sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (FORMATS))
|
GST_STATIC_CAPS (ASSRENDER_ALL_CAPS)
|
||||||
);
|
);
|
||||||
|
|
||||||
static GstStaticPadTemplate text_sink_factory =
|
static GstStaticPadTemplate text_sink_factory =
|
||||||
|
@ -111,7 +118,9 @@ static GstStateChangeReturn gst_ass_render_change_state (GstElement * element,
|
||||||
#define gst_ass_render_parent_class parent_class
|
#define gst_ass_render_parent_class parent_class
|
||||||
G_DEFINE_TYPE (GstAssRender, gst_ass_render, GST_TYPE_ELEMENT);
|
G_DEFINE_TYPE (GstAssRender, gst_ass_render, GST_TYPE_ELEMENT);
|
||||||
|
|
||||||
static GstCaps *gst_ass_render_getcaps (GstPad * pad, GstCaps * filter);
|
static GstCaps *gst_ass_render_get_videosink_caps (GstPad * pad,
|
||||||
|
GstCaps * filter);
|
||||||
|
static GstCaps *gst_ass_render_get_src_caps (GstPad * pad, GstCaps * filter);
|
||||||
|
|
||||||
static gboolean gst_ass_render_setcaps_video (GstPad * pad, GstCaps * caps);
|
static gboolean gst_ass_render_setcaps_video (GstPad * pad, GstCaps * caps);
|
||||||
static gboolean gst_ass_render_setcaps_text (GstPad * pad, GstCaps * caps);
|
static gboolean gst_ass_render_setcaps_text (GstPad * pad, GstCaps * caps);
|
||||||
|
@ -420,7 +429,7 @@ gst_ass_render_query_src (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_ass_render_getcaps (pad, filter);
|
caps = gst_ass_render_get_src_caps (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;
|
||||||
|
@ -491,37 +500,220 @@ gst_ass_render_event_src (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_ass_render_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 *
|
static GstCaps *
|
||||||
gst_ass_render_getcaps (GstPad * pad, GstCaps * filter)
|
gst_ass_render_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);
|
||||||
|
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_ass_render_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_ass_render_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_ass_render_get_videosink_caps (GstPad * pad, GstCaps * filter)
|
||||||
{
|
{
|
||||||
GstAssRender *render = GST_ASS_RENDER (gst_pad_get_parent (pad));
|
GstAssRender *render = GST_ASS_RENDER (gst_pad_get_parent (pad));
|
||||||
GstPad *otherpad;
|
GstPad *srcpad = render->srcpad;
|
||||||
GstCaps *caps;
|
GstCaps *peer_caps = NULL, *caps = NULL, *assrender_filter = NULL;
|
||||||
GstCaps *templ;
|
|
||||||
|
|
||||||
if (pad == render->srcpad)
|
if (filter) {
|
||||||
otherpad = render->video_sinkpad;
|
/* filter caps + composition feature + filter caps
|
||||||
else
|
* filtered by the software caps. */
|
||||||
otherpad = render->srcpad;
|
GstCaps *sw_caps = gst_static_caps_get (&sw_template_caps);
|
||||||
|
assrender_filter = gst_ass_render_add_feature_and_intersect (filter,
|
||||||
|
GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION, sw_caps);
|
||||||
|
gst_caps_unref (sw_caps);
|
||||||
|
|
||||||
templ = gst_pad_get_pad_template_caps (otherpad);
|
GST_DEBUG_OBJECT (render, "assrender filter %" GST_PTR_FORMAT,
|
||||||
|
assrender_filter);
|
||||||
|
}
|
||||||
|
|
||||||
/* we can do what the peer can */
|
peer_caps = gst_pad_peer_query_caps (srcpad, assrender_filter);
|
||||||
caps = gst_pad_peer_query_caps (otherpad, filter);
|
|
||||||
if (caps) {
|
if (assrender_filter)
|
||||||
GstCaps *temp;
|
gst_caps_unref (assrender_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_ass_render_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);
|
||||||
|
|
||||||
/* filtered against our padtemplate */
|
|
||||||
temp = gst_caps_intersect (caps, templ);
|
|
||||||
gst_caps_unref (caps);
|
|
||||||
gst_caps_unref (templ);
|
|
||||||
/* this is what we can do */
|
|
||||||
caps = temp;
|
|
||||||
} else {
|
} else {
|
||||||
/* no peer, our padtemplate is enough then */
|
/* no peer, our padtemplate is enough then */
|
||||||
caps = templ;
|
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);
|
||||||
|
|
||||||
|
gst_object_unref (render);
|
||||||
|
|
||||||
|
return caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstCaps *
|
||||||
|
gst_ass_render_get_src_caps (GstPad * pad, GstCaps * filter)
|
||||||
|
{
|
||||||
|
GstAssRender *render = GST_ASS_RENDER (gst_pad_get_parent (pad));
|
||||||
|
GstPad *sinkpad = render->video_sinkpad;
|
||||||
|
GstCaps *peer_caps = NULL, *caps = NULL, *assrender_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);
|
||||||
|
assrender_filter =
|
||||||
|
gst_ass_render_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, assrender_filter);
|
||||||
|
|
||||||
|
if (assrender_filter)
|
||||||
|
gst_caps_unref (assrender_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_ass_render_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);
|
||||||
|
|
||||||
gst_object_unref (render);
|
gst_object_unref (render);
|
||||||
|
|
||||||
return caps;
|
return caps;
|
||||||
|
@ -588,6 +780,20 @@ blit_bgra_premultiplied (GstAssRender * render, ASS_Image * ass_image,
|
||||||
GST_LOG_OBJECT (render, "amount of rendered ass_image: %u", counter);
|
GST_LOG_OBJECT (render, "amount of rendered ass_image: %u", counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_ass_render_can_handle_caps (GstCaps * incaps)
|
||||||
|
{
|
||||||
|
gboolean ret;
|
||||||
|
GstCaps *caps;
|
||||||
|
GstStaticCaps static_caps = GST_STATIC_CAPS (ASSRENDER_CAPS);
|
||||||
|
|
||||||
|
caps = gst_static_caps_get (&static_caps);
|
||||||
|
ret = gst_caps_is_subset (incaps, caps);
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_ass_render_setcaps_video (GstPad * pad, GstCaps * caps)
|
gst_ass_render_setcaps_video (GstPad * pad, GstCaps * caps)
|
||||||
{
|
{
|
||||||
|
@ -621,6 +827,9 @@ gst_ass_render_setcaps_video (GstPad * pad, GstCaps * caps)
|
||||||
|
|
||||||
render->attach_compo_to_buffer = attach;
|
render->attach_compo_to_buffer = attach;
|
||||||
|
|
||||||
|
if (!attach && !gst_ass_render_can_handle_caps (caps))
|
||||||
|
goto unsupported_caps;
|
||||||
|
|
||||||
g_mutex_lock (&render->ass_mutex);
|
g_mutex_lock (&render->ass_mutex);
|
||||||
ass_set_frame_size (render->ass_renderer, render->width, render->height);
|
ass_set_frame_size (render->ass_renderer, render->width, render->height);
|
||||||
|
|
||||||
|
@ -662,6 +871,12 @@ invalid_caps:
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
unsupported_caps:
|
||||||
|
{
|
||||||
|
GST_ERROR_OBJECT (render, "Unsupported caps: %" GST_PTR_FORMAT, caps);
|
||||||
|
ret = FALSE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -1336,7 +1551,7 @@ gst_ass_render_query_video (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_ass_render_getcaps (pad, filter);
|
caps = gst_ass_render_get_videosink_caps (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;
|
||||||
|
|
|
@ -39,6 +39,8 @@ G_BEGIN_DECLS
|
||||||
#define GST_TYPE_ASS_RENDER (gst_ass_render_get_type())
|
#define GST_TYPE_ASS_RENDER (gst_ass_render_get_type())
|
||||||
#define GST_ASS_RENDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ASS_RENDER,GstAssRender))
|
#define GST_ASS_RENDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ASS_RENDER,GstAssRender))
|
||||||
#define GST_ASS_RENDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ASS_RENDER,GstAssRenderClass))
|
#define GST_ASS_RENDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ASS_RENDER,GstAssRenderClass))
|
||||||
|
#define GST_ASS_RENDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
|
||||||
|
GST_TYPE_ASS_RENDER, GstAssRenderClass))
|
||||||
#define GST_IS_ASS_RENDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ASS_RENDER))
|
#define GST_IS_ASS_RENDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ASS_RENDER))
|
||||||
#define GST_IS_ASS_RENDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ASS_RENDER))
|
#define GST_IS_ASS_RENDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ASS_RENDER))
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue