Merge remote-tracking branch 'origin/master' into 0.11
[platform/upstream/gstreamer.git] / gst / playback / gstsubtitleoverlay.c
index 061d049..3ff5107 100644 (file)
@@ -29,7 +29,7 @@
  * <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>
  */
@@ -40,7 +40,6 @@
 
 #include "gstsubtitleoverlay.h"
 
-#include <gst/gstfilter.h>
 #include <gst/pbutils/missing-plugins.h>
 #include <gst/video/video.h>
 #include <string.h>
@@ -81,11 +80,8 @@ enum
   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;
 
@@ -93,11 +89,10 @@ static void
 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;
   }
 }
@@ -106,14 +101,64 @@ static void
 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)
 {
@@ -187,7 +232,7 @@ _is_raw_video (GstStructure * s)
 
   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;
 }
@@ -195,22 +240,10 @@ _is_raw_video (GstStructure * s)
 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;
@@ -560,26 +593,16 @@ _remove_element (GstSubtitleOverlay * self, GstElement ** element)
 }
 
 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
@@ -643,17 +666,12 @@ _setup_passthrough (GstSubtitleOverlay * self)
   /* 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 */
@@ -670,12 +688,8 @@ _setup_passthrough (GstSubtitleOverlay * self)
 
 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;
 }
@@ -746,25 +760,20 @@ _has_font_desc_property (GstElement * element)
   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 */
 
@@ -775,9 +784,9 @@ _pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
 
     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;
@@ -811,18 +820,14 @@ _pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
     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);
@@ -831,8 +836,7 @@ _pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
 
   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;
   }
 
@@ -912,23 +916,26 @@ _pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
       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;
+            }
           }
         }
 
@@ -1072,7 +1079,7 @@ _pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
       /* 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");
@@ -1088,22 +1095,16 @@ _pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
           }
         }
 
-        _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)) {
@@ -1111,16 +1112,10 @@ _pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
           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);
       }
@@ -1281,9 +1276,9 @@ _pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
 
         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);
         }
@@ -1293,7 +1288,7 @@ _pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
           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)
@@ -1329,7 +1324,7 @@ _pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
       /* 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)) {
@@ -1337,21 +1332,15 @@ _pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
           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)) {
@@ -1359,16 +1348,10 @@ _pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
           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);
       }
 
@@ -1422,10 +1405,8 @@ _pad_blocked_cb (GstPad * pad, gboolean blocked, gpointer user_data)
     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);
   }
 
@@ -1433,6 +1414,8 @@ out:
   if (factories)
     gst_plugin_feature_list_free (factories);
   GST_SUBTITLE_OVERLAY_UNLOCK (self);
+
+  return GST_PAD_PROBE_OK;
 }
 
 static GstStateChangeReturn
@@ -1454,10 +1437,8 @@ gst_subtitle_overlay_change_state (GstElement * element,
 
       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:
@@ -1506,9 +1487,7 @@ gst_subtitle_overlay_change_state (GstElement * element,
       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);
@@ -1521,17 +1500,8 @@ gst_subtitle_overlay_change_state (GstElement * element,
           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;
@@ -1544,7 +1514,6 @@ gst_subtitle_overlay_change_state (GstElement * element,
       GST_SUBTITLE_OVERLAY_UNLOCK (self);
 
       break;
-    }
     default:
       break;
   }
@@ -1589,11 +1558,8 @@ gst_subtitle_overlay_handle_message (GstBin * bin, GstMessage * message)
       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);
     }
   }
@@ -1648,11 +1614,8 @@ gst_subtitle_overlay_set_property (GObject * object, guint prop_id,
         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;
@@ -1684,24 +1647,6 @@ gst_subtitle_overlay_set_property (GObject * object, guint prop_id,
 }
 
 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;
@@ -1733,6 +1678,19 @@ gst_subtitle_overlay_class_init (GstSubtitleOverlayClass * 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);
 
@@ -1741,13 +1699,14 @@ gst_subtitle_overlay_class_init (GstSubtitleOverlayClass * klass)
 }
 
 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;
@@ -1759,7 +1718,7 @@ gst_subtitle_overlay_src_proxy_chain (GstPad * proxypad, GstBuffer * buffer)
     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",
@@ -1768,20 +1727,20 @@ gst_subtitle_overlay_src_proxy_chain (GstPad * proxypad, GstBuffer * buffer)
   }
 
   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));
@@ -1791,12 +1750,12 @@ 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);
+        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;
   }
 
@@ -1805,111 +1764,116 @@ out:
     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;
@@ -1918,11 +1882,8 @@ gst_subtitle_overlay_video_sink_chain (GstPad * pad, GstBuffer * buffer)
         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;
@@ -1932,26 +1893,24 @@ gst_subtitle_overlay_video_sink_chain (GstPad * pad, GstBuffer * buffer)
 }
 
 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;
@@ -1962,7 +1921,7 @@ gst_subtitle_overlay_subtitle_sink_chain (GstPad * pad, GstBuffer * buffer)
 }
 
 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;
@@ -1970,6 +1929,10 @@ gst_subtitle_overlay_subtitle_sink_getcaps (GstPad * pad)
   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);
@@ -1982,24 +1945,13 @@ gst_subtitle_overlay_subtitle_sink_getcaps (GstPad * pad)
 }
 
 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));
@@ -2007,28 +1959,23 @@ gst_subtitle_overlay_subtitle_sink_setcaps (GstPad * pad, GstCaps * caps)
   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;
 }
 
@@ -2041,9 +1988,9 @@ gst_subtitle_overlay_subtitle_sink_link (GstPad * pad, GstPad * peer)
 
   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;
@@ -2057,11 +2004,8 @@ gst_subtitle_overlay_subtitle_sink_link (GstPad * pad, GstPad * peer)
 
     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);
   }
@@ -2090,120 +2034,125 @@ gst_subtitle_overlay_subtitle_sink_unlink (GstPad * pad)
   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;
@@ -2231,8 +2180,6 @@ gst_subtitle_overlay_init (GstSubtitleOverlay * self,
   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));
 
@@ -2253,15 +2200,10 @@ gst_subtitle_overlay_init (GstSubtitleOverlay * self,
       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