* <refsect2>
* <title>Examples</title>
* |[
- * gst-launch -v filesrc location=test.mkv ! matroskademux name=demux ! "video/x-h264" ! queue2 ! decodebin2 ! subtitleoverlay name=overlay ! ffmpegcolorspace ! autovideosink demux. ! "video/x-dvd-subpicture" ! queue2 ! overlay.
+ * gst-launch -v filesrc location=test.mkv ! matroskademux name=demux ! "video/x-h264" ! queue2 ! decodebin ! subtitleoverlay name=overlay ! videoconvert ! autovideosink demux. ! "video/x-dvd-subpicture" ! queue2 ! overlay.
* ]| This will play back the given Matroska file with h264 video and subpicture subtitles.
* </refsect2>
*/
#include "gstsubtitleoverlay.h"
-#include <gst/gstfilter.h>
#include <gst/pbutils/missing-plugins.h>
#include <gst/video/video.h>
#include <string.h>
PROP_SUBTITLE_ENCODING
};
-GST_BOILERPLATE (GstSubtitleOverlay, gst_subtitle_overlay, GstBin,
- GST_TYPE_BIN);
-
-static void _pad_blocked_cb (GstPad * pad, gboolean blocked,
- gpointer user_data);
+#define gst_subtitle_overlay_parent_class parent_class
+G_DEFINE_TYPE (GstSubtitleOverlay, gst_subtitle_overlay, GST_TYPE_BIN);
static GQuark _subtitle_overlay_event_marker_id = 0;
do_async_start (GstSubtitleOverlay * self)
{
if (!self->do_async) {
- GstMessage *msg =
- gst_message_new_async_start (GST_OBJECT_CAST (self), FALSE);
+ GstMessage *msg = gst_message_new_async_start (GST_OBJECT_CAST (self));
GST_DEBUG_OBJECT (self, "Posting async-start");
- parent_class->handle_message (GST_BIN_CAST (self), msg);
+ GST_BIN_CLASS (parent_class)->handle_message (GST_BIN_CAST (self), msg);
self->do_async = TRUE;
}
}
do_async_done (GstSubtitleOverlay * self)
{
if (self->do_async) {
- GstMessage *msg = gst_message_new_async_done (GST_OBJECT_CAST (self));
+ GstMessage *msg =
+ gst_message_new_async_done (GST_OBJECT_CAST (self), FALSE);
GST_DEBUG_OBJECT (self, "Posting async-done");
- parent_class->handle_message (GST_BIN_CAST (self), msg);
+ GST_BIN_CLASS (parent_class)->handle_message (GST_BIN_CAST (self), msg);
self->do_async = FALSE;
}
}
+static GstPadProbeReturn
+_pad_blocked_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data);
+
+static void
+block_video (GstSubtitleOverlay * self)
+{
+ if (self->video_block_id != 0)
+ return;
+
+ if (self->video_block_pad) {
+ self->video_block_id =
+ gst_pad_add_probe (self->video_block_pad,
+ GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, _pad_blocked_cb, self, NULL);
+ }
+}
+
+static void
+unblock_video (GstSubtitleOverlay * self)
+{
+ if (self->video_block_id) {
+ gst_pad_remove_probe (self->video_block_pad, self->video_block_id);
+ self->video_sink_blocked = FALSE;
+ self->video_block_id = 0;
+ }
+}
+
+static void
+block_subtitle (GstSubtitleOverlay * self)
+{
+ if (self->subtitle_block_id != 0)
+ return;
+
+ if (self->subtitle_block_pad) {
+ self->subtitle_block_id =
+ gst_pad_add_probe (self->subtitle_block_pad,
+ GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, _pad_blocked_cb, self, NULL);
+ }
+}
+
+static void
+unblock_subtitle (GstSubtitleOverlay * self)
+{
+ if (self->subtitle_block_id) {
+ gst_pad_remove_probe (self->subtitle_block_pad, self->subtitle_block_id);
+ self->subtitle_sink_blocked = FALSE;
+ self->subtitle_block_id = 0;
+ }
+}
+
static void
gst_subtitle_overlay_finalize (GObject * object)
{
name = gst_structure_get_name (s);
- if (g_str_has_prefix (name, "video/x-raw-"))
+ if (g_str_has_prefix (name, "video/x-raw"))
return TRUE;
return FALSE;
}
static gboolean
_is_video_pad (GstPad * pad, gboolean * hw_accelerated)
{
- GstPad *peer = gst_pad_get_peer (pad);
- GstCaps *caps;
+ GstCaps *caps = gst_pad_get_current_caps (pad);
gboolean ret;
const gchar *name;
- if (peer) {
- caps = gst_pad_get_negotiated_caps (peer);
- if (!caps) {
- caps = gst_pad_get_caps_reffed (peer);
- }
- gst_object_unref (peer);
- } else {
- caps = gst_pad_get_caps_reffed (pad);
- }
-
-
name = gst_structure_get_name (gst_caps_get_structure (caps, 0));
if (g_str_has_prefix (name, "video/x-raw-")) {
ret = TRUE;
}
static void
-_generate_update_newsegment_event (GstSegment * segment, GstEvent ** event1,
- GstEvent ** event2)
+_generate_update_segment_event (GstSegment * segment, GstEvent ** event1)
{
GstEvent *event;
+ GstStructure *structure;
- *event1 = NULL;
- *event2 = NULL;
-
- event = gst_event_new_new_segment_full (FALSE, segment->rate,
- segment->applied_rate, segment->format, 0, segment->accum, 0);
- gst_structure_id_set (event->structure, _subtitle_overlay_event_marker_id,
+ event = gst_event_new_segment (segment);
+ structure = gst_event_writable_structure (event);
+ gst_structure_id_set (structure, _subtitle_overlay_event_marker_id,
G_TYPE_BOOLEAN, TRUE, NULL);
*event1 = event;
-
- event = gst_event_new_new_segment_full (FALSE, segment->rate,
- segment->applied_rate, segment->format,
- segment->start, segment->stop, segment->time);
- gst_structure_id_set (event->structure, _subtitle_overlay_event_marker_id,
- G_TYPE_BOOLEAN, TRUE, NULL);
- *event2 = event;
}
static gboolean
/* Send segment to the identity. This is dropped because identity
* is not linked downstream yet */
if (self->video_segment.format != GST_FORMAT_UNDEFINED) {
- GstEvent *event1, *event2;
+ GstEvent *event1;
- _generate_update_newsegment_event (&self->video_segment, &event1, &event2);
- GST_DEBUG_OBJECT (self,
- "Pushing video accumulate newsegment event: %" GST_PTR_FORMAT,
- event1->structure);
+ _generate_update_segment_event (&self->video_segment, &event1);
GST_DEBUG_OBJECT (self,
- "Pushing video update newsegment event: %" GST_PTR_FORMAT,
- event2->structure);
+ "Pushing video segment event: %" GST_PTR_FORMAT, event1);
gst_pad_send_event (sink, event1);
- gst_pad_send_event (sink, event2);
}
/* Link sink ghostpads to identity */
out:
/* Unblock pads */
- gst_pad_set_blocked_async_full (self->video_block_pad, FALSE,
- _pad_blocked_cb, self, NULL);
-
- if (self->subtitle_sink_blocked)
- gst_pad_set_blocked_async_full (self->subtitle_block_pad, FALSE,
- _pad_blocked_cb, self, NULL);
+ unblock_video (self);
+ unblock_subtitle (self);
return TRUE;
}
return (pspec && pspec->value_type == G_TYPE_STRING);
}
-static void
-_pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
+static GstPadProbeReturn
+_pad_blocked_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY_CAST (user_data);
GstCaps *subcaps;
GList *l, *factories = NULL;
- GST_DEBUG_OBJECT (pad, "Pad blocked: %d", blocked);
+ GST_DEBUG_OBJECT (pad, "Pad blocked");
GST_SUBTITLE_OVERLAY_LOCK (self);
if (pad == self->video_block_pad)
- self->video_sink_blocked = blocked;
+ self->video_sink_blocked = TRUE;
else if (pad == self->subtitle_block_pad)
- self->subtitle_sink_blocked = blocked;
-
- if (!blocked) {
- GST_SUBTITLE_OVERLAY_UNLOCK (self);
- return;
- }
+ self->subtitle_sink_blocked = TRUE;
/* Now either both or the video sink are blocked */
peer = gst_pad_get_peer (self->subtitle_sinkpad);
if (peer) {
- subcaps = gst_pad_get_negotiated_caps (peer);
+ subcaps = gst_pad_get_current_caps (peer);
if (!subcaps) {
- subcaps = gst_pad_get_caps_reffed (peer);
+ subcaps = gst_pad_query_caps (peer, NULL);
if (!gst_caps_is_fixed (subcaps)) {
gst_caps_unref (subcaps);
subcaps = NULL;
GstPad *target =
gst_ghost_pad_get_target (GST_GHOST_PAD_CAST (self->subtitle_sinkpad));
- if (target && gst_pad_accept_caps (target, subcaps)) {
+ if (target && gst_pad_query_accept_caps (target, subcaps)) {
GST_DEBUG_OBJECT (pad, "Target accepts caps");
gst_object_unref (target);
/* Unblock pads */
- gst_pad_set_blocked_async_full (self->video_block_pad, FALSE,
- _pad_blocked_cb, self, NULL);
-
- if (self->subtitle_sink_blocked)
- gst_pad_set_blocked_async_full (self->subtitle_block_pad, FALSE,
- _pad_blocked_cb, self, NULL);
+ unblock_video (self);
+ unblock_subtitle (self);
goto out;
} else if (target) {
gst_object_unref (target);
if (self->subtitle_sink_blocked && !self->video_sink_blocked) {
GST_DEBUG_OBJECT (self, "Subtitle sink blocked but video not blocked");
- gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
+ block_video (self);
goto out;
}
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);
+ video_caps = gst_pad_get_current_caps (video_peer);
if (!video_caps) {
- video_caps = gst_pad_get_caps_reffed (video_peer);
+ video_caps = gst_pad_query_caps (video_peer, NULL);
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) {
+ GstVideoInfo info;
+
+ if (gst_video_info_from_caps (&info, video_caps)) {
+ if (self->fps_n != info.fps_n || self->fps_d != info.fps_d) {
+ GST_DEBUG_OBJECT (self, "New video fps: %d/%d", info.fps_n,
+ info.fps_d);
+ self->fps_n = info.fps_n;
+ self->fps_d = info.fps_d;
+ }
}
}
/* 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;
+ GstEvent *event1;
if (is_video) {
sink = gst_element_get_static_pad (self->pre_colorspace, "sink");
}
}
- _generate_update_newsegment_event (&self->video_segment, &event1,
- &event2);
- GST_DEBUG_OBJECT (self,
- "Pushing video accumulate newsegment event: %" GST_PTR_FORMAT,
- event1->structure);
+ _generate_update_segment_event (&self->video_segment, &event1);
GST_DEBUG_OBJECT (self,
- "Pushing video update newsegment event: %" GST_PTR_FORMAT,
- event2->structure);
+ "Pushing video segment event: %" GST_PTR_FORMAT, event1);
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;
+ GstEvent *event1;
sink = gst_element_get_static_pad (element, "sink");
if (G_UNLIKELY (!sink)) {
continue;
}
- _generate_update_newsegment_event (&self->subtitle_segment, &event1,
- &event2);
+ _generate_update_segment_event (&self->subtitle_segment, &event1);
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);
+ "Pushing subtitle segment event: %" GST_PTR_FORMAT, event1);
gst_pad_send_event (sink, event1);
- gst_pad_send_event (sink, event2);
gst_object_unref (sink);
}
video_peer = gst_pad_get_peer (self->video_sinkpad);
if (video_peer) {
- video_caps = gst_pad_get_negotiated_caps (video_peer);
+ video_caps = gst_pad_get_current_caps (video_peer);
if (!video_caps) {
- video_caps = gst_pad_get_caps_reffed (video_peer);
+ video_caps = gst_pad_query_caps (video_peer, NULL);
}
gst_object_unref (video_peer);
}
GST_WARNING_OBJECT (self, "Can't get video sink from renderer");
continue;
}
- allowed_caps = gst_pad_get_caps_reffed (sink);
+ allowed_caps = gst_pad_query_caps (sink, NULL);
gst_object_unref (sink);
if (allowed_caps && video_caps)
/* 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;
+ GstEvent *event1;
sink = gst_element_get_static_pad (self->pre_colorspace, "sink");
if (G_UNLIKELY (!sink)) {
continue;
}
- _generate_update_newsegment_event (&self->video_segment, &event1,
- &event2);
- GST_DEBUG_OBJECT (self,
- "Pushing video accumulate newsegment event: %" GST_PTR_FORMAT,
- event1->structure);
+ _generate_update_segment_event (&self->video_segment, &event1);
GST_DEBUG_OBJECT (self,
- "Pushing video update newsegment event: %" GST_PTR_FORMAT,
- event2->structure);
+ "Pushing video segment event: %" GST_PTR_FORMAT, event1);
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;
+ GstEvent *event1;
sink = _get_sub_pad (element);
if (G_UNLIKELY (!sink)) {
continue;
}
- _generate_update_newsegment_event (&self->subtitle_segment, &event1,
- &event2);
- GST_DEBUG_OBJECT (self,
- "Pushing subtitle accumulate newsegment event: %" GST_PTR_FORMAT,
- event1->structure);
+ _generate_update_segment_event (&self->subtitle_segment, &event1);
GST_DEBUG_OBJECT (self,
- "Pushing subtitle update newsegment event: %" GST_PTR_FORMAT,
- event2->structure);
+ "Pushing subtitle segment event: %" GST_PTR_FORMAT, event1);
gst_pad_send_event (sink, event1);
- gst_pad_send_event (sink, event2);
gst_object_unref (sink);
}
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);
+ unblock_video (self);
+ unblock_subtitle (self);
do_async_done (self);
}
if (factories)
gst_plugin_feature_list_free (factories);
GST_SUBTITLE_OVERLAY_UNLOCK (self);
+
+ return GST_PAD_PROBE_OK;
}
static GstStateChangeReturn
GST_SUBTITLE_OVERLAY_LOCK (self);
/* Set the internal pads to blocking */
- gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
- gst_pad_set_blocked_async_full (self->subtitle_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
+ block_video (self);
+ block_subtitle (self);
GST_SUBTITLE_OVERLAY_UNLOCK (self);
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
do_async_done (self);
break;
- case GST_STATE_CHANGE_READY_TO_NULL:{
- GstPad *pad;
-
+ case GST_STATE_CHANGE_READY_TO_NULL:
GST_DEBUG_OBJECT (self, "State change READY->NULL");
GST_SUBTITLE_OVERLAY_LOCK (self);
NULL);
/* Unblock pads */
- if (self->video_block_pad) {
- pad = self->video_block_pad;
- gst_pad_set_blocked_async_full (pad, FALSE, _pad_blocked_cb,
- self, NULL);
- }
-
- if (self->subtitle_block_pad) {
- pad = self->subtitle_block_pad;
- gst_pad_set_blocked_async_full (pad, FALSE, _pad_blocked_cb,
- self, NULL);
- }
+ unblock_video (self);
+ unblock_subtitle (self);
/* Remove elements */
self->silent_property = NULL;
GST_SUBTITLE_OVERLAY_UNLOCK (self);
break;
- }
default:
break;
}
GST_SUBTITLE_OVERLAY_LOCK (self);
self->subtitle_error = TRUE;
- gst_pad_set_blocked_async_full (self->subtitle_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
-
- gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
+ block_subtitle (self);
+ block_video (self);
GST_SUBTITLE_OVERLAY_UNLOCK (self);
}
}
else if (self->renderer)
g_object_set (self->renderer, self->silent_property, silent, NULL);
} else {
- gst_pad_set_blocked_async_full (self->subtitle_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
-
- gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
+ block_subtitle (self);
+ block_video (self);
}
GST_SUBTITLE_OVERLAY_UNLOCK (self);
break;
}
static void
-gst_subtitle_overlay_base_init (gpointer g_class)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
-
- gst_element_class_add_static_pad_template (gstelement_class,
- &video_sinktemplate);
- gst_element_class_add_static_pad_template (gstelement_class,
- &subtitle_sinktemplate);
-
- gst_element_class_set_details_simple (gstelement_class, "Subtitle Overlay",
- "Video/Overlay/Subtitle",
- "Overlays a video stream with subtitles",
- "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
-}
-
-static void
gst_subtitle_overlay_class_init (GstSubtitleOverlayClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
"ISO-8859-15 will be assumed.", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&srctemplate));
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&video_sinktemplate));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&subtitle_sinktemplate));
+
+ gst_element_class_set_details_simple (element_class, "Subtitle Overlay",
+ "Video/Overlay/Subtitle",
+ "Overlays a video stream with subtitles",
+ "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
element_class->change_state =
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_change_state);
}
static GstFlowReturn
-gst_subtitle_overlay_src_proxy_chain (GstPad * proxypad, GstBuffer * buffer)
+gst_subtitle_overlay_src_proxy_chain (GstPad * proxypad, GstObject * parent,
+ GstBuffer * buffer)
{
GstPad *ghostpad;
GstSubtitleOverlay *self;
GstFlowReturn ret;
- ghostpad = GST_PAD_CAST (gst_pad_get_parent (proxypad));
+ ghostpad = GST_PAD_CAST (parent);
if (G_UNLIKELY (!ghostpad)) {
gst_buffer_unref (buffer);
return GST_FLOW_ERROR;
return GST_FLOW_ERROR;
}
- ret = gst_proxy_pad_chain_default (proxypad, buffer);
+ ret = gst_proxy_pad_chain_default (proxypad, parent, buffer);
if (IS_VIDEO_CHAIN_IGNORE_ERROR (ret)) {
GST_ERROR_OBJECT (self, "Downstream chain error: %s",
}
gst_object_unref (self);
- gst_object_unref (ghostpad);
return ret;
}
static gboolean
-gst_subtitle_overlay_src_proxy_event (GstPad * proxypad, GstEvent * event)
+gst_subtitle_overlay_src_proxy_event (GstPad * proxypad, GstObject * parent,
+ GstEvent * event)
{
GstPad *ghostpad = NULL;
GstSubtitleOverlay *self = NULL;
gboolean ret = FALSE;
const GstStructure *s;
- ghostpad = GST_PAD_CAST (gst_pad_get_parent (proxypad));
+ ghostpad = GST_PAD_CAST (parent);
if (G_UNLIKELY (!ghostpad))
goto out;
self = GST_SUBTITLE_OVERLAY_CAST (gst_pad_get_parent (ghostpad));
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);
+ event);
gst_event_unref (event);
event = NULL;
ret = TRUE;
} else {
- ret = gst_proxy_pad_event_default (proxypad, event);
+ ret = gst_proxy_pad_event_default (proxypad, parent, event);
event = NULL;
}
gst_event_unref (event);
if (self)
gst_object_unref (self);
- if (ghostpad)
- gst_object_unref (ghostpad);
+
return ret;
}
static gboolean
-gst_subtitle_overlay_video_sink_setcaps (GstPad * pad, GstCaps * caps)
+gst_subtitle_overlay_video_sink_setcaps (GstSubtitleOverlay * self,
+ GstCaps * caps)
{
- GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY (gst_pad_get_parent (pad));
GstPad *target;
gboolean ret = TRUE;
- gint fps_n, fps_d;
+ GstVideoInfo info;
- GST_DEBUG_OBJECT (pad, "Setting caps: %" GST_PTR_FORMAT, caps);
+ GST_DEBUG_OBJECT (self, "Setting caps: %" GST_PTR_FORMAT, caps);
+
+ if (!gst_video_info_from_caps (&info, caps)) {
+ GST_ERROR_OBJECT (self, "Failed to parse caps");
+ ret = FALSE;
+ GST_SUBTITLE_OVERLAY_UNLOCK (self);
+ goto out;
+ }
target = gst_ghost_pad_get_target (GST_GHOST_PAD_CAST (self->video_sinkpad));
GST_SUBTITLE_OVERLAY_LOCK (self);
- if (!target || !gst_pad_accept_caps (target, caps)) {
- GST_DEBUG_OBJECT (pad, "Target did not accept caps -- reconfiguring");
+ if (!target || !gst_pad_query_accept_caps (target, caps)) {
+ GST_DEBUG_OBJECT (target, "Target did not accept caps -- reconfiguring");
- gst_pad_set_blocked_async_full (self->subtitle_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
-
- gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
- }
-
- if (!gst_video_parse_caps_framerate (caps, &fps_n, &fps_d)) {
- GST_ERROR_OBJECT (pad, "Failed to parse framerate from caps");
- ret = FALSE;
- GST_SUBTITLE_OVERLAY_UNLOCK (self);
- goto out;
+ block_subtitle (self);
+ block_video (self);
}
- 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;
+ GST_SUBTITLE_OVERLAY_LOCK (self);
+ if (self->fps_n != info.fps_n || self->fps_d != info.fps_d) {
+ GST_DEBUG_OBJECT (self, "New video fps: %d/%d", info.fps_n, info.fps_d);
+ self->fps_n = info.fps_n;
+ self->fps_d = info.fps_d;
gst_subtitle_overlay_set_fps (self);
}
GST_SUBTITLE_OVERLAY_UNLOCK (self);
- ret = gst_ghost_pad_setcaps_default (pad, caps);
-
-out:
if (target)
gst_object_unref (target);
- gst_object_unref (self);
+
+out:
+
return ret;
}
static gboolean
-gst_subtitle_overlay_video_sink_event (GstPad * pad, GstEvent * event)
+gst_subtitle_overlay_video_sink_event (GstPad * pad, GstObject * parent,
+ GstEvent * event)
{
- GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY (gst_pad_get_parent (pad));
+ GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY (parent);
gboolean ret;
- if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
- GST_DEBUG_OBJECT (pad,
- "Resetting video segment because of flush-stop event");
- gst_segment_init (&self->video_segment, GST_FORMAT_UNDEFINED);
- self->fps_n = self->fps_d = 0;
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_STOP:
+ {
+ GST_DEBUG_OBJECT (pad,
+ "Resetting video segment because of flush-stop event");
+ gst_segment_init (&self->video_segment, GST_FORMAT_UNDEFINED);
+ self->fps_n = self->fps_d = 0;
+ break;
+ }
+ case GST_EVENT_CAPS:
+ {
+ GstCaps *caps;
+
+ gst_event_parse_caps (event, &caps);
+ ret = gst_subtitle_overlay_video_sink_setcaps (self, caps);
+ if (!ret)
+ goto done;
+ break;
+ }
+ default:
+ break;
}
- ret = gst_proxy_pad_event_default (pad, gst_event_ref (event));
-
- if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
- gboolean update;
- gdouble rate, applied_rate;
- GstFormat format;
- gint64 start, stop, position;
+ ret = gst_proxy_pad_event_default (pad, parent, gst_event_ref (event));
- GST_DEBUG_OBJECT (pad, "Newsegment event: %" GST_PTR_FORMAT,
- event->structure);
- gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
- &format, &start, &stop, &position);
+ if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
+ GST_DEBUG_OBJECT (pad, "segment event: %" GST_PTR_FORMAT, event);
+ gst_event_copy_segment (event, &self->video_segment);
- if (format != GST_FORMAT_TIME) {
- GST_ERROR_OBJECT (pad, "Newsegment event in non-time format: %s",
- gst_format_get_name (format));
- gst_event_unref (event);
- gst_object_unref (self);
- return FALSE;
- }
-
- GST_DEBUG_OBJECT (pad, "Old video segment: %" GST_SEGMENT_FORMAT,
- &self->video_segment);
- gst_segment_set_newsegment_full (&self->video_segment, update, rate,
- applied_rate, format, start, stop, position);
- GST_DEBUG_OBJECT (pad, "New video segment: %" GST_SEGMENT_FORMAT,
- &self->video_segment);
+ if (self->video_segment.format != GST_FORMAT_TIME)
+ goto invalid_format;
}
+done:
gst_event_unref (event);
- gst_object_unref (self);
+
return ret;
+
+ /* ERRORS */
+invalid_format:
+ {
+ GST_ERROR_OBJECT (pad, "Newsegment event in non-time format: %s",
+ gst_format_get_name (self->video_segment.format));
+ ret = FALSE;
+ goto done;
+ }
}
static GstFlowReturn
-gst_subtitle_overlay_video_sink_chain (GstPad * pad, GstBuffer * buffer)
+gst_subtitle_overlay_video_sink_chain (GstPad * pad, GstObject * parent,
+ GstBuffer * buffer)
{
- GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY (GST_PAD_PARENT (pad));
- GstFlowReturn ret = gst_proxy_pad_chain_default (pad, buffer);
+ GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY (parent);
+ GstFlowReturn ret = gst_proxy_pad_chain_default (pad, parent, buffer);
if (G_UNLIKELY (self->downstream_chain_error) || self->passthrough_identity) {
return ret;
gst_flow_get_name (ret));
GST_SUBTITLE_OVERLAY_LOCK (self);
self->subtitle_error = TRUE;
- gst_pad_set_blocked_async_full (self->subtitle_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
-
- gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
+ block_subtitle (self);
+ block_video (self);
GST_SUBTITLE_OVERLAY_UNLOCK (self);
return GST_FLOW_OK;
}
static GstFlowReturn
-gst_subtitle_overlay_subtitle_sink_chain (GstPad * pad, GstBuffer * buffer)
+gst_subtitle_overlay_subtitle_sink_chain (GstPad * pad, GstObject * parent,
+ GstBuffer * buffer)
{
- GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY (GST_PAD_PARENT (pad));
+ GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY (parent);
if (self->subtitle_error) {
gst_buffer_unref (buffer);
return GST_FLOW_OK;
} else {
- GstFlowReturn ret = gst_proxy_pad_chain_default (pad, buffer);
+ GstFlowReturn ret = gst_proxy_pad_chain_default (pad, parent, buffer);
if (IS_SUBTITLE_CHAIN_IGNORE_ERROR (ret)) {
GST_DEBUG_OBJECT (self, "Subtitle chain error: %s",
gst_flow_get_name (ret));
GST_SUBTITLE_OVERLAY_LOCK (self);
self->subtitle_error = TRUE;
- gst_pad_set_blocked_async_full (self->subtitle_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
-
- gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
+ block_subtitle (self);
+ block_video (self);
GST_SUBTITLE_OVERLAY_UNLOCK (self);
return GST_FLOW_OK;
}
static GstCaps *
-gst_subtitle_overlay_subtitle_sink_getcaps (GstPad * pad)
+gst_subtitle_overlay_subtitle_sink_getcaps (GstPad * pad, GstCaps * filter)
{
GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY (gst_pad_get_parent (pad));
GstCaps *ret;
g_mutex_lock (self->factories_lock);
if (G_UNLIKELY (!gst_subtitle_overlay_update_factory_list (self)))
ret = GST_CAPS_NONE;
+ else if (filter)
+ ret =
+ gst_caps_intersect_full (filter, self->factory_caps,
+ GST_CAPS_INTERSECT_FIRST);
else
ret = gst_caps_ref (self->factory_caps);
g_mutex_unlock (self->factories_lock);
}
static gboolean
-gst_subtitle_overlay_subtitle_sink_acceptcaps (GstPad * pad, GstCaps * caps)
-{
- GstCaps *othercaps = gst_subtitle_overlay_subtitle_sink_getcaps (pad);
- gboolean ret = gst_caps_is_subset (caps, othercaps);
-
- gst_caps_unref (othercaps);
-
- return ret;
-}
-
-static gboolean
-gst_subtitle_overlay_subtitle_sink_setcaps (GstPad * pad, GstCaps * caps)
+gst_subtitle_overlay_subtitle_sink_setcaps (GstSubtitleOverlay * self,
+ GstCaps * caps)
{
- GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY (gst_pad_get_parent (pad));
gboolean ret = TRUE;
GstPad *target = NULL;;
- GST_DEBUG_OBJECT (pad, "Setting caps: %" GST_PTR_FORMAT, caps);
+ GST_DEBUG_OBJECT (self, "Setting caps: %" GST_PTR_FORMAT, caps);
target =
gst_ghost_pad_get_target (GST_GHOST_PAD_CAST (self->subtitle_sinkpad));
GST_SUBTITLE_OVERLAY_LOCK (self);
gst_caps_replace (&self->subcaps, caps);
- if (target && gst_pad_accept_caps (target, caps)) {
- GST_DEBUG_OBJECT (pad, "Target accepts caps");
- ret = gst_ghost_pad_setcaps_default (pad, caps);
+ if (target && gst_pad_query_accept_caps (target, caps)) {
+ GST_DEBUG_OBJECT (self, "Target accepts caps");
GST_SUBTITLE_OVERLAY_UNLOCK (self);
goto out;
}
- GST_DEBUG_OBJECT (pad, "Target did not accept caps");
+ GST_DEBUG_OBJECT (self, "Target did not accept caps");
self->subtitle_error = FALSE;
-
- gst_pad_set_blocked_async_full (self->subtitle_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
-
- gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
+ block_subtitle (self);
+ block_video (self);
GST_SUBTITLE_OVERLAY_UNLOCK (self);
out:
if (target)
gst_object_unref (target);
- gst_object_unref (self);
+
return ret;
}
GST_DEBUG_OBJECT (pad, "Linking pad to peer %" GST_PTR_FORMAT, peer);
- caps = gst_pad_get_negotiated_caps (peer);
+ caps = gst_pad_get_current_caps (peer);
if (!caps) {
- caps = gst_pad_get_caps_reffed (peer);
+ caps = gst_pad_query_caps (peer, NULL);
if (!gst_caps_is_fixed (caps)) {
gst_caps_unref (caps);
caps = NULL;
self->subtitle_error = FALSE;
- gst_pad_set_blocked_async_full (self->subtitle_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
-
- gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
+ block_subtitle (self);
+ block_video (self);
GST_SUBTITLE_OVERLAY_UNLOCK (self);
gst_caps_unref (caps);
}
GST_SUBTITLE_OVERLAY_LOCK (self);
self->subtitle_error = FALSE;
- if (self->subtitle_block_pad)
- gst_pad_set_blocked_async_full (self->subtitle_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
-
- if (self->video_block_pad)
- gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
+ block_subtitle (self);
+ block_video (self);
GST_SUBTITLE_OVERLAY_UNLOCK (self);
gst_object_unref (self);
}
static gboolean
-gst_subtitle_overlay_subtitle_sink_event (GstPad * pad, GstEvent * event)
+gst_subtitle_overlay_subtitle_sink_event (GstPad * pad, GstObject * parent,
+ GstEvent * event)
{
- GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY (gst_pad_get_parent (pad));
+ GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY (parent);
gboolean ret;
- GstFormat format;
if (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_DOWNSTREAM_OOB &&
- event->structure
- && strcmp (gst_structure_get_name (event->structure),
- "subtitleoverlay-flush-subtitle") == 0) {
+ gst_event_has_name (event, "subtitleoverlay-flush-subtitle")) {
GST_DEBUG_OBJECT (pad, "Custom subtitle flush event");
GST_SUBTITLE_OVERLAY_LOCK (self);
self->subtitle_flush = TRUE;
self->subtitle_error = FALSE;
- if (self->subtitle_block_pad)
- gst_pad_set_blocked_async_full (self->subtitle_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
- if (self->video_block_pad)
- gst_pad_set_blocked_async_full (self->video_block_pad, TRUE,
- _pad_blocked_cb, self, NULL);
+ block_subtitle (self);
+ block_video (self);
GST_SUBTITLE_OVERLAY_UNLOCK (self);
gst_event_unref (event);
event = NULL;
ret = TRUE;
goto out;
- } else if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
- gst_event_parse_new_segment_full (event, NULL, NULL, NULL,
- &format, NULL, NULL, NULL);
- if (self->subtitle_segment.format != GST_FORMAT_UNDEFINED &&
- self->subtitle_segment.format != format) {
- GST_DEBUG_OBJECT (pad, "Subtitle segment format changed: %s -> %s",
- gst_format_get_name (self->subtitle_segment.format),
- gst_format_get_name (format));
- gst_segment_init (&self->subtitle_segment, GST_FORMAT_UNDEFINED);
- }
}
switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_CAPS:
+ {
+ GstCaps *caps;
+
+ gst_event_parse_caps (event, &caps);
+ ret = gst_subtitle_overlay_subtitle_sink_setcaps (self, caps);
+ if (!ret)
+ goto out;
+ break;
+ }
case GST_EVENT_FLUSH_STOP:
GST_DEBUG_OBJECT (pad,
"Resetting subtitle segment because of flush-stop");
gst_segment_init (&self->subtitle_segment, GST_FORMAT_UNDEFINED);
/* fall through */
case GST_EVENT_FLUSH_START:
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_SEGMENT:
case GST_EVENT_EOS:
+ {
+ GstStructure *structure;
+
/* Add our event marker to make sure no events from here go ever outside
* the element, they're only interesting for our internal elements */
- event =
- GST_EVENT_CAST (gst_mini_object_make_writable (GST_MINI_OBJECT_CAST
- (event)));
- if (!event->structure) {
- event->structure =
- gst_structure_id_empty_new (_subtitle_overlay_event_marker_id);
- gst_structure_set_parent_refcount (event->structure,
- &event->mini_object.refcount);
- }
- gst_structure_id_set (event->structure, _subtitle_overlay_event_marker_id,
+ event = GST_EVENT_CAST (gst_event_make_writable (event));
+ structure = gst_event_writable_structure (event);
+
+ gst_structure_id_set (structure, _subtitle_overlay_event_marker_id,
G_TYPE_BOOLEAN, TRUE, NULL);
break;
+ }
default:
break;
}
- ret = gst_proxy_pad_event_default (pad, gst_event_ref (event));
-
- if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
- gboolean update;
- gdouble rate, applied_rate;
- gint64 start, stop, position;
+ ret = gst_proxy_pad_event_default (pad, parent, gst_event_ref (event));
- GST_DEBUG_OBJECT (pad, "Newsegment event: %" GST_PTR_FORMAT,
- event->structure);
- gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
- &format, &start, &stop, &position);
-
- GST_DEBUG_OBJECT (pad, "Old subtitle segment: %" GST_SEGMENT_FORMAT,
- &self->subtitle_segment);
- if (self->subtitle_segment.format != format) {
- GST_DEBUG_OBJECT (pad, "Subtitle segment format changed: %s -> %s",
- gst_format_get_name (self->subtitle_segment.format),
- gst_format_get_name (format));
- gst_segment_init (&self->subtitle_segment, format);
- }
-
- gst_segment_set_newsegment_full (&self->subtitle_segment, update, rate,
- applied_rate, format, start, stop, position);
+ if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
+ GST_DEBUG_OBJECT (pad, "segment event: %" GST_PTR_FORMAT, event);
+ gst_event_copy_segment (event, &self->subtitle_segment);
GST_DEBUG_OBJECT (pad, "New subtitle segment: %" GST_SEGMENT_FORMAT,
&self->subtitle_segment);
}
gst_event_unref (event);
out:
- gst_object_unref (self);
+ return ret;
+}
+
+static gboolean
+gst_subtitle_overlay_subtitle_sink_query (GstPad * pad, GstObject * parent,
+ GstQuery * query)
+{
+ gboolean ret;
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_ACCEPT_CAPS:
+ {
+ GstCaps *caps, *othercaps;
+
+ gst_query_parse_accept_caps (query, &caps);
+ othercaps = gst_subtitle_overlay_subtitle_sink_getcaps (pad, NULL);
+ ret = gst_caps_is_subset (caps, othercaps);
+ gst_caps_unref (othercaps);
+ gst_query_set_accept_caps_result (query, ret);
+ ret = TRUE;
+ break;
+ }
+ case GST_QUERY_CAPS:
+ {
+ GstCaps *filter, *caps;
+
+ gst_query_parse_caps (query, &filter);
+ caps = gst_subtitle_overlay_subtitle_sink_getcaps (pad, filter);
+ gst_query_set_caps_result (query, caps);
+ gst_caps_unref (caps);
+ ret = TRUE;
+ break;
+ }
+ default:
+ ret = gst_pad_query_default (pad, parent, query);
+ break;
+ }
+
return ret;
}
static void
-gst_subtitle_overlay_init (GstSubtitleOverlay * self,
- GstSubtitleOverlayClass * klass)
+gst_subtitle_overlay_init (GstSubtitleOverlay * self)
{
GstPadTemplate *templ;
GstPad *proxypad = NULL;
gst_object_unref (templ);
gst_pad_set_event_function (self->video_sinkpad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_video_sink_event));
- gst_pad_set_setcaps_function (self->video_sinkpad,
- GST_DEBUG_FUNCPTR (gst_subtitle_overlay_video_sink_setcaps));
gst_pad_set_chain_function (self->video_sinkpad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_video_sink_chain));
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_unlink));
gst_pad_set_event_function (self->subtitle_sinkpad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_event));
- gst_pad_set_setcaps_function (self->subtitle_sinkpad,
- GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_setcaps));
+ gst_pad_set_query_function (self->subtitle_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_query));
gst_pad_set_chain_function (self->subtitle_sinkpad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_chain));
- gst_pad_set_getcaps_function (self->subtitle_sinkpad,
- GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_getcaps));
- gst_pad_set_acceptcaps_function (self->subtitle_sinkpad,
- GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_acceptcaps));
- gst_pad_set_bufferalloc_function (self->subtitle_sinkpad, NULL);
proxypad =
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD