Title: [154988] trunk/Source/WebCore
Revision
154988
Author
commit-qu...@webkit.org
Date
2013-09-03 09:51:19 -0700 (Tue, 03 Sep 2013)

Log Message

[GStreamer] Don't set state to NULL until element is destroyed
https://bugs.webkit.org/show_bug.cgi?id=117354

Patch by Andre Moreira Magalhaes <andre.magalh...@collabora.co.uk> on 2013-09-03
Reviewed by Philippe Normand.

Don't set playbin to NULL until it is going to be destroyed or if we stay
for too long on the READY state. Instead only set the state to READY as this
allows much faster state changes to PAUSED/PLAYING again. playbin internally
caches some state that is destroyed when setting it to NULL.
This state is independent of the URI and it is even possible to change the
URI in READY state.

To avoid having resources (e.g. audio devices) open indefinitely,
when setting the state to READY we create a timeout and if the timeout
is reached we reset the pipeline state to NULL to free resources.

Also now all state changes use the changePipelineState method instead of setting
the playbin state directly with gst_element_set_state, so we have a better control
of when we are requesting state changes.

* platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
(WebCore::mediaPlayerPrivateReadyStateTimeoutCallback):
(WebCore::MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer):
(WebCore::MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer):
(WebCore::MediaPlayerPrivateGStreamer::commitLoad):
(WebCore::MediaPlayerPrivateGStreamer::changePipelineState):
(WebCore::MediaPlayerPrivateGStreamer::setRate):
(WebCore::MediaPlayerPrivateGStreamer::handlePluginInstallerResult):
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (154987 => 154988)


--- trunk/Source/WebCore/ChangeLog	2013-09-03 16:51:03 UTC (rev 154987)
+++ trunk/Source/WebCore/ChangeLog	2013-09-03 16:51:19 UTC (rev 154988)
@@ -1,3 +1,35 @@
+2013-09-03  Andre Moreira Magalhaes   <andre.magalh...@collabora.co.uk>
+
+        [GStreamer] Don't set state to NULL until element is destroyed
+        https://bugs.webkit.org/show_bug.cgi?id=117354
+
+        Reviewed by Philippe Normand.
+
+        Don't set playbin to NULL until it is going to be destroyed or if we stay
+        for too long on the READY state. Instead only set the state to READY as this
+        allows much faster state changes to PAUSED/PLAYING again. playbin internally
+        caches some state that is destroyed when setting it to NULL.
+        This state is independent of the URI and it is even possible to change the
+        URI in READY state.
+
+        To avoid having resources (e.g. audio devices) open indefinitely,
+        when setting the state to READY we create a timeout and if the timeout
+        is reached we reset the pipeline state to NULL to free resources.
+
+        Also now all state changes use the changePipelineState method instead of setting
+        the playbin state directly with gst_element_set_state, so we have a better control
+        of when we are requesting state changes.
+
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
+        (WebCore::mediaPlayerPrivateReadyStateTimeoutCallback):
+        (WebCore::MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer):
+        (WebCore::MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer):
+        (WebCore::MediaPlayerPrivateGStreamer::commitLoad):
+        (WebCore::MediaPlayerPrivateGStreamer::changePipelineState):
+        (WebCore::MediaPlayerPrivateGStreamer::setRate):
+        (WebCore::MediaPlayerPrivateGStreamer::handlePluginInstallerResult):
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:
+
 2013-09-03  pe...@outlook.com  <pe...@outlook.com>
 
         [WinCairo] Unneeded code in method GlyphPage::fill().

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp (154987 => 154988)


--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp	2013-09-03 16:51:03 UTC (rev 154987)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp	2013-09-03 16:51:19 UTC (rev 154988)
@@ -81,6 +81,9 @@
 static const char* gPlaybinName = "playbin2";
 static const gint64 gPercentMax = 100;
 #endif
+// Max interval in seconds to stay in the READY state on manual
+// state change requests.
+static const guint gReadyStateTimerInterval = 60;
 
 GST_DEBUG_CATEGORY_EXTERN(webkit_media_player_debug);
 #define GST_CAT_DEFAULT webkit_media_player_debug
@@ -158,6 +161,14 @@
 }
 #endif
 
+static gboolean mediaPlayerPrivateReadyStateTimeoutCallback(MediaPlayerPrivateGStreamer* player)
+{
+    // This is the callback of the timeout source created in ::changePipelineState.
+    // Reset pipeline if we are sitting on READY state when timeout is reached
+    player->changePipelineState(GST_STATE_NULL);
+    return FALSE;
+}
+
 static void mediaPlayerPrivatePluginInstallerResultFunction(GstInstallPluginsReturn result, gpointer userData)
 {
     MediaPlayerPrivateGStreamer* player = reinterpret_cast<MediaPlayerPrivateGStreamer*>(userData);
@@ -257,6 +268,7 @@
     , m_audioTimerHandler(0)
     , m_textTimerHandler(0)
     , m_videoTimerHandler(0)
+    , m_readyTimerHandler(0)
     , m_webkitAudioSink(0)
     , m_totalBytes(-1)
     , m_preservesPitch(false)
@@ -283,6 +295,9 @@
         g_signal_handlers_disconnect_by_func(G_OBJECT(m_autoAudioSink.get()),
             reinterpret_cast<gpointer>(setAudioStreamPropertiesCallback), this);
 
+    if (m_readyTimerHandler)
+        g_source_remove(m_readyTimerHandler);
+
     if (m_playBin) {
         GRefPtr<GstBus> bus = webkitGstPipelineGetBus(GST_PIPELINE(m_playBin.get()));
         ASSERT(bus);
@@ -367,7 +382,7 @@
 
     // GStreamer needs to have the pipeline set to a paused state to
     // start providing anything useful.
-    gst_element_set_state(m_playBin.get(), GST_STATE_PAUSED);
+    changePipelineState(GST_STATE_PAUSED);
 
     setDownloadBuffering();
     updateStates();
@@ -408,7 +423,7 @@
 
 bool MediaPlayerPrivateGStreamer::changePipelineState(GstState newState)
 {
-    ASSERT(newState == GST_STATE_PLAYING || newState == GST_STATE_PAUSED);
+    ASSERT(m_playBin);
 
     GstState currentState;
     GstState pending;
@@ -429,6 +444,18 @@
         loadingFailed(MediaPlayer::Empty);
         return false;
     }
+
+    // Create a timer when entering the READY state so that we can free resources
+    // if we stay for too long on READY.
+    // 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
+    if (newState == GST_STATE_READY && !m_readyTimerHandler) {
+        m_readyTimerHandler = g_timeout_add_seconds(gReadyStateTimerInterval, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateReadyStateTimeoutCallback), this);
+    } else if (newState != GST_STATE_READY && m_readyTimerHandler) {
+        g_source_remove(m_readyTimerHandler);
+        m_readyTimerHandler = 0;
+    }
+
     return true;
 }
 
@@ -728,7 +755,7 @@
     m_changingRate = true;
 
     if (!rate) {
-        gst_element_set_state(m_playBin.get(), GST_STATE_PAUSED);
+        changePipelineState(GST_STATE_PAUSED);
         return;
     }
 
@@ -938,8 +965,8 @@
 {
     m_missingPlugins = false;
     if (result == GST_INSTALL_PLUGINS_SUCCESS) {
-        gst_element_set_state(m_playBin.get(), GST_STATE_READY);
-        gst_element_set_state(m_playBin.get(), GST_STATE_PAUSED);
+        changePipelineState(GST_STATE_READY);
+        changePipelineState(GST_STATE_PAUSED);
     }
 }
 
@@ -1144,7 +1171,7 @@
         return;
 
     if (m_playBin)
-        gst_element_set_state(m_playBin.get(), GST_STATE_NULL);
+        changePipelineState(GST_STATE_READY);
 }
 
 void MediaPlayerPrivateGStreamer::asyncStateChangeDone()
@@ -1211,8 +1238,12 @@
             m_networkState = MediaPlayer::Empty;
             break;
         case GST_STATE_READY:
-            m_readyState = MediaPlayer::HaveMetadata;
-            m_networkState = MediaPlayer::Empty;
+            // Do not change network/ready states if on EOS and state changed to READY to avoid
+            // recreating the player on HTMLMediaElement.
+            if (!m_isEndReached) {
+                m_readyState = MediaPlayer::HaveMetadata;
+                m_networkState = MediaPlayer::Empty;
+            }
             break;
         case GST_STATE_PAUSED:
         case GST_STATE_PLAYING:
@@ -1253,14 +1284,14 @@
 
             if (didBuffering && !m_buffering && !m_paused) {
                 LOG_MEDIA_MESSAGE("[Buffering] Restarting playback.");
-                gst_element_set_state(m_playBin.get(), GST_STATE_PLAYING);
+                changePipelineState(GST_STATE_PLAYING);
             }
         } else if (state == GST_STATE_PLAYING) {
             m_paused = false;
 
             if (m_buffering && !isLiveStream()) {
                 LOG_MEDIA_MESSAGE("[Buffering] Pausing stream for buffering.");
-                gst_element_set_state(m_playBin.get(), GST_STATE_PAUSED);
+                changePipelineState(GST_STATE_PAUSED);
             }
         } else
             m_paused = true;
@@ -1283,8 +1314,8 @@
 
         // A live stream was paused, reset the pipeline.
         if (state == GST_STATE_PAUSED && pending == GST_STATE_PLAYING && isLiveStream()) {
-            gst_element_set_state(m_playBin.get(), GST_STATE_NULL);
-            gst_element_set_state(m_playBin.get(), GST_STATE_PLAYING);
+            changePipelineState(GST_STATE_READY);
+            changePipelineState(GST_STATE_PLAYING);
         }
 
         break;
@@ -1308,7 +1339,7 @@
             m_paused = false;
 
         if (!m_paused)
-            gst_element_set_state(m_playBin.get(), GST_STATE_PLAYING);
+            changePipelineState(GST_STATE_PLAYING);
 
         m_networkState = MediaPlayer::Loading;
         break;
@@ -1413,7 +1444,7 @@
 
             // Reset pipeline state.
             m_resetPipeline = true;
-            gst_element_set_state(m_playBin.get(), GST_STATE_READY);
+            changePipelineState(GST_STATE_READY);
 
             GstState state;
             gst_element_get_state(m_playBin.get(), &state, 0, 0);
@@ -1421,7 +1452,7 @@
                 // Set the new uri and start playing.
                 g_object_set(m_playBin.get(), "uri", newUrl.string().utf8().data(), NULL);
                 m_url = newUrl;
-                gst_element_set_state(m_playBin.get(), GST_STATE_PLAYING);
+                changePipelineState(GST_STATE_PLAYING);
                 return true;
             }
         } else
@@ -1459,7 +1490,7 @@
 
     if (!m_player->mediaPlayerClient()->mediaPlayerIsLooping()) {
         m_paused = true;
-        gst_element_set_state(m_playBin.get(), GST_STATE_NULL);
+        changePipelineState(GST_STATE_READY);
         m_downloadFinished = false;
     }
 }
@@ -1504,6 +1535,13 @@
         m_readyState = MediaPlayer::HaveNothing;
         m_player->readyStateChanged();
     }
+
+    // Loading failed, force reset pipeline and remove ready timer.
+    gst_element_set_state(m_playBin.get(), GST_STATE_NULL);
+    if (m_readyTimerHandler) {
+        g_source_remove(m_readyTimerHandler);
+        m_readyTimerHandler = 0;
+    }
 }
 
 static HashSet<String> mimeTypeCache()

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h (154987 => 154988)


--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h	2013-09-03 16:51:03 UTC (rev 154987)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h	2013-09-03 16:51:19 UTC (rev 154988)
@@ -107,6 +107,8 @@
 
     void simulateAudioInterruption();
 
+    bool changePipelineState(GstState);
+
 private:
     MediaPlayerPrivateGStreamer(MediaPlayer*);
 
@@ -127,7 +129,6 @@
     void asyncStateChangeDone();
 
     void createGSTPlayBin();
-    bool changePipelineState(GstState);
 
     bool loadNextLocation();
     void mediaLocationChanged(GstMessage*);
@@ -176,6 +177,7 @@
     guint m_audioTimerHandler;
     guint m_textTimerHandler;
     guint m_videoTimerHandler;
+    guint m_readyTimerHandler;
     GRefPtr<GstElement> m_webkitAudioSink;
     mutable long m_totalBytes;
     KURL m_url;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to