Diff
Modified: trunk/Source/WebCore/ChangeLog (175369 => 175370)
--- trunk/Source/WebCore/ChangeLog 2014-10-30 08:02:20 UTC (rev 175369)
+++ trunk/Source/WebCore/ChangeLog 2014-10-30 08:53:39 UTC (rev 175370)
@@ -1,3 +1,54 @@
+2014-10-24 Philippe Normand <[email protected]>
+
+ [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 <[email protected]>
FormDataBuilder should not use Document
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/ImageGStreamer.h (175369 => 175370)
--- trunk/Source/WebCore/platform/graphics/gstreamer/ImageGStreamer.h 2014-10-30 08:02:20 UTC (rev 175369)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/ImageGStreamer.h 2014-10-30 08:53:39 UTC (rev 175370)
@@ -38,9 +38,9 @@
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 @@
}
private:
- ImageGStreamer(GstBuffer*, GstCaps*);
+ ImageGStreamer(GstSample*);
RefPtr<BitmapImage> m_image;
FloatRect m_cropRect;
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp (175369 => 175370)
--- trunk/Source/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp 2014-10-30 08:02:20 UTC (rev 175369)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp 2014-10-30 08:53:39 UTC (rev 175370)
@@ -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 @@
// 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;
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp (175369 => 175370)
--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp 2014-10-30 08:02:20 UTC (rev 175369)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp 2014-10-30 08:53:39 UTC (rev 175370)
@@ -79,9 +79,9 @@
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 @@
, 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 @@
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 @@
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 @@
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 @@
#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 @@
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 @@
}
#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 @@
if (!m_player->visible())
return;
- GMutexLocker<GMutex> lock(m_bufferMutex);
- if (!m_buffer)
+ GMutexLocker<GMutex> lock(m_sampleMutex);
+ if (!m_sample)
return;
- GRefPtr<GstCaps> caps = currentVideoSinkCaps();
- if (!caps)
- return;
-
- RefPtr<ImageGStreamer> gstImage = ImageGStreamer::createImage(m_buffer, caps.get());
+ RefPtr<ImageGStreamer> gstImage = ImageGStreamer::createImage(m_sample);
if (!gstImage)
return;
@@ -409,16 +412,6 @@
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", ¤tCaps.outPtr(), NULL);
- return currentCaps;
-}
-
GstElement* MediaPlayerPrivateGStreamerBase::createVideoSink()
{
ASSERT(initializeGStreamer());
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h (175369 => 175370)
--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h 2014-10-30 08:02:20 UTC (rev 175369)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h 2014-10-30 08:53:39 UTC (rev 175370)
@@ -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 @@
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 @@
protected:
MediaPlayerPrivateGStreamerBase(MediaPlayer*);
virtual GstElement* createVideoSink();
- GRefPtr<GstCaps> currentVideoSinkCaps() const;
void setStreamVolumeElement(GstStreamVolume*);
virtual GstElement* createAudioSink() { return 0; }
@@ -123,8 +122,8 @@
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;
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp (175369 => 175370)
--- trunk/Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp 2014-10-30 08:02:20 UTC (rev 175369)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp 2014-10-30 08:53:39 UTC (rev 175370)
@@ -66,30 +66,25 @@
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 @@
// 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 @@
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 @@
{
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 @@
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 @@
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 @@
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 @@
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,33 +232,15 @@
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;
+ if (priv->sample) {
+ gst_sample_unref(priv->sample);
+ priv->sample = 0;
}
- 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;
- }
-
priv->unlocked = true;
g_cond_signal(&priv->dataCondition);
@@ -273,7 +250,7 @@
{
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 @@
WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(baseSink)->priv;
{
- GMutexLocker<GMutex> lock(priv->bufferMutex);
+ GMutexLocker<GMutex> lock(priv->sampleMutex);
priv->unlocked = false;
}
@@ -294,7 +271,7 @@
{
WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(baseSink)->priv;
- unlockBufferMutex(priv);
+ unlockSampleMutex(priv);
if (priv->currentCaps) {
gst_caps_unref(priv->currentCaps);
@@ -308,7 +285,7 @@
{
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 @@
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 @@
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 @@
g_cclosure_marshal_generic,
G_TYPE_NONE, // Return type
1, // Only one parameter
- GST_TYPE_BUFFER);
+ GST_TYPE_SAMPLE);
}