Changeset 154988 in webkit


Ignore:
Timestamp:
Sep 3, 2013 9:51:19 AM (11 years ago)
Author:
commit-queue@webkit.org
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 Moreira Magalhaes> 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:
Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r154984 r154988  
     12013-09-03  Andre Moreira Magalhaes   <andre.magalhaes@collabora.co.uk>
     2
     3        [GStreamer] Don't set state to NULL until element is destroyed
     4        https://bugs.webkit.org/show_bug.cgi?id=117354
     5
     6        Reviewed by Philippe Normand.
     7
     8        Don't set playbin to NULL until it is going to be destroyed or if we stay
     9        for too long on the READY state. Instead only set the state to READY as this
     10        allows much faster state changes to PAUSED/PLAYING again. playbin internally
     11        caches some state that is destroyed when setting it to NULL.
     12        This state is independent of the URI and it is even possible to change the
     13        URI in READY state.
     14
     15        To avoid having resources (e.g. audio devices) open indefinitely,
     16        when setting the state to READY we create a timeout and if the timeout
     17        is reached we reset the pipeline state to NULL to free resources.
     18
     19        Also now all state changes use the changePipelineState method instead of setting
     20        the playbin state directly with gst_element_set_state, so we have a better control
     21        of when we are requesting state changes.
     22
     23        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
     24        (WebCore::mediaPlayerPrivateReadyStateTimeoutCallback):
     25        (WebCore::MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer):
     26        (WebCore::MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer):
     27        (WebCore::MediaPlayerPrivateGStreamer::commitLoad):
     28        (WebCore::MediaPlayerPrivateGStreamer::changePipelineState):
     29        (WebCore::MediaPlayerPrivateGStreamer::setRate):
     30        (WebCore::MediaPlayerPrivateGStreamer::handlePluginInstallerResult):
     31        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:
     32
    1332013-09-03  peavo@outlook.com  <peavo@outlook.com>
    234
  • trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp

    r154908 r154988  
    8282static const gint64 gPercentMax = 100;
    8383#endif
     84// Max interval in seconds to stay in the READY state on manual
     85// state change requests.
     86static const guint gReadyStateTimerInterval = 60;
    8487
    8588GST_DEBUG_CATEGORY_EXTERN(webkit_media_player_debug);
     
    158161}
    159162#endif
     163
     164static gboolean mediaPlayerPrivateReadyStateTimeoutCallback(MediaPlayerPrivateGStreamer* player)
     165{
     166    // This is the callback of the timeout source created in ::changePipelineState.
     167    // Reset pipeline if we are sitting on READY state when timeout is reached
     168    player->changePipelineState(GST_STATE_NULL);
     169    return FALSE;
     170}
    160171
    161172static void mediaPlayerPrivatePluginInstallerResultFunction(GstInstallPluginsReturn result, gpointer userData)
     
    258269    , m_textTimerHandler(0)
    259270    , m_videoTimerHandler(0)
     271    , m_readyTimerHandler(0)
    260272    , m_webkitAudioSink(0)
    261273    , m_totalBytes(-1)
     
    283295        g_signal_handlers_disconnect_by_func(G_OBJECT(m_autoAudioSink.get()),
    284296            reinterpret_cast<gpointer>(setAudioStreamPropertiesCallback), this);
     297
     298    if (m_readyTimerHandler)
     299        g_source_remove(m_readyTimerHandler);
    285300
    286301    if (m_playBin) {
     
    368383    // GStreamer needs to have the pipeline set to a paused state to
    369384    // start providing anything useful.
    370     gst_element_set_state(m_playBin.get(), GST_STATE_PAUSED);
     385    changePipelineState(GST_STATE_PAUSED);
    371386
    372387    setDownloadBuffering();
     
    409424bool MediaPlayerPrivateGStreamer::changePipelineState(GstState newState)
    410425{
    411     ASSERT(newState == GST_STATE_PLAYING || newState == GST_STATE_PAUSED);
     426    ASSERT(m_playBin);
    412427
    413428    GstState currentState;
     
    430445        return false;
    431446    }
     447
     448    // Create a timer when entering the READY state so that we can free resources
     449    // if we stay for too long on READY.
     450    // Also lets remove the timer if we request a state change for any state other than READY.
     451    // See also https://bugs.webkit.org/show_bug.cgi?id=117354
     452    if (newState == GST_STATE_READY && !m_readyTimerHandler) {
     453        m_readyTimerHandler = g_timeout_add_seconds(gReadyStateTimerInterval, reinterpret_cast<GSourceFunc>(mediaPlayerPrivateReadyStateTimeoutCallback), this);
     454    } else if (newState != GST_STATE_READY && m_readyTimerHandler) {
     455        g_source_remove(m_readyTimerHandler);
     456        m_readyTimerHandler = 0;
     457    }
     458
    432459    return true;
    433460}
     
    729756
    730757    if (!rate) {
    731         gst_element_set_state(m_playBin.get(), GST_STATE_PAUSED);
     758        changePipelineState(GST_STATE_PAUSED);
    732759        return;
    733760    }
     
    939966    m_missingPlugins = false;
    940967    if (result == GST_INSTALL_PLUGINS_SUCCESS) {
    941         gst_element_set_state(m_playBin.get(), GST_STATE_READY);
    942         gst_element_set_state(m_playBin.get(), GST_STATE_PAUSED);
     968        changePipelineState(GST_STATE_READY);
     969        changePipelineState(GST_STATE_PAUSED);
    943970    }
    944971}
     
    11451172
    11461173    if (m_playBin)
    1147         gst_element_set_state(m_playBin.get(), GST_STATE_NULL);
     1174        changePipelineState(GST_STATE_READY);
    11481175}
    11491176
     
    12121239            break;
    12131240        case GST_STATE_READY:
    1214             m_readyState = MediaPlayer::HaveMetadata;
    1215             m_networkState = MediaPlayer::Empty;
     1241            // Do not change network/ready states if on EOS and state changed to READY to avoid
     1242            // recreating the player on HTMLMediaElement.
     1243            if (!m_isEndReached) {
     1244                m_readyState = MediaPlayer::HaveMetadata;
     1245                m_networkState = MediaPlayer::Empty;
     1246            }
    12161247            break;
    12171248        case GST_STATE_PAUSED:
     
    12541285            if (didBuffering && !m_buffering && !m_paused) {
    12551286                LOG_MEDIA_MESSAGE("[Buffering] Restarting playback.");
    1256                 gst_element_set_state(m_playBin.get(), GST_STATE_PLAYING);
     1287                changePipelineState(GST_STATE_PLAYING);
    12571288            }
    12581289        } else if (state == GST_STATE_PLAYING) {
     
    12611292            if (m_buffering && !isLiveStream()) {
    12621293                LOG_MEDIA_MESSAGE("[Buffering] Pausing stream for buffering.");
    1263                 gst_element_set_state(m_playBin.get(), GST_STATE_PAUSED);
     1294                changePipelineState(GST_STATE_PAUSED);
    12641295            }
    12651296        } else
     
    12841315        // A live stream was paused, reset the pipeline.
    12851316        if (state == GST_STATE_PAUSED && pending == GST_STATE_PLAYING && isLiveStream()) {
    1286             gst_element_set_state(m_playBin.get(), GST_STATE_NULL);
    1287             gst_element_set_state(m_playBin.get(), GST_STATE_PLAYING);
     1317            changePipelineState(GST_STATE_READY);
     1318            changePipelineState(GST_STATE_PLAYING);
    12881319        }
    12891320
     
    13091340
    13101341        if (!m_paused)
    1311             gst_element_set_state(m_playBin.get(), GST_STATE_PLAYING);
     1342            changePipelineState(GST_STATE_PLAYING);
    13121343
    13131344        m_networkState = MediaPlayer::Loading;
     
    14141445            // Reset pipeline state.
    14151446            m_resetPipeline = true;
    1416             gst_element_set_state(m_playBin.get(), GST_STATE_READY);
     1447            changePipelineState(GST_STATE_READY);
    14171448
    14181449            GstState state;
     
    14221453                g_object_set(m_playBin.get(), "uri", newUrl.string().utf8().data(), NULL);
    14231454                m_url = newUrl;
    1424                 gst_element_set_state(m_playBin.get(), GST_STATE_PLAYING);
     1455                changePipelineState(GST_STATE_PLAYING);
    14251456                return true;
    14261457            }
     
    14601491    if (!m_player->mediaPlayerClient()->mediaPlayerIsLooping()) {
    14611492        m_paused = true;
    1462         gst_element_set_state(m_playBin.get(), GST_STATE_NULL);
     1493        changePipelineState(GST_STATE_READY);
    14631494        m_downloadFinished = false;
    14641495    }
     
    15041535        m_readyState = MediaPlayer::HaveNothing;
    15051536        m_player->readyStateChanged();
     1537    }
     1538
     1539    // Loading failed, force reset pipeline and remove ready timer.
     1540    gst_element_set_state(m_playBin.get(), GST_STATE_NULL);
     1541    if (m_readyTimerHandler) {
     1542        g_source_remove(m_readyTimerHandler);
     1543        m_readyTimerHandler = 0;
    15061544    }
    15071545}
  • trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h

    r154908 r154988  
    108108    void simulateAudioInterruption();
    109109
     110    bool changePipelineState(GstState);
     111
    110112private:
    111113    MediaPlayerPrivateGStreamer(MediaPlayer*);
     
    128130
    129131    void createGSTPlayBin();
    130     bool changePipelineState(GstState);
    131132
    132133    bool loadNextLocation();
     
    177178    guint m_textTimerHandler;
    178179    guint m_videoTimerHandler;
     180    guint m_readyTimerHandler;
    179181    GRefPtr<GstElement> m_webkitAudioSink;
    180182    mutable long m_totalBytes;
Note: See TracChangeset for help on using the changeset viewer.