mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 20:21:24 +00:00
subtitleoverlay: Refactor autoplugging code and select overlay element by rank too
Previously we always used textoverlay for rendering the output of a parser, now the same code as for the renderers is used and the element with the highest rank is used. Fixes bug #663822.
This commit is contained in:
parent
739de5fbf9
commit
87a4cbd0e3
1 changed files with 400 additions and 488 deletions
|
@ -746,6 +746,277 @@ _has_font_desc_property (GstElement * element)
|
|||
return (pspec && pspec->value_type == G_TYPE_STRING);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_setup_parser (GstSubtitleOverlay * self)
|
||||
{
|
||||
GstPad *video_peer;
|
||||
|
||||
/* Try to get the latest video framerate */
|
||||
video_peer = gst_pad_get_peer (self->video_sinkpad);
|
||||
if (video_peer) {
|
||||
GstCaps *video_caps;
|
||||
gint fps_n, fps_d;
|
||||
|
||||
video_caps = gst_pad_get_negotiated_caps (video_peer);
|
||||
if (!video_caps) {
|
||||
video_caps = gst_pad_get_caps_reffed (video_peer);
|
||||
if (!gst_caps_is_fixed (video_caps)) {
|
||||
gst_caps_unref (video_caps);
|
||||
video_caps = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (video_caps
|
||||
&& gst_video_parse_caps_framerate (video_caps, &fps_n, &fps_d)) {
|
||||
if (self->fps_n != fps_n || self->fps_d != fps_d) {
|
||||
GST_DEBUG_OBJECT (self, "New video fps: %d/%d", fps_n, fps_d);
|
||||
self->fps_n = fps_n;
|
||||
self->fps_d = fps_d;
|
||||
}
|
||||
}
|
||||
|
||||
if (video_caps)
|
||||
gst_caps_unref (video_caps);
|
||||
gst_object_unref (video_peer);
|
||||
}
|
||||
|
||||
if (_has_subtitle_encoding_property (self->parser))
|
||||
g_object_set (self->parser, "subtitle-encoding", self->encoding, NULL);
|
||||
|
||||
/* Try to set video fps on the parser */
|
||||
gst_subtitle_overlay_set_fps (self);
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_setup_renderer (GstSubtitleOverlay * self, GstElement * renderer)
|
||||
{
|
||||
GstElementFactory *factory = gst_element_get_factory (renderer);
|
||||
const gchar *name =
|
||||
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE_CAST (factory));
|
||||
|
||||
if (strcmp (name, "textoverlay") == 0) {
|
||||
/* Set some textoverlay specific properties */
|
||||
g_object_set (G_OBJECT (renderer),
|
||||
"halign", "center", "valign", "bottom", "wait-text", FALSE, NULL);
|
||||
if (self->font_desc)
|
||||
g_object_set (G_OBJECT (renderer), "font-desc", self->font_desc, NULL);
|
||||
self->silent_property = "silent";
|
||||
self->silent_property_invert = FALSE;
|
||||
} else {
|
||||
self->silent_property =
|
||||
_get_silent_property (renderer, &self->silent_property_invert);
|
||||
if (_has_subtitle_encoding_property (renderer))
|
||||
g_object_set (renderer, "subtitle-encoding", self->encoding, NULL);
|
||||
if (_has_font_desc_property (renderer))
|
||||
g_object_set (renderer, "font-desc", self->font_desc, NULL);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* subtitle_src==NULL means: use subtitle_sink ghostpad */
|
||||
static gboolean
|
||||
_link_renderer (GstSubtitleOverlay * self, GstElement * renderer,
|
||||
GstPad * subtitle_src)
|
||||
{
|
||||
GstPad *sink, *src;
|
||||
gboolean is_video, is_hw;
|
||||
|
||||
is_video = _is_video_pad (self->video_sinkpad, &is_hw);
|
||||
|
||||
if (is_video) {
|
||||
gboolean render_is_hw;
|
||||
|
||||
/* First check that renderer also supports the video format */
|
||||
sink = _get_video_pad (renderer);
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get video sink from renderer");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (is_video != _is_video_pad (sink, &render_is_hw) ||
|
||||
is_hw != render_is_hw) {
|
||||
GST_DEBUG_OBJECT (self, "Renderer doesn't support %s video",
|
||||
is_hw ? "surface" : "raw");
|
||||
gst_object_unref (sink);
|
||||
return FALSE;
|
||||
}
|
||||
gst_object_unref (sink);
|
||||
|
||||
if (!is_hw) {
|
||||
/* First link everything internally */
|
||||
if (G_UNLIKELY (!_create_element (self, &self->post_colorspace,
|
||||
COLORSPACE, NULL, "post-colorspace", FALSE))) {
|
||||
return FALSE;
|
||||
}
|
||||
src = gst_element_get_static_pad (renderer, "src");
|
||||
if (G_UNLIKELY (!src)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get src pad from renderer");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sink = gst_element_get_static_pad (self->post_colorspace, "sink");
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get sink pad from " COLORSPACE);
|
||||
gst_object_unref (src);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (gst_pad_link (src, sink) != GST_PAD_LINK_OK)) {
|
||||
GST_WARNING_OBJECT (self, "Can't link renderer with " COLORSPACE);
|
||||
gst_object_unref (src);
|
||||
gst_object_unref (sink);
|
||||
return FALSE;
|
||||
}
|
||||
gst_object_unref (src);
|
||||
gst_object_unref (sink);
|
||||
|
||||
if (G_UNLIKELY (!_create_element (self, &self->pre_colorspace,
|
||||
COLORSPACE, NULL, "pre-colorspace", FALSE))) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sink = _get_video_pad (renderer);
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get video sink from renderer");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
src = gst_element_get_static_pad (self->pre_colorspace, "src");
|
||||
if (G_UNLIKELY (!src)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get srcpad from " COLORSPACE);
|
||||
gst_object_unref (sink);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (gst_pad_link (src, sink) != GST_PAD_LINK_OK)) {
|
||||
GST_WARNING_OBJECT (self, "Can't link " COLORSPACE " to renderer");
|
||||
gst_object_unref (src);
|
||||
gst_object_unref (sink);
|
||||
return FALSE;
|
||||
}
|
||||
gst_object_unref (src);
|
||||
gst_object_unref (sink);
|
||||
|
||||
/* Set src ghostpad target */
|
||||
src = gst_element_get_static_pad (self->post_colorspace, "src");
|
||||
if (G_UNLIKELY (!src)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get src pad from " COLORSPACE);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
/* Set src ghostpad target in the harware accelerated case */
|
||||
|
||||
src = gst_element_get_static_pad (renderer, "src");
|
||||
if (G_UNLIKELY (!src)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get src pad from renderer");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
} else { /* No video pad */
|
||||
GstCaps *allowed_caps, *video_caps = NULL;
|
||||
GstPad *video_peer;
|
||||
gboolean can_intersect = FALSE;
|
||||
|
||||
video_peer = gst_pad_get_peer (self->video_sinkpad);
|
||||
if (video_peer) {
|
||||
video_caps = gst_pad_get_negotiated_caps (video_peer);
|
||||
if (!video_caps) {
|
||||
video_caps = gst_pad_get_caps_reffed (video_peer);
|
||||
}
|
||||
gst_object_unref (video_peer);
|
||||
}
|
||||
|
||||
sink = _get_video_pad (renderer);
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get video sink from renderer");
|
||||
return FALSE;
|
||||
}
|
||||
allowed_caps = gst_pad_get_caps_reffed (sink);
|
||||
gst_object_unref (sink);
|
||||
|
||||
if (allowed_caps && video_caps)
|
||||
can_intersect = gst_caps_can_intersect (allowed_caps, video_caps);
|
||||
|
||||
if (allowed_caps)
|
||||
gst_caps_unref (allowed_caps);
|
||||
|
||||
if (video_caps)
|
||||
gst_caps_unref (video_caps);
|
||||
|
||||
if (G_UNLIKELY (!can_intersect)) {
|
||||
GST_WARNING_OBJECT (self, "Renderer with custom caps is not "
|
||||
"compatible with video stream");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
src = gst_element_get_static_pad (renderer, "src");
|
||||
if (G_UNLIKELY (!src)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get src pad from renderer");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST
|
||||
(self->srcpad), src))) {
|
||||
GST_WARNING_OBJECT (self, "Can't set srcpad target");
|
||||
gst_object_unref (src);
|
||||
return FALSE;
|
||||
}
|
||||
gst_object_unref (src);
|
||||
|
||||
/* Set the sink ghostpad targets */
|
||||
if (self->pre_colorspace) {
|
||||
sink = gst_element_get_static_pad (self->pre_colorspace, "sink");
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get sink pad from " COLORSPACE);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
sink = _get_video_pad (renderer);
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get sink pad from %" GST_PTR_FORMAT,
|
||||
renderer);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST
|
||||
(self->video_sinkpad), sink))) {
|
||||
GST_WARNING_OBJECT (self, "Can't set video sinkpad target");
|
||||
gst_object_unref (sink);
|
||||
return FALSE;
|
||||
}
|
||||
gst_object_unref (sink);
|
||||
|
||||
sink = _get_sub_pad (renderer);
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Failed to get subpad");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (subtitle_src) {
|
||||
if (G_UNLIKELY (gst_pad_link (subtitle_src, sink) != GST_PAD_LINK_OK)) {
|
||||
GST_WARNING_OBJECT (self, "Failed to link subtitle srcpad with renderer");
|
||||
gst_object_unref (sink);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
if (G_UNLIKELY (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST
|
||||
(self->subtitle_sinkpad), sink))) {
|
||||
GST_WARNING_OBJECT (self, "Failed to set subtitle sink target");
|
||||
gst_object_unref (sink);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
gst_object_unref (sink);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
|
||||
{
|
||||
|
@ -870,8 +1141,7 @@ _pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
|
|||
|
||||
for (l = factories; l; l = l->next) {
|
||||
GstElementFactory *factory = l->data;
|
||||
gboolean is_video, is_hw, is_renderer = _is_renderer (factory);
|
||||
GstElement *element;
|
||||
gboolean is_renderer = _is_renderer (factory);
|
||||
GstPad *sink, *src;
|
||||
|
||||
/* Unlink & destroy everything */
|
||||
|
@ -899,519 +1169,114 @@ _pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
|
|||
"parser", FALSE))))
|
||||
continue;
|
||||
|
||||
element = is_renderer ? self->renderer : self->parser;
|
||||
|
||||
is_video = _is_video_pad (self->video_sinkpad, &is_hw);
|
||||
/* If this is a parser, create textoverlay and link video and the parser to it
|
||||
* Else link the renderer to the output colorspace */
|
||||
if (!is_renderer) {
|
||||
GstElement *overlay;
|
||||
GstPad *video_peer;
|
||||
GstCaps *parser_caps;
|
||||
GList *overlay_factories, *k;
|
||||
|
||||
/* Try to get the latest video framerate */
|
||||
video_peer = gst_pad_get_peer (self->video_sinkpad);
|
||||
if (video_peer) {
|
||||
GstCaps *video_caps;
|
||||
gint fps_n, fps_d;
|
||||
|
||||
video_caps = gst_pad_get_negotiated_caps (video_peer);
|
||||
if (!video_caps) {
|
||||
video_caps = gst_pad_get_caps_reffed (video_peer);
|
||||
if (!gst_caps_is_fixed (video_caps)) {
|
||||
gst_caps_unref (video_caps);
|
||||
video_caps = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (video_caps
|
||||
&& gst_video_parse_caps_framerate (video_caps, &fps_n, &fps_d)) {
|
||||
if (self->fps_n != fps_n || self->fps_d != fps_d) {
|
||||
GST_DEBUG_OBJECT (self, "New video fps: %d/%d", fps_n, fps_d);
|
||||
self->fps_n = fps_n;
|
||||
self->fps_d = fps_d;
|
||||
}
|
||||
}
|
||||
|
||||
if (video_caps)
|
||||
gst_caps_unref (video_caps);
|
||||
gst_object_unref (video_peer);
|
||||
}
|
||||
|
||||
if (_has_subtitle_encoding_property (self->parser))
|
||||
g_object_set (self->parser, "subtitle-encoding", self->encoding, NULL);
|
||||
|
||||
/* Try to set video fps on the parser */
|
||||
gst_subtitle_overlay_set_fps (self);
|
||||
|
||||
/* First link everything internally */
|
||||
if (G_UNLIKELY (!_create_element (self, &self->overlay, "textoverlay",
|
||||
NULL, "overlay", FALSE))) {
|
||||
if (!_setup_parser (self))
|
||||
continue;
|
||||
}
|
||||
overlay = self->overlay;
|
||||
self->silent_property = "silent";
|
||||
self->silent_property_invert = FALSE;
|
||||
|
||||
/* Set some properties */
|
||||
g_object_set (G_OBJECT (overlay),
|
||||
"halign", "center", "valign", "bottom", "wait-text", FALSE, NULL);
|
||||
if (self->font_desc)
|
||||
g_object_set (G_OBJECT (overlay), "font-desc", self->font_desc, NULL);
|
||||
|
||||
src = gst_element_get_static_pad (element, "src");
|
||||
if (G_UNLIKELY (!src)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sink = gst_element_get_static_pad (overlay, "text_sink");
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get text sink from textoverlay");
|
||||
gst_object_unref (src);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (gst_pad_link (src, sink) != GST_PAD_LINK_OK)) {
|
||||
GST_WARNING_OBJECT (self, "Can't link parser to textoverlay");
|
||||
gst_object_unref (sink);
|
||||
gst_object_unref (src);
|
||||
continue;
|
||||
}
|
||||
gst_object_unref (sink);
|
||||
/* Find our factories */
|
||||
src = gst_element_get_static_pad (self->parser, "src");
|
||||
parser_caps = gst_pad_get_caps_reffed (src);
|
||||
gst_object_unref (src);
|
||||
|
||||
/* If we are working with video/x-surface, we do not add
|
||||
* colorspace conversion elements */
|
||||
if (is_video && !is_hw) {
|
||||
if (G_UNLIKELY (!_create_element (self, &self->post_colorspace,
|
||||
COLORSPACE, NULL, "post-colorspace", FALSE))) {
|
||||
continue;
|
||||
}
|
||||
g_assert (parser_caps != NULL);
|
||||
|
||||
src = gst_element_get_static_pad (overlay, "src");
|
||||
if (G_UNLIKELY (!src)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get src pad from overlay");
|
||||
continue;
|
||||
}
|
||||
g_mutex_lock (self->factories_lock);
|
||||
gst_subtitle_overlay_update_factory_list (self);
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"Searching overlay factories for caps %" GST_PTR_FORMAT, parser_caps);
|
||||
overlay_factories =
|
||||
gst_subtitle_overlay_get_factories_for_caps (self->factories,
|
||||
parser_caps);
|
||||
g_mutex_unlock (self->factories_lock);
|
||||
|
||||
sink = gst_element_get_static_pad (self->post_colorspace, "sink");
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get sink pad from " COLORSPACE);
|
||||
gst_object_unref (src);
|
||||
continue;
|
||||
}
|
||||
if (!overlay_factories) {
|
||||
GST_WARNING_OBJECT (self,
|
||||
"Found no suitable overlay factories for caps %" GST_PTR_FORMAT,
|
||||
parser_caps);
|
||||
gst_caps_unref (parser_caps);
|
||||
continue;
|
||||
}
|
||||
gst_caps_unref (parser_caps);
|
||||
|
||||
if (G_UNLIKELY (gst_pad_link (src, sink) != GST_PAD_LINK_OK)) {
|
||||
GST_WARNING_OBJECT (self, "Can't link overlay with " COLORSPACE);
|
||||
gst_object_unref (src);
|
||||
gst_object_unref (sink);
|
||||
continue;
|
||||
}
|
||||
gst_object_unref (src);
|
||||
gst_object_unref (sink);
|
||||
/* Sort the factories by rank */
|
||||
overlay_factories =
|
||||
g_list_sort (overlay_factories, (GCompareFunc) _sort_by_ranks);
|
||||
|
||||
if (G_UNLIKELY (!_create_element (self, &self->pre_colorspace,
|
||||
"identity", NULL, "pre-colorspace", FALSE))) {
|
||||
continue;
|
||||
}
|
||||
for (k = overlay_factories; k; k = k->next) {
|
||||
GstElementFactory *overlay_factory = k->data;
|
||||
|
||||
sink = gst_element_get_static_pad (overlay, "video_sink");
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get video sink from textoverlay");
|
||||
continue;
|
||||
}
|
||||
GST_DEBUG_OBJECT (self, "Trying overlay factory '%s'",
|
||||
GST_STR_NULL (gst_plugin_feature_get_name (GST_PLUGIN_FEATURE_CAST
|
||||
(overlay_factory))));
|
||||
|
||||
src = gst_element_get_static_pad (self->pre_colorspace, "src");
|
||||
if (G_UNLIKELY (!src)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get srcpad from " COLORSPACE);
|
||||
gst_object_unref (sink);
|
||||
continue;
|
||||
}
|
||||
/* Try this factory and link it, otherwise unlink everything
|
||||
* again and remove the overlay. Up to this point only the
|
||||
* parser was instantiated and setup, nothing was linked
|
||||
*/
|
||||
|
||||
if (G_UNLIKELY (gst_pad_link (src, sink) != GST_PAD_LINK_OK)) {
|
||||
GST_WARNING_OBJECT (self, "Can't link " COLORSPACE " to textoverlay");
|
||||
gst_object_unref (src);
|
||||
gst_object_unref (sink);
|
||||
continue;
|
||||
}
|
||||
gst_object_unref (src);
|
||||
gst_object_unref (sink);
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL);
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->video_sinkpad),
|
||||
NULL);
|
||||
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->subtitle_sinkpad),
|
||||
NULL);
|
||||
self->silent_property = NULL;
|
||||
_remove_element (self, &self->post_colorspace);
|
||||
_remove_element (self, &self->overlay);
|
||||
_remove_element (self, &self->pre_colorspace);
|
||||
|
||||
/* Set src ghostpad target */
|
||||
src = gst_element_get_static_pad (self->post_colorspace, "src");
|
||||
if (G_UNLIKELY (!src)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get src pad from " COLORSPACE);
|
||||
if (!_create_element (self, &self->overlay, NULL, overlay_factory,
|
||||
"overlay", FALSE))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST
|
||||
(self->srcpad), src))) {
|
||||
GST_WARNING_OBJECT (self, "Can't set srcpad target");
|
||||
if (!_setup_renderer (self, self->overlay))
|
||||
continue;
|
||||
|
||||
src = gst_element_get_static_pad (self->parser, "src");
|
||||
if (!_link_renderer (self, self->overlay, src)) {
|
||||
gst_object_unref (src);
|
||||
continue;
|
||||
}
|
||||
gst_object_unref (src);
|
||||
} else if (is_hw) {
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"Is Hardware, not adding colorspace converters, ");
|
||||
/* Set src ghostpad target */
|
||||
src = gst_element_get_static_pad (self->overlay, "src");
|
||||
if (G_UNLIKELY (!src)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get src pad from textoverlay");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST
|
||||
(self->srcpad), src))) {
|
||||
GST_WARNING_OBJECT (self, "Can't set srcpad target");
|
||||
gst_object_unref (src);
|
||||
continue;
|
||||
}
|
||||
gst_object_unref (src);
|
||||
/* Everything done here, go out of loop */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Send segments to the parser/overlay if necessary. These are not sent
|
||||
* outside this element because of the proxy pad event function */
|
||||
if (self->video_segment.format != GST_FORMAT_UNDEFINED) {
|
||||
GstEvent *event1, *event2;
|
||||
if (overlay_factories)
|
||||
gst_plugin_feature_list_free (overlay_factories);
|
||||
|
||||
if (is_video) {
|
||||
sink = gst_element_get_static_pad (self->pre_colorspace, "sink");
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get sink pad from " COLORSPACE);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
sink = gst_element_get_static_pad (self->overlay, "video_sink");
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get sink pad from textoverlay");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
_generate_update_newsegment_event (&self->video_segment, &event1,
|
||||
&event2);
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"Pushing video accumulate newsegment event: %" GST_PTR_FORMAT,
|
||||
event1->structure);
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"Pushing video update newsegment event: %" GST_PTR_FORMAT,
|
||||
event2->structure);
|
||||
gst_pad_send_event (sink, event1);
|
||||
gst_pad_send_event (sink, event2);
|
||||
|
||||
gst_object_unref (sink);
|
||||
if (G_UNLIKELY (k == NULL)) {
|
||||
GST_WARNING_OBJECT (self, "Failed to find usable overlay factory");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (self->subtitle_segment.format != GST_FORMAT_UNDEFINED) {
|
||||
GstEvent *event1, *event2;
|
||||
|
||||
sink = gst_element_get_static_pad (element, "sink");
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Failed to get subpad");
|
||||
continue;
|
||||
}
|
||||
|
||||
_generate_update_newsegment_event (&self->subtitle_segment, &event1,
|
||||
&event2);
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"Pushing subtitle accumulate newsegment event: %" GST_PTR_FORMAT,
|
||||
event1->structure);
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"Pushing subtitle update newsegment event: %" GST_PTR_FORMAT,
|
||||
event2->structure);
|
||||
gst_pad_send_event (sink, event1);
|
||||
gst_pad_send_event (sink, event2);
|
||||
|
||||
gst_object_unref (sink);
|
||||
}
|
||||
|
||||
/* Set the sink ghostpad targets */
|
||||
if (is_video && !is_hw) {
|
||||
sink = gst_element_get_static_pad (self->pre_colorspace, "sink");
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get sink pad from " COLORSPACE);
|
||||
continue;
|
||||
}
|
||||
} else if (is_video && is_hw) {
|
||||
GST_DEBUG_OBJECT (self, "Setting ghostpad to overlay video sink");
|
||||
sink = gst_element_get_static_pad (self->overlay, "video_sink");
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get sink pad from overlay");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST
|
||||
(self->video_sinkpad), sink))) {
|
||||
GST_WARNING_OBJECT (self, "Can't set video sinkpad target");
|
||||
/* Now link subtitle sinkpad of the bin and the parser */
|
||||
sink = gst_element_get_static_pad (self->parser, "sink");
|
||||
if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST
|
||||
(self->subtitle_sinkpad), sink)) {
|
||||
gst_object_unref (sink);
|
||||
continue;
|
||||
}
|
||||
gst_object_unref (sink);
|
||||
|
||||
/* Link subtitle identity to subtitle pad of our element */
|
||||
sink = gst_element_get_static_pad (element, "sink");
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Failed to get subpad");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST
|
||||
(self->subtitle_sinkpad), sink))) {
|
||||
GST_WARNING_OBJECT (self, "Failed to set subtitle sink target");
|
||||
gst_object_unref (sink);
|
||||
continue;
|
||||
}
|
||||
gst_object_unref (sink);
|
||||
/* Everything done here, go out of loop */
|
||||
break;
|
||||
} else {
|
||||
const gchar *name =
|
||||
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE_CAST (factory));
|
||||
/* Is renderer factory */
|
||||
|
||||
if (strcmp (name, "textoverlay") == 0) {
|
||||
/* Set some textoverlay specific properties */
|
||||
g_object_set (G_OBJECT (element),
|
||||
"halign", "center", "valign", "bottom", "wait-text", FALSE, NULL);
|
||||
if (self->font_desc)
|
||||
g_object_set (G_OBJECT (element), "font-desc", self->font_desc, NULL);
|
||||
self->silent_property = "silent";
|
||||
self->silent_property_invert = FALSE;
|
||||
} else {
|
||||
self->silent_property =
|
||||
_get_silent_property (element, &self->silent_property_invert);
|
||||
if (_has_subtitle_encoding_property (self->renderer))
|
||||
g_object_set (self->renderer, "subtitle-encoding", self->encoding,
|
||||
NULL);
|
||||
if (_has_font_desc_property (self->renderer))
|
||||
g_object_set (self->renderer, "font-desc", self->font_desc, NULL);
|
||||
}
|
||||
|
||||
if (is_video) {
|
||||
gboolean render_is_hw;
|
||||
|
||||
/* First check that renderer also supports the video format */
|
||||
sink = _get_video_pad (element);
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get video sink from renderer");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_video != _is_video_pad (sink, &render_is_hw) ||
|
||||
is_hw != render_is_hw) {
|
||||
GST_DEBUG_OBJECT (self, "Renderer doesn't support %s video",
|
||||
is_hw ? "surface" : "raw");
|
||||
gst_object_unref (sink);
|
||||
continue;
|
||||
}
|
||||
gst_object_unref (sink);
|
||||
|
||||
if (!is_hw) {
|
||||
/* First link everything internally */
|
||||
if (G_UNLIKELY (!_create_element (self, &self->post_colorspace,
|
||||
COLORSPACE, NULL, "post-colorspace", FALSE))) {
|
||||
continue;
|
||||
}
|
||||
src = gst_element_get_static_pad (element, "src");
|
||||
if (G_UNLIKELY (!src)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get src pad from renderer");
|
||||
continue;
|
||||
}
|
||||
|
||||
sink = gst_element_get_static_pad (self->post_colorspace, "sink");
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get sink pad from " COLORSPACE);
|
||||
gst_object_unref (src);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (gst_pad_link (src, sink) != GST_PAD_LINK_OK)) {
|
||||
GST_WARNING_OBJECT (self, "Can't link renderer with " COLORSPACE);
|
||||
gst_object_unref (src);
|
||||
gst_object_unref (sink);
|
||||
continue;
|
||||
}
|
||||
gst_object_unref (src);
|
||||
gst_object_unref (sink);
|
||||
|
||||
if (G_UNLIKELY (!_create_element (self, &self->pre_colorspace,
|
||||
COLORSPACE, NULL, "pre-colorspace", FALSE))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sink = _get_video_pad (element);
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get video sink from renderer");
|
||||
continue;
|
||||
}
|
||||
|
||||
src = gst_element_get_static_pad (self->pre_colorspace, "src");
|
||||
if (G_UNLIKELY (!src)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get srcpad from " COLORSPACE);
|
||||
gst_object_unref (sink);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (gst_pad_link (src, sink) != GST_PAD_LINK_OK)) {
|
||||
GST_WARNING_OBJECT (self, "Can't link " COLORSPACE " to renderer");
|
||||
gst_object_unref (src);
|
||||
gst_object_unref (sink);
|
||||
continue;
|
||||
}
|
||||
gst_object_unref (src);
|
||||
gst_object_unref (sink);
|
||||
|
||||
/* Set src ghostpad target */
|
||||
src = gst_element_get_static_pad (self->post_colorspace, "src");
|
||||
if (G_UNLIKELY (!src)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get src pad from " COLORSPACE);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
/* Set src ghostpad target in the harware accelerated case */
|
||||
|
||||
src = gst_element_get_static_pad (self->renderer, "src");
|
||||
if (G_UNLIKELY (!src)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get src pad from renderer");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else { /* No video pad */
|
||||
GstCaps *allowed_caps, *video_caps = NULL;
|
||||
GstPad *video_peer;
|
||||
gboolean can_intersect = FALSE;
|
||||
|
||||
video_peer = gst_pad_get_peer (self->video_sinkpad);
|
||||
if (video_peer) {
|
||||
video_caps = gst_pad_get_negotiated_caps (video_peer);
|
||||
if (!video_caps) {
|
||||
video_caps = gst_pad_get_caps_reffed (video_peer);
|
||||
}
|
||||
gst_object_unref (video_peer);
|
||||
}
|
||||
|
||||
sink = _get_video_pad (element);
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get video sink from renderer");
|
||||
continue;
|
||||
}
|
||||
allowed_caps = gst_pad_get_caps_reffed (sink);
|
||||
gst_object_unref (sink);
|
||||
|
||||
if (allowed_caps && video_caps)
|
||||
can_intersect = gst_caps_can_intersect (allowed_caps, video_caps);
|
||||
|
||||
if (allowed_caps)
|
||||
gst_caps_unref (allowed_caps);
|
||||
|
||||
if (video_caps)
|
||||
gst_caps_unref (video_caps);
|
||||
|
||||
if (G_UNLIKELY (!can_intersect)) {
|
||||
GST_WARNING_OBJECT (self, "Renderer with custom caps is not "
|
||||
"compatible with video stream");
|
||||
continue;
|
||||
}
|
||||
|
||||
src = gst_element_get_static_pad (element, "src");
|
||||
if (G_UNLIKELY (!src)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get src pad from renderer");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST
|
||||
(self->srcpad), src))) {
|
||||
GST_WARNING_OBJECT (self, "Can't set srcpad target");
|
||||
gst_object_unref (src);
|
||||
if (!_setup_renderer (self, self->renderer))
|
||||
continue;
|
||||
}
|
||||
gst_object_unref (src);
|
||||
|
||||
/* Send segments to the renderer if necessary. These are not sent
|
||||
* outside this element because of the proxy pad event handler */
|
||||
if (self->video_segment.format != GST_FORMAT_UNDEFINED) {
|
||||
GstEvent *event1, *event2;
|
||||
|
||||
sink = gst_element_get_static_pad (self->pre_colorspace, "sink");
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get sink pad from " COLORSPACE);
|
||||
continue;
|
||||
}
|
||||
|
||||
_generate_update_newsegment_event (&self->video_segment, &event1,
|
||||
&event2);
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"Pushing video accumulate newsegment event: %" GST_PTR_FORMAT,
|
||||
event1->structure);
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"Pushing video update newsegment event: %" GST_PTR_FORMAT,
|
||||
event2->structure);
|
||||
gst_pad_send_event (sink, event1);
|
||||
gst_pad_send_event (sink, event2);
|
||||
gst_object_unref (sink);
|
||||
}
|
||||
|
||||
if (self->subtitle_segment.format != GST_FORMAT_UNDEFINED) {
|
||||
GstEvent *event1, *event2;
|
||||
|
||||
sink = _get_sub_pad (element);
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Failed to get subpad");
|
||||
continue;
|
||||
}
|
||||
|
||||
_generate_update_newsegment_event (&self->subtitle_segment, &event1,
|
||||
&event2);
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"Pushing subtitle accumulate newsegment event: %" GST_PTR_FORMAT,
|
||||
event1->structure);
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"Pushing subtitle update newsegment event: %" GST_PTR_FORMAT,
|
||||
event2->structure);
|
||||
gst_pad_send_event (sink, event1);
|
||||
gst_pad_send_event (sink, event2);
|
||||
gst_object_unref (sink);
|
||||
}
|
||||
|
||||
/* Set the sink ghostpad targets */
|
||||
if (self->pre_colorspace) {
|
||||
sink = gst_element_get_static_pad (self->pre_colorspace, "sink");
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get sink pad from " COLORSPACE);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
sink = _get_video_pad (element);
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Can't get sink pad from %" GST_PTR_FORMAT,
|
||||
element);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST
|
||||
(self->video_sinkpad), sink))) {
|
||||
GST_WARNING_OBJECT (self, "Can't set video sinkpad target");
|
||||
gst_object_unref (sink);
|
||||
/* subtitle_src==NULL means: use subtitle_sink ghostpad */
|
||||
if (!_link_renderer (self, self->renderer, NULL))
|
||||
continue;
|
||||
}
|
||||
gst_object_unref (sink);
|
||||
|
||||
sink = _get_sub_pad (element);
|
||||
if (G_UNLIKELY (!sink)) {
|
||||
GST_WARNING_OBJECT (self, "Failed to get subpad");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST
|
||||
(self->subtitle_sinkpad), sink))) {
|
||||
GST_WARNING_OBJECT (self, "Failed to set subtitle sink target");
|
||||
gst_object_unref (sink);
|
||||
continue;
|
||||
}
|
||||
gst_object_unref (sink);
|
||||
/* Everything done here, go out of loop */
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (l == NULL)) {
|
||||
|
@ -1420,15 +1285,62 @@ _pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
|
|||
self->subtitle_error = TRUE;
|
||||
_setup_passthrough (self);
|
||||
do_async_done (self);
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (self, "Everything worked, unblocking pads");
|
||||
gst_pad_set_blocked_async_full (self->video_block_pad, FALSE,
|
||||
_pad_blocked_cb, self, NULL);
|
||||
gst_pad_set_blocked_async_full (self->subtitle_block_pad, FALSE,
|
||||
_pad_blocked_cb, self, NULL);
|
||||
do_async_done (self);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Send segments to the renderer if necessary. These are not sent
|
||||
* outside this element because of the proxy pad event handler */
|
||||
if (self->video_segment.format != GST_FORMAT_UNDEFINED) {
|
||||
GstEvent *event1, *event2;
|
||||
GstPad *sink;
|
||||
|
||||
if (self->pre_colorspace) {
|
||||
sink = gst_element_get_static_pad (self->pre_colorspace, "sink");
|
||||
} else {
|
||||
sink = _get_video_pad ((self->renderer) ? self->renderer : self->overlay);
|
||||
}
|
||||
|
||||
_generate_update_newsegment_event (&self->video_segment, &event1, &event2);
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"Pushing video accumulate newsegment event: %" GST_PTR_FORMAT,
|
||||
event1->structure);
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"Pushing video update newsegment event: %" GST_PTR_FORMAT,
|
||||
event2->structure);
|
||||
gst_pad_send_event (sink, event1);
|
||||
gst_pad_send_event (sink, event2);
|
||||
gst_object_unref (sink);
|
||||
}
|
||||
|
||||
if (self->subtitle_segment.format != GST_FORMAT_UNDEFINED) {
|
||||
GstEvent *event1, *event2;
|
||||
GstPad *sink;
|
||||
|
||||
if (self->renderer)
|
||||
sink = _get_sub_pad (self->renderer);
|
||||
else
|
||||
sink = gst_element_get_static_pad (self->parser, "sink");
|
||||
|
||||
_generate_update_newsegment_event (&self->subtitle_segment, &event1,
|
||||
&event2);
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"Pushing subtitle accumulate newsegment event: %" GST_PTR_FORMAT,
|
||||
event1->structure);
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"Pushing subtitle update newsegment event: %" GST_PTR_FORMAT,
|
||||
event2->structure);
|
||||
gst_pad_send_event (sink, event1);
|
||||
gst_pad_send_event (sink, event2);
|
||||
gst_object_unref (sink);
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Everything worked, unblocking pads");
|
||||
gst_pad_set_blocked_async_full (self->video_block_pad, FALSE,
|
||||
_pad_blocked_cb, self, NULL);
|
||||
gst_pad_set_blocked_async_full (self->subtitle_block_pad, FALSE,
|
||||
_pad_blocked_cb, self, NULL);
|
||||
do_async_done (self);
|
||||
|
||||
out:
|
||||
if (factories)
|
||||
gst_plugin_feature_list_free (factories);
|
||||
|
@ -1790,8 +1702,8 @@ gst_subtitle_overlay_src_proxy_event (GstPad * proxypad, GstEvent * event)
|
|||
|
||||
s = gst_event_get_structure (event);
|
||||
if (s && gst_structure_id_has_field (s, _subtitle_overlay_event_marker_id)) {
|
||||
GST_DEBUG_OBJECT (ghostpad, "Dropping event with marker: %" GST_PTR_FORMAT,
|
||||
event->structure);
|
||||
GST_DEBUG_OBJECT (ghostpad,
|
||||
"Dropping event with marker: %" GST_PTR_FORMAT, event->structure);
|
||||
gst_event_unref (event);
|
||||
event = NULL;
|
||||
ret = TRUE;
|
||||
|
@ -2161,8 +2073,8 @@ gst_subtitle_overlay_subtitle_sink_event (GstPad * pad, GstEvent * event)
|
|||
gst_structure_set_parent_refcount (event->structure,
|
||||
&event->mini_object.refcount);
|
||||
}
|
||||
gst_structure_id_set (event->structure, _subtitle_overlay_event_marker_id,
|
||||
G_TYPE_BOOLEAN, TRUE, NULL);
|
||||
gst_structure_id_set (event->structure,
|
||||
_subtitle_overlay_event_marker_id, G_TYPE_BOOLEAN, TRUE, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
Loading…
Reference in a new issue