WebKit Bugzilla
Attachment 371048 Details for
Bug 197558
: REGRESSION(r243197): [GStreamer] Web process hangs when scrolling twitter timeline which contains HLS videos
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
WiP patch
0001-WIP.patch (text/plain), 29.14 KB, created by
Philippe Normand
on 2019-05-31 03:52:48 PDT
(
hide
)
Description:
WiP patch
Filename:
MIME Type:
Creator:
Philippe Normand
Created:
2019-05-31 03:52:48 PDT
Size:
29.14 KB
patch
obsolete
>From c95144a19b4424b8fc6a488ce74de47bb9da412d Mon Sep 17 00:00:00 2001 >From: Philippe Normand <pnormand@igalia.com> >Date: Thu, 9 May 2019 12:24:08 +0100 >Subject: [PATCH xserver] WIP > >--- > Source/WebCore/ChangeLog | 46 ++++++ > Source/WebCore/platform/AbortableTaskQueue.h | 3 + > .../AudioSourceProviderGStreamer.cpp | 1 + > .../graphics/gstreamer/MainThreadNotifier.h | 89 +++++++--- > .../gstreamer/MediaPlayerPrivateGStreamer.cpp | 3 +- > .../MediaPlayerPrivateGStreamerBase.cpp | 17 +- > .../gstreamer/TrackPrivateBaseGStreamer.cpp | 2 + > .../gstreamer/WebKitWebSourceGStreamer.cpp | 153 ++++++++++++++++-- > .../mse/WebKitMediaSourceGStreamer.cpp | 1 + > 9 files changed, 279 insertions(+), 36 deletions(-) > >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index d3ceeb9a62c..6157acd5bcc 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,49 @@ >+2019-05-09 Philippe Normand <pnormand@igalia.com> >+ >+ REGRESSION(r243197): [GStreamer] Web process hangs when scrolling twitter timeline which contains HLS videos >+ https://bugs.webkit.org/show_bug.cgi?id=197558 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ The deadlock was due to the player disposal running and blocking >+ the main thread while the webkitwebsrc element used to download >+ fragments requires the main thread as well to close its HTTP >+ session. The proposed solution is to ask all webkitwebsrc elements >+ to close their session before disposing of the whole pipeline. >+ >+ This patch also includes GStreamer logging support for the >+ MainThreadNotifier. Whenever possible the notifier uses a >+ reference of the GStreamer object that is most likely associated >+ with it, to facilitate debugging. >+ >+ * platform/audio/gstreamer/AudioSourceProviderGStreamer.cpp: >+ (WebCore::AudioSourceProviderGStreamer::AudioSourceProviderGStreamer): >+ Associate notifier with the MediaStream pipeline. >+ * platform/graphics/gstreamer/MainThreadNotifier.h: Add logging >+ support. Usual GST_TRACE macros can't be used here because we >+ can't safely assume GST_CAT_DEFAULT is defined, because this is a >+ header file. >+ * platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp: >+ (WebCore::MediaPlayerPrivateGStreamerBase::~MediaPlayerPrivateGStreamerBase): >+ Close HTTP sessions before tearing down the whole pipeline. >+ (WebCore::MediaPlayerPrivateGStreamerBase::setPipeline): Associate >+ notifier with the playback pipeline. >+ * platform/graphics/gstreamer/TrackPrivateBaseGStreamer.cpp: >+ (WebCore::TrackPrivateBaseGStreamer::TrackPrivateBaseGStreamer): >+ Associate notifier with pad or GstStream, depending on the runtime >+ use-case. >+ * platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp: >+ (webkit_web_src_class_init): Add an event handler. >+ (webkit_web_src_init): Associate notifier with the src element. >+ (webKitWebSrcCloseSession): Cancel pending notifications and >+ return early if the HTTP session was already closed. >+ (webKitWebSrcEvent): Handle custom upstream webkit-close-http-session events. >+ (webKitWebSrcStop): Session is now closed from the event handler. >+ (webKitWebSrcUnLock): Cancel pending notifications, might avoid >+ potential deadlocks as well. >+ * platform/graphics/gstreamer/mse/WebKitMediaSourceGStreamer.cpp: >+ (webkit_media_src_init): Associate notifier with the src element. >+ > 2019-05-30 Zan Dobersek <zdobersek@igalia.com> > > Unreviewed. Suppress -Wunused-variable warnings for the unused static >diff --git a/Source/WebCore/platform/AbortableTaskQueue.h b/Source/WebCore/platform/AbortableTaskQueue.h >index 74c7e0e8532..abc48a9f5ae 100644 >--- a/Source/WebCore/platform/AbortableTaskQueue.h >+++ b/Source/WebCore/platform/AbortableTaskQueue.h >@@ -148,6 +148,9 @@ public: > return WTF::nullopt; > > Optional<R> response = WTF::nullopt; >+ if (isMainThread()) >+ return mainThreadTaskHandler(); >+ > postTask([this, &response, &mainThreadTaskHandler]() { > R responseValue = mainThreadTaskHandler(); > LockHolder lockHolder(m_mutex); >diff --git a/Source/WebCore/platform/audio/gstreamer/AudioSourceProviderGStreamer.cpp b/Source/WebCore/platform/audio/gstreamer/AudioSourceProviderGStreamer.cpp >index 54b39f45a5b..e5e2b5a0b84 100644 >--- a/Source/WebCore/platform/audio/gstreamer/AudioSourceProviderGStreamer.cpp >+++ b/Source/WebCore/platform/audio/gstreamer/AudioSourceProviderGStreamer.cpp >@@ -111,6 +111,7 @@ AudioSourceProviderGStreamer::AudioSourceProviderGStreamer(MediaStreamTrackPriva > m_frontRightAdapter = gst_adapter_new(); > auto pipelineName = makeString("WebAudioProvider_MediaStreamTrack_", source.id()); > m_pipeline = adoptGRef(GST_ELEMENT(g_object_ref_sink(gst_element_factory_make("pipeline", pipelineName.utf8().data())))); >+ m_notifier->setGstObject(GST_OBJECT_CAST(m_pipeline.get())); > auto src = webkitMediaStreamSrcNew(); > webkitMediaStreamSrcAddTrack(WEBKIT_MEDIA_STREAM_SRC(src), &source, true); > >diff --git a/Source/WebCore/platform/graphics/gstreamer/MainThreadNotifier.h b/Source/WebCore/platform/graphics/gstreamer/MainThreadNotifier.h >index 3548989216d..c93042ed10c 100644 >--- a/Source/WebCore/platform/graphics/gstreamer/MainThreadNotifier.h >+++ b/Source/WebCore/platform/graphics/gstreamer/MainThreadNotifier.h >@@ -19,12 +19,23 @@ > #pragma once > > #include <functional> >+#include <gst/gst.h> >+#include <inttypes.h> > #include <wtf/Atomics.h> > #include <wtf/Lock.h> > #include <wtf/MainThread.h> >+#include <wtf/PrintStream.h> > #include <wtf/RunLoop.h> > #include <wtf/ThreadSafeRefCounted.h> > >+// This class is used only by components enabled for VIDEO support so far. So >+// it's safe to assume the media player logging category is available. >+GST_DEBUG_CATEGORY_EXTERN(webkit_media_player_debug); >+ >+#define NOTIFIER_TRACE(formatString, ...) GST_CAT_LEVEL_LOG(webkit_media_player_debug, GST_LEVEL_TRACE, m_gstObject.get(), formatString, ##__VA_ARGS__) >+#define NOTIFIER_INFO(formatString, ...) GST_CAT_LEVEL_LOG(webkit_media_player_debug, GST_LEVEL_INFO, m_gstObject.get(), formatString, ##__VA_ARGS__) >+#define NOTIFIER_WARNING(formatString, ...) GST_CAT_LEVEL_LOG(webkit_media_player_debug, GST_LEVEL_WARNING, m_gstObject.get(), formatString, ##__VA_ARGS__) >+ > namespace WebCore { > > template <typename T> >@@ -35,6 +46,11 @@ public: > return adoptRef(*new MainThreadNotifier()); > } > >+ MainThreadNotifier() >+ { >+ m_isValid.store(true); >+ } >+ > ~MainThreadNotifier() > { > ASSERT(!m_isValid.load()); >@@ -45,52 +61,85 @@ public: > template<typename F> > void notify(T notificationType, F&& callbackFunctor) > { >+ NOTIFIER_TRACE("Notify for type %" PRIu64, static_cast<uint64_t>(notificationType)); > ASSERT(m_isValid.load()); > // Assert that there is only one bit on at a time. > ASSERT(!(static_cast<int>(notificationType) & (static_cast<int>(notificationType) - 1))); > if (isMainThread()) { > removePendingNotification(notificationType); > callbackFunctor(); >+ NOTIFIER_TRACE("Functor called on main thread"); > return; > } > >- if (!addPendingNotification(notificationType)) >+ if (!addPendingNotification(notificationType)) { >+ NOTIFIER_INFO("Notification already pending"); > return; >+ } > >- RunLoop::main().dispatch([this, protectedThis = makeRef(*this), notificationType, callback = WTF::Function<void()>(WTFMove(callbackFunctor))] { >- if (!m_isValid.load()) >+ NOTIFIER_TRACE("Scheduling dispatch"); >+ RunLoop::main().dispatch([this, notificationType, callback = WTF::Function<void()>(WTFMove(callbackFunctor))] { >+ NOTIFIER_TRACE("Dispatch"); >+ if (!m_isValid.load()) { >+ NOTIFIER_INFO("Notifier was invalidated, bailing out"); > return; >- if (removePendingNotification(notificationType)) >+ } >+ if (removePendingNotification(notificationType)) { > callback(); >+ NOTIFIER_TRACE("Functor called"); >+ } else >+ NOTIFIER_WARNING("Unable to remove pending notification"); > }); > } > > template<typename F> >- void notifyAndWait(T notificationType, F&& callbackFunctor) >+ bool notifyAndWait(T notificationType, F&& callbackFunctor, Seconds relativeTimeout = Seconds::nan()) > { >- Lock mutex; >- Condition condition; >- >- notify(notificationType, [functor = WTFMove(callbackFunctor), &condition, &mutex] { >+ bool wasTimeoutReached = true; >+ auto wrappedFunctor = [&] () mutable { >+ callbackFunctor(); >+ wasTimeoutReached = false; >+ }; >+ NOTIFIER_TRACE("Blocking notify for type %" PRIu64, notificationType); >+ notify(notificationType, [this, functor = WTFMove(wrappedFunctor)] () mutable { > functor(); >- LockHolder holder(mutex); >- condition.notifyOne(); >+ LockHolder holder(m_synchronousNotificationMutex); >+ m_synchronousNotificationCondition.notifyOne(); > }); > > if (!isMainThread()) { >- LockHolder holder(mutex); >- condition.wait(mutex); >+ NOTIFIER_TRACE("Waiting for completion"); >+ LockHolder holder(m_synchronousNotificationMutex); >+ auto predicate = [this, notificationType] { >+ LockHolder locker(m_pendingNotificationsLock); >+ bool wasNotificationRemoved = !(notificationType & m_pendingNotifications); >+ NOTIFIER_TRACE("Notification removed: %s", boolForPrinting(wasNotificationRemoved)); >+ return wasNotificationRemoved; >+ }; >+ if (relativeTimeout) >+ m_synchronousNotificationCondition.waitFor(m_synchronousNotificationMutex, relativeTimeout, predicate); >+ else >+ m_synchronousNotificationCondition.wait(m_synchronousNotificationMutex, predicate); >+ NOTIFIER_TRACE("Blocking notification completed, timeout: %s", boolForPrinting(wasTimeoutReached)); > } >+ return wasTimeoutReached; > } > >- void cancelPendingNotifications(unsigned mask = 0) >+ void cancelPendingNotifications(uint64_t mask = 0) > { > ASSERT(m_isValid.load()); >+ NOTIFIER_TRACE("Cancelling pending notifications for mask %" PRIu64, mask); >+ > LockHolder locker(m_pendingNotificationsLock); > if (mask) > m_pendingNotifications &= ~mask; > else > m_pendingNotifications = 0; >+ >+ { >+ LockHolder holder(m_synchronousNotificationMutex); >+ m_synchronousNotificationCondition.notifyAll(); >+ } > } > > void invalidate() >@@ -99,12 +148,12 @@ public: > m_isValid.store(false); > } > >-private: >- MainThreadNotifier() >+ void setGstObject(GstObject* object) > { >- m_isValid.store(true); >+ m_gstObject = object; > } > >+private: > bool addPendingNotification(T notificationType) > { > LockHolder locker(m_pendingNotificationsLock); >@@ -118,6 +167,7 @@ private: > { > LockHolder locker(m_pendingNotificationsLock); > if (notificationType & m_pendingNotifications) { >+ NOTIFIER_TRACE("Removing pending notification %" PRIu64, static_cast<uint64_t>(notificationType)); > m_pendingNotifications &= ~notificationType; > return true; > } >@@ -125,8 +175,11 @@ private: > } > > Lock m_pendingNotificationsLock; >- unsigned m_pendingNotifications { 0 }; >+ uint64_t m_pendingNotifications { 0 }; > Atomic<bool> m_isValid; >+ GRefPtr<GstObject> m_gstObject; >+ Lock m_synchronousNotificationMutex; >+ Condition m_synchronousNotificationCondition; > }; > > } // namespace WebCore >diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp >index 4a6dabfbd48..b18abe2af43 100644 >--- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp >+++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp >@@ -2386,8 +2386,7 @@ void MediaPlayerPrivateGStreamer::createGSTPlayBin(const URL& url, const String& > > // gst_element_factory_make() returns a floating reference so > // we should not adopt. >- setPipeline(gst_element_factory_make(playbinName, >- (pipelineName.isEmpty() ? makeString("play_0x", hex(reinterpret_cast<uintptr_t>(this), Lowercase)) : pipelineName).utf8().data())); >+ setPipeline(gst_element_factory_make(playbinName, pipelineName.isEmpty() ? nullptr : pipelineName.utf8().data())); > setStreamVolumeElement(GST_STREAM_VOLUME(m_pipeline.get())); > > GST_INFO_OBJECT(pipeline(), "Using legacy playbin element: %s", boolForPrinting(m_isLegacyPlaybin)); >diff --git a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp >index f0b7a43dd8a..92d3dc4c4b3 100644 >--- a/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp >+++ b/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp >@@ -284,10 +284,19 @@ MediaPlayerPrivateGStreamerBase::~MediaPlayerPrivateGStreamerBase() > // waiting there, and ensure that any triggerRepaint call reaching the lock won't wait on m_drawCondition. > cancelRepaint(true); > >- // The change to GST_STATE_NULL state is always synchronous. So after this gets executed we don't need to worry >- // about handlers running in the GStreamer thread. >- if (m_pipeline) >+ if (m_pipeline) { >+ // Notify all webkitwebsrc elements of the pipeline that they should >+ // close their HTTP session ASAP. Because this has to happen in the >+ // WebProcess main thread it might deadlock HLS pipelines if that was >+ // requested during a standard PAUSED->READY transition. >+ gst_element_send_event(m_pipeline.get(), gst_event_new_custom(GST_EVENT_CUSTOM_UPSTREAM, >+ gst_structure_new_empty("webkit-close-http-session"))); >+ >+ // The change to GST_STATE_NULL state is always synchronous. So after >+ // this gets executed we don't need to worry about handlers running in >+ // the GStreamer thread. > gst_element_set_state(m_pipeline.get(), GST_STATE_NULL); >+ } > > m_player = nullptr; > } >@@ -296,6 +305,8 @@ void MediaPlayerPrivateGStreamerBase::setPipeline(GstElement* pipeline) > { > m_pipeline = pipeline; > >+ m_notifier->setGstObject(GST_OBJECT_CAST(pipeline)); >+ > GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline.get()))); > gst_bus_set_sync_handler(bus.get(), [](GstBus*, GstMessage* message, gpointer userData) { > auto& player = *static_cast<MediaPlayerPrivateGStreamerBase*>(userData); >diff --git a/Source/WebCore/platform/graphics/gstreamer/TrackPrivateBaseGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/TrackPrivateBaseGStreamer.cpp >index 05ba1e5b123..56f4af37e3f 100644 >--- a/Source/WebCore/platform/graphics/gstreamer/TrackPrivateBaseGStreamer.cpp >+++ b/Source/WebCore/platform/graphics/gstreamer/TrackPrivateBaseGStreamer.cpp >@@ -50,6 +50,7 @@ TrackPrivateBaseGStreamer::TrackPrivateBaseGStreamer(TrackPrivateBase* owner, gi > , m_owner(owner) > { > ASSERT(m_pad); >+ m_notifier->setGstObject(GST_OBJECT_CAST(m_pad.get())); > > g_signal_connect_swapped(m_pad.get(), "notify::active", G_CALLBACK(activeChangedCallback), this); > g_signal_connect_swapped(m_pad.get(), "notify::tags", G_CALLBACK(tagsChangedCallback), this); >@@ -66,6 +67,7 @@ TrackPrivateBaseGStreamer::TrackPrivateBaseGStreamer(TrackPrivateBase* owner, gi > , m_owner(owner) > { > ASSERT(m_stream); >+ m_notifier->setGstObject(GST_OBJECT_CAST(m_stream.get())); > > // We can't call notifyTrackOfTagsChanged() directly, because we need tagsChanged() to setup m_tags. > tagsChanged(); >diff --git a/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp >index 3f6c2f36e1a..423d7207d52 100644 >--- a/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp >+++ b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp >@@ -32,6 +32,7 @@ > #include "ResourceRequest.h" > #include "ResourceResponse.h" > #include <cstdint> >+#include <inttypes.h> > #include <wtf/Condition.h> > #include <wtf/Scope.h> > #include <wtf/text/CString.h> >@@ -72,16 +73,47 @@ private: > HashSet<RefPtr<WebCore::SecurityOrigin>> m_origins; > }; > >-enum MainThreadSourceNotification { >+#define USE_GLOBAL_NOTIFIER 1 >+static MainThreadNotifier<uint64_t> gNotifier; >+static Atomic<uint64_t> gNotificationId = 1; >+ >+#if USE(GLOBAL_NOTIFIER) >+enum class MainThreadSourceNotification2 { >+ Start = 1, >+ Stop = 2, >+ Dispose = 3, >+}; >+ >+static inline uint64_t notificationMask(uint64_t notificationId, MainThreadSourceNotification2 notification) { >+ return 1 << (notificationId + static_cast<uint64_t>(notification)); >+} >+ >+#else >+enum class MainThreadSourceNotification { > Start = 1 << 0, > Stop = 1 << 1, > Dispose = 1 << 2, > }; >+#endif > > #define WEBKIT_WEB_SRC_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), WEBKIT_TYPE_WEB_SRC, WebKitWebSrcPrivate)) > struct _WebKitWebSrcPrivate { > ~_WebKitWebSrcPrivate() > { >+#if USE(GLOBAL_NOTIFIER) >+ if (gNotifier.isValid()) { >+ gNotifier.notifyAndWait(notificationMask(notificationId, MainThreadSourceNotification2::Dispose), [&] { >+ if (resource) { >+ auto* client = static_cast<CachedResourceStreamingClient*>(resource->client()); >+ if (client) >+ client->setSourceElement(nullptr); >+ >+ resource->setClient(nullptr); >+ } >+ loader = nullptr; >+ }); >+ } >+#else > if (notifier && notifier->isValid()) { > notifier->notifyAndWait(MainThreadSourceNotification::Dispose, [&] { > if (resource) { >@@ -96,8 +128,11 @@ struct _WebKitWebSrcPrivate { > notifier->invalidate(); > notifier = nullptr; > } >+#endif > } > >+ uint64_t notificationId; >+ bool disposePending; > CString originalURI; > CString redirectedURI; > bool keepAlive; >@@ -107,7 +142,9 @@ struct _WebKitWebSrcPrivate { > WebCore::MediaPlayer* player; > RefPtr<PlatformMediaResourceLoader> loader; > RefPtr<PlatformMediaResource> resource; >+#if !USE(GLOBAL_NOTIFIER) > RefPtr<MainThreadNotifier<MainThreadSourceNotification>> notifier; >+#endif > bool didPassAccessControlCheck; > bool wereHeadersReceived; > Condition headersCondition; >@@ -165,6 +202,7 @@ static gboolean webKitWebSrcQuery(GstBaseSrc*, GstQuery*); > static gboolean webKitWebSrcUnLock(GstBaseSrc*); > static gboolean webKitWebSrcUnLockStop(GstBaseSrc*); > static void webKitWebSrcSetContext(GstElement*, GstContext*); >+static gboolean webKitWebSrcEvent(GstBaseSrc*, GstEvent*); > > #define webkit_web_src_parent_class parent_class > // We split this out into another macro to avoid a check-webkit-style error. >@@ -225,6 +263,7 @@ static void webkit_web_src_class_init(WebKitWebSrcClass* klass) > baseSrcClass->is_seekable = GST_DEBUG_FUNCPTR(webKitWebSrcIsSeekable); > baseSrcClass->do_seek = GST_DEBUG_FUNCPTR(webKitWebSrcDoSeek); > baseSrcClass->query = GST_DEBUG_FUNCPTR(webKitWebSrcQuery); >+ baseSrcClass->event = GST_DEBUG_FUNCPTR(webKitWebSrcEvent); > > GstPushSrcClass* pushSrcClass = GST_PUSH_SRC_CLASS(klass); > pushSrcClass->create = GST_DEBUG_FUNCPTR(webKitWebSrcCreate); >@@ -237,6 +276,7 @@ static void webkitWebSrcReset(WebKitWebSrc* src) > { > WebKitWebSrcPrivate* priv = WEBKIT_WEB_SRC_GET_PRIVATE(src); > >+ GST_DEBUG_OBJECT(src, "Reset"); > priv->haveSize = false; > priv->wereHeadersReceived = false; > priv->isSeekable = false; >@@ -253,18 +293,28 @@ static void webkit_web_src_init(WebKitWebSrc* src) > src->priv = priv; > new (priv) WebKitWebSrcPrivate(); > >+ priv->notificationId = gNotificationId.exchangeAdd(1); >+ GST_DEBUG_OBJECT(src, "Initialize, notificationId: %" PRIu64, priv->notificationId); >+ >+ priv->disposePending = false; >+#if !USE(GLOBAL_NOTIFIER) > priv->notifier = MainThreadNotifier<MainThreadSourceNotification>::create(); >+ priv->notifier->setGstObject(GST_OBJECT_CAST(src)); >+#endif > priv->adapter = adoptGRef(gst_adapter_new()); > priv->minimumBlocksize = gst_base_src_get_blocksize(GST_BASE_SRC_CAST(src)); > > webkitWebSrcReset(src); > gst_base_src_set_automatic_eos(GST_BASE_SRC_CAST(src), FALSE); >+ //gst_base_src_set_async(GST_BASE_SRC_CAST(src), TRUE); > } > > static void webKitWebSrcDispose(GObject* object) > { >- WebKitWebSrcPrivate* priv = WEBKIT_WEB_SRC(object)->priv; >+ WebKitWebSrc* src = WEBKIT_WEB_SRC(object); >+ WebKitWebSrcPrivate* priv = src->priv; > >+ GST_DEBUG_OBJECT(src, "Disposing"); > priv->~WebKitWebSrcPrivate(); > > GST_CALL_PARENT(G_OBJECT_CLASS, dispose, (object)); >@@ -365,14 +415,18 @@ static GstFlowReturn webKitWebSrcCreate(GstPushSrc* pushSrc, GstBuffer** buffer) > > { > LockHolder locker(priv->responseLock); >- priv->responseCondition.wait(priv->responseLock, [priv] () { >- return priv->wasResponseReceived || priv->isFlushing; >- }); >+ if (!priv->wasResponseReceived && !priv->isFlushing && !priv->disposePending) { >+ priv->responseCondition.waitFor(priv->responseLock, Seconds(3), [src] () { >+ WebKitWebSrcPrivate* priv = src->priv; >+ GST_TRACE_OBJECT(src, "disposePending: %s, flushing: %s, wasResponseReceived: %s", boolForPrinting(priv->disposePending), boolForPrinting(priv->isFlushing), boolForPrinting(priv->wasResponseReceived)); >+ return priv->wasResponseReceived || priv->isFlushing || priv->disposePending; >+ }); >+ } > } > >- GST_TRACE_OBJECT(src, "flushing: %s, doesHaveEOS: %s, queueSize: %" G_GSIZE_FORMAT, boolForPrinting(priv->isFlushing), boolForPrinting(priv->doesHaveEOS), priv->queueSize); >+ GST_TRACE_OBJECT(src, "disposePending: %s, flushing: %s, doesHaveEOS: %s, queueSize: %" G_GSIZE_FORMAT, boolForPrinting(priv->disposePending), boolForPrinting(priv->isFlushing), boolForPrinting(priv->doesHaveEOS), priv->queueSize); > >- if (priv->isFlushing) { >+ if (priv->isFlushing || priv->disposePending || !priv->wasResponseReceived) { > GST_DEBUG_OBJECT(src, "Flushing"); > return GST_FLOW_FLUSHING; > } >@@ -497,6 +551,10 @@ static gboolean webKitWebSrcStart(GstBaseSrc* baseSrc) > WebKitWebSrc* src = WEBKIT_WEB_SRC(baseSrc); > WebKitWebSrcPrivate* priv = src->priv; > >+ GST_DEBUG_OBJECT(src, "Starting up, dispose pending: %s", boolForPrinting(priv->disposePending)); >+ if (priv->disposePending) >+ return FALSE; >+ > if (webkitGstCheckVersion(1, 12, 0) && !priv->player) { > GRefPtr<GstQuery> query = adoptGRef(gst_query_new_context(WEBKIT_WEB_SRC_PLAYER_CONTEXT_TYPE_NAME)); > if (gst_pad_peer_query(GST_BASE_SRC_PAD(baseSrc), query.get())) { >@@ -579,6 +637,25 @@ static gboolean webKitWebSrcStart(GstBaseSrc* baseSrc) > request.setHTTPHeaderField(HTTPHeaderName::IcyMetadata, "1"); > > GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src); >+#if USE(GLOBAL_NOTIFIER) >+ gNotifier.notifyAndWait(notificationMask(priv->notificationId, MainThreadSourceNotification2::Start), [protector, request = WTFMove(request)] { >+ WebKitWebSrcPrivate* priv = protector->priv; >+ if (!priv->loader) >+ priv->loader = priv->player->createResourceLoader(); >+ >+ PlatformMediaResourceLoader::LoadOptions loadOptions = 0; >+ if (request.url().protocolIsBlob()) >+ loadOptions |= PlatformMediaResourceLoader::LoadOption::BufferData; >+ priv->resource = priv->loader->requestResource(ResourceRequest(request), loadOptions); >+ if (priv->resource) { >+ priv->resource->setClient(std::make_unique<CachedResourceStreamingClient>(protector.get(), ResourceRequest(request))); >+ GST_DEBUG_OBJECT(protector.get(), "Started request"); >+ } else { >+ GST_ERROR_OBJECT(protector.get(), "Failed to setup streaming client"); >+ priv->loader = nullptr; >+ } >+ }, Seconds(3)); >+#else > priv->notifier->notifyAndWait(MainThreadSourceNotification::Start, [protector, request = WTFMove(request)] { > WebKitWebSrcPrivate* priv = protector->priv; > if (!priv->loader) >@@ -596,9 +673,10 @@ static gboolean webKitWebSrcStart(GstBaseSrc* baseSrc) > priv->loader = nullptr; > } > }); >+#endif > >- GST_DEBUG_OBJECT(src, "Resource loader started"); >- return TRUE; >+ GST_DEBUG_OBJECT(src, "Resource loader started: %s", boolForPrinting(!!priv->loader)); >+ return !!priv->loader; > } > > static void webKitWebSrcCloseSession(WebKitWebSrc* src) >@@ -606,6 +684,36 @@ static void webKitWebSrcCloseSession(WebKitWebSrc* src) > WebKitWebSrcPrivate* priv = src->priv; > GRefPtr<WebKitWebSrc> protector = WTF::ensureGRef(src); > >+#if USE(GLOBAL_NOTIFIER) >+ gNotifier.cancelPendingNotifications(notificationMask(priv->notificationId, MainThreadSourceNotification2::Start)); >+ gNotifier.cancelPendingNotifications(notificationMask(priv->notificationId, MainThreadSourceNotification2::Stop)); >+ gNotifier.cancelPendingNotifications(notificationMask(priv->notificationId, MainThreadSourceNotification2::Dispose)); >+#else >+ priv->notifier->cancelPendingNotifications(); >+#endif >+ >+ if (!priv->resource || (priv->keepAlive && !priv->loader)) { >+ GST_DEBUG_OBJECT(src, "Session already closed"); >+ return; >+ } >+ >+ GST_DEBUG_OBJECT(src, "Closing session, loader: %p, resource: %p", priv->loader.get(), priv->resource.get()); >+#if USE(GLOBAL_NOTIFIER) >+ if (gNotifier.notifyAndWait(notificationMask(priv->notificationId, MainThreadSourceNotification2::Stop), [protector, keepAlive = priv->keepAlive] { >+ WebKitWebSrcPrivate* priv = protector->priv; >+ >+ GST_DEBUG_OBJECT(protector.get(), "Stopping resource loader"); >+ >+ if (priv->resource) { >+ priv->resource->stop(); >+ priv->resource->setClient(nullptr); >+ priv->resource = nullptr; >+ } >+ >+ if (!keepAlive) >+ priv->loader = nullptr; >+ }, Seconds(3))) >+#else > priv->notifier->notifyAndWait(MainThreadSourceNotification::Stop, [protector, keepAlive = priv->keepAlive] { > WebKitWebSrcPrivate* priv = protector->priv; > >@@ -620,18 +728,32 @@ static void webKitWebSrcCloseSession(WebKitWebSrc* src) > if (!keepAlive) > priv->loader = nullptr; > }); >- >+#endif > GST_DEBUG_OBJECT(src, "Resource loader stopped"); > } > >+static gboolean webKitWebSrcEvent(GstBaseSrc* baseSrc, GstEvent* event) >+{ >+ GST_DEBUG_OBJECT(baseSrc, "Handle event %" GST_PTR_FORMAT, event); >+ const GstStructure* structure = gst_event_get_structure(event); >+ if (structure && gst_structure_has_name(structure, "webkit-close-http-session")) { >+ WebKitWebSrc* src = WEBKIT_WEB_SRC(baseSrc); >+ WebKitWebSrcPrivate* priv = src->priv; >+ >+ priv->disposePending = true; >+ if (priv->resource || (priv->loader && !priv->keepAlive)) >+ webKitWebSrcCloseSession(src); >+ >+ return TRUE; >+ } >+ return GST_BASE_SRC_CLASS(parent_class)->event(baseSrc, event); >+} >+ > static gboolean webKitWebSrcStop(GstBaseSrc* baseSrc) > { > WebKitWebSrc* src = WEBKIT_WEB_SRC(baseSrc); > WebKitWebSrcPrivate* priv = src->priv; > >- if (priv->resource || (priv->loader && !priv->keepAlive)) >- webKitWebSrcCloseSession(src); >- > { > LockHolder adapterLocker(priv->adapterLock); > gst_adapter_clear(priv->adapter.get()); >@@ -731,6 +853,10 @@ static gboolean webKitWebSrcUnLock(GstBaseSrc* baseSrc) > GST_DEBUG_OBJECT(src, "Unlock"); > src->priv->isFlushing = true; > src->priv->responseCondition.notifyOne(); >+#if USE(GLOBAL_NOTIFIER) >+#else >+ src->priv->notifier->cancelPendingNotifications(); >+#endif > return TRUE; > } > >@@ -834,6 +960,7 @@ static gboolean webKitWebSrcSetUri(GstURIHandler* handler, const gchar* uri, GEr > return FALSE; > } > >+ GST_DEBUG_OBJECT(src, "Setting URI to %s", url.string().utf8().data()); > priv->originalURI = url.string().utf8(); > return TRUE; > } >diff --git a/Source/WebCore/platform/graphics/gstreamer/mse/WebKitMediaSourceGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/mse/WebKitMediaSourceGStreamer.cpp >index 1ad44249021..09783e83284 100644 >--- a/Source/WebCore/platform/graphics/gstreamer/mse/WebKitMediaSourceGStreamer.cpp >+++ b/Source/WebCore/platform/graphics/gstreamer/mse/WebKitMediaSourceGStreamer.cpp >@@ -260,6 +260,7 @@ static void webkit_media_src_init(WebKitMediaSrc* source) > source->priv->appsrcSeekDataNextAction = Nothing; > source->priv->flowCombiner = GUniquePtr<GstFlowCombiner>(gst_flow_combiner_new()); > source->priv->notifier = WebCore::MainThreadNotifier<WebKitMediaSrcMainThreadNotification>::create(); >+ source->priv->notifier->setGstObject(GST_OBJECT_CAST(source)); > > // No need to reset Stream.appsrcNeedDataFlag because there are no Streams at this point yet. > } >-- >2.20.1 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 197558
:
369484
|
369493
|
371048
|
373468
|
373621
|
373622