Merge branch 'master' into 0.11
[platform/upstream/gst-plugins-base.git] / gst / playback / gstplaysink.c
index 61bdcee..c365378 100644 (file)
 #include "config.h"
 #endif
 
-/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
- * with newer GLib versions (>= 2.31.0) */
-#define GLIB_DISABLE_DEPRECATION_WARNINGS
-
 #include <string.h>
 #include <gst/gst.h>
 
 #include <gst/gst-i18n-plugin.h>
 #include <gst/pbutils/pbutils.h>
 #include <gst/video/video.h>
-#include <gst/interfaces/streamvolume.h>
-#include <gst/interfaces/colorbalance.h>
-#include <gst/interfaces/xoverlay.h>
+#include <gst/audio/streamvolume.h>
+#include <gst/video/colorbalance.h>
+#include <gst/video/videooverlay.h>
 #include <gst/interfaces/navigation.h>
 
 #include "gstplaysink.h"
@@ -127,12 +123,12 @@ typedef struct
 #define GST_PLAY_SINK_GET_LOCK(playsink) (&((GstPlaySink *)playsink)->lock)
 #define GST_PLAY_SINK_LOCK(playsink)     G_STMT_START { \
   GST_LOG_OBJECT (playsink, "locking from thread %p", g_thread_self ()); \
-  g_static_rec_mutex_lock (GST_PLAY_SINK_GET_LOCK (playsink)); \
+  g_rec_mutex_lock (GST_PLAY_SINK_GET_LOCK (playsink)); \
   GST_LOG_OBJECT (playsink, "locked from thread %p", g_thread_self ()); \
 } G_STMT_END
 #define GST_PLAY_SINK_UNLOCK(playsink)   G_STMT_START { \
   GST_LOG_OBJECT (playsink, "unlocking from thread %p", g_thread_self ()); \
-  g_static_rec_mutex_unlock (GST_PLAY_SINK_GET_LOCK (playsink)); \
+  g_rec_mutex_unlock (GST_PLAY_SINK_GET_LOCK (playsink)); \
 } G_STMT_END
 
 #define PENDING_FLAG_SET(playsink, flagtype) \
@@ -152,7 +148,7 @@ struct _GstPlaySink
 {
   GstBin bin;
 
-  GStaticRecMutex lock;
+  GRecMutex lock;
 
   gboolean async_pending;
   gboolean need_async_start;
@@ -174,6 +170,7 @@ struct _GstPlaySink
   gboolean audio_pad_blocked;
   GstPad *audio_srcpad_stream_synchronizer;
   GstPad *audio_sinkpad_stream_synchronizer;
+  gulong audio_block_id;
   /* audio tee */
   GstElement *audio_tee;
   GstPad *audio_tee_sink;
@@ -185,11 +182,13 @@ struct _GstPlaySink
   gboolean video_pad_blocked;
   GstPad *video_srcpad_stream_synchronizer;
   GstPad *video_sinkpad_stream_synchronizer;
+  gulong video_block_id;
   /* text */
   GstPad *text_pad;
   gboolean text_pad_blocked;
   GstPad *text_srcpad_stream_synchronizer;
   GstPad *text_sinkpad_stream_synchronizer;
+  gulong text_block_id;
 
   guint32 pending_blocked_pads;
 
@@ -203,19 +202,19 @@ struct _GstPlaySink
   gchar *font_desc;             /* font description */
   gchar *subtitle_encoding;     /* subtitle encoding */
   guint connection_speed;       /* connection speed in bits/sec (0 = unknown) */
-  gint count;
+  guint count;
   gboolean volume_changed;      /* volume/mute changed while no audiochain */
   gboolean mute_changed;        /* ... has been created yet */
   gint64 av_offset;
 
-  /* xoverlay proxy interface */
-  GstXOverlay *xoverlay_element;        /* protected with LOCK */
-  gboolean xoverlay_handle_set;
-  guintptr xoverlay_handle;
-  gboolean xoverlay_render_rectangle_set;
-  gint xoverlay_x, xoverlay_y, xoverlay_width, xoverlay_height;
-  gboolean xoverlay_handle_events_set;
-  gboolean xoverlay_handle_events;
+  /* videooverlay proxy interface */
+  GstVideoOverlay *overlay_element;     /* protected with LOCK */
+  gboolean overlay_handle_set;
+  guintptr overlay_handle;
+  gboolean overlay_render_rectangle_set;
+  gint overlay_x, overlay_y, overlay_width, overlay_height;
+  gboolean overlay_handle_events_set;
+  gboolean overlay_handle_events;
 
   /* colorbalance proxy interface */
   GstColorBalance *colorbalance_element;
@@ -229,7 +228,7 @@ struct _GstPlaySinkClass
 
     gboolean (*reconfigure) (GstPlaySink * playsink);
 
-  GstBuffer *(*convert_frame) (GstPlaySink * playsink, GstCaps * caps);
+  GstSample *(*convert_sample) (GstPlaySink * playsink, GstCaps * caps);
 };
 
 
@@ -271,7 +270,7 @@ enum
   PROP_FONT_DESC,
   PROP_SUBTITLE_ENCODING,
   PROP_VIS_PLUGIN,
-  PROP_FRAME,
+  PROP_SAMPLE,
   PROP_AV_OFFSET,
   PROP_VIDEO_SINK,
   PROP_AUDIO_SINK,
@@ -293,7 +292,7 @@ static void gst_play_sink_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * spec);
 
 static GstPad *gst_play_sink_request_new_pad (GstElement * element,
-    GstPadTemplate * templ, const gchar * name);
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
 static void gst_play_sink_release_request_pad (GstElement * element,
     GstPad * pad);
 static gboolean gst_play_sink_send_event (GstElement * element,
@@ -311,18 +310,18 @@ static void notify_mute_cb (GObject * object, GParamSpec * pspec,
 static void update_av_offset (GstPlaySink * playsink);
 
 void
-gst_play_marshal_BUFFER__BOXED (GClosure * closure,
+gst_play_marshal_SAMPLE__BOXED (GClosure * closure,
     GValue * return_value G_GNUC_UNUSED,
     guint n_param_values,
     const GValue * param_values,
     gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
 {
-  typedef GstBuffer *(*GMarshalFunc_OBJECT__BOXED) (gpointer data1,
+  typedef GstSample *(*GMarshalFunc_OBJECT__BOXED) (gpointer data1,
       gpointer arg_1, gpointer data2);
   register GMarshalFunc_OBJECT__BOXED callback;
   register GCClosure *cc = (GCClosure *) closure;
   register gpointer data1, data2;
-  GstBuffer *v_return;
+  GstSample *v_return;
   g_return_if_fail (return_value != NULL);
   g_return_if_fail (n_param_values == 2);
 
@@ -338,14 +337,12 @@ gst_play_marshal_BUFFER__BOXED (GClosure * closure,
 
   v_return = callback (data1, g_value_get_boxed (param_values + 1), data2);
 
-  gst_value_take_buffer (return_value, v_return);
+  gst_value_take_sample (return_value, v_return);
 }
 
 /* static guint gst_play_sink_signals[LAST_SIGNAL] = { 0 }; */
 
-static void gst_play_sink_implements_interface_init (gpointer g_iface,
-    gpointer g_iface_data);
-static void gst_play_sink_xoverlay_init (gpointer g_iface,
+static void gst_play_sink_overlay_init (gpointer g_iface,
     gpointer g_iface_data);
 static void gst_play_sink_navigation_init (gpointer g_iface,
     gpointer g_iface_data);
@@ -355,15 +352,11 @@ static void gst_play_sink_colorbalance_init (gpointer g_iface,
 static void
 _do_init (GType type)
 {
-  static const GInterfaceInfo impl_info = {
-    gst_play_sink_implements_interface_init,
-    NULL, NULL
-  };
   static const GInterfaceInfo svol_info = {
     NULL, NULL, NULL
   };
-  static const GInterfaceInfo xov_info = {
-    gst_play_sink_xoverlay_init,
+  static const GInterfaceInfo ov_info = {
+    gst_play_sink_overlay_init,
     NULL, NULL
   };
   static const GInterfaceInfo nav_info = {
@@ -375,9 +368,8 @@ _do_init (GType type)
     NULL, NULL
   };
 
-  g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, &impl_info);
   g_type_add_interface_static (type, GST_TYPE_STREAM_VOLUME, &svol_info);
-  g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &xov_info);
+  g_type_add_interface_static (type, GST_TYPE_VIDEO_OVERLAY, &ov_info);
   g_type_add_interface_static (type, GST_TYPE_NAVIGATION, &nav_info);
   g_type_add_interface_static (type, GST_TYPE_COLOR_BALANCE, &col_info);
 }
@@ -445,17 +437,15 @@ gst_play_sink_class_init (GstPlaySinkClass * klass)
           "the visualization element to use (NULL = default)",
           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   /**
-   * GstPlaySink:frame:
+   * GstPlaySink:sample:
    *
-   * Get the currently rendered or prerolled frame in the video sink.
-   * The #GstCaps on the buffer will describe the format of the buffer.
-   *
-   * Since: 0.10.30
+   * Get the currently rendered or prerolled sample in the video sink.
+   * The #GstCaps in the sample will describe the format of the buffer.
    */
-  g_object_class_install_property (gobject_klass, PROP_FRAME,
-      gst_param_spec_mini_object ("frame", "Frame",
-          "The last frame (NULL = no video available)",
-          GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_klass, PROP_SAMPLE,
+      g_param_spec_boxed ("sample", "Sample",
+          "The last sample (NULL = no video available)",
+          GST_TYPE_SAMPLE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
   /**
    * GstPlaySink:av-offset:
    *
@@ -515,34 +505,35 @@ gst_play_sink_class_init (GstPlaySinkClass * klass)
           reconfigure), NULL, NULL, gst_marshal_BOOLEAN__VOID, G_TYPE_BOOLEAN,
       0, G_TYPE_NONE);
   /**
-   * GstPlaySink::convert-frame
+   * GstPlaySink::convert-sample
    * @playsink: a #GstPlaySink
-   * @caps: the target format of the frame
+   * @caps: the target format of the sample
    *
-   * Action signal to retrieve the currently playing video frame in the format
+   * Action signal to retrieve the currently playing video sample in the format
    * specified by @caps.
    * If @caps is %NULL, no conversion will be performed and this function is
-   * equivalent to the #GstPlaySink::frame property.
+   * equivalent to the #GstPlaySink::sample property.
    *
-   * Returns: a #GstBuffer of the current video frame converted to #caps.
-   * The caps on the buffer will describe the final layout of the buffer data.
-   * %NULL is returned when no current buffer can be retrieved or when the
+   * Returns: a #GstSample of the current video sample converted to #caps.
+   * The caps in the sample will describe the final layout of the buffer data.
+   * %NULL is returned when no current sample can be retrieved or when the
    * conversion failed.
-   *
-   * Since: 0.10.30
    */
-  g_signal_new ("convert-frame", G_TYPE_FROM_CLASS (klass),
+  g_signal_new ("convert-sample", G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-      G_STRUCT_OFFSET (GstPlaySinkClass, convert_frame), NULL, NULL,
-      gst_play_marshal_BUFFER__BOXED, GST_TYPE_BUFFER, 1, GST_TYPE_CAPS);
-
-  gst_element_class_add_static_pad_template (gstelement_klass,
-      &audiorawtemplate);
-  gst_element_class_add_static_pad_template (gstelement_klass, &audiotemplate);
-  gst_element_class_add_static_pad_template (gstelement_klass,
-      &videorawtemplate);
-  gst_element_class_add_static_pad_template (gstelement_klass, &videotemplate);
-  gst_element_class_add_static_pad_template (gstelement_klass, &texttemplate);
+      G_STRUCT_OFFSET (GstPlaySinkClass, convert_sample), NULL, NULL,
+      gst_play_marshal_SAMPLE__BOXED, GST_TYPE_SAMPLE, 1, GST_TYPE_CAPS);
+
+  gst_element_class_add_pad_template (gstelement_klass,
+      gst_static_pad_template_get (&audiorawtemplate));
+  gst_element_class_add_pad_template (gstelement_klass,
+      gst_static_pad_template_get (&audiotemplate));
+  gst_element_class_add_pad_template (gstelement_klass,
+      gst_static_pad_template_get (&videorawtemplate));
+  gst_element_class_add_pad_template (gstelement_klass,
+      gst_static_pad_template_get (&videotemplate));
+  gst_element_class_add_pad_template (gstelement_klass,
+      gst_static_pad_template_get (&texttemplate));
   gst_element_class_set_details_simple (gstelement_klass, "Player Sink",
       "Generic/Bin/Sink",
       "Convenience sink for multiple streams",
@@ -560,7 +551,7 @@ gst_play_sink_class_init (GstPlaySinkClass * klass)
       GST_DEBUG_FUNCPTR (gst_play_sink_handle_message);
 
   klass->reconfigure = GST_DEBUG_FUNCPTR (gst_play_sink_reconfigure);
-  klass->convert_frame = GST_DEBUG_FUNCPTR (gst_play_sink_convert_frame);
+  klass->convert_sample = GST_DEBUG_FUNCPTR (gst_play_sink_convert_sample);
 }
 
 static void
@@ -583,8 +574,8 @@ gst_play_sink_init (GstPlaySink * playsink)
   gst_bin_add (GST_BIN_CAST (playsink),
       GST_ELEMENT_CAST (playsink->stream_synchronizer));
 
-  g_static_rec_mutex_init (&playsink->lock);
-  GST_OBJECT_FLAG_SET (playsink, GST_ELEMENT_IS_SINK);
+  g_rec_mutex_init (&playsink->lock);
+  GST_OBJECT_FLAG_SET (playsink, GST_ELEMENT_FLAG_SINK);
 
   channel =
       GST_COLOR_BALANCE_CHANNEL (g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL,
@@ -731,7 +722,7 @@ gst_play_sink_finalize (GObject * object)
 
   playsink = GST_PLAY_SINK (object);
 
-  g_static_rec_mutex_free (&playsink->lock);
+  g_rec_mutex_clear (&playsink->lock);
 
   G_OBJECT_CLASS (gst_play_sink_parent_class)->finalize (object);
 }
@@ -824,20 +815,8 @@ gst_play_sink_get_sink (GstPlaySink * playsink, GstPlaySinkType type)
   return result;
 }
 
-static void
-gst_play_sink_vis_unblocked (GstPad * tee_pad, gboolean blocked,
-    gpointer user_data)
-{
-  GstPlaySink *playsink;
-
-  playsink = GST_PLAY_SINK (user_data);
-  /* nothing to do here, we need a dummy callback here to make the async call
-   * non-blocking. */
-  GST_DEBUG_OBJECT (playsink, "vis pad unblocked");
-}
-
-static void
-gst_play_sink_vis_blocked (GstPad * tee_pad, gboolean blocked,
+static GstPadProbeReturn
+gst_play_sink_vis_blocked (GstPad * tee_pad, GstPadProbeInfo * info,
     gpointer user_data)
 {
   GstPlaySink *playsink;
@@ -875,10 +854,10 @@ gst_play_sink_vis_blocked (GstPad * tee_pad, gboolean blocked,
       chain->vissrcpad);
 
 done:
-  /* Unblock the pad */
-  gst_pad_set_blocked_async (tee_pad, FALSE, gst_play_sink_vis_unblocked,
-      playsink);
   GST_PLAY_SINK_UNLOCK (playsink);
+
+  /* remove the probe and unblock the pad */
+  return GST_PAD_PROBE_REMOVE;
 }
 
 void
@@ -915,8 +894,8 @@ gst_play_sink_set_vis_plugin (GstPlaySink * playsink, GstElement * vis)
    * function returns FALSE but the previous pad block will do the right thing
    * anyway. */
   GST_DEBUG_OBJECT (playsink, "blocking vis pad");
-  gst_pad_set_blocked_async (chain->blockpad, TRUE, gst_play_sink_vis_blocked,
-      playsink);
+  gst_pad_add_probe (chain->blockpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
+      gst_play_sink_vis_blocked, playsink, NULL);
 done:
   GST_PLAY_SINK_UNLOCK (playsink);
 
@@ -1048,7 +1027,7 @@ add_chain (GstPlayChain * chain, gboolean add)
   else {
     gst_bin_remove (GST_BIN_CAST (chain->playsink), chain->bin);
     /* we don't want to lose our sink status */
-    GST_OBJECT_FLAG_SET (chain->playsink, GST_ELEMENT_IS_SINK);
+    GST_OBJECT_FLAG_SET (chain->playsink, GST_ELEMENT_FLAG_SINK);
   }
 
   chain->added = add;
@@ -1084,7 +1063,7 @@ element_is_sink (GstElement * element)
   gboolean is_sink;
 
   GST_OBJECT_LOCK (element);
-  is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK);
+  is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_SINK);
   GST_OBJECT_UNLOCK (element);
 
   GST_DEBUG_OBJECT (element, "is a sink: %s", (is_sink) ? "yes" : "no");
@@ -1125,15 +1104,14 @@ typedef struct
 } FindPropertyHelper;
 
 static gint
-find_property (GstElement * element, FindPropertyHelper * helper)
+find_property (const GValue * item, FindPropertyHelper * helper)
 {
+  GstElement *element = g_value_get_object (item);
   if (helper->need_sink && !element_is_sink (element)) {
-    gst_object_unref (element);
     return 1;
   }
 
   if (!element_has_property (element, helper->prop_name, helper->prop_type)) {
-    gst_object_unref (element);
     return 1;
   }
 
@@ -1156,15 +1134,19 @@ gst_play_sink_find_property_sinks (GstPlaySink * playsink, GstElement * obj,
   if (element_has_property (obj, name, expected_type)) {
     result = obj;
   } else if (GST_IS_BIN (obj)) {
+    gboolean found;
+    GValue item = { 0, };
     FindPropertyHelper helper = { name, expected_type, TRUE };
 
     it = gst_bin_iterate_recurse (GST_BIN_CAST (obj));
-    result = gst_iterator_find_custom (it,
-        (GCompareFunc) find_property, &helper);
+    found = gst_iterator_find_custom (it,
+        (GCompareFunc) find_property, &item, &helper);
     gst_iterator_free (it);
-    /* we don't need the extra ref */
-    if (result)
-      gst_object_unref (result);
+    if (found) {
+      result = g_value_get_object (&item);
+      /* we don't need the extra ref */
+      g_value_unset (&item);
+    }
   }
   return result;
 }
@@ -1178,12 +1160,17 @@ gst_play_sink_find_property (GstPlaySink * playsink, GstElement * obj,
   GstIterator *it;
 
   if (GST_IS_BIN (obj)) {
+    gboolean found;
+    GValue item = { 0, };
     FindPropertyHelper helper = { name, expected_type, FALSE };
 
     it = gst_bin_iterate_recurse (GST_BIN_CAST (obj));
-    result = gst_iterator_find_custom (it,
-        (GCompareFunc) find_property, &helper);
+    found = gst_iterator_find_custom (it,
+        (GCompareFunc) find_property, &item, &helper);
     gst_iterator_free (it);
+    if (found)
+      result = g_value_dup_object (&item);
+    g_value_unset (&item);
   } else {
     if (element_has_property (obj, name, expected_type)) {
       result = obj;
@@ -1206,7 +1193,7 @@ do_async_start (GstPlaySink * playsink)
   playsink->async_pending = TRUE;
 
   GST_INFO_OBJECT (playsink, "Sending async_start message");
-  message = gst_message_new_async_start (GST_OBJECT_CAST (playsink), FALSE);
+  message = gst_message_new_async_start (GST_OBJECT_CAST (playsink));
   GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (GST_BIN_CAST
       (playsink), message);
 }
@@ -1218,7 +1205,7 @@ do_async_done (GstPlaySink * playsink)
 
   if (playsink->async_pending) {
     GST_INFO_OBJECT (playsink, "Sending async_done message");
-    message = gst_message_new_async_done (GST_OBJECT_CAST (playsink));
+    message = gst_message_new_async_done (GST_OBJECT_CAST (playsink), FALSE);
     GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (GST_BIN_CAST
         (playsink), message);
 
@@ -1344,9 +1331,8 @@ link_failed:
 }
 
 static gboolean
-is_valid_color_balance_element (GstElement * element)
+is_valid_color_balance_element (GstColorBalance * bal)
 {
-  GstColorBalance *bal = GST_COLOR_BALANCE (element);
   gboolean have_brightness = FALSE;
   gboolean have_contrast = FALSE;
   gboolean have_hue = FALSE;
@@ -1371,23 +1357,23 @@ is_valid_color_balance_element (GstElement * element)
 }
 
 static void
-iterate_color_balance_elements (gpointer data, gpointer user_data)
+iterate_color_balance_elements (const GValue * item, gpointer user_data)
 {
-  gboolean valid = is_valid_color_balance_element (data);
-  GstColorBalance **cb_out = user_data;
+  gboolean valid;
+  GstColorBalance *cb, **cb_out = user_data;
 
+  cb = GST_COLOR_BALANCE (g_value_get_object (item));
+  valid = is_valid_color_balance_element (cb);
   if (valid) {
     if (*cb_out
         && gst_color_balance_get_balance_type (*cb_out) ==
         GST_COLOR_BALANCE_SOFTWARE) {
       gst_object_unref (*cb_out);
-      *cb_out = GST_COLOR_BALANCE (gst_object_ref (data));
+      *cb_out = GST_COLOR_BALANCE (gst_object_ref (cb));
     } else if (!*cb_out) {
-      *cb_out = GST_COLOR_BALANCE (gst_object_ref (data));
+      *cb_out = GST_COLOR_BALANCE (gst_object_ref (cb));
     }
   }
-
-  gst_object_unref (data);
 }
 
 static GstColorBalance *
@@ -1397,7 +1383,7 @@ find_color_balance_element (GstElement * element)
   GstColorBalance *cb = NULL;
 
   if (GST_IS_COLOR_BALANCE (element)
-      && is_valid_color_balance_element (element))
+      && is_valid_color_balance_element (GST_COLOR_BALANCE (element)))
     return GST_COLOR_BALANCE (gst_object_ref (element));
   else if (!GST_IS_BIN (element))
     return FALSE;
@@ -1573,31 +1559,31 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
   gst_object_ref_sink (bin);
   gst_bin_add (bin, chain->sink);
 
-  /* Get the XOverlay element */
+  /* Get the VideoOverlay element */
   {
-    GstXOverlay *xoverlay = NULL;
+    GstVideoOverlay *overlay = NULL;
 
     GST_OBJECT_LOCK (playsink);
-    if (playsink->xoverlay_element)
-      gst_object_unref (playsink->xoverlay_element);
-    playsink->xoverlay_element =
-        GST_X_OVERLAY (gst_bin_get_by_interface (GST_BIN (chain->chain.bin),
-            GST_TYPE_X_OVERLAY));
-    if (playsink->xoverlay_element)
-      xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element));
+    if (playsink->overlay_element)
+      gst_object_unref (playsink->overlay_element);
+    playsink->overlay_element =
+        GST_VIDEO_OVERLAY (gst_bin_get_by_interface (GST_BIN (chain->chain.bin),
+            GST_TYPE_VIDEO_OVERLAY));
+    if (playsink->overlay_element)
+      overlay = GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element));
     GST_OBJECT_UNLOCK (playsink);
 
-    if (xoverlay) {
-      if (playsink->xoverlay_handle_set)
-        gst_x_overlay_set_window_handle (xoverlay, playsink->xoverlay_handle);
-      if (playsink->xoverlay_handle_events_set)
-        gst_x_overlay_handle_events (xoverlay,
-            playsink->xoverlay_handle_events);
-      if (playsink->xoverlay_render_rectangle_set)
-        gst_x_overlay_set_render_rectangle (xoverlay,
-            playsink->xoverlay_x, playsink->xoverlay_y,
-            playsink->xoverlay_width, playsink->xoverlay_height);
-      gst_object_unref (xoverlay);
+    if (overlay) {
+      if (playsink->overlay_handle_set)
+        gst_video_overlay_set_window_handle (overlay, playsink->overlay_handle);
+      if (playsink->overlay_handle_events_set)
+        gst_video_overlay_handle_events (overlay,
+            playsink->overlay_handle_events);
+      if (playsink->overlay_render_rectangle_set)
+        gst_video_overlay_set_render_rectangle (overlay,
+            playsink->overlay_x, playsink->overlay_y,
+            playsink->overlay_width, playsink->overlay_height);
+      gst_object_unref (overlay);
     }
   }
 
@@ -1741,31 +1727,31 @@ setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
   if (ret == GST_STATE_CHANGE_FAILURE)
     return FALSE;
 
-  /* Get the XOverlay element */
+  /* Get the VideoOverlay element */
   {
-    GstXOverlay *xoverlay = NULL;
+    GstVideoOverlay *overlay = NULL;
 
     GST_OBJECT_LOCK (playsink);
-    if (playsink->xoverlay_element)
-      gst_object_unref (playsink->xoverlay_element);
-    playsink->xoverlay_element =
-        GST_X_OVERLAY (gst_bin_get_by_interface (GST_BIN (chain->chain.bin),
-            GST_TYPE_X_OVERLAY));
-    if (playsink->xoverlay_element)
-      xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element));
+    if (playsink->overlay_element)
+      gst_object_unref (playsink->overlay_element);
+    playsink->overlay_element =
+        GST_VIDEO_OVERLAY (gst_bin_get_by_interface (GST_BIN (chain->chain.bin),
+            GST_TYPE_VIDEO_OVERLAY));
+    if (playsink->overlay_element)
+      overlay = GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element));
     GST_OBJECT_UNLOCK (playsink);
 
-    if (xoverlay) {
-      if (playsink->xoverlay_handle_set)
-        gst_x_overlay_set_window_handle (xoverlay, playsink->xoverlay_handle);
-      if (playsink->xoverlay_handle_events_set)
-        gst_x_overlay_handle_events (xoverlay,
-            playsink->xoverlay_handle_events);
-      if (playsink->xoverlay_render_rectangle_set)
-        gst_x_overlay_set_render_rectangle (xoverlay,
-            playsink->xoverlay_x, playsink->xoverlay_y,
-            playsink->xoverlay_width, playsink->xoverlay_height);
-      gst_object_unref (xoverlay);
+    if (overlay) {
+      if (playsink->overlay_handle_set)
+        gst_video_overlay_set_window_handle (overlay, playsink->overlay_handle);
+      if (playsink->overlay_handle_events_set)
+        gst_video_overlay_handle_events (overlay,
+            playsink->overlay_handle_events);
+      if (playsink->overlay_render_rectangle_set)
+        gst_video_overlay_set_render_rectangle (overlay,
+            playsink->overlay_x, playsink->overlay_y,
+            playsink->overlay_width, playsink->overlay_height);
+      gst_object_unref (overlay);
     }
   }
 
@@ -2544,9 +2530,9 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
   }
 
   GST_OBJECT_LOCK (playsink);
-  if (playsink->xoverlay_element)
-    gst_object_unref (playsink->xoverlay_element);
-  playsink->xoverlay_element = NULL;
+  if (playsink->overlay_element)
+    gst_object_unref (playsink->overlay_element);
+  playsink->overlay_element = NULL;
 
   if (playsink->colorbalance_element) {
     g_signal_handlers_disconnect_by_func (playsink->colorbalance_element,
@@ -2650,16 +2636,18 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
       goto no_chain;
 
     if (!playsink->video_sinkpad_stream_synchronizer) {
+      GValue item = { 0, };
       GstIterator *it;
 
       playsink->video_sinkpad_stream_synchronizer =
           gst_element_get_request_pad (GST_ELEMENT_CAST
-          (playsink->stream_synchronizer), "sink_%d");
+          (playsink->stream_synchronizer), "sink_%u");
       it = gst_pad_iterate_internal_links
           (playsink->video_sinkpad_stream_synchronizer);
       g_assert (it);
-      gst_iterator_next (it,
-          (gpointer *) & playsink->video_srcpad_stream_synchronizer);
+      gst_iterator_next (it, &item);
+      playsink->video_srcpad_stream_synchronizer = g_value_dup_object (&item);
+      g_value_unset (&item);
       g_assert (playsink->video_srcpad_stream_synchronizer);
       gst_iterator_free (it);
     }
@@ -2810,16 +2798,18 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
     }
 
     if (!playsink->audio_sinkpad_stream_synchronizer) {
+      GValue item = { 0, };
       GstIterator *it;
 
       playsink->audio_sinkpad_stream_synchronizer =
           gst_element_get_request_pad (GST_ELEMENT_CAST
-          (playsink->stream_synchronizer), "sink_%d");
+          (playsink->stream_synchronizer), "sink_%u");
       it = gst_pad_iterate_internal_links
           (playsink->audio_sinkpad_stream_synchronizer);
       g_assert (it);
-      gst_iterator_next (it,
-          (gpointer *) & playsink->audio_srcpad_stream_synchronizer);
+      gst_iterator_next (it, &item);
+      playsink->audio_srcpad_stream_synchronizer = g_value_dup_object (&item);
+      g_value_unset (&item);
       g_assert (playsink->audio_srcpad_stream_synchronizer);
       gst_iterator_free (it);
     }
@@ -2828,7 +2818,7 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
       GST_DEBUG_OBJECT (playsink, "adding audio chain");
       if (playsink->audio_tee_asrc == NULL) {
         playsink->audio_tee_asrc =
-            gst_element_get_request_pad (playsink->audio_tee, "src%d");
+            gst_element_get_request_pad (playsink->audio_tee, "src_%u");
       }
       add_chain (GST_PLAY_CHAIN (playsink->audiochain), TRUE);
       activate_chain (GST_PLAY_CHAIN (playsink->audiochain), TRUE);
@@ -2890,7 +2880,7 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
       activate_chain (GST_PLAY_CHAIN (playsink->vischain), TRUE);
       if (playsink->audio_tee_vissrc == NULL) {
         playsink->audio_tee_vissrc =
-            gst_element_get_request_pad (playsink->audio_tee, "src%d");
+            gst_element_get_request_pad (playsink->audio_tee, "src_%u");
       }
       gst_pad_link_full (playsink->audio_tee_vissrc,
           playsink->vischain->sinkpad, GST_PAD_LINK_CHECK_NOTHING);
@@ -2931,14 +2921,17 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
       add_chain (GST_PLAY_CHAIN (playsink->textchain), TRUE);
 
       if (!playsink->text_sinkpad_stream_synchronizer) {
+        GValue item = { 0, };
+
         playsink->text_sinkpad_stream_synchronizer =
             gst_element_get_request_pad (GST_ELEMENT_CAST
-            (playsink->stream_synchronizer), "sink_%d");
+            (playsink->stream_synchronizer), "sink_%u");
         it = gst_pad_iterate_internal_links
             (playsink->text_sinkpad_stream_synchronizer);
         g_assert (it);
-        gst_iterator_next (it,
-            (gpointer *) & playsink->text_srcpad_stream_synchronizer);
+        gst_iterator_next (it, &item);
+        playsink->text_srcpad_stream_synchronizer = g_value_dup_object (&item);
+        g_value_unset (&item);
         g_assert (playsink->text_srcpad_stream_synchronizer);
         gst_iterator_free (it);
 
@@ -3186,24 +3179,24 @@ gst_play_sink_get_av_offset (GstPlaySink * playsink)
 }
 
 /**
- * gst_play_sink_get_last_frame:
+ * gst_play_sink_get_last_sample:
  * @playsink: a #GstPlaySink
  *
- * Get the last displayed frame from @playsink. This frame is in the native
- * format of the sink element, the caps on the result buffer contain the format
+ * Get the last displayed sample from @playsink. This sample is in the native
+ * format of the sink element, the caps in the result sample contain the format
  * of the frame data.
  *
- * Returns: a #GstBuffer with the frame data or %NULL when no video frame is
+ * Returns: a #GstSample with the frame data or %NULL when no video frame is
  * available.
  */
-GstBuffer *
-gst_play_sink_get_last_frame (GstPlaySink * playsink)
+GstSample *
+gst_play_sink_get_last_sample (GstPlaySink * playsink)
 {
-  GstBuffer *result = NULL;
+  GstSample *result = NULL;
   GstPlayVideoChain *chain;
 
   GST_PLAY_SINK_LOCK (playsink);
-  GST_DEBUG_OBJECT (playsink, "taking last frame");
+  GST_DEBUG_OBJECT (playsink, "taking last sample");
   /* get the video chain if we can */
   if ((chain = (GstPlayVideoChain *) playsink->videochain)) {
     GST_DEBUG_OBJECT (playsink, "found video chain");
@@ -3216,9 +3209,9 @@ gst_play_sink_get_last_frame (GstPlaySink * playsink)
       /* find and get the last-buffer property now */
       if ((elem =
               gst_play_sink_find_property (playsink, chain->sink,
-                  "last-buffer", GST_TYPE_BUFFER))) {
-        GST_DEBUG_OBJECT (playsink, "getting last-buffer property");
-        g_object_get (elem, "last-buffer", &result, NULL);
+                  "last-sample", GST_TYPE_SAMPLE))) {
+        GST_DEBUG_OBJECT (playsink, "getting last-sample property");
+        g_object_get (elem, "last-sample", &result, NULL);
         gst_object_unref (elem);
       }
     }
@@ -3229,7 +3222,7 @@ gst_play_sink_get_last_frame (GstPlaySink * playsink)
 }
 
 /**
- * gst_play_sink_convert_frame:
+ * gst_play_sink_convert_sample:
  * @playsink: a #GstPlaySink
  * @caps: a #GstCaps
  *
@@ -3241,28 +3234,36 @@ gst_play_sink_get_last_frame (GstPlaySink * playsink)
  * Returns: a #GstBuffer with the frame data or %NULL when no video frame is
  * available or when the conversion failed.
  */
-GstBuffer *
-gst_play_sink_convert_frame (GstPlaySink * playsink, GstCaps * caps)
+GstSample *
+gst_play_sink_convert_sample (GstPlaySink * playsink, GstCaps * caps)
 {
-  GstBuffer *result;
+  GstSample *result;
+  GError *err = NULL;
 
-  result = gst_play_sink_get_last_frame (playsink);
+  result = gst_play_sink_get_last_sample (playsink);
   if (result != NULL && caps != NULL) {
-    GstBuffer *temp;
-    GError *err = NULL;
-
-    temp = gst_video_convert_frame (result, caps, 25 * GST_SECOND, &err);
-    gst_buffer_unref (result);
-    if (temp == NULL && err) {
-      /* I'm really uncertain whether we should make playsink post an error
-       * on the bus or not. It's not like it's a critical issue regarding
-       * playsink behaviour. */
-      GST_ERROR ("Error converting frame: %s", err->message);
-      g_error_free (err);
-    }
+    GstSample *temp;
+
+    temp = gst_video_convert_sample (result, caps, 25 * GST_SECOND, &err);
+    if (temp == NULL && err)
+      goto error;
+
+    gst_sample_unref (result);
     result = temp;
   }
   return result;
+
+  /* ERRORS */
+error:
+  {
+    /* I'm really uncertain whether we should make playsink post an error
+     * on the bus or not. It's not like it's a critical issue regarding
+     * playsink behaviour. */
+    GST_ERROR ("Error converting frame: %s", err->message);
+    gst_sample_unref (result);
+    g_error_free (err);
+    return NULL;
+  }
 }
 
 static gboolean
@@ -3272,8 +3273,7 @@ is_raw_structure (GstStructure * s)
 
   name = gst_structure_get_name (s);
 
-  if (g_str_has_prefix (name, "video/x-raw-") ||
-      g_str_has_prefix (name, "audio/x-raw-"))
+  if (g_str_equal (name, "video/x-raw") || g_str_equal (name, "audio/x-raw"))
     return TRUE;
   return FALSE;
 }
@@ -3288,11 +3288,11 @@ is_raw_pad (GstPad * pad)
   if (!peer)
     return raw;
 
-  caps = gst_pad_get_negotiated_caps (peer);
+  caps = gst_pad_get_current_caps (peer);
   if (!caps) {
     guint i, n;
 
-    caps = gst_pad_get_caps_reffed (peer);
+    caps = gst_pad_query_caps (peer, NULL);
 
     n = gst_caps_get_size (caps);
     for (i = 0; i < n; i++) {
@@ -3316,40 +3316,97 @@ is_raw_pad (GstPad * pad)
   return raw;
 }
 
+static GstPadProbeReturn
+sinkpad_blocked_cb (GstPad * blockedpad, GstPadProbeInfo * info,
+    gpointer user_data);
+
 static void
-sinkpad_blocked_cb (GstPad * blockedpad, gboolean blocked, gpointer user_data)
+video_set_blocked (GstPlaySink * playsink, gboolean blocked)
 {
-  GstPlaySink *playsink = (GstPlaySink *) user_data;
-  GstPad *pad;
-
-  GST_PLAY_SINK_LOCK (playsink);
-
-  pad = GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD (blockedpad)));
-  if (pad == playsink->video_pad) {
-    playsink->video_pad_blocked = blocked;
-    GST_DEBUG_OBJECT (pad, "Video pad blocked: %d", blocked);
-    if (!blocked) {
+  if (playsink->video_pad) {
+    GstPad *opad =
+        GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
+            (playsink->video_pad)));
+    if (blocked && playsink->video_block_id == 0) {
+      playsink->video_block_id =
+          gst_pad_add_probe (opad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
+          sinkpad_blocked_cb, gst_object_ref (playsink),
+          (GDestroyNotify) gst_object_unref);
+    } else if (!blocked && playsink->video_block_id) {
+      gst_pad_remove_probe (opad, playsink->video_block_id);
       PENDING_FLAG_UNSET (playsink, GST_PLAY_SINK_TYPE_VIDEO_RAW);
       PENDING_FLAG_UNSET (playsink, GST_PLAY_SINK_TYPE_VIDEO);
+      playsink->video_block_id = 0;
+      playsink->video_pad_blocked = FALSE;
     }
-  } else if (pad == playsink->audio_pad) {
-    playsink->audio_pad_blocked = blocked;
-    GST_DEBUG_OBJECT (pad, "Audio pad blocked: %d", blocked);
-    if (!blocked) {
+    gst_object_unref (opad);
+  }
+}
+
+static void
+audio_set_blocked (GstPlaySink * playsink, gboolean blocked)
+{
+  if (playsink->audio_pad) {
+    GstPad *opad =
+        GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
+            (playsink->audio_pad)));
+    if (blocked && playsink->audio_block_id == 0) {
+      playsink->audio_block_id =
+          gst_pad_add_probe (opad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
+          sinkpad_blocked_cb, gst_object_ref (playsink),
+          (GDestroyNotify) gst_object_unref);
+    } else if (!blocked && playsink->audio_block_id) {
+      gst_pad_remove_probe (opad, playsink->audio_block_id);
       PENDING_FLAG_UNSET (playsink, GST_PLAY_SINK_TYPE_AUDIO_RAW);
       PENDING_FLAG_UNSET (playsink, GST_PLAY_SINK_TYPE_AUDIO);
+      playsink->audio_block_id = 0;
+      playsink->audio_pad_blocked = FALSE;
     }
-  } else if (pad == playsink->text_pad) {
-    playsink->text_pad_blocked = blocked;
-    GST_DEBUG_OBJECT (pad, "Text pad blocked: %d", blocked);
-    if (!blocked)
+    gst_object_unref (opad);
+  }
+}
+
+static void
+text_set_blocked (GstPlaySink * playsink, gboolean blocked)
+{
+  if (playsink->text_pad) {
+    GstPad *opad =
+        GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
+            (playsink->text_pad)));
+    if (blocked && playsink->text_block_id == 0) {
+      playsink->text_block_id =
+          gst_pad_add_probe (opad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
+          sinkpad_blocked_cb, gst_object_ref (playsink),
+          (GDestroyNotify) gst_object_unref);
+    } else if (!blocked && playsink->text_block_id) {
+      gst_pad_remove_probe (opad, playsink->text_block_id);
       PENDING_FLAG_UNSET (playsink, GST_PLAY_SINK_TYPE_TEXT);
+      playsink->text_block_id = 0;
+      playsink->text_pad_blocked = FALSE;
+    }
+    gst_object_unref (opad);
   }
+}
 
-  if (!blocked) {
-    gst_object_unref (pad);
-    GST_PLAY_SINK_UNLOCK (playsink);
-    return;
+static GstPadProbeReturn
+sinkpad_blocked_cb (GstPad * blockedpad, GstPadProbeInfo * info,
+    gpointer user_data)
+{
+  GstPlaySink *playsink = (GstPlaySink *) user_data;
+  GstPad *pad;
+
+  GST_PLAY_SINK_LOCK (playsink);
+
+  pad = GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD (blockedpad)));
+  if (pad == playsink->video_pad) {
+    playsink->video_pad_blocked = TRUE;
+    GST_DEBUG_OBJECT (pad, "Video pad blocked");
+  } else if (pad == playsink->audio_pad) {
+    playsink->audio_pad_blocked = TRUE;
+    GST_DEBUG_OBJECT (pad, "Audio pad blocked");
+  } else if (pad == playsink->text_pad) {
+    playsink->text_pad_blocked = TRUE;
+    GST_DEBUG_OBJECT (pad, "Text pad blocked");
   }
 
   /* We reconfigure when for ALL streams:
@@ -3379,37 +3436,16 @@ sinkpad_blocked_cb (GstPad * blockedpad, gboolean blocked, gpointer user_data)
 
     gst_play_sink_reconfigure (playsink);
 
-    if (playsink->video_pad) {
-      GstPad *opad =
-          GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
-              (playsink->video_pad)));
-      gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb,
-          gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
-      gst_object_unref (opad);
-    }
-
-    if (playsink->audio_pad) {
-      GstPad *opad =
-          GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
-              (playsink->audio_pad)));
-      gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb,
-          gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
-      gst_object_unref (opad);
-    }
-
-    if (playsink->text_pad) {
-      GstPad *opad =
-          GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
-              (playsink->text_pad)));
-      gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb,
-          gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
-      gst_object_unref (opad);
-    }
+    video_set_blocked (playsink, FALSE);
+    audio_set_blocked (playsink, FALSE);
+    text_set_blocked (playsink, FALSE);
   }
 
   gst_object_unref (pad);
 
   GST_PLAY_SINK_UNLOCK (playsink);
+
+  return GST_PAD_PROBE_OK;
 }
 
 static void
@@ -3443,32 +3479,9 @@ caps_notify_cb (GstPad * pad, GParamSpec * unused, GstPlaySink * playsink)
 
   if (reconfigure) {
     GST_PLAY_SINK_LOCK (playsink);
-    if (playsink->video_pad) {
-      GstPad *opad =
-          GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
-              (playsink->video_pad)));
-      gst_pad_set_blocked_async_full (opad, TRUE, sinkpad_blocked_cb,
-          gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
-      gst_object_unref (opad);
-    }
-
-    if (playsink->audio_pad) {
-      GstPad *opad =
-          GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
-              (playsink->audio_pad)));
-      gst_pad_set_blocked_async_full (opad, TRUE, sinkpad_blocked_cb,
-          gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
-      gst_object_unref (opad);
-    }
-
-    if (playsink->text_pad) {
-      GstPad *opad =
-          GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
-              (playsink->text_pad)));
-      gst_pad_set_blocked_async_full (opad, TRUE, sinkpad_blocked_cb,
-          gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
-      gst_object_unref (opad);
-    }
+    video_set_blocked (playsink, TRUE);
+    audio_set_blocked (playsink, TRUE);
+    text_set_blocked (playsink, TRUE);
     GST_PLAY_SINK_UNLOCK (playsink);
   }
 }
@@ -3489,6 +3502,7 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
   gboolean created = FALSE;
   gboolean activate = TRUE;
   const gchar *pad_name = NULL;
+  gulong *block_id = NULL;
 
   GST_DEBUG_OBJECT (playsink, "request pad type %d", type);
 
@@ -3528,6 +3542,7 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
       }
       playsink->audio_pad_raw = FALSE;
       res = playsink->audio_pad;
+      block_id = &playsink->audio_block_id;
       break;
     case GST_PLAY_SINK_TYPE_VIDEO_RAW:
     case GST_PLAY_SINK_TYPE_VIDEO:
@@ -3542,6 +3557,7 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
       }
       playsink->video_pad_raw = FALSE;
       res = playsink->video_pad;
+      block_id = &playsink->video_block_id;
       break;
     case GST_PLAY_SINK_TYPE_TEXT:
       GST_LOG_OBJECT (playsink, "ghosting text");
@@ -3551,13 +3567,14 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
         created = TRUE;
       }
       res = playsink->text_pad;
+      block_id = &playsink->text_block_id;
       break;
     case GST_PLAY_SINK_TYPE_FLUSHING:
     {
       gchar *padname;
 
       /* we need a unique padname for the flushing pad. */
-      padname = g_strdup_printf ("flushing_%d", playsink->count);
+      padname = g_strdup_printf ("flushing_%u", playsink->count);
       res = gst_ghost_pad_new_no_target (padname, GST_PAD_SINK);
       g_free (padname);
       playsink->count++;
@@ -3576,12 +3593,14 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
      * element is 'running' */
     gst_pad_set_active (res, TRUE);
     gst_element_add_pad (GST_ELEMENT_CAST (playsink), res);
-    if (type != GST_PLAY_SINK_TYPE_FLUSHING) {
+    if (block_id && *block_id == 0) {
       GstPad *blockpad =
           GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD (res)));
 
-      gst_pad_set_blocked_async_full (blockpad, TRUE, sinkpad_blocked_cb,
-          gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
+      *block_id =
+          gst_pad_add_probe (blockpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
+          sinkpad_blocked_cb, gst_object_ref (playsink),
+          (GDestroyNotify) gst_object_unref);
       PENDING_FLAG_SET (playsink, type);
       gst_object_unref (blockpad);
     }
@@ -3594,7 +3613,7 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
 
 static GstPad *
 gst_play_sink_request_new_pad (GstElement * element, GstPadTemplate * templ,
-    const gchar * name)
+    const gchar * name, const GstCaps * caps)
 {
   GstPlaySink *psink;
   GstPad *pad;
@@ -3715,39 +3734,40 @@ gst_play_sink_handle_message (GstBin * bin, GstMessage * message)
       break;
     }
     case GST_MESSAGE_ELEMENT:{
-      if (gst_structure_has_name (message->structure, "prepare-xwindow-id")) {
-        GstXOverlay *xoverlay;
+      if (gst_is_video_overlay_prepare_window_handle_message (message)) {
+        GstVideoOverlay *overlay;
 
         GST_OBJECT_LOCK (playsink);
-        if (playsink->xoverlay_element
-            && GST_OBJECT_CAST (playsink->xoverlay_element) !=
+        if (playsink->overlay_element
+            && GST_OBJECT_CAST (playsink->overlay_element) !=
             GST_MESSAGE_SRC (message)) {
-          gst_object_unref (playsink->xoverlay_element);
-          playsink->xoverlay_element = NULL;
+          gst_object_unref (playsink->overlay_element);
+          playsink->overlay_element = NULL;
         }
 
-        if (!playsink->xoverlay_element)
-          playsink->xoverlay_element =
-              GST_X_OVERLAY (gst_object_ref (GST_MESSAGE_SRC (message)));
-        xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element));
+        if (!playsink->overlay_element)
+          playsink->overlay_element =
+              GST_VIDEO_OVERLAY (gst_object_ref (GST_MESSAGE_SRC (message)));
+        overlay =
+            GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element));
         GST_OBJECT_UNLOCK (playsink);
 
         GST_DEBUG_OBJECT (playsink, "Got prepare-xwindow-id message");
 
-        if (playsink->xoverlay_handle_set)
-          gst_x_overlay_set_window_handle (playsink->xoverlay_element,
-              playsink->xoverlay_handle);
-        if (playsink->xoverlay_handle_events_set)
-          gst_x_overlay_handle_events (playsink->xoverlay_element,
-              playsink->xoverlay_handle_events);
-        if (playsink->xoverlay_render_rectangle_set)
-          gst_x_overlay_set_render_rectangle (playsink->xoverlay_element,
-              playsink->xoverlay_x, playsink->xoverlay_y,
-              playsink->xoverlay_width, playsink->xoverlay_height);
-
-        gst_object_unref (xoverlay);
+        if (playsink->overlay_handle_set)
+          gst_video_overlay_set_window_handle (playsink->overlay_element,
+              playsink->overlay_handle);
+        if (playsink->overlay_handle_events_set)
+          gst_video_overlay_handle_events (playsink->overlay_element,
+              playsink->overlay_handle_events);
+        if (playsink->overlay_render_rectangle_set)
+          gst_video_overlay_set_render_rectangle (playsink->overlay_element,
+              playsink->overlay_x, playsink->overlay_y,
+              playsink->overlay_width, playsink->overlay_height);
+
+        gst_object_unref (overlay);
         gst_message_unref (message);
-        gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (playsink));
+        gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (playsink));
       }
       break;
     }
@@ -3858,41 +3878,9 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition)
     case GST_STATE_CHANGE_PAUSED_TO_READY:
       /* unblock all pads here */
       GST_PLAY_SINK_LOCK (playsink);
-      if (playsink->video_pad) {
-        GstPad *opad =
-            GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
-                (playsink->video_pad)));
-        if (gst_pad_is_blocked (opad)) {
-          gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb,
-              gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
-        }
-        gst_object_unref (opad);
-        playsink->video_pad_blocked = FALSE;
-      }
-
-      if (playsink->audio_pad) {
-        GstPad *opad =
-            GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
-                (playsink->audio_pad)));
-        if (gst_pad_is_blocked (opad)) {
-          gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb,
-              gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
-        }
-        gst_object_unref (opad);
-        playsink->audio_pad_blocked = FALSE;
-      }
-
-      if (playsink->text_pad) {
-        GstPad *opad =
-            GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
-                (playsink->text_pad)));
-        if (gst_pad_is_blocked (opad)) {
-          gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb,
-              gst_object_ref (playsink), (GDestroyNotify) gst_object_unref);
-        }
-        gst_object_unref (opad);
-        playsink->text_pad_blocked = FALSE;
-      }
+      video_set_blocked (playsink, FALSE);
+      audio_set_blocked (playsink, FALSE);
+      text_set_blocked (playsink, FALSE);
       GST_PLAY_SINK_UNLOCK (playsink);
       /* fall through */
     case GST_STATE_CHANGE_READY_TO_NULL:
@@ -3915,9 +3903,9 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition)
       }
 
       GST_OBJECT_LOCK (playsink);
-      if (playsink->xoverlay_element)
-        gst_object_unref (playsink->xoverlay_element);
-      playsink->xoverlay_element = NULL;
+      if (playsink->overlay_element)
+        gst_object_unref (playsink->overlay_element);
+      playsink->overlay_element = NULL;
 
       if (playsink->colorbalance_element) {
         g_signal_handlers_disconnect_by_func (playsink->colorbalance_element,
@@ -4140,8 +4128,8 @@ gst_play_sink_get_property (GObject * object, guint prop_id,
     case PROP_VIS_PLUGIN:
       g_value_take_object (value, gst_play_sink_get_vis_plugin (playsink));
       break;
-    case PROP_FRAME:
-      gst_value_take_buffer (value, gst_play_sink_get_last_frame (playsink));
+    case PROP_SAMPLE:
+      gst_value_take_sample (value, gst_play_sink_get_last_sample (playsink));
       break;
     case PROP_AV_OFFSET:
       g_value_set_int64 (value, gst_play_sink_get_av_offset (playsink));
@@ -4165,123 +4153,109 @@ gst_play_sink_get_property (GObject * object, guint prop_id,
 }
 
 static void
-gst_play_sink_xoverlay_expose (GstXOverlay * overlay)
+gst_play_sink_overlay_expose (GstVideoOverlay * overlay)
 {
   GstPlaySink *playsink = GST_PLAY_SINK (overlay);
-  GstXOverlay *xoverlay;
+  GstVideoOverlay *overlay_element;
 
   GST_OBJECT_LOCK (playsink);
-  if (playsink->xoverlay_element)
-    xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element));
+  if (playsink->overlay_element)
+    overlay_element =
+        GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element));
   else
-    xoverlay = NULL;
+    overlay_element = NULL;
   GST_OBJECT_UNLOCK (playsink);
 
-  if (xoverlay) {
-    gst_x_overlay_expose (xoverlay);
-    gst_object_unref (xoverlay);
+  if (overlay_element) {
+    gst_video_overlay_expose (overlay_element);
+    gst_object_unref (overlay_element);
   }
 }
 
 static void
-gst_play_sink_xoverlay_handle_events (GstXOverlay * overlay,
+gst_play_sink_overlay_handle_events (GstVideoOverlay * overlay,
     gboolean handle_events)
 {
   GstPlaySink *playsink = GST_PLAY_SINK (overlay);
-  GstXOverlay *xoverlay;
+  GstVideoOverlay *overlay_element;
 
   GST_OBJECT_LOCK (playsink);
-  if (playsink->xoverlay_element)
-    xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element));
+  if (playsink->overlay_element)
+    overlay_element =
+        GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element));
   else
-    xoverlay = NULL;
+    overlay_element = NULL;
   GST_OBJECT_UNLOCK (playsink);
 
-  playsink->xoverlay_handle_events_set = TRUE;
-  playsink->xoverlay_handle_events = handle_events;
+  playsink->overlay_handle_events_set = TRUE;
+  playsink->overlay_handle_events = handle_events;
 
-  if (xoverlay) {
-    gst_x_overlay_handle_events (xoverlay, handle_events);
-    gst_object_unref (xoverlay);
+  if (overlay_element) {
+    gst_video_overlay_handle_events (overlay_element, handle_events);
+    gst_object_unref (overlay_element);
   }
 }
 
 static void
-gst_play_sink_xoverlay_set_render_rectangle (GstXOverlay * overlay, gint x,
+gst_play_sink_overlay_set_render_rectangle (GstVideoOverlay * overlay, gint x,
     gint y, gint width, gint height)
 {
   GstPlaySink *playsink = GST_PLAY_SINK (overlay);
-  GstXOverlay *xoverlay;
+  GstVideoOverlay *overlay_element;
 
   GST_OBJECT_LOCK (playsink);
-  if (playsink->xoverlay_element)
-    xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element));
+  if (playsink->overlay_element)
+    overlay_element =
+        GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element));
   else
-    xoverlay = NULL;
+    overlay_element = NULL;
   GST_OBJECT_UNLOCK (playsink);
 
-  playsink->xoverlay_render_rectangle_set = TRUE;
-  playsink->xoverlay_x = x;
-  playsink->xoverlay_y = y;
-  playsink->xoverlay_width = width;
-  playsink->xoverlay_height = height;
+  playsink->overlay_render_rectangle_set = TRUE;
+  playsink->overlay_x = x;
+  playsink->overlay_y = y;
+  playsink->overlay_width = width;
+  playsink->overlay_height = height;
 
-  if (xoverlay) {
-    gst_x_overlay_set_render_rectangle (xoverlay, x, y, width, height);
-    gst_object_unref (xoverlay);
+  if (overlay_element) {
+    gst_video_overlay_set_render_rectangle (overlay_element, x, y, width,
+        height);
+    gst_object_unref (overlay_element);
   }
 }
 
 static void
-gst_play_sink_xoverlay_set_window_handle (GstXOverlay * overlay,
+gst_play_sink_overlay_set_window_handle (GstVideoOverlay * overlay,
     guintptr handle)
 {
   GstPlaySink *playsink = GST_PLAY_SINK (overlay);
-  GstXOverlay *xoverlay;
+  GstVideoOverlay *overlay_element;
 
   GST_OBJECT_LOCK (playsink);
-  if (playsink->xoverlay_element)
-    xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element));
+  if (playsink->overlay_element)
+    overlay_element =
+        GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element));
   else
-    xoverlay = NULL;
+    overlay_element = NULL;
   GST_OBJECT_UNLOCK (playsink);
 
-  playsink->xoverlay_handle_set = TRUE;
-  playsink->xoverlay_handle = handle;
+  playsink->overlay_handle_set = TRUE;
+  playsink->overlay_handle = handle;
 
-  if (xoverlay) {
-    gst_x_overlay_set_window_handle (xoverlay, handle);
-    gst_object_unref (xoverlay);
+  if (overlay_element) {
+    gst_video_overlay_set_window_handle (overlay_element, handle);
+    gst_object_unref (overlay_element);
   }
 }
 
 static void
-gst_play_sink_xoverlay_init (gpointer g_iface, gpointer g_iface_data)
-{
-  GstXOverlayClass *iface = (GstXOverlayClass *) g_iface;
-  iface->expose = gst_play_sink_xoverlay_expose;
-  iface->handle_events = gst_play_sink_xoverlay_handle_events;
-  iface->set_render_rectangle = gst_play_sink_xoverlay_set_render_rectangle;
-  iface->set_window_handle = gst_play_sink_xoverlay_set_window_handle;
-}
-
-static gboolean
-gst_play_sink_implements_interface_supported (GstImplementsInterface * iface,
-    GType type)
-{
-  if (type == GST_TYPE_X_OVERLAY || type == GST_TYPE_STREAM_VOLUME ||
-      type == GST_TYPE_NAVIGATION || type == GST_TYPE_COLOR_BALANCE)
-    return TRUE;
-  else
-    return FALSE;
-}
-
-static void
-gst_play_sink_implements_interface_init (gpointer g_iface,
-    gpointer g_iface_data)
+gst_play_sink_overlay_init (gpointer g_iface, gpointer g_iface_data)
 {
-  GstImplementsInterfaceClass *iface = (GstImplementsInterfaceClass *) g_iface;
-  iface->supported = gst_play_sink_implements_interface_supported;
+  GstVideoOverlayInterface *iface = (GstVideoOverlayInterface *) g_iface;
+  iface->expose = gst_play_sink_overlay_expose;
+  iface->handle_events = gst_play_sink_overlay_handle_events;
+  iface->set_render_rectangle = gst_play_sink_overlay_set_render_rectangle;
+  iface->set_window_handle = gst_play_sink_overlay_set_window_handle;
 }
 
 static void
@@ -4433,7 +4407,7 @@ gst_play_sink_colorbalance_get_balance_type (GstColorBalance * balance)
 static void
 gst_play_sink_colorbalance_init (gpointer g_iface, gpointer g_iface_data)
 {
-  GstColorBalanceClass *iface = (GstColorBalanceClass *) g_iface;
+  GstColorBalanceInterface *iface = (GstColorBalanceInterface *) g_iface;
 
   iface->list_channels = gst_play_sink_colorbalance_list_channels;
   iface->set_value = gst_play_sink_colorbalance_set_value;