[GStreamer] Video resolution changes trigger a crash in the TextureMapper
authorphiln@webkit.org <philn@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 30 Oct 2014 08:53:39 +0000 (08:53 +0000)
committerphiln@webkit.org <philn@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 30 Oct 2014 08:53:39 +0000 (08:53 +0000)
https://bugs.webkit.org/show_bug.cgi?id=137065

Reviewed by Gustavo Noronha Silva.

Switch to GstSample for buffer+caps communication between the
video sink and the player. Using a single object type for this
avoid issues where the caps might not correctly describe the
buffer contents anymore, for example when the video resolution is
changed.

* platform/graphics/gstreamer/ImageGStreamer.h: Use GstSample
instead of GstBuffer+GstCaps.
(WebCore::ImageGStreamer::createImage):
* platform/graphics/gstreamer/ImageGStreamerCairo.cpp: Ditto.
(ImageGStreamer::ImageGStreamer):
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp:
(WebCore::mediaPlayerPrivateRepaintCallback): The repaint signal
now uses a GstSample instead of a GstBuffer.
(WebCore::MediaPlayerPrivateGStreamerBase::MediaPlayerPrivateGStreamerBase):
Store the current sample instead of a buffer. Also renamed the
mutex protecting access to the sample.
(WebCore::MediaPlayerPrivateGStreamerBase::~MediaPlayerPrivateGStreamerBase): Ditto.
(WebCore::MediaPlayerPrivateGStreamerBase::naturalSize): Return
early if no sample is available. The caps used to get the video
size are store in the sample.
(WebCore::MediaPlayerPrivateGStreamerBase::updateTexture): Use
GstSample instead of GstBuffer.
(WebCore::MediaPlayerPrivateGStreamerBase::triggerRepaint): Ditto.
(WebCore::MediaPlayerPrivateGStreamerBase::paint): Ditto.
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h:
* platform/graphics/gstreamer/VideoSinkGStreamer.cpp: Now store a
GstSample internally. Also removed the now useless current-caps property.
(_WebKitVideoSinkPrivate::_WebKitVideoSinkPrivate): Renamed the
mutex protecting access to the sample.
(_WebKitVideoSinkPrivate::~_WebKitVideoSinkPrivate): Ditto.
(webkit_video_sink_init): Disable last-sample in basesink since we
already store one in our sink anyway.
(webkitVideoSinkTimeoutCallback): Switch to GstSample.
(webkitVideoSinkRender): Ditto.
(unlockSampleMutex): Ditto.
(webkitVideoSinkUnlock): Ditto.
(webkitVideoSinkUnlockStop): Ditto.
(webkitVideoSinkStop): Ditto!
(webkitVideoSinkStart): Ditto.
(webkit_video_sink_class_init): Drop current-caps property.
(webkitVideoSinkGetProperty): Deleted.
(unlockBufferMutex): Deleted.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@175370 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/gstreamer/ImageGStreamer.h
Source/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp
Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp
Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h
Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp

index fc72fa1..1b38e3c 100644 (file)
@@ -1,3 +1,54 @@
+2014-10-24  Philippe Normand  <pnormand@igalia.com>
+
+        [GStreamer] Video resolution changes trigger a crash in the TextureMapper
+        https://bugs.webkit.org/show_bug.cgi?id=137065
+
+        Reviewed by Gustavo Noronha Silva.
+
+        Switch to GstSample for buffer+caps communication between the
+        video sink and the player. Using a single object type for this
+        avoid issues where the caps might not correctly describe the
+        buffer contents anymore, for example when the video resolution is
+        changed.
+
+        * platform/graphics/gstreamer/ImageGStreamer.h: Use GstSample
+        instead of GstBuffer+GstCaps.
+        (WebCore::ImageGStreamer::createImage):
+        * platform/graphics/gstreamer/ImageGStreamerCairo.cpp: Ditto.
+        (ImageGStreamer::ImageGStreamer):
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp:
+        (WebCore::mediaPlayerPrivateRepaintCallback): The repaint signal
+        now uses a GstSample instead of a GstBuffer.
+        (WebCore::MediaPlayerPrivateGStreamerBase::MediaPlayerPrivateGStreamerBase):
+        Store the current sample instead of a buffer. Also renamed the
+        mutex protecting access to the sample.
+        (WebCore::MediaPlayerPrivateGStreamerBase::~MediaPlayerPrivateGStreamerBase): Ditto.
+        (WebCore::MediaPlayerPrivateGStreamerBase::naturalSize): Return
+        early if no sample is available. The caps used to get the video
+        size are store in the sample.
+        (WebCore::MediaPlayerPrivateGStreamerBase::updateTexture): Use
+        GstSample instead of GstBuffer.
+        (WebCore::MediaPlayerPrivateGStreamerBase::triggerRepaint): Ditto.
+        (WebCore::MediaPlayerPrivateGStreamerBase::paint): Ditto.
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h:
+        * platform/graphics/gstreamer/VideoSinkGStreamer.cpp: Now store a
+        GstSample internally. Also removed the now useless current-caps property.
+        (_WebKitVideoSinkPrivate::_WebKitVideoSinkPrivate): Renamed the
+        mutex protecting access to the sample.
+        (_WebKitVideoSinkPrivate::~_WebKitVideoSinkPrivate): Ditto.
+        (webkit_video_sink_init): Disable last-sample in basesink since we
+        already store one in our sink anyway.
+        (webkitVideoSinkTimeoutCallback): Switch to GstSample.
+        (webkitVideoSinkRender): Ditto.
+        (unlockSampleMutex): Ditto.
+        (webkitVideoSinkUnlock): Ditto.
+        (webkitVideoSinkUnlockStop): Ditto.
+        (webkitVideoSinkStop): Ditto!
+        (webkitVideoSinkStart): Ditto.
+        (webkit_video_sink_class_init): Drop current-caps property.
+        (webkitVideoSinkGetProperty): Deleted.
+        (unlockBufferMutex): Deleted.
+
 2014-10-30  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         FormDataBuilder should not use Document
index c9d2fb4..3931a19 100644 (file)
@@ -38,9 +38,9 @@ class IntSize;
 
 class ImageGStreamer : public RefCounted<ImageGStreamer> {
     public:
-        static PassRefPtr<ImageGStreamer> createImage(GstBuffer* buffer, GstCaps* caps)
+        static PassRefPtr<ImageGStreamer> createImage(GstSample* sample)
         {
-            return adoptRef(new ImageGStreamer(buffer, caps));
+            return adoptRef(new ImageGStreamer(sample));
         }
         ~ImageGStreamer();
 
@@ -60,7 +60,7 @@ class ImageGStreamer : public RefCounted<ImageGStreamer> {
         }
 
     private:
-        ImageGStreamer(GstBuffer*, GstCaps*);
+        ImageGStreamer(GstSample*);
         RefPtr<BitmapImage> m_image;
         FloatRect m_cropRect;
 
index b153f09..06faeca 100644 (file)
@@ -32,8 +32,9 @@
 using namespace std;
 using namespace WebCore;
 
-ImageGStreamer::ImageGStreamer(GstBuffer* buffer, GstCaps* caps)
+ImageGStreamer::ImageGStreamer(GstSample* sample)
 {
+    GstCaps* caps = gst_sample_get_caps(sample);
     GstVideoInfo videoInfo;
     gst_video_info_init(&videoInfo);
     if (!gst_video_info_from_caps(&videoInfo, caps))
@@ -42,6 +43,7 @@ ImageGStreamer::ImageGStreamer(GstBuffer* buffer, GstCaps* caps)
     // Right now the TextureMapper only supports chromas with one plane
     ASSERT(GST_VIDEO_INFO_N_PLANES(&videoInfo) == 1);
 
+    GstBuffer* buffer = gst_sample_get_buffer(sample);
     if (!gst_video_frame_map(&m_videoFrame, &videoInfo, buffer, GST_MAP_READ))
         return;
 
index d179bd4..44de756 100644 (file)
@@ -79,9 +79,9 @@ static void mediaPlayerPrivateMuteChangedCallback(GObject*, GParamSpec*, MediaPl
     player->muteChanged();
 }
 
-static void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivateGStreamerBase* playerPrivate)
+static void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstSample* sample, MediaPlayerPrivateGStreamerBase* playerPrivate)
 {
-    playerPrivate->triggerRepaint(buffer);
+    playerPrivate->triggerRepaint(sample);
 }
 
 MediaPlayerPrivateGStreamerBase::MediaPlayerPrivateGStreamerBase(MediaPlayer* player)
@@ -89,12 +89,12 @@ MediaPlayerPrivateGStreamerBase::MediaPlayerPrivateGStreamerBase(MediaPlayer* pl
     , m_fpsSink(0)
     , m_readyState(MediaPlayer::HaveNothing)
     , m_networkState(MediaPlayer::Empty)
-    , m_buffer(0)
+    , m_sample(0)
     , m_repaintHandler(0)
     , m_volumeSignalHandler(0)
     , m_muteSignalHandler(0)
 {
-    g_mutex_init(&m_bufferMutex);
+    g_mutex_init(&m_sampleMutex);
 }
 
 MediaPlayerPrivateGStreamerBase::~MediaPlayerPrivateGStreamerBase()
@@ -104,11 +104,11 @@ MediaPlayerPrivateGStreamerBase::~MediaPlayerPrivateGStreamerBase()
         m_repaintHandler = 0;
     }
 
-    g_mutex_clear(&m_bufferMutex);
+    g_mutex_clear(&m_sampleMutex);
 
-    if (m_buffer)
-        gst_buffer_unref(m_buffer);
-    m_buffer = 0;
+    if (m_sample)
+        gst_sample_unref(m_sample);
+    m_sample = 0;
 
     m_player = 0;
 
@@ -137,7 +137,11 @@ IntSize MediaPlayerPrivateGStreamerBase::naturalSize() const
     if (!m_videoSize.isEmpty())
         return m_videoSize;
 
-    GRefPtr<GstCaps> caps = currentVideoSinkCaps();
+    GMutexLocker<GMutex> lock(m_sampleMutex);
+    if (!m_sample)
+        return IntSize();
+
+    GstCaps* caps = gst_sample_get_caps(m_sample);
     if (!caps)
         return IntSize();
 
@@ -152,7 +156,7 @@ IntSize MediaPlayerPrivateGStreamerBase::naturalSize() const
     int pixelAspectRatioNumerator, pixelAspectRatioDenominator, stride;
     IntSize originalSize;
     GstVideoFormat format;
-    if (!getVideoSizeAndFormatFromCaps(caps.get(), originalSize, format, pixelAspectRatioNumerator, pixelAspectRatioDenominator, stride))
+    if (!getVideoSizeAndFormatFromCaps(caps, originalSize, format, pixelAspectRatioNumerator, pixelAspectRatioDenominator, stride))
         return IntSize();
 
     LOG_MEDIA_MESSAGE("Original video size: %dx%d", originalSize.width(), originalSize.height());
@@ -275,25 +279,26 @@ void MediaPlayerPrivateGStreamerBase::muteChanged()
 #if USE(TEXTURE_MAPPER_GL) && !USE(COORDINATED_GRAPHICS)
 PassRefPtr<BitmapTexture> MediaPlayerPrivateGStreamerBase::updateTexture(TextureMapper* textureMapper)
 {
-    GMutexLocker<GMutex> lock(m_bufferMutex);
-    if (!m_buffer)
+    GMutexLocker<GMutex> lock(m_sampleMutex);
+    if (!m_sample)
         return nullptr;
 
-    GRefPtr<GstCaps> caps = currentVideoSinkCaps();
+    GstCaps* caps = gst_sample_get_caps(m_sample);
     if (!caps)
         return nullptr;
 
     GstVideoInfo videoInfo;
     gst_video_info_init(&videoInfo);
-    if (!gst_video_info_from_caps(&videoInfo, caps.get()))
+    if (!gst_video_info_from_caps(&videoInfo, caps))
         return nullptr;
 
     IntSize size = IntSize(GST_VIDEO_INFO_WIDTH(&videoInfo), GST_VIDEO_INFO_HEIGHT(&videoInfo));
     RefPtr<BitmapTexture> texture = textureMapper->acquireTextureFromPool(size, GST_VIDEO_INFO_HAS_ALPHA(&videoInfo) ? BitmapTexture::SupportsAlpha : BitmapTexture::NoFlag);
+    GstBuffer* buffer = gst_sample_get_buffer(m_sample);
 
 #if GST_CHECK_VERSION(1, 1, 0)
     GstVideoGLTextureUploadMeta* meta;
-    if ((meta = gst_buffer_get_video_gl_texture_upload_meta(m_buffer))) {
+    if ((meta = gst_buffer_get_video_gl_texture_upload_meta(buffer))) {
         if (meta->n_textures == 1) { // BRGx & BGRA formats use only one texture.
             const BitmapTextureGL* textureGL = static_cast<const BitmapTextureGL*>(texture.get());
             guint ids[4] = { textureGL->id(), 0, 0, 0 };
@@ -308,7 +313,7 @@ PassRefPtr<BitmapTexture> MediaPlayerPrivateGStreamerBase::updateTexture(Texture
     ASSERT(GST_VIDEO_INFO_N_PLANES(&videoInfo) == 1);
 
     GstVideoFrame videoFrame;
-    if (!gst_video_frame_map(&videoFrame, &videoInfo, m_buffer, GST_MAP_READ))
+    if (!gst_video_frame_map(&videoFrame, &videoInfo, buffer, GST_MAP_READ))
         return nullptr;
 
     int stride = GST_VIDEO_FRAME_PLANE_STRIDE(&videoFrame, 0);
@@ -320,13 +325,15 @@ PassRefPtr<BitmapTexture> MediaPlayerPrivateGStreamerBase::updateTexture(Texture
 }
 #endif
 
-void MediaPlayerPrivateGStreamerBase::triggerRepaint(GstBuffer* buffer)
+void MediaPlayerPrivateGStreamerBase::triggerRepaint(GstSample* sample)
 {
-    g_return_if_fail(GST_IS_BUFFER(buffer));
+    g_return_if_fail(GST_IS_SAMPLE(sample));
 
     {
-        GMutexLocker<GMutex> lock(m_bufferMutex);
-        gst_buffer_replace(&m_buffer, buffer);
+        GMutexLocker<GMutex> lock(m_sampleMutex);
+        if (m_sample)
+            gst_sample_unref(m_sample);
+        m_sample = gst_sample_ref(sample);
     }
 
 #if USE(TEXTURE_MAPPER_GL) && !USE(COORDINATED_GRAPHICS)
@@ -357,15 +364,11 @@ void MediaPlayerPrivateGStreamerBase::paint(GraphicsContext* context, const IntR
     if (!m_player->visible())
         return;
 
-    GMutexLocker<GMutex> lock(m_bufferMutex);
-    if (!m_buffer)
-        return;
-
-    GRefPtr<GstCaps> caps = currentVideoSinkCaps();
-    if (!caps)
+    GMutexLocker<GMutex> lock(m_sampleMutex);
+    if (!m_sample)
         return;
 
-    RefPtr<ImageGStreamer> gstImage = ImageGStreamer::createImage(m_buffer, caps.get());
+    RefPtr<ImageGStreamer> gstImage = ImageGStreamer::createImage(m_sample);
     if (!gstImage)
         return;
 
@@ -409,16 +412,6 @@ MediaPlayer::MovieLoadType MediaPlayerPrivateGStreamerBase::movieLoadType() cons
     return MediaPlayer::Download;
 }
 
-GRefPtr<GstCaps> MediaPlayerPrivateGStreamerBase::currentVideoSinkCaps() const
-{
-    if (!m_webkitVideoSink)
-        return nullptr;
-
-    GRefPtr<GstCaps> currentCaps;
-    g_object_get(G_OBJECT(m_webkitVideoSink.get()), "current-caps", &currentCaps.outPtr(), NULL);
-    return currentCaps;
-}
-
 GstElement* MediaPlayerPrivateGStreamerBase::createVideoSink()
 {
     ASSERT(initializeGStreamer());
index 460e861..ea8497b 100644 (file)
@@ -36,7 +36,7 @@
 #include "TextureMapperPlatformLayer.h"
 #endif
 
-typedef struct _GstBuffer GstBuffer;
+typedef struct _GstSample GstSample;
 typedef struct _GstElement GstElement;
 typedef struct _GstMessage GstMessage;
 typedef struct _GstStreamVolume GstStreamVolume;
@@ -77,7 +77,7 @@ public:
     void setSize(const IntSize&);
     void sizeChanged();
 
-    void triggerRepaint(GstBuffer*);
+    void triggerRepaint(GstSample*);
     void paint(GraphicsContext*, const IntRect&);
 
     virtual bool hasSingleSecurityOrigin() const { return true; }
@@ -110,7 +110,6 @@ public:
 protected:
     MediaPlayerPrivateGStreamerBase(MediaPlayer*);
     virtual GstElement* createVideoSink();
-    GRefPtr<GstCaps> currentVideoSinkCaps() const;
 
     void setStreamVolumeElement(GstStreamVolume*);
     virtual GstElement* createAudioSink() { return 0; }
@@ -123,8 +122,8 @@ protected:
     MediaPlayer::ReadyState m_readyState;
     MediaPlayer::NetworkState m_networkState;
     IntSize m_size;
-    GMutex m_bufferMutex;
-    GstBuffer* m_buffer;
+    mutable GMutex m_sampleMutex;
+    GstSample* m_sample;
     GThreadSafeMainLoopSource m_volumeTimerHandler;
     GThreadSafeMainLoopSource m_muteTimerHandler;
     unsigned long m_repaintHandler;
index 7cb193e..255e760 100644 (file)
@@ -66,30 +66,25 @@ enum {
     LAST_SIGNAL
 };
 
-enum {
-    PROP_0,
-    PROP_CAPS
-};
-
 static guint webkitVideoSinkSignals[LAST_SIGNAL] = { 0, };
 
 struct _WebKitVideoSinkPrivate {
     _WebKitVideoSinkPrivate()
     {
-        g_mutex_init(&bufferMutex);
+        g_mutex_init(&sampleMutex);
         g_cond_init(&dataCondition);
         gst_video_info_init(&info);
     }
 
     ~_WebKitVideoSinkPrivate()
     {
-        g_mutex_clear(&bufferMutex);
+        g_mutex_clear(&sampleMutex);
         g_cond_clear(&dataCondition);
     }
 
-    GstBuffer* buffer;
+    GstSample* sample;
     GThreadSafeMainLoopSource timeoutSource;
-    GMutex bufferMutex;
+    GMutex sampleMutex;
     GCond dataCondition;
 
     GstVideoInfo info;
@@ -103,7 +98,7 @@ struct _WebKitVideoSinkPrivate {
     // everything else isn't running anymore. This will lead
     // to deadlocks because render() holds the stream lock.
     //
-    // Protected by the buffer mutex
+    // Protected by the sample mutex
     bool unlocked;
 };
 
@@ -114,6 +109,7 @@ G_DEFINE_TYPE_WITH_CODE(WebKitVideoSink, webkit_video_sink, GST_TYPE_VIDEO_SINK,
 static void webkit_video_sink_init(WebKitVideoSink* sink)
 {
     sink->priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkPrivate);
+    g_object_set(GST_BASE_SINK(sink), "enable-last-sample", FALSE, NULL);
     new (sink->priv) WebKitVideoSinkPrivate();
 }
 
@@ -121,17 +117,17 @@ static void webkitVideoSinkTimeoutCallback(WebKitVideoSink* sink)
 {
     WebKitVideoSinkPrivate* priv = sink->priv;
 
-    GMutexLocker<GMutex> lock(priv->bufferMutex);
-    GstBuffer* buffer = priv->buffer;
-    priv->buffer = 0;
+    GMutexLocker<GMutex> lock(priv->sampleMutex);
+    GstSample* sample = priv->sample;
+    priv->sample = 0;
 
-    if (!buffer || priv->unlocked || UNLIKELY(!GST_IS_BUFFER(buffer))) {
+    if (!sample || priv->unlocked || UNLIKELY(!GST_IS_SAMPLE(sample))) {
         g_cond_signal(&priv->dataCondition);
         return;
     }
 
-    g_signal_emit(sink, webkitVideoSinkSignals[REPAINT_REQUESTED], 0, buffer);
-    gst_buffer_unref(buffer);
+    g_signal_emit(sink, webkitVideoSinkSignals[REPAINT_REQUESTED], 0, sample);
+    gst_sample_unref(sample);
     g_cond_signal(&priv->dataCondition);
 }
 
@@ -140,17 +136,17 @@ static GstFlowReturn webkitVideoSinkRender(GstBaseSink* baseSink, GstBuffer* buf
     WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(baseSink);
     WebKitVideoSinkPrivate* priv = sink->priv;
 
-    GMutexLocker<GMutex> lock(priv->bufferMutex);
+    GMutexLocker<GMutex> lock(priv->sampleMutex);
 
     if (priv->unlocked)
         return GST_FLOW_OK;
 
-    priv->buffer = gst_buffer_ref(buffer);
+    priv->sample = gst_sample_new(buffer, priv->currentCaps, 0, 0);
 
     // The video info structure is valid only if the sink handled an allocation query.
     GstVideoFormat format = GST_VIDEO_INFO_FORMAT(&priv->info);
     if (format == GST_VIDEO_FORMAT_UNKNOWN) {
-        gst_buffer_unref(buffer);
+        gst_sample_unref(priv->sample);
         return GST_FLOW_ERROR;
     }
 
@@ -179,13 +175,12 @@ static GstFlowReturn webkitVideoSinkRender(GstBaseSink* baseSink, GstBuffer* buf
         GstVideoFrame destinationFrame;
 
         if (!gst_video_frame_map(&sourceFrame, &priv->info, buffer, GST_MAP_READ)) {
-            gst_buffer_unref(buffer);
+            gst_sample_unref(priv->sample);
             gst_buffer_unref(newBuffer);
             return GST_FLOW_ERROR;
         }
         if (!gst_video_frame_map(&destinationFrame, &priv->info, newBuffer, GST_MAP_WRITE)) {
             gst_video_frame_unmap(&sourceFrame);
-            gst_buffer_unref(buffer);
             gst_buffer_unref(newBuffer);
             return GST_FLOW_ERROR;
         }
@@ -215,8 +210,8 @@ static GstFlowReturn webkitVideoSinkRender(GstBaseSink* baseSink, GstBuffer* buf
 
         gst_video_frame_unmap(&sourceFrame);
         gst_video_frame_unmap(&destinationFrame);
-        gst_buffer_unref(buffer);
-        buffer = priv->buffer = newBuffer;
+        gst_sample_unref(priv->sample);
+        priv->sample = gst_sample_new(newBuffer, priv->currentCaps, 0, 0);
     }
 #endif
 
@@ -227,7 +222,7 @@ static GstFlowReturn webkitVideoSinkRender(GstBaseSink* baseSink, GstBuffer* buf
     priv->timeoutSource.schedule("[WebKit] webkitVideoSinkTimeoutCallback", std::function<void()>(std::bind(webkitVideoSinkTimeoutCallback, sink)), G_PRIORITY_DEFAULT,
         [sink] { gst_object_unref(sink); });
 
-    g_cond_wait(&priv->dataCondition, &priv->bufferMutex);
+    g_cond_wait(&priv->dataCondition, &priv->sampleMutex);
     return GST_FLOW_OK;
 }
 
@@ -237,31 +232,13 @@ static void webkitVideoSinkFinalize(GObject* object)
     G_OBJECT_CLASS(parent_class)->finalize(object);
 }
 
-static void webkitVideoSinkGetProperty(GObject* object, guint propertyId, GValue* value, GParamSpec* parameterSpec)
+static void unlockSampleMutex(WebKitVideoSinkPrivate* priv)
 {
-    WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object);
-    WebKitVideoSinkPrivate* priv = sink->priv;
+    GMutexLocker<GMutex> lock(priv->sampleMutex);
 
-    switch (propertyId) {
-    case PROP_CAPS: {
-        GstCaps* caps = priv->currentCaps;
-        if (caps)
-            gst_caps_ref(caps);
-        g_value_take_boxed(value, caps);
-        break;
-    }
-    default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyId, parameterSpec);
-    }
-}
-
-static void unlockBufferMutex(WebKitVideoSinkPrivate* priv)
-{
-    GMutexLocker<GMutex> lock(priv->bufferMutex);
-
-    if (priv->buffer) {
-        gst_buffer_unref(priv->buffer);
-        priv->buffer = 0;
+    if (priv->sample) {
+        gst_sample_unref(priv->sample);
+        priv->sample = 0;
     }
 
     priv->unlocked = true;
@@ -273,7 +250,7 @@ static gboolean webkitVideoSinkUnlock(GstBaseSink* baseSink)
 {
     WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(baseSink);
 
-    unlockBufferMutex(sink->priv);
+    unlockSampleMutex(sink->priv);
 
     return GST_CALL_PARENT_WITH_DEFAULT(GST_BASE_SINK_CLASS, unlock, (baseSink), TRUE);
 }
@@ -283,7 +260,7 @@ static gboolean webkitVideoSinkUnlockStop(GstBaseSink* baseSink)
     WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(baseSink)->priv;
 
     {
-        GMutexLocker<GMutex> lock(priv->bufferMutex);
+        GMutexLocker<GMutex> lock(priv->sampleMutex);
         priv->unlocked = false;
     }
 
@@ -294,7 +271,7 @@ static gboolean webkitVideoSinkStop(GstBaseSink* baseSink)
 {
     WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(baseSink)->priv;
 
-    unlockBufferMutex(priv);
+    unlockSampleMutex(priv);
 
     if (priv->currentCaps) {
         gst_caps_unref(priv->currentCaps);
@@ -308,7 +285,7 @@ static gboolean webkitVideoSinkStart(GstBaseSink* baseSink)
 {
     WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(baseSink)->priv;
 
-    GMutexLocker<GMutex> lock(priv->bufferMutex);
+    GMutexLocker<GMutex> lock(priv->sampleMutex);
     priv->unlocked = false;
     return TRUE;
 }
@@ -363,7 +340,6 @@ static void webkit_video_sink_class_init(WebKitVideoSinkClass* klass)
     g_type_class_add_private(klass, sizeof(WebKitVideoSinkPrivate));
 
     gobjectClass->finalize = webkitVideoSinkFinalize;
-    gobjectClass->get_property = webkitVideoSinkGetProperty;
 
     baseSinkClass->unlock = webkitVideoSinkUnlock;
     baseSinkClass->unlock_stop = webkitVideoSinkUnlockStop;
@@ -374,9 +350,6 @@ static void webkit_video_sink_class_init(WebKitVideoSinkClass* klass)
     baseSinkClass->set_caps = webkitVideoSinkSetCaps;
     baseSinkClass->propose_allocation = webkitVideoSinkProposeAllocation;
 
-    g_object_class_install_property(gobjectClass, PROP_CAPS,
-        g_param_spec_boxed("current-caps", "Current-Caps", "Current caps", GST_TYPE_CAPS, G_PARAM_READABLE));
-
     webkitVideoSinkSignals[REPAINT_REQUESTED] = g_signal_new("repaint-requested",
             G_TYPE_FROM_CLASS(klass),
             static_cast<GSignalFlags>(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
@@ -386,7 +359,7 @@ static void webkit_video_sink_class_init(WebKitVideoSinkClass* klass)
             g_cclosure_marshal_generic,
             G_TYPE_NONE, // Return type
             1, // Only one parameter
-            GST_TYPE_BUFFER);
+            GST_TYPE_SAMPLE);
 }