You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[MSE][GStreamer] Support markEndOfStream() before appendBuffer()
https://bugs.webkit.org/show_bug.cgi?id=278726
Reviewed by Xabier Rodriguez-Calvar.
In the past, WebKit MSE couldn't complete playback when JavaScript
performs MediaSource.markEndOfStream() before appending any samples with
SourceBuffer.appendBuffer(). A previous patch added that support, but
still the error keeps happening under some circumstances downstream
(wpe-2.46, GStreamer 1.18) as well as upstream (where it was believed
not to happen in GStreamer 1.24).
This happens when the test case is exercised in a loop and the race
condition for an error occurs while errors are ignored, but the
GstMessage with the error takes a moment to propagate to the main thread
(when the errors are no longer ignored).
See: #1558
This patch now applies the fix to any GStreamer version (because the
issue appears in all of them). When an EOS without buffers happens, the
pipeline goes to READY, and errors are ignored. The m_ignoreErrors flag
is kept enabled while the pipeline is being set to READY, but if any
error has been detected by the sync message handler, it stays enabled
until the last enqueued error is processed by the main thread. In any
case m_ignoreErrors is only changed from the main thread (in different
loop cycles in the worst case, but always from the main thread) and
doesn't need concurrent access protection.
As mentioned in the previous paragraph, a new sync error signal listener
has been added. This listener doesn't do any actual error processing,
just increases the m_queuedSyncErrors counter. The async message handler
will end up getting the error message anyway. That's where the message
will be ignored (if the m_ignoreErrors flag is set) and, ignored or not,
the m_queuedSyncErrors counter will be decremented. Note that this
counter is an Atomic, in order to support access from the (potentially)
non-main thread that handles the sync error signal, from the main thread
that ends up processing the error, and from the main thread that
processes setEosWithNoBuffers().
If an error has happened, an EOS in the pipeline is simulated by calling
didEnd(), the same method that would be called if such an EOS had
happened. This call usually triggers a pipeline teardown and the further
destruction of the player private. This may trigger a
gst_bus_set_flushing() call and cause the error message to never be
dispatched to the main thread. While this may mean that the
m_queuedSyncErrors counter is never decremented, this isn't a real
problem, since the player is being destructed anyway and nobody cares
about the count anymore.
* Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
(WebCore::MediaPlayerPrivateGStreamer::handleSyncErrorMessage): Detect errors as they happen, in the same thread where they were generated (often a non-main thread). The count of m_queuedSyncErrors is atomically increased to indicate the main thread that there are error messages pending to process. There's no need to forward the processing to the main thread, since the bus will eventually dispatch it asynchronously.
(WebCore::MediaPlayerPrivateGStreamer::handleMessage): If the last error is being processed while in a "ignore errors" state, reset the state to false. Also, exit early if we were in "ignore errors" state. In any case (early or standard exit), decrease the m_queuedSyncErrors count atomically.
(WebCore::MediaPlayerPrivateGStreamer::createGSTPlayBin): Process error messages synchronously with the handleSyncErrorMessage() handler.
* Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h: didEnd() is now protected, so it can be called by the subclass. Added the m_queuedSyncErrors atomic counter to signal how many errors are waiting to be processed by the main thread.
* Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp:
(WebCore::MediaPlayerPrivateGStreamerMSE::setEosWithNoBuffers): Ignore the errors on all GStreamer versions by declaring m_ignoreErrors as true. If pending error messages are enqueued, report EOS by calling didEnd() (m_ignoreErrors will be reset when the last error is processed). If no pending error messages appeared, just reset the m_ignoreErrors flag here.
Canonical link: https://commits.webkit.org/300605@main
0 commit comments