Skip to content

Commit 04b8550

Browse files
suresh-khurdiya-epameocanha
authored andcommitted
[GStreamer] Video goes blank on some platforms after playback ends
https://bugs.webkit.org/show_bug.cgi?id=264739 Reviewed by Philippe Normand. On some downstream platforms, the video gets black after playback finishes. This happens because https://bugs.webkit.org/show_bug.cgi?id=89122 used to set the pipeline to NULL, although later https://bugs.webkit.org/show_bug.cgi?id=117354 set it to READY. This change deinitializes a big part of the pipeline, which should otherwise stay in a working state if the state was PAUSED as it should be without those changes. While on desktop platforms the last video frame is still kept and shown, on some downstream platforms using a custom multimedia subsystem the deinitialization destroys internal resources and makes that last video frame not to be visible anymore. The original purpose of the mentioned bugs was to avoid having the audio device opened after the video finished. This was relevant in 2012, when many platforms still used ALSA as a sound system, but it's not so relevant nowadays, when PulseAudio is the usual choice on desktop. This patch reworks the readyTimerHandler and readyTimerFired into pausedTimerHandler and pausedTimerFired, because now the pipeline stays in PAUSED and having a timer to eventually releasing resources by transitioning to NULL still makes sense. The timeout has been increased to 5 minutes and maybe it would eventually need to be even larger. Original author: suresh-khurdiya-epam <skhurdiya.contractor@libertyglobal.com> See: #1205 * Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp: (WebCore::MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer): Renamed m_readyTimerHandler to m_pausedTimerHandler. (WebCore::MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer): Ditto. (WebCore::MediaPlayerPrivateGStreamer::changePipelineState): Ditto, and added extra conditions to only start the timer on PAUSE at end. (WebCore::MediaPlayerPrivateGStreamer::loadingFailed): Ditto. (WebCore::MediaPlayerPrivateGStreamer::didEnd): Set the pipeline to PAUSED on end, instead of setting it to READY. (WebCore::MediaPlayerPrivateGStreamer::pausedTimerFired): Renamed from readyTimerFired. (WebCore::MediaPlayerPrivateGStreamer::readyTimerFired): Deleted. * Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h: Renamed m_readyTimerHandler to m_pausedTimerHandler and readyTimerFired() to pausedTimerFired(). Canonical link: https://commits.webkit.org/270766@main
1 parent 98827e7 commit 04b8550

2 files changed

Lines changed: 16 additions & 15 deletions

File tree

Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer(MediaPlayer* player)
168168
, m_preload(player->preload())
169169
, m_maxTimeLoadedAtLastDidLoadingProgress(MediaTime::zeroTime())
170170
, m_drawTimer(RunLoop::main(), this, &MediaPlayerPrivateGStreamer::repaint)
171-
, m_readyTimerHandler(RunLoop::main(), this, &MediaPlayerPrivateGStreamer::readyTimerFired)
171+
, m_pausedTimerHandler(RunLoop::main(), this, &MediaPlayerPrivateGStreamer::pausedTimerFired)
172172
#if USE(TEXTURE_MAPPER_GL) && !USE(NICOSIA)
173173
, m_platformLayerProxy(adoptRef(new TextureMapperPlatformLayerProxyGL))
174174
#endif
@@ -181,7 +181,7 @@ MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer(MediaPlayer* player)
181181
#endif
182182
{
183183
#if USE(GLIB)
184-
m_readyTimerHandler.setPriority(G_PRIORITY_DEFAULT_IDLE);
184+
m_pausedTimerHandler.setPriority(G_PRIORITY_DEFAULT_IDLE);
185185
#endif
186186
m_isPlayerShuttingDown.store(false);
187187

@@ -230,7 +230,7 @@ MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer()
230230
if (m_fillTimer.isActive())
231231
m_fillTimer.stop();
232232

233-
m_readyTimerHandler.stop();
233+
m_pausedTimerHandler.stop();
234234
for (auto& missingPluginCallback : m_missingPluginCallbacks) {
235235
if (missingPluginCallback)
236236
missingPluginCallback->invalidate();
@@ -936,12 +936,13 @@ bool MediaPlayerPrivateGStreamer::changePipelineState(GstState newState)
936936

937937
// Create a timer when entering the READY state so that we can free resources if we stay for too long on READY.
938938
// Also lets remove the timer if we request a state change for any state other than READY. See also https://bugs.webkit.org/show_bug.cgi?id=117354
939-
if (newState == GST_STATE_READY && !m_readyTimerHandler.isActive()) {
940-
// Max interval in seconds to stay in the READY state on manual state change requests.
941-
static const Seconds readyStateTimerDelay { 1_min };
942-
m_readyTimerHandler.startOneShot(readyStateTimerDelay);
943-
} else if (newState != GST_STATE_READY)
944-
m_readyTimerHandler.stop();
939+
if (newState == GST_STATE_PAUSED && m_isEndReached && m_player && !m_player->isLooping()
940+
&& !isMediaSource() && !m_pausedTimerHandler.isActive()) {
941+
// Max interval in seconds to stay in the PAUSED state after video finished on manual state change requests.
942+
static const Seconds readyStateTimerDelay { 5_min };
943+
m_pausedTimerHandler.startOneShot(readyStateTimerDelay);
944+
} else if (newState != GST_STATE_PAUSED)
945+
m_pausedTimerHandler.stop();
945946

946947
return true;
947948
}
@@ -1247,7 +1248,7 @@ void MediaPlayerPrivateGStreamer::loadingFailed(MediaPlayer::NetworkState networ
12471248
}
12481249

12491250
// Loading failed, remove ready timer.
1250-
m_readyTimerHandler.stop();
1251+
m_pausedTimerHandler.stop();
12511252
}
12521253

12531254
GstElement* MediaPlayerPrivateGStreamer::createAudioSink()
@@ -2733,7 +2734,7 @@ void MediaPlayerPrivateGStreamer::didEnd()
27332734

27342735
if (!m_player->isLooping() && !isMediaSource()) {
27352736
m_isPaused = true;
2736-
changePipelineState(GST_STATE_READY);
2737+
changePipelineState(GST_STATE_PAUSED);
27372738
m_didDownloadFinish = false;
27382739
configureMediaStreamAudioTracks();
27392740

@@ -3070,9 +3071,9 @@ bool MediaPlayerPrivateGStreamer::canSaveMediaData() const
30703071
return false;
30713072
}
30723073

3073-
void MediaPlayerPrivateGStreamer::readyTimerFired()
3074+
void MediaPlayerPrivateGStreamer::pausedTimerFired()
30743075
{
3075-
GST_DEBUG_OBJECT(pipeline(), "In READY for too long. Releasing pipeline resources.");
3076+
GST_DEBUG_OBJECT(pipeline(), "In PAUSED for too long. Releasing pipeline resources.");
30763077
changePipelineState(GST_STATE_NULL);
30773078
}
30783079

Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface
351351
static void volumeChangedCallback(MediaPlayerPrivateGStreamer*);
352352
static void muteChangedCallback(MediaPlayerPrivateGStreamer*);
353353

354-
void readyTimerFired();
354+
void pausedTimerFired();
355355

356356
template <typename TrackPrivateType> void notifyPlayerOfTrack();
357357

@@ -573,7 +573,7 @@ class MediaPlayerPrivateGStreamer : public MediaPlayerPrivateInterface
573573
Condition m_drawCondition;
574574
Lock m_drawLock;
575575
RunLoop::Timer<MediaPlayerPrivateGStreamer> m_drawTimer WTF_GUARDED_BY_LOCK(m_drawLock);
576-
RunLoop::Timer<MediaPlayerPrivateGStreamer> m_readyTimerHandler;
576+
RunLoop::Timer<MediaPlayerPrivateGStreamer> m_pausedTimerHandler;
577577
#if USE(TEXTURE_MAPPER_GL)
578578
#if USE(NICOSIA)
579579
RefPtr<Nicosia::ContentLayer> m_nicosiaLayer;

0 commit comments

Comments
 (0)