Diff
Modified: trunk/Source/WebCore/ChangeLog (141820 => 141821)
--- trunk/Source/WebCore/ChangeLog 2013-02-04 23:07:46 UTC (rev 141820)
+++ trunk/Source/WebCore/ChangeLog 2013-02-04 23:18:33 UTC (rev 141821)
@@ -1,3 +1,56 @@
+2013-02-04 Gustavo Noronha Silva <gustavo.noro...@collabora.com>
+
+ [GStreamer][Soup] Let GStreamer provide the buffer data is downloaded to, to avoid copying
+ https://bugs.webkit.org/show_bug.cgi?id=105552
+
+ Reviewed by Philippe Normand.
+
+ Makes it possible for the GStreamer media backend to provide the buffer to which
+ the Soup networking backend will use to download data to. This makes copying
+ memory unnecessary when ResourceHandle hands data over to the media player's
+ StreamingClient. Thanks to Dan Winship for help designing the interface.
+
+ No behaviour change, covered by existing tests.
+
+ * platform/graphics/gstreamer/GStreamerVersioning.cpp:
+ (createGstBufferForData): New helper to create a GstBuffer when
+ we have a data pointer and a length.
+ (getGstBufferSize): Abstract obtaining the size of the buffer, so the code
+ is cleaner while still working for both GST 0.10 and 1.0.
+ (setGstBufferSize): Ditto, but for setting the size.
+ (getGstBufferDataPointer): Ditto, but for grabbing the data pointer.
+ (mapGstBuffer): Convenience method to take care of mapping the buffer so that
+ we can provide the data pointer to ResourceHandle.
+ (unmapGstBuffer): Convenience method which takes care of unmapping the buffer
+ and properly freeing the GstMapInfo.
+ * platform/graphics/gstreamer/GStreamerVersioning.h:
+ * platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp:
+ (StreamingClient): New methods.
+ (_WebKitWebSrcPrivate): We now store the GstBuffer we provided the data pointer from
+ so we can later unmap it and push it to the pipeline.
+ (webKitWebSrcDispose): Deal with the GstBuffer in case it exists when the source is
+ destroyed.
+ (webKitWebSrcStop): Also clear the GstBuffer in this case.
+ (StreamingClient::didReceiveData): Handle the hand-over of the buffer.
+ (StreamingClient::getBuffer): Provide ResourceHandle with a new GstBuffer's data pointer.
+ * platform/network/ResourceHandleClient.h:
+ (ResourceHandleClient):
+ (WebCore::ResourceHandleClient::ResourceHandleClient): Constructor to initialize the buffer
+ member variable to 0.
+ (WebCore::ResourceHandleClient::~ResourceHandleClient): Destructor to free the buffer if it
+ has been allocated.
+ (WebCore::ResourceHandleClient::getBuffer): Default implementation which returns a
+ newly allocated char pointer.
+ * platform/network/ResourceHandleInternal.h:
+ (WebCore::ResourceHandleInternal::ResourceHandleInternal):
+ (ResourceHandleInternal): Store actual buffer size, which is no longer a constant.
+ * platform/network/soup/ResourceHandleSoup.cpp:
+ (WebCore::cleanupSoupRequestOperation): Clear the buffer pointer, the life-cycle of the
+ buffer is handled by the ResourceHandleClient.
+ (WebCore::nextMultipartResponsePartCallback): Get a new buffer from the client before reading.
+ (WebCore::sendRequestCallback): Ditto.
+ (WebCore::readCallback): Ditto.
+
2013-02-04 Mark Pilgrim <pilg...@chromium.org>
[Chromium] Move WorkerContextProxy to WebCore
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerVersioning.cpp (141820 => 141821)
--- trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerVersioning.cpp 2013-02-04 23:07:46 UTC (rev 141820)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerVersioning.cpp 2013-02-04 23:18:33 UTC (rev 141821)
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012 Igalia, S.L.
+ * Copyright (C) 2013 Collabora Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -31,6 +32,10 @@
#include <gst/audio/multichannel.h>
#endif
+#ifdef GST_API_VERSION_1
+const char* webkitGstMapInfoQuarkString = "webkit-gst-map-info";
+#endif
+
void webkitGstObjectRefSink(GstObject* gstObject)
{
#ifdef GST_API_VERSION_1
@@ -132,6 +137,75 @@
return newBuffer;
}
+GstBuffer* createGstBufferForData(const char* data, int length)
+{
+ GstBuffer* buffer = gst_buffer_new_and_alloc(length);
+
+#ifdef GST_API_VERSION_1
+ gst_buffer_fill(buffer, 0, data, length);
+#else
+ memcpy(GST_BUFFER_DATA(buffer), data, length);
+#endif
+
+ return buffer;
+}
+
+int getGstBufferSize(GstBuffer* buffer)
+{
+#ifdef GST_API_VERSION_1
+ return gst_buffer_get_size(buffer);
+#else
+ return GST_BUFFER_SIZE(buffer);
+#endif
+}
+
+void setGstBufferSize(GstBuffer* buffer, int newSize)
+{
+#ifdef GST_API_VERSION_1
+ gst_buffer_set_size(buffer, static_cast<gssize>(newSize));
+#else
+ GST_BUFFER_SIZE(buffer) = static_cast<gsize>(newSize);
+#endif
+}
+
+char* getGstBufferDataPointer(GstBuffer* buffer)
+{
+#ifdef GST_API_VERSION_1
+ GstMiniObject* miniObject = reinterpret_cast<GstMiniObject*>(buffer);
+ GstMapInfo* mapInfo = static_cast<GstMapInfo*>(gst_mini_object_get_qdata(miniObject, g_quark_from_static_string(webkitGstMapInfoQuarkString)));
+ return reinterpret_cast<char*>(mapInfo->data);
+#else
+ return reinterpret_cast<char*>(GST_BUFFER_DATA(buffer));
+#endif
+}
+
+#ifdef GST_API_VERSION_1
+void mapGstBuffer(GstBuffer* buffer)
+{
+ GstMapInfo* mapInfo = g_slice_new(GstMapInfo);
+ if (!gst_buffer_map(buffer, mapInfo, GST_MAP_WRITE)) {
+ g_slice_free(GstMapInfo, mapInfo);
+ gst_buffer_unref(buffer);
+ return;
+ }
+
+ GstMiniObject* miniObject = reinterpret_cast<GstMiniObject*>(buffer);
+ gst_mini_object_set_qdata(miniObject, g_quark_from_static_string(webkitGstMapInfoQuarkString), mapInfo, 0);
+}
+
+void unmapGstBuffer(GstBuffer* buffer)
+{
+ GstMiniObject* miniObject = reinterpret_cast<GstMiniObject*>(buffer);
+ GstMapInfo* mapInfo = static_cast<GstMapInfo*>(gst_mini_object_steal_qdata(miniObject, g_quark_from_static_string(webkitGstMapInfoQuarkString)));
+
+ if (!mapInfo)
+ return;
+
+ gst_buffer_unmap(buffer, mapInfo);
+ g_slice_free(GstMapInfo, mapInfo);
+}
+#endif
+
void setGstElementClassMetadata(GstElementClass* elementClass, const char* name, const char* longName, const char* description, const char* author)
{
#ifdef GST_API_VERSION_1
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerVersioning.h (141820 => 141821)
--- trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerVersioning.h 2013-02-04 23:07:46 UTC (rev 141820)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerVersioning.h 2013-02-04 23:18:33 UTC (rev 141821)
@@ -37,6 +37,14 @@
bool getVideoSizeAndFormatFromCaps(GstCaps*, WebCore::IntSize&, GstVideoFormat&, int& pixelAspectRatioNumerator, int& pixelAspectRatioDenominator, int& stride);
#endif
GstBuffer* createGstBuffer(GstBuffer*);
+GstBuffer* createGstBufferForData(const char* data, int length);
+int getGstBufferSize(GstBuffer*);
+void setGstBufferSize(GstBuffer*, int newSize);
+char* getGstBufferDataPointer(GstBuffer*);
+#ifdef GST_API_VERSION_1
+void mapGstBuffer(GstBuffer*);
+void unmapGstBuffer(GstBuffer*);
+#endif
void setGstElementClassMetadata(GstElementClass*, const char* name, const char* longName, const char* description, const char* author);
bool gstObjectIsFloating(GstObject*);
void notifyGstTagsOnPad(GstElement*, GstPad*, GstTagList*);
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp (141820 => 141821)
--- trunk/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp 2013-02-04 23:07:46 UTC (rev 141820)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp 2013-02-04 23:18:33 UTC (rev 141821)
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2009, 2010 Sebastian Dröge <sebastian.dro...@collabora.co.uk>
+ * Copyright (C) 2013 Collabora Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -33,10 +34,9 @@
#include "ResourceHandleInternal.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
-
#include <gst/app/gstappsrc.h>
+#include <gst/gst.h>
#include <gst/pbutils/missing-plugins.h>
-
#include <wtf/Noncopyable.h>
#include <wtf/gobject/GOwnPtr.h>
#include <wtf/gobject/GRefPtr.h>
@@ -52,6 +52,9 @@
virtual void willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse&);
virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
+
+ virtual char* getBuffer(int, int*);
+
virtual void didReceiveData(ResourceHandle*, const char*, int, int);
virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/);
virtual void didFail(ResourceHandle*, const ResourceError&);
@@ -85,6 +88,8 @@
guint enoughDataID;
guint seekID;
+ GRefPtr<GstBuffer> buffer;
+
// icecast stuff
gboolean iradioMode;
gchar* iradioName;
@@ -116,6 +121,7 @@
static void webKitWebSrcUriHandlerInit(gpointer gIface, gpointer ifaceData);
+static void webKitWebSrcDispose(GObject*);
static void webKitWebSrcFinalize(GObject*);
static void webKitWebSrcSetProperty(GObject*, guint propertyID, const GValue*, GParamSpec*);
static void webKitWebSrcGetProperty(GObject*, guint propertyID, GValue*, GParamSpec*);
@@ -151,6 +157,7 @@
GObjectClass* oklass = G_OBJECT_CLASS(klass);
GstElementClass* eklass = GST_ELEMENT_CLASS(klass);
+ oklass->dispose = webKitWebSrcDispose;
oklass->finalize = webKitWebSrcFinalize;
oklass->set_property = webKitWebSrcSetProperty;
oklass->get_property = webKitWebSrcGetProperty;
@@ -275,6 +282,21 @@
webKitWebSrcStop(src, false);
}
+static void webKitWebSrcDispose(GObject* object)
+{
+ WebKitWebSrc* src = ""
+ WebKitWebSrcPrivate* priv = src->priv;
+
+ if (priv->buffer) {
+#ifdef GST_API_VERSION_1
+ unmapGstBuffer(priv->buffer.get());
+#endif
+ priv->buffer.clear();
+ }
+
+ GST_CALL_PARENT(G_OBJECT_CLASS, dispose, (object));
+}
+
static void webKitWebSrcFinalize(GObject* object)
{
WebKitWebSrc* src = ""
@@ -284,7 +306,7 @@
g_free(priv->uri);
- GST_CALL_PARENT(G_OBJECT_CLASS, finalize, ((GObject* )(src)));
+ GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object));
}
static void webKitWebSrcSetProperty(GObject* object, guint propID, const GValue* value, GParamSpec* pspec)
@@ -355,6 +377,13 @@
priv->player = 0;
+ if (priv->buffer) {
+#ifdef GST_API_VERSION_1
+ unmapGstBuffer(priv->buffer.get());
+#endif
+ priv->buffer.clear();
+ }
+
GST_OBJECT_LOCK(src);
if (priv->needDataID)
g_source_remove(priv->needDataID);
@@ -857,25 +886,33 @@
{
WebKitWebSrcPrivate* priv = m_src->priv;
- GST_LOG_OBJECT(m_src, "Have %d bytes of data", length);
+ GST_LOG_OBJECT(m_src, "Have %d bytes of data", priv->buffer ? getGstBufferSize(priv->buffer.get()) : length);
+ ASSERT(!priv->buffer || data == getGstBufferDataPointer(priv->buffer.get()));
+
+#ifdef GST_API_VERSION_1
+ if (priv->buffer)
+ unmapGstBuffer(priv->buffer.get());
+#endif
+
if (priv->seekID || handle != priv->resourceHandle) {
GST_DEBUG_OBJECT(m_src, "Seek in progress, ignoring data");
+ priv->buffer.clear();
return;
}
- GstBuffer* buffer = gst_buffer_new_and_alloc(length);
+ // Ports using the GStreamer backend but not the soup implementation of ResourceHandle
+ // won't be using buffers provided by this client, the buffer is created here in that case.
+ if (!priv->buffer)
+ priv->buffer = adoptGRef(createGstBufferForData(data, length));
+ else
+ setGstBufferSize(priv->buffer.get(), length);
-#ifdef GST_API_VERSION_1
- gst_buffer_fill(buffer, 0, data, length);
-#else
- memcpy(GST_BUFFER_DATA(buffer), data, length);
-#endif
- GST_BUFFER_OFFSET(buffer) = priv->offset;
+ GST_BUFFER_OFFSET(priv->buffer.get()) = priv->offset;
priv->offset += length;
- GST_BUFFER_OFFSET_END(buffer) = priv->offset;
+ GST_BUFFER_OFFSET_END(priv->buffer.get()) = priv->offset;
- GstFlowReturn ret = gst_app_src_push_buffer(priv->appsrc, buffer);
+ GstFlowReturn ret = gst_app_src_push_buffer(priv->appsrc, priv->buffer.leakRef());
#ifdef GST_API_VERSION_1
if (ret != GST_FLOW_OK && ret != GST_FLOW_EOS)
#else
@@ -884,6 +921,24 @@
GST_ELEMENT_ERROR(m_src, CORE, FAILED, (0), (0));
}
+char* StreamingClient::getBuffer(int requestedSize, int* actualSize)
+{
+ WebKitWebSrcPrivate* priv = m_src->priv;
+
+ ASSERT(!priv->buffer);
+
+ GstBuffer* buffer = gst_buffer_new_and_alloc(requestedSize);
+
+#ifdef GST_API_VERSION_1
+ mapGstBuffer(buffer);
+#endif
+
+ priv->buffer = adoptGRef(buffer);
+
+ *actualSize = getGstBufferSize(buffer);
+ return getGstBufferDataPointer(buffer);
+}
+
void StreamingClient::didFinishLoading(ResourceHandle*, double)
{
WebKitWebSrcPrivate* priv = m_src->priv;
Modified: trunk/Source/WebCore/platform/network/ResourceHandleClient.h (141820 => 141821)
--- trunk/Source/WebCore/platform/network/ResourceHandleClient.h 2013-02-04 23:07:46 UTC (rev 141820)
+++ trunk/Source/WebCore/platform/network/ResourceHandleClient.h 2013-02-04 23:18:33 UTC (rev 141821)
@@ -35,6 +35,10 @@
#include <CFNetwork/CFURLResponsePriv.h>
#endif
+#if USE(SOUP)
+#include <glib.h>
+#endif
+
#if PLATFORM(WIN) && USE(CFNETWORK)
#include <ConditionalMacros.h>
#endif
@@ -63,7 +67,19 @@
class ResourceHandleClient {
public:
+#if USE(SOUP)
+ ResourceHandleClient(): m_buffer(0) { }
+
+ virtual ~ResourceHandleClient()
+ {
+ if (m_buffer) {
+ g_free(m_buffer);
+ m_buffer = 0;
+ }
+ }
+#else
virtual ~ResourceHandleClient() { }
+#endif
// request may be modified
virtual void willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse& /*redirectResponse*/) { }
@@ -82,6 +98,18 @@
virtual void didReceiveDataArray(ResourceHandle*, CFArrayRef) { }
#endif
+#if USE(SOUP)
+ virtual char* getBuffer(int requestedLength, int* actualLength)
+ {
+ *actualLength = requestedLength;
+
+ if (!m_buffer)
+ m_buffer = static_cast<char*>(g_malloc(requestedLength));
+
+ return m_buffer;
+ }
+#endif
+
virtual bool shouldUseCredentialStorage(ResourceHandle*) { return false; }
virtual void didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge&) { }
virtual void didCancelAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge&) { }
@@ -107,6 +135,11 @@
#if ENABLE(BLOB)
virtual AsyncFileStream* createAsyncFileStream(FileStreamClient*) { return 0; }
#endif
+
+#if USE(SOUP)
+private:
+ char* m_buffer;
+#endif
};
}
Modified: trunk/Source/WebCore/platform/network/ResourceHandleInternal.h (141820 => 141821)
--- trunk/Source/WebCore/platform/network/ResourceHandleInternal.h 2013-02-04 23:07:46 UTC (rev 141820)
+++ trunk/Source/WebCore/platform/network/ResourceHandleInternal.h 2013-02-04 23:18:33 UTC (rev 141821)
@@ -113,6 +113,7 @@
#if USE(SOUP)
, m_cancelled(false)
, m_buffer(0)
+ , m_bufferSize(0)
, m_bodySize(0)
, m_bodyDataSent(0)
, m_redirectCount(0)
@@ -200,6 +201,7 @@
GRefPtr<GAsyncResult> m_deferredResult;
GRefPtr<GSource> m_timeoutSource;
char* m_buffer;
+ int m_bufferSize;
unsigned long m_bodySize;
unsigned long m_bodyDataSent;
RefPtr<NetworkingContext> m_context;
Modified: trunk/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp (141820 => 141821)
--- trunk/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp 2013-02-04 23:07:46 UTC (rev 141820)
+++ trunk/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp 2013-02-04 23:18:33 UTC (rev 141821)
@@ -532,7 +532,8 @@
}
if (bytesSkipped > 0) {
- g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT,
+ d->m_buffer = handle->client()->getBuffer(READ_BUFFER_SIZE, &d->m_bufferSize);
+ g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, d->m_bufferSize, G_PRIORITY_DEFAULT,
d->m_cancellable.get(), redirectSkipCallback, handle.get());
return;
}
@@ -573,8 +574,8 @@
}
if (d->m_buffer) {
- g_slice_free1(READ_BUFFER_SIZE, d->m_buffer);
d->m_buffer = 0;
+ d->m_bufferSize = 0;
}
if (d->m_timeoutSource) {
@@ -645,7 +646,8 @@
return;
}
- g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, READ_BUFFER_SIZE,
+ d->m_buffer = handle->client()->getBuffer(READ_BUFFER_SIZE, &d->m_bufferSize);
+ g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, d->m_bufferSize,
G_PRIORITY_DEFAULT, d->m_cancellable.get(), readCallback, handle.get());
}
@@ -675,7 +677,7 @@
return;
}
- d->m_buffer = static_cast<char*>(g_slice_alloc(READ_BUFFER_SIZE));
+ ASSERT(!d->m_buffer);
if (soupMessage) {
if (SOUP_STATUS_IS_REDIRECTION(soupMessage->status_code) && shouldRedirect(handle.get())) {
@@ -683,7 +685,8 @@
// We use read_async() rather than skip_async() to work around
// https://bugzilla.gnome.org/show_bug.cgi?id=691489 until we can
// depend on glib > 2.35.4
- g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT,
+ d->m_buffer = handle->client()->getBuffer(READ_BUFFER_SIZE, &d->m_bufferSize);
+ g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, d->m_bufferSize, G_PRIORITY_DEFAULT,
d->m_cancellable.get(), redirectSkipCallback, handle.get());
return;
}
@@ -722,7 +725,9 @@
}
d->m_inputStream = inputStream;
- g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, READ_BUFFER_SIZE,
+
+ d->m_buffer = handle->client()->getBuffer(READ_BUFFER_SIZE, &d->m_bufferSize);
+ g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, d->m_bufferSize,
G_PRIORITY_DEFAULT, d->m_cancellable.get(), readCallback, handle.get());
}
@@ -1379,7 +1384,8 @@
return;
}
- g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT,
+ d->m_buffer = handle->client()->getBuffer(READ_BUFFER_SIZE, &d->m_bufferSize);
+ g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, d->m_bufferSize, G_PRIORITY_DEFAULT,
d->m_cancellable.get(), readCallback, handle.get());
}