⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 140420 in webkit


Ignore:
Timestamp:
Jan 22, 2013, 6:40:50 AM (14 years ago)
Author:
kov@webkit.org
Message:

[GStreamer][Soup] Let GStreamer provide the buffer data is downloaded to, to avoid copying
https://bugs.webkit.org/show_bug.cgi?id=105552

Patch by Gustavo Noronha Silva <gustavo.noronha@collabora.com> on 2013-01-22
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.

Location:
trunk/Source/WebCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r140419 r140420  
     12013-01-22  Gustavo Noronha Silva  <gustavo.noronha@collabora.com>
     2
     3        [GStreamer][Soup] Let GStreamer provide the buffer data is downloaded to, to avoid copying
     4        https://bugs.webkit.org/show_bug.cgi?id=105552
     5
     6        Reviewed by Philippe Normand.
     7
     8        Makes it possible for the GStreamer media backend to provide the buffer to which
     9        the Soup networking backend will use to download data to. This makes copying
     10        memory unnecessary when ResourceHandle hands data over to the media player's
     11        StreamingClient. Thanks to Dan Winship for help designing the interface.
     12
     13        No behaviour change, covered by existing tests.
     14
     15        * platform/graphics/gstreamer/GStreamerVersioning.cpp:
     16        (createGstBufferForData): New helper to create a GstBuffer when
     17        we have a data pointer and a length.
     18        (getGstBufferSize): Abstract obtaining the size of the buffer, so the code
     19        is cleaner while still working for both GST 0.10 and 1.0.
     20        (setGstBufferSize): Ditto, but for setting the size.
     21        (getGstBufferDataPointer): Ditto, but for grabbing the data pointer.
     22        (mapGstBuffer): Convenience method to take care of mapping the buffer so that
     23        we can provide the data pointer to ResourceHandle.
     24        (unmapGstBuffer): Convenience method which takes care of unmapping the buffer
     25        and properly freeing the GstMapInfo.
     26        * platform/graphics/gstreamer/GStreamerVersioning.h:
     27        * platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp:
     28        (StreamingClient): New methods.
     29        (_WebKitWebSrcPrivate): We now store the GstBuffer we provided the data pointer from
     30        so we can later unmap it and push it to the pipeline.
     31        (webKitWebSrcDispose): Deal with the GstBuffer in case it exists when the source is
     32        destroyed.
     33        (webKitWebSrcStop): Also clear the GstBuffer in this case.
     34        (StreamingClient::didReceiveData): Handle the hand-over of the buffer.
     35        (StreamingClient::getBuffer): Provide ResourceHandle with a new GstBuffer's data pointer.
     36        * platform/network/ResourceHandleClient.h:
     37        (ResourceHandleClient):
     38        (WebCore::ResourceHandleClient::ResourceHandleClient): Constructor to initialize the buffer
     39        member variable to 0.
     40        (WebCore::ResourceHandleClient::~ResourceHandleClient): Destructor to free the buffer if it
     41        has been allocated.
     42        (WebCore::ResourceHandleClient::getBuffer): Default implementation which returns a
     43        newly allocated char pointer.
     44        * platform/network/ResourceHandleInternal.h:
     45        (WebCore::ResourceHandleInternal::ResourceHandleInternal):
     46        (ResourceHandleInternal): Store actual buffer size, which is no longer a constant.
     47        * platform/network/soup/ResourceHandleSoup.cpp:
     48        (WebCore::cleanupSoupRequestOperation): Clear the buffer pointer, the life-cycle of the
     49        buffer is handled by the ResourceHandleClient.
     50        (WebCore::nextMultipartResponsePartCallback): Get a new buffer from the client before reading.
     51        (WebCore::sendRequestCallback): Ditto.
     52        (WebCore::readCallback): Ditto.
     53
    1542013-01-22  Michał Pakuła vel Rutka  <m.pakula@samsung.com>
    255
  • trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerVersioning.cpp

    r139884 r140420  
    11/*
    22 * Copyright (C) 2012 Igalia, S.L.
     3 * Copyright (C) 2013 Collabora Ltd.
    34 *
    45 *  This library is free software; you can redistribute it and/or
     
    3233#endif
    3334
     35#ifdef GST_API_VERSION_1
     36const char* webkitGstMapInfoQuarkString = "webkit-gst-map-info";
     37#endif
     38
    3439void webkitGstObjectRefSink(GstObject* gstObject)
    3540{
     
    122127}
    123128
     129GstBuffer* createGstBufferForData(const char* data, int length)
     130{
     131    GstBuffer* buffer = gst_buffer_new_and_alloc(length);
     132
     133#ifdef GST_API_VERSION_1
     134    gst_buffer_fill(buffer, 0, data, length);
     135#else
     136    memcpy(GST_BUFFER_DATA(buffer), data, length);
     137#endif
     138
     139    return buffer;
     140}
     141
     142int getGstBufferSize(GstBuffer* buffer)
     143{
     144#ifdef GST_API_VERSION_1
     145    return gst_buffer_get_size(buffer);
     146#else
     147    return GST_BUFFER_SIZE(buffer);
     148#endif
     149}
     150
     151void setGstBufferSize(GstBuffer* buffer, int newSize)
     152{
     153#ifdef GST_API_VERSION_1
     154    gst_buffer_set_size(buffer, static_cast<gssize>(newSize));
     155#else
     156    GST_BUFFER_SIZE(buffer) = static_cast<gsize>(newSize);
     157#endif
     158}
     159
     160char* getGstBufferDataPointer(GstBuffer* buffer)
     161{
     162#ifdef GST_API_VERSION_1
     163    GstMiniObject* miniObject = reinterpret_cast<GstMiniObject*>(buffer);
     164    GstMapInfo* mapInfo = static_cast<GstMapInfo*>(gst_mini_object_get_qdata(miniObject, g_quark_from_static_string(webkitGstMapInfoQuarkString)));
     165    return reinterpret_cast<char*>(mapInfo->data);
     166#else
     167    return reinterpret_cast<char*>(GST_BUFFER_DATA(buffer));
     168#endif
     169}
     170
     171#ifdef GST_API_VERSION_1
     172void mapGstBuffer(GstBuffer* buffer)
     173{
     174    GstMapInfo* mapInfo = g_slice_new(GstMapInfo);
     175    if (!gst_buffer_map(buffer, mapInfo, GST_MAP_WRITE)) {
     176        g_slice_free(GstMapInfo, mapInfo);
     177        gst_buffer_unref(buffer);
     178        return;
     179    }
     180
     181    GstMiniObject* miniObject = reinterpret_cast<GstMiniObject*>(buffer);
     182    gst_mini_object_set_qdata(miniObject, g_quark_from_static_string(webkitGstMapInfoQuarkString), mapInfo, 0);
     183}
     184
     185void unmapGstBuffer(GstBuffer* buffer)
     186{
     187    GstMiniObject* miniObject = reinterpret_cast<GstMiniObject*>(buffer);
     188    GstMapInfo* mapInfo = static_cast<GstMapInfo*>(gst_mini_object_steal_qdata(miniObject, g_quark_from_static_string(webkitGstMapInfoQuarkString)));
     189
     190    if (!mapInfo)
     191        return;
     192
     193    gst_buffer_unmap(buffer, mapInfo);
     194    g_slice_free(GstMapInfo, mapInfo);
     195}
     196#endif
     197
    124198void setGstElementClassMetadata(GstElementClass* elementClass, const char* name, const char* longName, const char* description, const char* author)
    125199{
  • trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerVersioning.h

    r139884 r140420  
    3737#endif
    3838GstBuffer* createGstBuffer(GstBuffer*);
     39GstBuffer* createGstBufferForData(const char* data, int length);
     40int getGstBufferSize(GstBuffer*);
     41void setGstBufferSize(GstBuffer*, int newSize);
     42char* getGstBufferDataPointer(GstBuffer*);
     43#ifdef GST_API_VERSION_1
     44void mapGstBuffer(GstBuffer*);
     45void unmapGstBuffer(GstBuffer*);
     46#endif
    3947void setGstElementClassMetadata(GstElementClass*, const char* name, const char* longName, const char* description, const char* author);
    4048bool gstObjectIsFloating(GstObject*);
  • trunk/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp

    r139884 r140420  
    11/*
    22 *  Copyright (C) 2009, 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
     3 *  Copyright (C) 2013 Collabora Ltd.
    34 *
    45 *  This library is free software; you can redistribute it and/or
     
    3334#include "ResourceRequest.h"
    3435#include "ResourceResponse.h"
    35  
    3636#include <gst/app/gstappsrc.h>
     37#include <gst/gst.h>
    3738#include <gst/pbutils/missing-plugins.h>
    38 
    3939#include <wtf/Noncopyable.h>
    4040#include <wtf/gobject/GOwnPtr.h>
     
    5252        virtual void willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse&);
    5353        virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
     54
     55        virtual char* getBuffer(int, int*);
     56
    5457        virtual void didReceiveData(ResourceHandle*, const char*, int, int);
    5558        virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/);
     
    8487    guint enoughDataID;
    8588    guint seekID;
     89
     90    GRefPtr<GstBuffer> buffer;
    8691
    8792    // icecast stuff
     
    116121static void webKitWebSrcUriHandlerInit(gpointer gIface, gpointer ifaceData);
    117122
     123static void webKitWebSrcDispose(GObject*);
    118124static void webKitWebSrcFinalize(GObject*);
    119125static void webKitWebSrcSetProperty(GObject*, guint propertyID, const GValue*, GParamSpec*);
     
    151157    GstElementClass* eklass = GST_ELEMENT_CLASS(klass);
    152158
     159    oklass->dispose = webKitWebSrcDispose;
    153160    oklass->finalize = webKitWebSrcFinalize;
    154161    oklass->set_property = webKitWebSrcSetProperty;
     
    275282}
    276283
     284static void webKitWebSrcDispose(GObject* object)
     285{
     286    WebKitWebSrc* src = WEBKIT_WEB_SRC(object);
     287    WebKitWebSrcPrivate* priv = src->priv;
     288
     289    if (priv->buffer) {
     290#ifdef GST_API_VERSION_1
     291        unmapGstBuffer(priv->buffer.get());
     292#endif
     293        priv->buffer.clear();
     294    }
     295
     296    GST_CALL_PARENT(G_OBJECT_CLASS, dispose, (object));
     297}
     298
    277299static void webKitWebSrcFinalize(GObject* object)
    278300{
     
    284306    g_free(priv->uri);
    285307
    286     GST_CALL_PARENT(G_OBJECT_CLASS, finalize, ((GObject* )(src)));
     308    GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object));
    287309}
    288310
     
    354376
    355377    priv->player = 0;
     378
     379    if (priv->buffer) {
     380#ifdef GST_API_VERSION_1
     381        unmapGstBuffer(priv->buffer.get());
     382#endif
     383        priv->buffer.clear();
     384    }
    356385
    357386    GST_OBJECT_LOCK(src);
     
    857886    WebKitWebSrcPrivate* priv = m_src->priv;
    858887
    859     GST_LOG_OBJECT(m_src, "Have %d bytes of data", length);
     888    GST_LOG_OBJECT(m_src, "Have %d bytes of data", priv->buffer ? getGstBufferSize(priv->buffer.get()) : length);
     889
     890#ifdef GST_API_VERSION_1
     891    if (priv->buffer)
     892        unmapGstBuffer(priv->buffer.get());
     893#endif
    860894
    861895    if (priv->seekID || handle != priv->resourceHandle) {
    862896        GST_DEBUG_OBJECT(m_src, "Seek in progress, ignoring data");
     897        priv->buffer.clear();
    863898        return;
    864899    }
    865900
    866     GstBuffer* buffer = gst_buffer_new_and_alloc(length);
    867 
    868 #ifdef GST_API_VERSION_1
    869     gst_buffer_fill(buffer, 0, data, length);
    870 #else
    871     memcpy(GST_BUFFER_DATA(buffer), data, length);
    872 #endif
    873     GST_BUFFER_OFFSET(buffer) = priv->offset;
     901    ASSERT(!priv->buffer || data == getGstBufferDataPointer(priv->buffer.get()));
     902
     903    // Ports using the GStreamer backend but not the soup implementation of ResourceHandle
     904    // won't be using buffers provided by this client, the buffer is created here in that case.
     905    if (!priv->buffer)
     906        priv->buffer = adoptGRef(createGstBufferForData(data, length));
     907    else
     908        setGstBufferSize(priv->buffer.get(), length);
     909
     910    GST_BUFFER_OFFSET(priv->buffer.get()) = priv->offset;
    874911    priv->offset += length;
    875     GST_BUFFER_OFFSET_END(buffer) = priv->offset;
    876 
    877     GstFlowReturn ret = gst_app_src_push_buffer(priv->appsrc, buffer);
     912    GST_BUFFER_OFFSET_END(priv->buffer.get()) = priv->offset;
     913
     914    GstFlowReturn ret = gst_app_src_push_buffer(priv->appsrc, priv->buffer.leakRef());
    878915#ifdef GST_API_VERSION_1
    879916    if (ret != GST_FLOW_OK && ret != GST_FLOW_EOS)
     
    884921}
    885922
     923char* StreamingClient::getBuffer(int requestedSize, int* actualSize)
     924{
     925    WebKitWebSrcPrivate* priv = m_src->priv;
     926
     927    ASSERT(!priv->buffer);
     928
     929    GstBuffer* buffer = gst_buffer_new_and_alloc(requestedSize);
     930
     931#ifdef GST_API_VERSION_1
     932    mapGstBuffer(buffer);
     933#endif
     934
     935    priv->buffer = adoptGRef(buffer);
     936
     937    *actualSize = getGstBufferSize(buffer);
     938    return getGstBufferDataPointer(buffer);
     939}
     940
    886941void StreamingClient::didFinishLoading(ResourceHandle*, double)
    887942{
  • trunk/Source/WebCore/platform/network/ResourceHandleClient.h

    r139884 r140420  
    3636#endif
    3737
     38#if USE(SOUP)
     39#include <glib.h>
     40#endif
     41
    3842#if PLATFORM(WIN) && USE(CFNETWORK)
    3943#include <ConditionalMacros.h>
     
    6468    class ResourceHandleClient {
    6569    public:
     70#if USE(SOUP)
     71        ResourceHandleClient(): m_buffer(0) { }
     72
     73        virtual ~ResourceHandleClient()
     74        {
     75            if (m_buffer) {
     76                g_free(m_buffer);
     77                m_buffer = 0;
     78            }
     79        }
     80#else
    6681        virtual ~ResourceHandleClient() { }
     82#endif
    6783
    6884        // request may be modified
     
    8197        virtual bool supportsDataArray() { return false; }
    8298        virtual void didReceiveDataArray(ResourceHandle*, CFArrayRef) { }
     99#endif
     100
     101#if USE(SOUP)
     102        virtual char* getBuffer(int requestedLength, int* actualLength)
     103        {
     104            *actualLength = requestedLength;
     105
     106            if (!m_buffer)
     107                m_buffer = static_cast<char*>(g_malloc(requestedLength));
     108
     109            return m_buffer;
     110        }
    83111#endif
    84112
     
    108136        virtual AsyncFileStream* createAsyncFileStream(FileStreamClient*) { return 0; }
    109137#endif
     138
     139#if USE(SOUP)
     140private:
     141        char* m_buffer;
     142#endif
    110143    };
    111144
  • trunk/Source/WebCore/platform/network/ResourceHandleInternal.h

    r139884 r140420  
    114114            , m_cancelled(false)
    115115            , m_buffer(0)
     116            , m_bufferSize(0)
    116117            , m_bodySize(0)
    117118            , m_bodyDataSent(0)
     
    201202        GRefPtr<GSource> m_timeoutSource;
    202203        char* m_buffer;
     204        int m_bufferSize;
    203205        unsigned long m_bodySize;
    204206        unsigned long m_bodyDataSent;
  • trunk/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp

    r140338 r140420  
    566566
    567567    if (d->m_buffer) {
    568         g_slice_free1(READ_BUFFER_SIZE, d->m_buffer);
    569568        d->m_buffer = 0;
     569        d->m_bufferSize = 0;
    570570    }
    571571
     
    634634    client->didReceiveResponse(handle.get(), d->m_response);
    635635
     636    // didReceiveResponse may cause the client to be changed.
     637    client = d->client();
     638
    636639    if (d->m_cancelled || !client) {
    637640        cleanupSoupRequestOperation(handle.get());
     
    639642    }
    640643
    641     g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, READ_BUFFER_SIZE,
     644    d->m_buffer = client->getBuffer(READ_BUFFER_SIZE, &d->m_bufferSize);
     645
     646    g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, d->m_bufferSize,
    642647        G_PRIORITY_DEFAULT, d->m_cancellable.get(), readCallback, handle.get());
    643648}
     
    669674    }
    670675
    671     d->m_buffer = static_cast<char*>(g_slice_alloc(READ_BUFFER_SIZE));
     676    ASSERT(!d->m_buffer);
     677
     678    d->m_buffer = client->getBuffer(READ_BUFFER_SIZE, &d->m_bufferSize);
    672679
    673680    if (soupMessage) {
     
    703710    client->didReceiveResponse(handle.get(), d->m_response);
    704711
    705     if (d->m_cancelled) {
     712    // didReceiveResponse may cause the client to be changed.
     713    client = d->client();
     714
     715    if (d->m_cancelled || !client) {
    706716        cleanupSoupRequestOperation(handle.get());
    707717        return;
     
    716726
    717727    d->m_inputStream = inputStream;
    718     g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, READ_BUFFER_SIZE,
     728
     729    g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, d->m_bufferSize,
    719730                              G_PRIORITY_DEFAULT, d->m_cancellable.get(), readCallback, handle.get());
    720731}
     
    13691380
    13701381    // didReceiveData may cancel the load, which may release the last reference.
    1371     if (d->m_cancelled || !client) {
     1382    if (d->m_cancelled || !handle->client()) {
    13721383        cleanupSoupRequestOperation(handle.get());
    13731384        return;
    13741385    }
    13751386
    1376     g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT,
     1387    d->m_buffer = client->getBuffer(READ_BUFFER_SIZE, &d->m_bufferSize);
     1388
     1389    g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, d->m_bufferSize, G_PRIORITY_DEFAULT,
    13771390                              d->m_cancellable.get(), readCallback, handle.get());
    13781391}
Note: See TracChangeset for help on using the changeset viewer.