Changeset 141821 in webkit


Ignore:
Timestamp:
Feb 4, 2013 3:18:33 PM (11 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-02-04
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

    r141818 r141821  
     12013-02-04  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-02-04  Mark Pilgrim  <pilgrim@chromium.org>
    255
  • trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerVersioning.cpp

    r140443 r141821  
    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{
     
    133138}
    134139
     140GstBuffer* createGstBufferForData(const char* data, int length)
     141{
     142    GstBuffer* buffer = gst_buffer_new_and_alloc(length);
     143
     144#ifdef GST_API_VERSION_1
     145    gst_buffer_fill(buffer, 0, data, length);
     146#else
     147    memcpy(GST_BUFFER_DATA(buffer), data, length);
     148#endif
     149
     150    return buffer;
     151}
     152
     153int getGstBufferSize(GstBuffer* buffer)
     154{
     155#ifdef GST_API_VERSION_1
     156    return gst_buffer_get_size(buffer);
     157#else
     158    return GST_BUFFER_SIZE(buffer);
     159#endif
     160}
     161
     162void setGstBufferSize(GstBuffer* buffer, int newSize)
     163{
     164#ifdef GST_API_VERSION_1
     165    gst_buffer_set_size(buffer, static_cast<gssize>(newSize));
     166#else
     167    GST_BUFFER_SIZE(buffer) = static_cast<gsize>(newSize);
     168#endif
     169}
     170
     171char* getGstBufferDataPointer(GstBuffer* buffer)
     172{
     173#ifdef GST_API_VERSION_1
     174    GstMiniObject* miniObject = reinterpret_cast<GstMiniObject*>(buffer);
     175    GstMapInfo* mapInfo = static_cast<GstMapInfo*>(gst_mini_object_get_qdata(miniObject, g_quark_from_static_string(webkitGstMapInfoQuarkString)));
     176    return reinterpret_cast<char*>(mapInfo->data);
     177#else
     178    return reinterpret_cast<char*>(GST_BUFFER_DATA(buffer));
     179#endif
     180}
     181
     182#ifdef GST_API_VERSION_1
     183void mapGstBuffer(GstBuffer* buffer)
     184{
     185    GstMapInfo* mapInfo = g_slice_new(GstMapInfo);
     186    if (!gst_buffer_map(buffer, mapInfo, GST_MAP_WRITE)) {
     187        g_slice_free(GstMapInfo, mapInfo);
     188        gst_buffer_unref(buffer);
     189        return;
     190    }
     191
     192    GstMiniObject* miniObject = reinterpret_cast<GstMiniObject*>(buffer);
     193    gst_mini_object_set_qdata(miniObject, g_quark_from_static_string(webkitGstMapInfoQuarkString), mapInfo, 0);
     194}
     195
     196void unmapGstBuffer(GstBuffer* buffer)
     197{
     198    GstMiniObject* miniObject = reinterpret_cast<GstMiniObject*>(buffer);
     199    GstMapInfo* mapInfo = static_cast<GstMapInfo*>(gst_mini_object_steal_qdata(miniObject, g_quark_from_static_string(webkitGstMapInfoQuarkString)));
     200
     201    if (!mapInfo)
     202        return;
     203
     204    gst_buffer_unmap(buffer, mapInfo);
     205    g_slice_free(GstMapInfo, mapInfo);
     206}
     207#endif
     208
    135209void setGstElementClassMetadata(GstElementClass* elementClass, const char* name, const char* longName, const char* description, const char* author)
    136210{
  • trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerVersioning.h

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

    r141695 r141821  
    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
     
    3435#include "ResourceRequest.h"
    3536#include "ResourceResponse.h"
    36  
    3737#include <gst/app/gstappsrc.h>
     38#include <gst/gst.h>
    3839#include <gst/pbutils/missing-plugins.h>
    39 
    4040#include <wtf/Noncopyable.h>
    4141#include <wtf/gobject/GOwnPtr.h>
     
    5353        virtual void willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse&);
    5454        virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
     55
     56        virtual char* getBuffer(int, int*);
     57
    5558        virtual void didReceiveData(ResourceHandle*, const char*, int, int);
    5659        virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/);
     
    8588    guint enoughDataID;
    8689    guint seekID;
     90
     91    GRefPtr<GstBuffer> buffer;
    8792
    8893    // icecast stuff
     
    117122static void webKitWebSrcUriHandlerInit(gpointer gIface, gpointer ifaceData);
    118123
     124static void webKitWebSrcDispose(GObject*);
    119125static void webKitWebSrcFinalize(GObject*);
    120126static void webKitWebSrcSetProperty(GObject*, guint propertyID, const GValue*, GParamSpec*);
     
    152158    GstElementClass* eklass = GST_ELEMENT_CLASS(klass);
    153159
     160    oklass->dispose = webKitWebSrcDispose;
    154161    oklass->finalize = webKitWebSrcFinalize;
    155162    oklass->set_property = webKitWebSrcSetProperty;
     
    276283}
    277284
     285static void webKitWebSrcDispose(GObject* object)
     286{
     287    WebKitWebSrc* src = WEBKIT_WEB_SRC(object);
     288    WebKitWebSrcPrivate* priv = src->priv;
     289
     290    if (priv->buffer) {
     291#ifdef GST_API_VERSION_1
     292        unmapGstBuffer(priv->buffer.get());
     293#endif
     294        priv->buffer.clear();
     295    }
     296
     297    GST_CALL_PARENT(G_OBJECT_CLASS, dispose, (object));
     298}
     299
    278300static void webKitWebSrcFinalize(GObject* object)
    279301{
     
    285307    g_free(priv->uri);
    286308
    287     GST_CALL_PARENT(G_OBJECT_CLASS, finalize, ((GObject* )(src)));
     309    GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object));
    288310}
    289311
     
    355377
    356378    priv->player = 0;
     379
     380    if (priv->buffer) {
     381#ifdef GST_API_VERSION_1
     382        unmapGstBuffer(priv->buffer.get());
     383#endif
     384        priv->buffer.clear();
     385    }
    357386
    358387    GST_OBJECT_LOCK(src);
     
    858887    WebKitWebSrcPrivate* priv = m_src->priv;
    859888
    860     GST_LOG_OBJECT(m_src, "Have %d bytes of data", length);
     889    GST_LOG_OBJECT(m_src, "Have %d bytes of data", priv->buffer ? getGstBufferSize(priv->buffer.get()) : length);
     890
     891    ASSERT(!priv->buffer || data == getGstBufferDataPointer(priv->buffer.get()));
     892
     893#ifdef GST_API_VERSION_1
     894    if (priv->buffer)
     895        unmapGstBuffer(priv->buffer.get());
     896#endif
    861897
    862898    if (priv->seekID || handle != priv->resourceHandle) {
    863899        GST_DEBUG_OBJECT(m_src, "Seek in progress, ignoring data");
     900        priv->buffer.clear();
    864901        return;
    865902    }
    866903
    867     GstBuffer* buffer = gst_buffer_new_and_alloc(length);
    868 
    869 #ifdef GST_API_VERSION_1
    870     gst_buffer_fill(buffer, 0, data, length);
    871 #else
    872     memcpy(GST_BUFFER_DATA(buffer), data, length);
    873 #endif
    874     GST_BUFFER_OFFSET(buffer) = priv->offset;
     904    // Ports using the GStreamer backend but not the soup implementation of ResourceHandle
     905    // won't be using buffers provided by this client, the buffer is created here in that case.
     906    if (!priv->buffer)
     907        priv->buffer = adoptGRef(createGstBufferForData(data, length));
     908    else
     909        setGstBufferSize(priv->buffer.get(), length);
     910
     911    GST_BUFFER_OFFSET(priv->buffer.get()) = priv->offset;
    875912    priv->offset += length;
    876     GST_BUFFER_OFFSET_END(buffer) = priv->offset;
    877 
    878     GstFlowReturn ret = gst_app_src_push_buffer(priv->appsrc, buffer);
     913    GST_BUFFER_OFFSET_END(priv->buffer.get()) = priv->offset;
     914
     915    GstFlowReturn ret = gst_app_src_push_buffer(priv->appsrc, priv->buffer.leakRef());
    879916#ifdef GST_API_VERSION_1
    880917    if (ret != GST_FLOW_OK && ret != GST_FLOW_EOS)
     
    885922}
    886923
     924char* StreamingClient::getBuffer(int requestedSize, int* actualSize)
     925{
     926    WebKitWebSrcPrivate* priv = m_src->priv;
     927
     928    ASSERT(!priv->buffer);
     929
     930    GstBuffer* buffer = gst_buffer_new_and_alloc(requestedSize);
     931
     932#ifdef GST_API_VERSION_1
     933    mapGstBuffer(buffer);
     934#endif
     935
     936    priv->buffer = adoptGRef(buffer);
     937
     938    *actualSize = getGstBufferSize(buffer);
     939    return getGstBufferDataPointer(buffer);
     940}
     941
    887942void StreamingClient::didFinishLoading(ResourceHandle*, double)
    888943{
  • trunk/Source/WebCore/platform/network/ResourceHandleClient.h

    r140425 r141821  
    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

    r141350 r141821  
    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

    r141749 r141821  
    533533
    534534    if (bytesSkipped > 0) {
    535         g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT,
     535        d->m_buffer = handle->client()->getBuffer(READ_BUFFER_SIZE, &d->m_bufferSize);
     536        g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, d->m_bufferSize, G_PRIORITY_DEFAULT,
    536537            d->m_cancellable.get(), redirectSkipCallback, handle.get());
    537538        return;
     
    574575
    575576    if (d->m_buffer) {
    576         g_slice_free1(READ_BUFFER_SIZE, d->m_buffer);
    577577        d->m_buffer = 0;
     578        d->m_bufferSize = 0;
    578579    }
    579580
     
    646647    }
    647648
    648     g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, READ_BUFFER_SIZE,
     649    d->m_buffer = handle->client()->getBuffer(READ_BUFFER_SIZE, &d->m_bufferSize);
     650    g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, d->m_bufferSize,
    649651        G_PRIORITY_DEFAULT, d->m_cancellable.get(), readCallback, handle.get());
    650652}
     
    676678    }
    677679
    678     d->m_buffer = static_cast<char*>(g_slice_alloc(READ_BUFFER_SIZE));
     680    ASSERT(!d->m_buffer);
    679681
    680682    if (soupMessage) {
     
    684686            // https://bugzilla.gnome.org/show_bug.cgi?id=691489 until we can
    685687            // depend on glib > 2.35.4
    686             g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT,
     688            d->m_buffer = handle->client()->getBuffer(READ_BUFFER_SIZE, &d->m_bufferSize);
     689            g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, d->m_bufferSize, G_PRIORITY_DEFAULT,
    687690                d->m_cancellable.get(), redirectSkipCallback, handle.get());
    688691            return;
     
    723726
    724727    d->m_inputStream = inputStream;
    725     g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, READ_BUFFER_SIZE,
     728
     729    d->m_buffer = handle->client()->getBuffer(READ_BUFFER_SIZE, &d->m_bufferSize);
     730    g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, d->m_bufferSize,
    726731                              G_PRIORITY_DEFAULT, d->m_cancellable.get(), readCallback, handle.get());
    727732}
     
    13801385    }
    13811386
    1382     g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT,
     1387    d->m_buffer = handle->client()->getBuffer(READ_BUFFER_SIZE, &d->m_bufferSize);
     1388    g_input_stream_read_async(d->m_inputStream.get(), d->m_buffer, d->m_bufferSize, G_PRIORITY_DEFAULT,
    13831389                              d->m_cancellable.get(), readCallback, handle.get());
    13841390}
Note: See TracChangeset for help on using the changeset viewer.