Changeset 243058 in webkit


Ignore:
Timestamp:
Mar 18, 2019 3:34:44 AM (5 years ago)
Author:
Philippe Normand
Message:

[GStreamer] Rewrite HTTP source element using pushsrc base class
https://bugs.webkit.org/show_bug.cgi?id=195631

Reviewed by Xabier Rodriguez-Calvar.

Source/WebCore:

If we want to use webkitwebsrc in adaptivedemux (HLS, DASH, etc)
we need a source element that behaves like souphttpsrc, which is
implemented using pushsrc. This rewrite might also fix some seek
issues.

No new tests, existing http/tests/media tests cover this patch.

  • platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:

(WebCore::MediaPlayerPrivateGStreamer::handleMessage):

  • platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp:

(webkit_web_src_class_init):
(webkitWebSrcReset):
(webkit_web_src_init):
(webKitWebSrcCreate):
(webKitWebSrcStart):
(webKitWebSrcCloseSession):
(webKitWebSrcStop):
(webKitWebSrcGetSize):
(webKitWebSrcIsSeekable):
(webKitWebSrcDoSeek):
(webKitWebSrcQuery):
(webKitWebSrcUnLock):
(webKitWebSrcUnLockStop):
(webKitWebSrcChangeState):
(CachedResourceStreamingClient::checkUpdateBlocksize):
(CachedResourceStreamingClient::responseReceived):
(CachedResourceStreamingClient::dataReceived):
(CachedResourceStreamingClient::accessControlCheckFailed):
(CachedResourceStreamingClient::loadFailed):
(CachedResourceStreamingClient::loadFinished):

  • platform/graphics/gstreamer/WebKitWebSourceGStreamer.h:

LayoutTests:

  • platform/gtk/TestExpectations:
  • platform/gtk/http/tests/media/hls/video-controls-live-stream-expected.txt:

Update expectations, though it's not really related with this
patch.

Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r243056 r243058  
     12019-03-18  Philippe Normand  <pnormand@igalia.com>
     2
     3        [GStreamer] Rewrite HTTP source element using pushsrc base class
     4        https://bugs.webkit.org/show_bug.cgi?id=195631
     5
     6        Reviewed by Xabier Rodriguez-Calvar.
     7
     8        * platform/gtk/TestExpectations:
     9        * platform/gtk/http/tests/media/hls/video-controls-live-stream-expected.txt:
     10        Update expectations, though it's not really related with this
     11        patch.
     12
    1132019-03-18  Claudio Saavedra  <csaavedra@igalia.com>
    214
  • trunk/LayoutTests/http/tests/media/video-play-stall-seek-expected.txt

    r41942 r243058  
     1
    12Test that playback can be resumed by seeking backwards after load stalls.
    23
  • trunk/LayoutTests/platform/gtk/TestExpectations

    r243056 r243058  
    22112211
    22122212Bug(GTK) http/tests/media/video-preload.html [ Pass Slow ]
    2213 webkit.org/b/143989 [ Release ] http/tests/media/hls/video-controls-live-stream.html [ Pass Slow Failure ]
    22142213
    22152214webkit.org/b/116958 http/tests/navigation/slowmetaredirect-basic.html [ Pass Slow ]
     
    27362735webkit.org/b/121995 media/video-controls-captions-trackmenu-includes-enabled-track.html [ Failure ]
    27372736
    2738 Bug(GTK) http/tests/media/video-play-stall-seek.html [ Skip ]
    2739 
    27402737Bug(GTK) http/tests/misc/acid3.html [ Failure ]
    27412738
  • trunk/LayoutTests/platform/gtk/http/tests/media/hls/video-controls-live-stream-expected.txt

    r177077 r243058  
    11
     2EVENT(canplaythrough)
    23EVENT(play)
    34EXPECTED (video.duration == 'Infinity') OK
    45-webkit-media-text-track-container: classes: [hidden]
    56-webkit-media-controls-enclosure: classes: []
    6 -webkit-media-controls-panel: classes: [paused]
     7-webkit-media-controls-panel: classes: [paused show]
    78-webkit-media-controls-play-button: classes: [paused]
    89-webkit-media-controls-timeline: classes: []
    910-webkit-media-controls-current-time-display: classes: [hour-long-time]
    10 -webkit-media-controls-time-remaining-display: classes: [hidden hour-long-time]
     11-webkit-media-controls-time-remaining-display: classes: [hour-long-time hidden]
    1112-webkit-media-controls-toggle-closed-captions-button: classes: [hidden]
    1213-webkit-media-controls-fullscreen-button: classes: []
  • trunk/Source/WebCore/ChangeLog

    r243057 r243058  
     12019-03-18  Philippe Normand  <pnormand@igalia.com>
     2
     3        [GStreamer] Rewrite HTTP source element using pushsrc base class
     4        https://bugs.webkit.org/show_bug.cgi?id=195631
     5
     6        Reviewed by Xabier Rodriguez-Calvar.
     7
     8        If we want to use webkitwebsrc in adaptivedemux (HLS, DASH, etc)
     9        we need a source element that behaves like souphttpsrc, which is
     10        implemented using pushsrc. This rewrite might also fix some seek
     11        issues.
     12
     13        No new tests, existing http/tests/media tests cover this patch.
     14
     15        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
     16        (WebCore::MediaPlayerPrivateGStreamer::handleMessage):
     17        * platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp:
     18        (webkit_web_src_class_init):
     19        (webkitWebSrcReset):
     20        (webkit_web_src_init):
     21        (webKitWebSrcCreate):
     22        (webKitWebSrcStart):
     23        (webKitWebSrcCloseSession):
     24        (webKitWebSrcStop):
     25        (webKitWebSrcGetSize):
     26        (webKitWebSrcIsSeekable):
     27        (webKitWebSrcDoSeek):
     28        (webKitWebSrcQuery):
     29        (webKitWebSrcUnLock):
     30        (webKitWebSrcUnLockStop):
     31        (webKitWebSrcChangeState):
     32        (CachedResourceStreamingClient::checkUpdateBlocksize):
     33        (CachedResourceStreamingClient::responseReceived):
     34        (CachedResourceStreamingClient::dataReceived):
     35        (CachedResourceStreamingClient::accessControlCheckFailed):
     36        (CachedResourceStreamingClient::loadFailed):
     37        (CachedResourceStreamingClient::loadFinished):
     38        * platform/graphics/gstreamer/WebKitWebSourceGStreamer.h:
     39
    1402019-03-18  Gyuyoung Kim  <gyuyoung.kim@webkit.org>
    241
  • trunk/Source/WebCore/platform/graphics/gstreamer/MainThreadNotifier.h

    r235732 r243058  
    6464    }
    6565
     66    template<typename F>
     67    void notifyAndWait(T notificationType, F&& callbackFunctor)
     68    {
     69        Lock mutex;
     70        Condition condition;
     71
     72        notify(notificationType, [functor = WTFMove(callbackFunctor), &condition, &mutex] {
     73            functor();
     74            LockHolder holder(mutex);
     75            condition.notifyOne();
     76        });
     77
     78        if (!isMainThread()) {
     79            LockHolder holder(mutex);
     80            condition.wait(mutex);
     81        }
     82    }
     83
    6684    void cancelPendingNotifications(unsigned mask = 0)
    6785    {
  • trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp

    r242793 r243058  
    534534
    535535    // Avoid useless seeking.
    536     if (mediaTime == currentMediaTime())
    537         return;
     536    if (mediaTime == currentMediaTime()) {
     537        GST_DEBUG_OBJECT(pipeline(), "[Seek] seek to EOS position unhandled");
     538        return;
     539    }
    538540
    539541    MediaTime time = std::min(mediaTime, durationMediaTime());
    540542
    541     if (isLiveStream())
    542         return;
     543    if (isLiveStream()) {
     544        GST_DEBUG_OBJECT(pipeline(), "[Seek] Live stream seek unhandled");
     545        return;
     546    }
    543547
    544548    GST_INFO_OBJECT(pipeline(), "[Seek] seeking to %s", toString(time).utf8().data());
     
    11971201    bool messageSourceIsPlaybin = GST_MESSAGE_SRC(message) == reinterpret_cast<GstObject*>(m_pipeline.get());
    11981202
    1199     GST_LOG("Message %s received from element %s", GST_MESSAGE_TYPE_NAME(message), GST_MESSAGE_SRC_NAME(message));
     1203    GST_LOG_OBJECT(pipeline(), "Message %s received from element %s", GST_MESSAGE_TYPE_NAME(message), GST_MESSAGE_SRC_NAME(message));
    12001204    switch (GST_MESSAGE_TYPE(message)) {
    12011205    case GST_MESSAGE_ERROR:
     
    13431347#endif
    13441348        else if (gst_structure_has_name(structure, "http-headers")) {
    1345             GstStructure* responseHeaders;
    1346             if (gst_structure_get(structure, "response-headers", GST_TYPE_STRUCTURE, &responseHeaders, nullptr)) {
    1347                 if (!gst_structure_has_field(responseHeaders, httpHeaderNameString(HTTPHeaderName::ContentLength).utf8().data())) {
    1348                     GST_INFO_OBJECT(pipeline(), "Live stream detected. Disabling on-disk buffering");
     1349            if (const char* uri = gst_structure_get_string(structure, "uri")) {
     1350                URL url(URL(), uri);
     1351                convertToInternalProtocol(url);
     1352                if (url != m_url) {
     1353                    GST_DEBUG_OBJECT(pipeline(), "Ignoring HTTP response headers for non-main URI.");
     1354                    break;
     1355                }
     1356            }
     1357            GUniqueOutPtr<GstStructure> responseHeaders;
     1358            if (gst_structure_get(structure, "response-headers", GST_TYPE_STRUCTURE, &responseHeaders.outPtr(), nullptr)) {
     1359                const char* contentLengthHeaderName = httpHeaderNameString(HTTPHeaderName::ContentLength).utf8().data();
     1360                uint64_t contentLength = 0;
     1361                if (!gst_structure_get_uint64(responseHeaders.get(), contentLengthHeaderName, &contentLength)) {
     1362                    // souphttpsrc sets a string for Content-Length, so
     1363                    // handle it here, until we remove the webkit+ protocol
     1364                    // prefix from webkitwebsrc.
     1365                    if (const char* contentLengthAsString = gst_structure_get_string(responseHeaders.get(), contentLengthHeaderName)) {
     1366                        contentLength = g_ascii_strtoull(contentLengthAsString, nullptr, 10);
     1367                        if (contentLength == G_MAXUINT64)
     1368                            contentLength = 0;
     1369                    }
     1370                }
     1371                GST_INFO_OBJECT(pipeline(), "%s stream detected", !contentLength ? "Live" : "Non-live");
     1372                if (!contentLength) {
    13491373                    m_isStreaming = true;
    13501374                    setDownloadBuffering();
    13511375                }
    1352                 gst_structure_free(responseHeaders);
    13531376            }
    13541377        } else if (gst_structure_has_name(structure, "adaptive-streaming-statistics")) {
     
    16481671MediaTime MediaPlayerPrivateGStreamer::maxMediaTimeSeekable() const
    16491672{
     1673    GST_TRACE_OBJECT(pipeline(), "errorOccured: %s, isLiveStream: %s", boolForPrinting(m_errorOccured), boolForPrinting(isLiveStream()));
    16501674    if (m_errorOccured)
     1675        return MediaTime::zeroTime();
     1676
     1677    if (isLiveStream())
    16511678        return MediaTime::zeroTime();
    16521679
  • trunk/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp

    r241444 r243058  
    22 *  Copyright (C) 2009, 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
    33 *  Copyright (C) 2013 Collabora Ltd.
     4 *  Copyright (C) 2019 Igalia S.L.
    45 *
    56 *  This library is free software; you can redistribute it and/or
     
    3334#include "SecurityOrigin.h"
    3435#include <cstdint>
    35 #include <gst/app/gstappsrc.h>
    36 #include <gst/pbutils/missing-plugins.h>
     36#include <wtf/Condition.h>
    3737#include <wtf/text/CString.h>
    3838
     
    7474    Start = 1 << 0,
    7575    Stop = 1 << 1,
    76     NeedData = 1 << 2,
    77     EnoughData = 1 << 3,
    78     Seek = 1 << 4
    7976};
    8077
    8178#define WEBKIT_WEB_SRC_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), WEBKIT_TYPE_WEB_SRC, WebKitWebSrcPrivate))
    8279struct _WebKitWebSrcPrivate {
    83     GstAppSrc* appsrc;
    84     GstPad* srcpad;
    8580    CString originalURI;
    8681    CString redirectedURI;
     
    8984    bool compress;
    9085    GUniquePtr<gchar> httpMethod;
    91 
    9286    WebCore::MediaPlayer* player;
    93 
    9487    RefPtr<PlatformMediaResourceLoader> loader;
    9588    RefPtr<PlatformMediaResource> resource;
    96 
     89    RefPtr<MainThreadNotifier<MainThreadSourceNotification>> notifier;
    9790    bool didPassAccessControlCheck;
    98 
    99     guint64 offset;
     91    bool wereHeadersReceived;
     92    Condition headersCondition;
     93    Lock responseLock;
     94    bool wasResponseReceived;
     95    Condition responseCondition;
     96    bool doesHaveEOS;
     97    bool isFlushing { false };
     98    uint64_t readPosition;
     99    uint64_t requestedPosition;
     100    uint64_t stopPosition;
     101    bool isDurationSet;
    100102    bool haveSize;
    101     guint64 size;
    102     gboolean seekable;
    103     bool paused;
     103    uint64_t size;
     104    bool isSeekable;
    104105    bool isSeeking;
    105 
    106     guint64 requestedOffset;
    107 
     106    bool wasSeeking { false };
    108107    uint64_t minimumBlocksize;
    109 
    110     RefPtr<MainThreadNotifier<MainThreadSourceNotification>> notifier;
     108    Lock adapterLock;
     109    Condition adapterCondition;
     110    uint64_t queueSize { 0 };
     111    GRefPtr<GstAdapter> adapter;
     112    GRefPtr<GstEvent> httpHeadersEvent;
    111113};
    112114
     
    121123};
    122124
    123 static GstStaticPadTemplate srcTemplate = GST_STATIC_PAD_TEMPLATE("src",
    124                                                                   GST_PAD_SRC,
    125                                                                   GST_PAD_ALWAYS,
    126                                                                   GST_STATIC_CAPS_ANY);
     125static GstStaticPadTemplate srcTemplate = GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY);
    127126
    128127GST_DEBUG_CATEGORY_STATIC(webkit_web_src_debug);
     
    136135static void webKitWebSrcGetProperty(GObject*, guint propertyID, GValue*, GParamSpec*);
    137136static GstStateChangeReturn webKitWebSrcChangeState(GstElement*, GstStateChange);
    138 
    139 static gboolean webKitWebSrcQueryWithParent(GstPad*, GstObject*, GstQuery*);
    140 
    141 static void webKitWebSrcNeedData(WebKitWebSrc*);
    142 static void webKitWebSrcEnoughData(WebKitWebSrc*);
    143 static gboolean webKitWebSrcSeek(WebKitWebSrc*, guint64);
    144 
    145 static GstAppSrcCallbacks appsrcCallbacks = {
    146     // need_data
    147     [](GstAppSrc*, guint, gpointer userData) {
    148         webKitWebSrcNeedData(WEBKIT_WEB_SRC(userData));
    149     },
    150     // enough_data
    151     [](GstAppSrc*, gpointer userData) {
    152         webKitWebSrcEnoughData(WEBKIT_WEB_SRC(userData));
    153     },
    154     // seek_data
    155     [](GstAppSrc*, guint64 offset, gpointer userData) -> gboolean {
    156         return webKitWebSrcSeek(WEBKIT_WEB_SRC(userData), offset);
    157     },
    158     { nullptr }
    159 };
     137static GstFlowReturn webKitWebSrcCreate(GstPushSrc*, GstBuffer**);
     138static gboolean webKitWebSrcStart(GstBaseSrc*);
     139static gboolean webKitWebSrcStop(GstBaseSrc*);
     140static gboolean webKitWebSrcGetSize(GstBaseSrc*, guint64* size);
     141static gboolean webKitWebSrcIsSeekable(GstBaseSrc*);
     142static gboolean webKitWebSrcDoSeek(GstBaseSrc*, GstSegment*);
     143static gboolean webKitWebSrcQuery(GstBaseSrc*, GstQuery*);
     144static gboolean webKitWebSrcUnLock(GstBaseSrc*);
     145static gboolean webKitWebSrcUnLockStop(GstBaseSrc*);
    160146
    161147#define webkit_web_src_parent_class parent_class
    162148// We split this out into another macro to avoid a check-webkit-style error.
    163149#define WEBKIT_WEB_SRC_CATEGORY_INIT GST_DEBUG_CATEGORY_INIT(webkit_web_src_debug, "webkitwebsrc", 0, "websrc element");
    164 G_DEFINE_TYPE_WITH_CODE(WebKitWebSrc, webkit_web_src, GST_TYPE_BIN,
    165                          G_IMPLEMENT_INTERFACE(GST_TYPE_URI_HANDLER, webKitWebSrcUriHandlerInit);
    166                          WEBKIT_WEB_SRC_CATEGORY_INIT);
     150G_DEFINE_TYPE_WITH_CODE(WebKitWebSrc, webkit_web_src, GST_TYPE_PUSH_SRC,
     151    G_IMPLEMENT_INTERFACE(GST_TYPE_URI_HANDLER, webKitWebSrcUriHandlerInit);
     152    WEBKIT_WEB_SRC_CATEGORY_INIT);
    167153
    168154static void webkit_web_src_class_init(WebKitWebSrcClass* klass)
    169155{
    170156    GObjectClass* oklass = G_OBJECT_CLASS(klass);
    171     GstElementClass* eklass = GST_ELEMENT_CLASS(klass);
    172157
    173158    oklass->dispose = webKitWebSrcDispose;
     
    176161    oklass->get_property = webKitWebSrcGetProperty;
    177162
    178     gst_element_class_add_pad_template(eklass,
    179                                        gst_static_pad_template_get(&srcTemplate));
     163    GstElementClass* eklass = GST_ELEMENT_CLASS(klass);
     164    gst_element_class_add_static_pad_template(eklass, &srcTemplate);
     165
    180166    gst_element_class_set_metadata(eklass, "WebKit Web source element", "Source", "Handles HTTP/HTTPS uris",
    181                                "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
     167        "Philippe Normand <philn@igalia.com>");
    182168
    183169    /* Allows setting the uri using the 'location' property, which is used
     
    207193            nullptr, static_cast<GParamFlags>(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
    208194
    209     eklass->change_state = webKitWebSrcChangeState;
     195    eklass->change_state = GST_DEBUG_FUNCPTR(webKitWebSrcChangeState);
     196
     197    GstBaseSrcClass* baseSrcClass = GST_BASE_SRC_CLASS(klass);
     198    baseSrcClass->start = GST_DEBUG_FUNCPTR(webKitWebSrcStart);
     199    baseSrcClass->stop = GST_DEBUG_FUNCPTR(webKitWebSrcStop);
     200    baseSrcClass->unlock = GST_DEBUG_FUNCPTR(webKitWebSrcUnLock);
     201    baseSrcClass->unlock_stop = GST_DEBUG_FUNCPTR(webKitWebSrcUnLockStop);
     202    baseSrcClass->get_size = GST_DEBUG_FUNCPTR(webKitWebSrcGetSize);
     203    baseSrcClass->is_seekable = GST_DEBUG_FUNCPTR(webKitWebSrcIsSeekable);
     204    baseSrcClass->do_seek = GST_DEBUG_FUNCPTR(webKitWebSrcDoSeek);
     205    baseSrcClass->query = GST_DEBUG_FUNCPTR(webKitWebSrcQuery);
     206
     207    GstPushSrcClass* pushSrcClass = GST_PUSH_SRC_CLASS(klass);
     208    pushSrcClass->create = GST_DEBUG_FUNCPTR(webKitWebSrcCreate);
    210209
    211210    g_type_class_add_private(klass, sizeof(WebKitWebSrcPrivate));
     211}
     212
     213
     214static void webkitWebSrcReset(WebKitWebSrc* src)
     215{
     216    WebKitWebSrcPrivate* priv = WEBKIT_WEB_SRC_GET_PRIVATE(src);
     217
     218    priv->haveSize = false;
     219    priv->wereHeadersReceived = false;
     220    priv->isSeekable = false;
     221    priv->readPosition = 0;
     222    priv->requestedPosition = 0;
     223    priv->stopPosition = -1;
     224    priv->size = 0;
    212225}
    213226
     
    220233
    221234    priv->notifier = MainThreadNotifier<MainThreadSourceNotification>::create();
    222 
    223     priv->haveSize = FALSE;
    224     priv->size = 0;
    225 
    226     priv->appsrc = GST_APP_SRC(gst_element_factory_make("appsrc", nullptr));
    227     if (!priv->appsrc) {
    228         GST_ERROR_OBJECT(src, "Failed to create appsrc");
    229         return;
    230     }
    231 
    232     gst_bin_add(GST_BIN(src), GST_ELEMENT(priv->appsrc));
    233 
    234     GRefPtr<GstPad> targetPad = adoptGRef(gst_element_get_static_pad(GST_ELEMENT(priv->appsrc), "src"));
    235     priv->srcpad = webkitGstGhostPadFromStaticTemplate(&srcTemplate, "src", targetPad.get());
    236 
    237     gst_element_add_pad(GST_ELEMENT(src), priv->srcpad);
    238 
    239     GST_OBJECT_FLAG_SET(priv->srcpad, GST_PAD_FLAG_NEED_PARENT);
    240     gst_pad_set_query_function(priv->srcpad, webKitWebSrcQueryWithParent);
    241 
    242     gst_app_src_set_callbacks(priv->appsrc, &appsrcCallbacks, src, nullptr);
    243     gst_app_src_set_emit_signals(priv->appsrc, FALSE);
    244     gst_app_src_set_stream_type(priv->appsrc, GST_APP_STREAM_TYPE_SEEKABLE);
    245 
    246     // 512k is a abitrary number but we should choose a value
    247     // here to not pause/unpause the SoupMessage too often and
    248     // to make sure there's always some data available for
    249     // GStreamer to handle.
    250     gst_app_src_set_max_bytes(priv->appsrc, 512 * 1024);
    251 
    252     // Emit the need-data signal if the queue contains less
    253     // than 20% of data. Without this the need-data signal
    254     // is emitted when the queue is empty, we then dispatch
    255     // the soup message unpausing to the main loop and from
    256     // there unpause the soup message. This already takes
    257     // quite some time and libsoup even needs some more time
    258     // to actually provide data again. If we do all this
    259     // already if the queue is 20% empty, it's much more
    260     // likely that libsoup already provides new data before
    261     // the queue is really empty.
    262     // This might need tweaking for ports not using libsoup.
    263     g_object_set(priv->appsrc, "min-percent", 20, nullptr);
    264 
    265     gst_base_src_set_automatic_eos(GST_BASE_SRC(priv->appsrc), FALSE);
    266 
    267     gst_app_src_set_caps(priv->appsrc, nullptr);
    268 
    269     priv->minimumBlocksize = gst_base_src_get_blocksize(GST_BASE_SRC_CAST(priv->appsrc));
     235    priv->adapter = adoptGRef(gst_adapter_new());
     236    priv->minimumBlocksize = gst_base_src_get_blocksize(GST_BASE_SRC_CAST(src));
     237
     238    webkitWebSrcReset(src);
     239    gst_base_src_set_automatic_eos(GST_BASE_SRC_CAST(src), FALSE);
    270240}
    271241
     
    348318}
    349319
    350 static void webKitWebSrcStop(WebKitWebSrc* src)
    351 {
    352     WebKitWebSrcPrivate* priv = src->priv;
    353 
    354     if (priv->resource || (priv->loader && !priv->keepAlive)) {
    355         GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src);
    356         priv->notifier->cancelPendingNotifications(MainThreadSourceNotification::NeedData | MainThreadSourceNotification::EnoughData | MainThreadSourceNotification::Seek);
    357         priv->notifier->notify(MainThreadSourceNotification::Stop, [protector, keepAlive = priv->keepAlive] {
    358             WebKitWebSrcPrivate* priv = protector->priv;
    359 
    360             if (priv->resource) {
    361                 priv->resource->stop();
    362                 priv->resource->setClient(nullptr);
    363                 priv->resource = nullptr;
    364             }
    365 
    366             if (!keepAlive)
    367                 priv->loader = nullptr;
     320static GstFlowReturn webKitWebSrcCreate(GstPushSrc* pushSrc, GstBuffer** buffer)
     321{
     322    GstBaseSrc* baseSrc = GST_BASE_SRC_CAST(pushSrc);
     323    WebKitWebSrc* src = WEBKIT_WEB_SRC(baseSrc);
     324    WebKitWebSrcPrivate* priv = src->priv;
     325
     326    GST_TRACE_OBJECT(src, "readPosition = %" G_GUINT64_FORMAT " requestedPosition = %" G_GUINT64_FORMAT, priv->readPosition, priv->requestedPosition);
     327
     328    if (priv->requestedPosition != priv->readPosition) {
     329        {
     330            LockHolder adapterLocker(priv->adapterLock);
     331            GST_DEBUG_OBJECT(src, "Seeking, flushing adapter");
     332            // Discard all the buffers coming before the requested seek position.
     333            gst_adapter_flush(priv->adapter.get(), priv->queueSize);
     334            priv->queueSize = 0;
     335        }
     336        uint64_t requestedPosition = priv->requestedPosition;
     337        webKitWebSrcStop(baseSrc);
     338        priv->requestedPosition = requestedPosition;
     339        webKitWebSrcStart(baseSrc);
     340    }
     341
     342    {
     343        LockHolder locker(priv->responseLock);
     344        priv->responseCondition.wait(priv->responseLock, [priv] () {
     345            return priv->wasResponseReceived || priv->isFlushing;
    368346        });
    369347    }
    370348
    371     bool wasSeeking = std::exchange(priv->isSeeking, false);
    372 
    373     priv->paused = false;
    374 
    375     priv->offset = 0;
    376 
    377     if (!wasSeeking) {
    378         priv->requestedOffset = 0;
    379         priv->player = nullptr;
    380         priv->seekable = FALSE;
    381     }
    382 
    383     if (priv->appsrc) {
    384         gst_app_src_set_caps(priv->appsrc, nullptr);
    385         if (!wasSeeking)
    386             gst_app_src_set_size(priv->appsrc, -1);
    387     }
    388 
    389     GST_DEBUG_OBJECT(src, "Stopped request");
     349    GST_TRACE_OBJECT(src, "flushing: %s, doesHaveEOS: %s, queueSize: %" G_GSIZE_FORMAT, boolForPrinting(priv->isFlushing), boolForPrinting(priv->doesHaveEOS), priv->queueSize);
     350
     351    if (priv->isFlushing) {
     352        GST_DEBUG_OBJECT(src, "Flushing");
     353        return GST_FLOW_FLUSHING;
     354    }
     355
     356    if (priv->doesHaveEOS) {
     357        GST_DEBUG_OBJECT(src, "EOS");
     358        return GST_FLOW_EOS;
     359    }
     360
     361    unsigned size = gst_base_src_get_blocksize(baseSrc);
     362    bool isAdapterDrained = false;
     363    {
     364        LockHolder adapterLocker(priv->adapterLock);
     365        unsigned retries = 0;
     366        size_t available = gst_adapter_available_fast(priv->adapter.get());
     367        while (available < size && !isAdapterDrained) {
     368            priv->adapterCondition.waitFor(priv->adapterLock, Seconds(1));
     369            retries++;
     370            available = gst_adapter_available_fast(priv->adapter.get());
     371            if (available && available < size)
     372                size = available;
     373            else if (retries > 3)
     374                isAdapterDrained = true;
     375        }
     376    }
     377
     378    if (isAdapterDrained) {
     379        GST_DEBUG_OBJECT(src, "Adapter still empty after 3 seconds of waiting, assuming EOS");
     380        return GST_FLOW_EOS;
     381    }
     382
     383    if (priv->haveSize && !priv->isDurationSet) {
     384        GST_DEBUG_OBJECT(src, "Setting duration to %" G_GUINT64_FORMAT, priv->size);
     385        baseSrc->segment.duration = priv->size;
     386        priv->isDurationSet = true;
     387        gst_element_post_message(GST_ELEMENT_CAST(src), gst_message_new_duration_changed(GST_OBJECT_CAST(src)));
     388    }
     389
     390    if (priv->httpHeadersEvent)
     391        gst_pad_push_event(GST_BASE_SRC_PAD(baseSrc), priv->httpHeadersEvent.leakRef());
     392
     393    {
     394        GST_TRACE_OBJECT(src, "Taking %u bytes from adapter", size);
     395        LockHolder adapterLocker(priv->adapterLock);
     396        if (size) {
     397            *buffer = gst_adapter_take_buffer_fast(priv->adapter.get(), size);
     398            RELEASE_ASSERT(*buffer);
     399
     400            priv->queueSize -= size;
     401
     402            GST_BUFFER_OFFSET(*buffer) = baseSrc->segment.position;
     403            GST_BUFFER_OFFSET_END(*buffer) = GST_BUFFER_OFFSET(*buffer) + size;
     404            GST_TRACE_OBJECT(src, "Buffer bounds set to %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT, GST_BUFFER_OFFSET(*buffer), GST_BUFFER_OFFSET_END(*buffer));
     405            GST_TRACE_OBJECT(src, "doesHaveEOS: %s, wasSeeking: %s, seeking: %s, size: %u", boolForPrinting(priv->doesHaveEOS), boolForPrinting(priv->wasSeeking), boolForPrinting(priv->isSeeking), size);
     406            if (priv->haveSize && GST_BUFFER_OFFSET_END(*buffer) >= priv->size) {
     407                if (priv->wasSeeking)
     408                    priv->wasSeeking = false;
     409                else
     410                    priv->doesHaveEOS = true;
     411            } else if (priv->wasSeeking)
     412                priv->wasSeeking = false;
     413        } else
     414            GST_ERROR_OBJECT(src, "Empty adapter?");
     415    }
     416
     417    return GST_FLOW_OK;
    390418}
    391419
     
    441469}
    442470
    443 static void webKitWebSrcStart(WebKitWebSrc* src)
    444 {
     471static gboolean webKitWebSrcStart(GstBaseSrc* baseSrc)
     472{
     473    WebKitWebSrc* src = WEBKIT_WEB_SRC(baseSrc);
    445474    WebKitWebSrcPrivate* priv = src->priv;
    446475    ASSERT(priv->player);
     476
     477    priv->wereHeadersReceived = false;
     478    priv->wasResponseReceived = false;
     479    priv->isDurationSet = false;
     480    priv->doesHaveEOS = false;
     481    priv->isFlushing = false;
    447482
    448483    priv->didPassAccessControlCheck = false;
     
    450485    if (priv->originalURI.isNull()) {
    451486        GST_ERROR_OBJECT(src, "No URI provided");
    452         webKitWebSrcStop(src);
    453         return;
     487        webKitWebSrcStop(baseSrc);
     488        return FALSE;
     489    }
     490
     491    if (priv->requestedPosition == priv->stopPosition) {
     492        GST_DEBUG_OBJECT(src, "Empty segment, signaling EOS");
     493        priv->doesHaveEOS = true;
     494        return FALSE;
    454495    }
    455496
     
    485526        request.setHTTPUserAgent("Quicktime/7.6.6");
    486527
    487     if (priv->requestedOffset) {
    488         GUniquePtr<gchar> val(g_strdup_printf("bytes=%" G_GUINT64_FORMAT "-", priv->requestedOffset));
    489         request.setHTTPHeaderField(HTTPHeaderName::Range, val.get());
    490     }
    491     priv->offset = priv->requestedOffset;
     528    if (priv->requestedPosition) {
     529        GUniquePtr<char> formatedRange(g_strdup_printf("bytes=%" G_GUINT64_FORMAT "-", priv->requestedPosition));
     530        GST_DEBUG_OBJECT(src, "Range request: %s", formatedRange.get());
     531        request.setHTTPHeaderField(HTTPHeaderName::Range, formatedRange.get());
     532    }
     533    priv->readPosition = priv->requestedPosition;
    492534
    493535    GST_DEBUG_OBJECT(src, "Persistent connection support %s", priv->keepAlive ? "enabled" : "disabled");
    494     if (!priv->keepAlive) {
     536    if (!priv->keepAlive)
    495537        request.setHTTPHeaderField(HTTPHeaderName::Connection, "close");
    496     }
    497538
    498539    if (priv->extraHeaders)
     
    503544
    504545    GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src);
    505     priv->notifier->notify(MainThreadSourceNotification::Start, [protector, request = WTFMove(request)] {
     546    priv->notifier->notifyAndWait(MainThreadSourceNotification::Start, [protector, request = WTFMove(request)] {
    506547        WebKitWebSrcPrivate* priv = protector->priv;
    507 
    508548        if (!priv->loader)
    509549            priv->loader = priv->player->createResourceLoader();
     
    519559            GST_ERROR_OBJECT(protector.get(), "Failed to setup streaming client");
    520560            priv->loader = nullptr;
    521             webKitWebSrcStop(protector.get());
    522561        }
    523562    });
    524 }
    525 
    526 static GstStateChangeReturn webKitWebSrcChangeState(GstElement* element, GstStateChange transition)
    527 {
    528     GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
    529     WebKitWebSrc* src = WEBKIT_WEB_SRC(element);
    530     WebKitWebSrcPrivate* priv = src->priv;
    531 
    532     switch (transition) {
    533     case GST_STATE_CHANGE_NULL_TO_READY:
    534         if (!priv->appsrc) {
    535             gst_element_post_message(element,
    536                                      gst_missing_element_message_new(element, "appsrc"));
    537             GST_ELEMENT_ERROR(src, CORE, MISSING_PLUGIN, (nullptr), ("no appsrc"));
    538             return GST_STATE_CHANGE_FAILURE;
    539         }
    540         break;
    541     default:
    542         break;
    543     }
    544 
    545     ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
    546     if (G_UNLIKELY(ret == GST_STATE_CHANGE_FAILURE)) {
    547         GST_DEBUG_OBJECT(src, "State change failed");
    548         return ret;
    549     }
    550 
    551     switch (transition) {
    552     case GST_STATE_CHANGE_READY_TO_PAUSED:
     563
     564    GST_DEBUG_OBJECT(src, "Resource loader started");
     565    return TRUE;
     566}
     567
     568static void webKitWebSrcCloseSession(WebKitWebSrc* src)
     569{
     570    WebKitWebSrcPrivate* priv = src->priv;
     571    GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src);
     572
     573    priv->notifier->notifyAndWait(MainThreadSourceNotification::Stop, [protector, keepAlive = priv->keepAlive] {
     574        WebKitWebSrcPrivate* priv = protector->priv;
     575
     576        GST_DEBUG_OBJECT(protector.get(), "Stopping resource loader");
     577
     578        if (priv->resource) {
     579            priv->resource->stop();
     580            priv->resource->setClient(nullptr);
     581            priv->resource = nullptr;
     582        }
     583
     584        if (!keepAlive)
     585            priv->loader = nullptr;
     586    });
     587
     588    GST_DEBUG_OBJECT(src, "Resource loader stopped");
     589}
     590
     591static gboolean webKitWebSrcStop(GstBaseSrc* baseSrc)
     592{
     593    WebKitWebSrc* src = WEBKIT_WEB_SRC(baseSrc);
     594    WebKitWebSrcPrivate* priv = src->priv;
     595
     596    if (priv->resource || (priv->loader && !priv->keepAlive))
     597        webKitWebSrcCloseSession(src);
     598
    553599    {
    554         GST_DEBUG_OBJECT(src, "READY->PAUSED");
    555         webKitWebSrcStart(src);
    556         break;
    557     }
    558     case GST_STATE_CHANGE_PAUSED_TO_READY:
    559     {
    560         GST_DEBUG_OBJECT(src, "PAUSED->READY");
    561         webKitWebSrcStop(src);
    562         break;
    563     }
    564     default:
    565         break;
    566     }
    567 
    568     return ret;
    569 }
    570 
    571 static gboolean webKitWebSrcQueryWithParent(GstPad* pad, GstObject* parent, GstQuery* query)
    572 {
    573     WebKitWebSrc* src = WEBKIT_WEB_SRC(GST_ELEMENT(parent));
     600        LockHolder adapterLocker(priv->adapterLock);
     601        gst_adapter_clear(priv->adapter.get());
     602        priv->queueSize = 0;
     603    }
     604
     605    webkitWebSrcReset(src);
     606    GST_DEBUG_OBJECT(src, "Stopped request");
     607    return TRUE;
     608}
     609
     610static gboolean webKitWebSrcGetSize(GstBaseSrc* baseSrc, guint64* size)
     611{
     612    WebKitWebSrc* src = WEBKIT_WEB_SRC(baseSrc);
     613    WebKitWebSrcPrivate* priv = src->priv;
     614
     615    GST_DEBUG_OBJECT(src, "haveSize: %s, size: %" G_GUINT64_FORMAT, boolForPrinting(priv->haveSize), priv->size);
     616    if (priv->haveSize) {
     617        *size = priv->size;
     618        return TRUE;
     619    }
     620
     621    return FALSE;
     622}
     623
     624static gboolean webKitWebSrcIsSeekable(GstBaseSrc* baseSrc)
     625{
     626    WebKitWebSrc* src = WEBKIT_WEB_SRC(baseSrc);
     627
     628    GST_DEBUG_OBJECT(src, "isSeekable: %s", boolForPrinting(src->priv->isSeekable));
     629    return src->priv->isSeekable;
     630}
     631
     632static gboolean webKitWebSrcDoSeek(GstBaseSrc* baseSrc, GstSegment* segment)
     633{
     634    WebKitWebSrc* src = WEBKIT_WEB_SRC(baseSrc);
     635    WebKitWebSrcPrivate* priv = src->priv;
     636    LockHolder locker(priv->responseLock);
     637
     638    GST_DEBUG_OBJECT(src, "Seek segment: (%" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT ")", segment->start, segment->stop);
     639    if (priv->readPosition == segment->start && priv->requestedPosition == priv->readPosition && priv->stopPosition == segment->stop) {
     640        GST_DEBUG_OBJECT(src, "Seek to current read/end position and no seek pending");
     641        return TRUE;
     642    }
     643
     644    if (priv->wereHeadersReceived && !priv->isSeekable) {
     645        GST_WARNING_OBJECT(src, "Not seekable");
     646        return FALSE;
     647    }
     648
     649    if (segment->rate < 0.0 || segment->format != GST_FORMAT_BYTES) {
     650        GST_WARNING_OBJECT(src, "Invalid seek segment");
     651        return FALSE;
     652    }
     653
     654    if (priv->haveSize && segment->start >= priv->size)
     655        GST_WARNING_OBJECT(src, "Potentially seeking behind end of file, might EOS immediately");
     656
     657    priv->isSeeking = true;
     658    priv->requestedPosition = segment->start;
     659    priv->stopPosition = segment->stop;
     660    return TRUE;
     661}
     662
     663static gboolean webKitWebSrcQuery(GstBaseSrc* baseSrc, GstQuery* query)
     664{
     665    WebKitWebSrc* src = WEBKIT_WEB_SRC(baseSrc);
    574666    WebKitWebSrcPrivate* priv = src->priv;
    575667    gboolean result = FALSE;
    576668
    577     switch (GST_QUERY_TYPE(query)) {
    578     case GST_QUERY_URI: {
     669    if (GST_QUERY_TYPE(query) == GST_QUERY_URI) {
    579670        gst_query_set_uri(query, priv->originalURI.data());
    580671        if (!priv->redirectedURI.isNull())
    581672            gst_query_set_uri_redirection(query, priv->redirectedURI.data());
    582673        result = TRUE;
    583         break;
    584     }
    585     case GST_QUERY_SCHEDULING: {
     674    }
     675
     676    if (!result)
     677        result = GST_BASE_SRC_CLASS(parent_class)->query(baseSrc, query);
     678
     679    if (GST_QUERY_TYPE(query) == GST_QUERY_SCHEDULING) {
    586680        GstSchedulingFlags flags;
    587681        int minSize, maxSize, align;
     
    589683        gst_query_parse_scheduling(query, &flags, &minSize, &maxSize, &align);
    590684        gst_query_set_scheduling(query, static_cast<GstSchedulingFlags>(flags | GST_SCHEDULING_FLAG_BANDWIDTH_LIMITED), minSize, maxSize, align);
    591         result = TRUE;
    592         break;
    593     }
    594     default: {
    595         GRefPtr<GstPad> target = adoptGRef(gst_ghost_pad_get_target(GST_GHOST_PAD_CAST(pad)));
    596 
    597         // Forward the query to the proxy target pad.
    598         if (target)
    599             result = gst_pad_query(target.get(), query);
    600         break;
    601     }
    602685    }
    603686
    604687    return result;
     688}
     689
     690static gboolean webKitWebSrcUnLock(GstBaseSrc* baseSrc)
     691{
     692    WebKitWebSrc* src = WEBKIT_WEB_SRC(baseSrc);
     693    LockHolder locker(src->priv->responseLock);
     694
     695    GST_DEBUG_OBJECT(src, "Unlock");
     696    src->priv->isFlushing = true;
     697    src->priv->responseCondition.notifyOne();
     698    return TRUE;
     699}
     700
     701static gboolean webKitWebSrcUnLockStop(GstBaseSrc* baseSrc)
     702{
     703    WebKitWebSrc* src = WEBKIT_WEB_SRC(baseSrc);
     704    LockHolder locker(src->priv->responseLock);
     705    GST_DEBUG_OBJECT(src, "Unlock stop");
     706    src->priv->isFlushing = false;
     707
     708    return TRUE;
     709}
     710
     711static GstStateChangeReturn webKitWebSrcChangeState(GstElement* element, GstStateChange transition)
     712{
     713    WebKitWebSrc* src = WEBKIT_WEB_SRC(element);
     714
     715#if GST_CHECK_VERSION(1, 14, 0)
     716    GST_DEBUG_OBJECT(src, gst_state_change_get_name(transition));
     717#endif
     718    switch (transition) {
     719    case GST_STATE_CHANGE_READY_TO_NULL:
     720        webKitWebSrcCloseSession(src);
     721        break;
     722    default:
     723        break;
     724    }
     725
     726    return GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
    605727}
    606728
     
    673795}
    674796
    675 static void webKitWebSrcNeedData(WebKitWebSrc* src)
    676 {
    677     WebKitWebSrcPrivate* priv = src->priv;
    678 
    679     GST_LOG_OBJECT(src, "Need more data");
    680 
    681     if (!priv->paused)
    682         return;
    683     priv->paused = false;
    684 
    685     GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src);
    686     priv->notifier->notify(MainThreadSourceNotification::NeedData, [protector] { });
    687 }
    688 
    689 static void webKitWebSrcEnoughData(WebKitWebSrc* src)
    690 {
    691     WebKitWebSrcPrivate* priv = src->priv;
    692 
    693     GST_DEBUG_OBJECT(src, "Have enough data");
    694 
    695     if (priv->paused)
    696         return;
    697     priv->paused = true;
    698 
    699     GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src);
    700     priv->notifier->notify(MainThreadSourceNotification::EnoughData, [protector] {
    701         WebKitWebSrcPrivate* priv = protector->priv;
    702         if (priv->resource)
    703             priv->resource->stop();
    704     });
    705 }
    706 
    707 static gboolean webKitWebSrcSeek(WebKitWebSrc* src, guint64 offset)
    708 {
    709     WebKitWebSrcPrivate* priv = src->priv;
    710 
    711     if (offset == priv->offset && priv->requestedOffset == priv->offset)
    712         return TRUE;
    713 
    714     if (!priv->seekable)
    715         return FALSE;
    716 
    717     priv->isSeeking = true;
    718     priv->requestedOffset = offset;
    719 
    720     GST_DEBUG_OBJECT(src, "Seeking to offset: %" G_GUINT64_FORMAT, src->priv->requestedOffset);
    721 
    722     GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src);
    723     priv->notifier->notify(MainThreadSourceNotification::Seek, [protector] {
    724         webKitWebSrcStop(protector.get());
    725         webKitWebSrcStart(protector.get());
    726     });
    727     return TRUE;
    728 }
    729 
    730797void webKitWebSrcSetMediaPlayer(WebKitWebSrc* src, WebCore::MediaPlayer* player)
    731798{
     
    750817{
    751818    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
    752     WebKitWebSrcPrivate* priv = src->priv;
    753 
    754     uint64_t blocksize = gst_base_src_get_blocksize(GST_BASE_SRC_CAST(priv->appsrc));
    755     GST_LOG_OBJECT(src, "Checking to update blocksize. Read:%" PRIu64 " blocksize:%" PRIu64, bytesRead, blocksize);
     819    GstBaseSrc* baseSrc = GST_BASE_SRC_CAST(src);
     820    WebKitWebSrcPrivate* priv = src->priv;
     821
     822    uint64_t blocksize = gst_base_src_get_blocksize(baseSrc);
     823    GST_LOG_OBJECT(src, "Checking to update blocksize. Read: %" PRIu64 ", current blocksize: %" PRIu64, bytesRead, blocksize);
    756824
    757825    if (bytesRead >= blocksize * s_growBlocksizeLimit) {
     
    762830            blocksize *= s_growBlocksizeFactor;
    763831            GST_DEBUG_OBJECT(src, "Increased blocksize to %" PRIu64, blocksize);
    764             gst_base_src_set_blocksize(GST_BASE_SRC_CAST(priv->appsrc), blocksize);
     832            gst_base_src_set_blocksize(baseSrc, blocksize);
    765833            m_increaseBlocksizeCount = 0;
    766834        }
     
    773841            blocksize = std::max(blocksize, priv->minimumBlocksize);
    774842            GST_DEBUG_OBJECT(src, "Decreased blocksize to %" PRIu64, blocksize);
    775             gst_base_src_set_blocksize(GST_BASE_SRC_CAST(priv->appsrc), blocksize);
     843            gst_base_src_set_blocksize(baseSrc, blocksize);
    776844            m_reduceBlocksizeCount = 0;
    777845        }
     
    799867    if (response.httpStatusCode() >= 400) {
    800868        GST_ELEMENT_ERROR(src, RESOURCE, READ, ("Received %d HTTP error code", response.httpStatusCode()), (nullptr));
    801         gst_app_src_end_of_stream(priv->appsrc);
    802         webKitWebSrcStop(src);
    803         return completionHandler(ShouldContinue::No);
    804     }
    805 
    806     if (priv->isSeeking) {
    807         GST_DEBUG_OBJECT(src, "Seek in progress, ignoring response");
    808         return completionHandler(ShouldContinue::Yes);
    809     }
    810 
    811     if (priv->requestedOffset) {
     869        priv->doesHaveEOS = true;
     870        webKitWebSrcStop(GST_BASE_SRC_CAST(src));
     871        completionHandler(ShouldContinue::No);
     872        return;
     873    }
     874
     875    if (priv->requestedPosition) {
    812876        // Seeking ... we expect a 206 == PARTIAL_CONTENT
    813877        if (response.httpStatusCode() == 200) {
    814878            // Range request didn't have a ranged response; resetting offset.
    815             priv->offset = 0;
     879            priv->readPosition = 0;
    816880        } else if (response.httpStatusCode() != 206) {
    817881            // Range request completely failed.
    818882            GST_ELEMENT_ERROR(src, RESOURCE, READ, ("Received unexpected %d HTTP status code", response.httpStatusCode()), (nullptr));
    819             gst_app_src_end_of_stream(priv->appsrc);
    820             webKitWebSrcStop(src);
    821             return completionHandler(ShouldContinue::No);
     883            priv->doesHaveEOS = true;
     884            webKitWebSrcStop(GST_BASE_SRC_CAST(src));
     885            completionHandler(ShouldContinue::No);
     886            return;
     887        } else {
     888            GST_DEBUG_OBJECT(src, "Range request succeeded");
     889            priv->isSeeking = false;
     890            priv->wasSeeking = true;
    822891        }
    823892    }
    824893
    825894    long long length = response.expectedContentLength();
    826     if (length > 0 && priv->requestedOffset && response.httpStatusCode() == 206)
    827         length += priv->requestedOffset;
    828 
    829     priv->seekable = length > 0 && g_ascii_strcasecmp("none", response.httpHeaderField(HTTPHeaderName::AcceptRanges).utf8().data());
    830 
    831     GST_DEBUG_OBJECT(src, "Size: %lld, seekable: %s", length, priv->seekable ? "yes" : "no");
    832     // notify size/duration
     895    if (length > 0 && priv->requestedPosition && response.httpStatusCode() == 206)
     896        length += priv->requestedPosition;
     897
     898    priv->isSeekable = length > 0 && g_ascii_strcasecmp("none", response.httpHeaderField(HTTPHeaderName::AcceptRanges).utf8().data());
     899
     900    GST_DEBUG_OBJECT(src, "Size: %lld, isSeekable: %s", length, boolForPrinting(priv->isSeekable));
    833901    if (length > 0) {
    834902        if (!priv->haveSize || (static_cast<long long>(priv->size) != length)) {
    835             priv->haveSize = TRUE;
     903            priv->haveSize = true;
    836904            priv->size = length;
    837             gst_app_src_set_size(priv->appsrc, length);
    838         }
    839     } else {
    840         gst_app_src_set_size(priv->appsrc, -1);
    841         if (!priv->seekable)
    842             gst_app_src_set_stream_type(priv->appsrc, GST_APP_STREAM_TYPE_STREAM);
     905            priv->isDurationSet = false;
     906        }
    843907    }
    844908
     
    855919            GST_DEBUG_OBJECT(src, "Response ContentType: %s", contentType.utf8().data());
    856920            gst_caps_set_simple(caps.get(), "content-type", G_TYPE_STRING, contentType.utf8().data(), nullptr);
    857 
    858             gst_app_src_set_stream_type(priv->appsrc, GST_APP_STREAM_TYPE_STREAM);
    859         }
    860     }
    861 
    862     gst_app_src_set_caps(priv->appsrc, caps.get());
    863 
    864     // Emit a GST_EVENT_CUSTOM_DOWNSTREAM_STICKY event and message to let
    865     // GStreamer know about the HTTP headers sent and received.
    866     GstStructure* httpHeaders = gst_structure_new_empty("http-headers");
    867     gst_structure_set(httpHeaders, "uri", G_TYPE_STRING, priv->originalURI.data(),
    868         "http-status-code", G_TYPE_UINT, response.httpStatusCode(), nullptr);
    869     if (!priv->redirectedURI.isNull())
    870         gst_structure_set(httpHeaders, "redirection-uri", G_TYPE_STRING, priv->redirectedURI.data(), nullptr);
    871     GUniquePtr<GstStructure> headers(gst_structure_new_empty("request-headers"));
    872     for (const auto& header : m_request.httpHeaderFields())
    873         gst_structure_set(headers.get(), header.key.utf8().data(), G_TYPE_STRING, header.value.utf8().data(), nullptr);
    874     GST_DEBUG_OBJECT(src, "Request headers going downstream: %" GST_PTR_FORMAT, headers.get());
    875     gst_structure_set(httpHeaders, "request-headers", GST_TYPE_STRUCTURE, headers.get(), nullptr);
    876     headers.reset(gst_structure_new_empty("response-headers"));
    877     for (const auto& header : response.httpHeaderFields())
    878         gst_structure_set(headers.get(), header.key.utf8().data(), G_TYPE_STRING, header.value.utf8().data(), nullptr);
    879     gst_structure_set(httpHeaders, "response-headers", GST_TYPE_STRUCTURE, headers.get(), nullptr);
    880     GST_DEBUG_OBJECT(src, "Response headers going downstream: %" GST_PTR_FORMAT, headers.get());
    881 
    882     gst_element_post_message(GST_ELEMENT_CAST(src), gst_message_new_element(GST_OBJECT_CAST(src),
    883         gst_structure_copy(httpHeaders)));
    884     gst_pad_push_event(GST_BASE_SRC_PAD(priv->appsrc), gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM_STICKY, httpHeaders));
    885    
     921        }
     922    }
     923
     924    if (caps) {
     925        GST_DEBUG_OBJECT(src, "Set caps to %" GST_PTR_FORMAT, caps.get());
     926        gst_base_src_set_caps(GST_BASE_SRC_CAST(src), caps.get());
     927    }
     928
     929    {
     930        LockHolder locker(priv->responseLock);
     931
     932        // Emit a GST_EVENT_CUSTOM_DOWNSTREAM_STICKY event and message to let
     933        // GStreamer know about the HTTP headers sent and received.
     934        GstStructure* httpHeaders = gst_structure_new_empty("http-headers");
     935        gst_structure_set(httpHeaders, "uri", G_TYPE_STRING, priv->originalURI.data(),
     936            "http-status-code", G_TYPE_UINT, response.httpStatusCode(), nullptr);
     937        if (!priv->redirectedURI.isNull())
     938            gst_structure_set(httpHeaders, "redirection-uri", G_TYPE_STRING, priv->redirectedURI.data(), nullptr);
     939        GUniquePtr<GstStructure> headers(gst_structure_new_empty("request-headers"));
     940        for (const auto& header : m_request.httpHeaderFields())
     941            gst_structure_set(headers.get(), header.key.utf8().data(), G_TYPE_STRING, header.value.utf8().data(), nullptr);
     942        GST_DEBUG_OBJECT(src, "Request headers going downstream: %" GST_PTR_FORMAT, headers.get());
     943        gst_structure_set(httpHeaders, "request-headers", GST_TYPE_STRUCTURE, headers.get(), nullptr);
     944        headers.reset(gst_structure_new_empty("response-headers"));
     945        for (const auto& header : response.httpHeaderFields()) {
     946            bool ok = false;
     947            uint64_t convertedValue = header.value.toUInt64(&ok);
     948            if (ok)
     949                gst_structure_set(headers.get(), header.key.utf8().data(), G_TYPE_UINT64, convertedValue, nullptr);
     950            else
     951                gst_structure_set(headers.get(), header.key.utf8().data(), G_TYPE_STRING, header.value.utf8().data(), nullptr);
     952        }
     953        auto contentLengthFieldName(httpHeaderNameString(HTTPHeaderName::ContentLength).toString());
     954        if (!gst_structure_has_field(headers.get(), contentLengthFieldName.utf8().data()))
     955            gst_structure_set(headers.get(), contentLengthFieldName.utf8().data(), G_TYPE_UINT64, static_cast<uint64_t>(length), nullptr);
     956        gst_structure_set(httpHeaders, "response-headers", GST_TYPE_STRUCTURE, headers.get(), nullptr);
     957        GST_DEBUG_OBJECT(src, "Response headers going downstream: %" GST_PTR_FORMAT, headers.get());
     958
     959        gst_element_post_message(GST_ELEMENT_CAST(src), gst_message_new_element(GST_OBJECT_CAST(src), gst_structure_copy(httpHeaders)));
     960
     961        priv->httpHeadersEvent = adoptGRef(gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM_STICKY, httpHeaders));
     962        priv->wereHeadersReceived = true;
     963        priv->headersCondition.notifyOne();
     964    }
    886965    completionHandler(ShouldContinue::Yes);
    887966}
     
    890969{
    891970    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
    892     WebKitWebSrcPrivate* priv = src->priv;
    893 
    894     if (priv->isSeeking) {
    895         GST_DEBUG_OBJECT(src, "Seek in progress, ignoring data");
    896         return;
    897     }
    898 
    899     if (priv->offset < priv->requestedOffset) {
    900         // Range request failed; seeking manually.
    901         if (priv->offset + length <= priv->requestedOffset) {
    902             // Discard all the buffers coming before the requested seek position.
    903             priv->offset += length;
    904             return;
    905         }
    906 
    907         if (priv->offset + length > priv->requestedOffset) {
    908             guint64 offset = priv->requestedOffset - priv->offset;
    909             data += offset;
    910             length -= offset;
    911             priv->offset = priv->requestedOffset;
    912         }
    913 
    914         priv->requestedOffset = 0;
     971    GstBaseSrc* baseSrc = GST_BASE_SRC_CAST(src);
     972    WebKitWebSrcPrivate* priv = src->priv;
     973
     974    GST_LOG_OBJECT(src, "Have %d bytes of data", length);
     975    LockHolder locker(priv->responseLock);
     976
     977    uint64_t newPosition = priv->readPosition + length;
     978    if (LIKELY (priv->requestedPosition == priv->readPosition))
     979        priv->requestedPosition = newPosition;
     980    priv->readPosition = newPosition;
     981
     982    uint64_t newSize = 0;
     983    if (priv->haveSize && (newPosition > priv->size)) {
     984        GST_DEBUG_OBJECT(src, "Got position previous estimated content size (%" G_GINT64_FORMAT " > %" G_GINT64_FORMAT ")", newPosition, priv->size);
     985        newSize = newPosition;
     986    } else if (!priv->haveSize) {
     987        GST_DEBUG_OBJECT(src, "Got initial response without Content-Length, assuming response size as duration.");
     988        newSize = length;
     989        priv->haveSize = true;
     990    }
     991
     992    if (newSize) {
     993        priv->size = newSize;
     994        baseSrc->segment.duration = priv->size;
     995        gst_element_post_message(GST_ELEMENT_CAST(src), gst_message_new_duration_changed(GST_OBJECT_CAST(src)));
    915996    }
    916997
    917998    checkUpdateBlocksize(length);
    918999
    919     uint64_t startingOffset = priv->offset;
    920 
    921     if (priv->requestedOffset == priv->offset)
    922         priv->requestedOffset += length;
    923     priv->offset += length;
    924     // priv->size == 0 if received length on didReceiveResponse < 0.
    925     if (priv->size > 0 && priv->offset > priv->size) {
    926         GST_DEBUG_OBJECT(src, "Updating internal size from %" G_GUINT64_FORMAT " to %" G_GUINT64_FORMAT, priv->size, priv->offset);
    927         gst_app_src_set_size(priv->appsrc, priv->offset);
    928         priv->size = priv->offset;
    929     }
    930 
    931     // Now split the recv'd buffer into buffers that are of a size basesrc suggests. It is important not
    932     // to push buffers that are too large, otherwise incorrect buffering messages can be sent from the
    933     // pipeline.
    934     uint64_t bufferSize = static_cast<uint64_t>(length);
    935     uint64_t blockSize = static_cast<uint64_t>(gst_base_src_get_blocksize(GST_BASE_SRC_CAST(priv->appsrc)));
    936     GST_LOG_OBJECT(src, "Splitting the received buffer into %" PRIu64 " blocks", bufferSize / blockSize);
    937     for (uint64_t currentOffset = 0; currentOffset < bufferSize; currentOffset += blockSize) {
    938         uint64_t subBufferOffset = startingOffset + currentOffset;
    939         uint64_t currentOffsetSize = std::min(blockSize, bufferSize - currentOffset);
    940 
    941         GstBuffer* subBuffer = gst_buffer_new_wrapped(g_memdup(data + currentOffset, currentOffsetSize), currentOffsetSize);
    942         if (UNLIKELY(!subBuffer)) {
    943             GST_ELEMENT_ERROR(src, CORE, FAILED, ("Failed to allocate sub-buffer"), (nullptr));
    944             break;
    945         }
    946 
    947         GST_TRACE_OBJECT(src, "Sub-buffer bounds: %" PRIu64 " -- %" PRIu64, subBufferOffset, subBufferOffset + currentOffsetSize);
    948         GST_BUFFER_OFFSET(subBuffer) = subBufferOffset;
    949         GST_BUFFER_OFFSET_END(subBuffer) = subBufferOffset + currentOffsetSize;
    950 
    951         if (priv->isSeeking) {
    952             GST_TRACE_OBJECT(src, "Stopping buffer appends due to seek");
    953             // A seek has happened in the middle of us breaking the
    954             // incoming data up from a previous request. Stop pushing
    955             // buffers that are now from the incorrect offset.
    956             break;
    957         }
    958 
    959         // It may be tempting to use a GstBufferList here, but note
    960         // that there is a race condition in GstDownloadBuffer during
    961         // seek flushes that can cause decoders to read at incorrect
    962         // offsets.
    963         GstFlowReturn ret = gst_app_src_push_buffer(priv->appsrc, subBuffer);
    964 
    965         if (UNLIKELY(ret != GST_FLOW_OK && ret != GST_FLOW_EOS && ret != GST_FLOW_FLUSHING)) {
    966             GST_ELEMENT_ERROR(src, CORE, FAILED, (nullptr), (nullptr));
    967             break;
    968         }
     1000    if (!priv->wasResponseReceived)
     1001        priv->wasResponseReceived = true;
     1002    priv->responseCondition.notifyOne();
     1003
     1004    {
     1005        LockHolder adapterLocker(priv->adapterLock);
     1006        GstBuffer* buffer = gst_buffer_new_wrapped(g_memdup(data, length), length);
     1007        priv->queueSize += length;
     1008        gst_adapter_push(priv->adapter.get(), buffer);
     1009        priv->adapterCondition.notifyOne();
    9691010    }
    9701011}
     
    9741015    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
    9751016    GST_ELEMENT_ERROR(src, RESOURCE, READ, ("%s", error.localizedDescription().utf8().data()), (nullptr));
    976     gst_app_src_end_of_stream(src->priv->appsrc);
    977     webKitWebSrcStop(src);
     1017    src->priv->doesHaveEOS = true;
     1018    webKitWebSrcStop(GST_BASE_SRC_CAST(src));
    9781019}
    9791020
     
    9871028    }
    9881029
    989     gst_app_src_end_of_stream(src->priv->appsrc);
     1030    src->priv->doesHaveEOS = true;
    9901031}
    9911032
     
    9951036    WebKitWebSrcPrivate* priv = src->priv;
    9961037
    997     GST_DEBUG_OBJECT(src, "Have EOS");
    998 
    999     if (!priv->isSeeking)
    1000         gst_app_src_end_of_stream(priv->appsrc);
     1038    if (priv->isSeeking && !priv->isFlushing)
     1039        priv->isSeeking = false;
    10011040}
    10021041
  • trunk/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.h

    r236961 r243058  
    2121#if ENABLE(VIDEO) && USE(GSTREAMER)
    2222
     23#include <gst/base/gstpushsrc.h>
    2324#include <gst/gst.h>
    2425
     
    4142
    4243struct _WebKitWebSrc {
    43     GstBin parent;
     44    GstPushSrc parent;
    4445
    4546    WebKitWebSrcPrivate *priv;
     
    4748
    4849struct _WebKitWebSrcClass {
    49     GstBinClass parentClass;
     50    GstPushSrcClass parentClass;
    5051};
    5152
Note: See TracChangeset for help on using the changeset viewer.