Changeset 150066 in webkit


Ignore:
Timestamp:
May 14, 2013, 5:49:06 AM (13 years ago)
Author:
kbalazs@webkit.org
Message:

[GStreamer] cannot seek after video finished
https://bugs.webkit.org/show_bug.cgi?id=114044

Patch by Balazs Kelemen <b.kelemen@sisa.samsung.com> on 2013-04-30
Reviewed by Philippe Normand.

Source/WebCore:

Test: media/video-seek-after-end.html

Reland without wrong assertion. If seek is called after didEnd the pipeline
state will not be in GST_STATE_NULL yet but it is not a problem because we handle that.

Rework the seeking logic to be able to seek after reseting the pipeline.
In addition to solve the actual problem this patch supposed to make seeking
more robust and correct.
The previous implementation tried to hide the complexity of asynchronous operations
on the pipeline. It did not handle the GST_MESSAGE_ASYNC_DONE message from the bus
but instead reported the seek as finished when it saw an asynchronous pending state
(GST_STATE_CHANGE_ASYNC) which could happen way before the seek is really done.
Now we pay attention to the GST_MESSAGE_ASYNC_DONE message to track the status of seeks.
Seeks are not the only operations executed asynchronously, changing the pipeling state is
similar. It means a seek can overlap with onother ongoing asynchronous operation.
This change address this by introducing an invariant for seeks, which is that we only request
a seek if there are no other ongoing asynchronous operations and the pipeline state is either
paused or playing (which is recommended anyway according to GStreamer's documentation).
This way we can be sure that the time when we get the next GST_MESSAGE_ASYNC_DONE message the
seek has been completed.

  • platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:

(WebCore::toGstClockTime): Factored time conversation into a helper.
(WebCore::MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer):

(WebCore::MediaPlayerPrivateGStreamer::playbackPosition): The position might not be available
if the pipeline still has a pending state. As a workaround, if we are right after a seek we can
use the seek time. Avoiding this situation would be possible by not allowing any asynchronous
operation to overlap. I believe it would add a lot more complexity so I decided to rather introduce
this workaround. Otherwise those overlapping operations are handled fine by GStreamer.

(WebCore::MediaPlayerPrivateGStreamer::prepareToPlay): Do not reset internal state variables.
This function called when there is an intent to restart playback but it does not actually restart it.
(WebCore::MediaPlayerPrivateGStreamer::currentTime): Just removed a staling newline.
(WebCore::MediaPlayerPrivateGStreamer::seek): Take a look to the pipeline state and act upon that.
If there is an ongoing asynchronous operation make the seek pending, otherwise do it now.
Now we handle overlapping seeks as well because I saw that it can happen in some tests.
Added an early return for live streams as it doesn't makes sense to try seeking in them.

(WebCore::MediaPlayerPrivateGStreamer::handleMessage): Handle GST_MESSAGE_ASYNC_DONE and some refactoring.
(WebCore::MediaPlayerPrivateGStreamer::asyncStateChangeDone):
(WebCore::MediaPlayerPrivateGStreamer::updateStates): Only handle seeks in the pending case, the rest is
now handled in asyncStateChangeDone.
(WebCore::MediaPlayerPrivateGStreamer::cacheDuration): Do not reset the m_mediaDurationKnown if the pipeline
has an asynchronous pending state because it would fail. It does actually happen when we get a duration message
after restarting the pipeline and it would result in restarting playback from the start. It seems to be a bug
in GStreamer that it sends the duration message too early. Also sanitized this function by merging redundant branches.

  • platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:

(MediaPlayerPrivateGStreamer):

LayoutTests:

  • media/video-seek-after-end-expected.txt: Added.
  • media/video-seek-after-end.html: Added.
Location:
trunk
Files:
2 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r150065 r150066  
     12013-04-30  Balazs Kelemen  <b.kelemen@sisa.samsung.com>
     2
     3        [GStreamer] cannot seek after video finished
     4        https://bugs.webkit.org/show_bug.cgi?id=114044
     5
     6        Reviewed by Philippe Normand.
     7
     8        * media/video-seek-after-end-expected.txt: Added.
     9        * media/video-seek-after-end.html: Added.
     10
    1112013-05-14  Zalan Bujtas  <zalan@apple.com>
    212
  • trunk/Source/WebCore/ChangeLog

    r150065 r150066  
     12013-04-30  Balazs Kelemen  <b.kelemen@sisa.samsung.com>
     2
     3        [GStreamer] cannot seek after video finished
     4        https://bugs.webkit.org/show_bug.cgi?id=114044
     5
     6        Reviewed by Philippe Normand.
     7
     8        Test: media/video-seek-after-end.html
     9
     10        Reland without wrong assertion. If seek is called after didEnd the pipeline
     11        state will not be in GST_STATE_NULL yet but it is not a problem because we handle that.
     12
     13        Rework the seeking logic to be able to seek after reseting the pipeline.
     14        In addition to solve the actual problem this patch supposed to make seeking
     15        more robust and correct.
     16        The previous implementation tried to hide the complexity of asynchronous operations
     17        on the pipeline. It did not handle the GST_MESSAGE_ASYNC_DONE message from the bus
     18        but instead reported the seek as finished when it saw an asynchronous pending state
     19        (GST_STATE_CHANGE_ASYNC) which could happen way before the seek is really done.
     20        Now we pay attention to the GST_MESSAGE_ASYNC_DONE message to track the status of seeks.
     21        Seeks are not the only operations executed asynchronously, changing the pipeling state is
     22        similar. It means a seek can overlap with onother ongoing asynchronous operation.
     23        This change address this by introducing an invariant for seeks, which is that we only request
     24        a seek if there are no other ongoing asynchronous operations and the pipeline state is either
     25        paused or playing (which is recommended anyway according to GStreamer's documentation).
     26        This way we can be sure that the time when we get the next GST_MESSAGE_ASYNC_DONE message the
     27        seek has been completed.
     28
     29        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
     30        (WebCore::toGstClockTime): Factored time conversation into a helper.
     31        (WebCore::MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer):
     32
     33        (WebCore::MediaPlayerPrivateGStreamer::playbackPosition): The position might not be available
     34        if the pipeline still has a pending state. As a workaround, if we are right after a seek we can
     35        use the seek time. Avoiding this situation would be possible by not allowing any asynchronous
     36        operation to overlap. I believe it would add a lot more complexity so I decided to rather introduce
     37        this workaround. Otherwise those overlapping operations are handled fine by GStreamer.
     38
     39        (WebCore::MediaPlayerPrivateGStreamer::prepareToPlay): Do not reset internal state variables.
     40        This function called when there is an intent to restart playback but it does not actually restart it.
     41        (WebCore::MediaPlayerPrivateGStreamer::currentTime): Just removed a staling newline.
     42        (WebCore::MediaPlayerPrivateGStreamer::seek): Take a look to the pipeline state and act upon that.
     43        If there is an ongoing asynchronous operation make the seek pending, otherwise do it now.
     44        Now we handle overlapping seeks as well because I saw that it can happen in some tests.
     45        Added an early return for live streams as it doesn't makes sense to try seeking in them.
     46
     47        (WebCore::MediaPlayerPrivateGStreamer::handleMessage): Handle GST_MESSAGE_ASYNC_DONE and some refactoring.
     48        (WebCore::MediaPlayerPrivateGStreamer::asyncStateChangeDone):
     49        (WebCore::MediaPlayerPrivateGStreamer::updateStates): Only handle seeks in the pending case, the rest is
     50        now handled in asyncStateChangeDone.
     51        (WebCore::MediaPlayerPrivateGStreamer::cacheDuration): Do not reset the m_mediaDurationKnown if the pipeline
     52        has an asynchronous pending state because it would fail. It does actually happen when we get a duration message
     53        after restarting the pipeline and it would result in restarting playback from the start. It seems to be a bug
     54        in GStreamer that it sends the duration message too early. Also sanitized this function by merging redundant branches.
     55        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:
     56        (MediaPlayerPrivateGStreamer):
     57
    1582013-05-14  Zalan Bujtas  <zalan@apple.com>
    259
  • trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp

    r150031 r150066  
    139139}
    140140
     141static GstClockTime toGstClockTime(float time)
     142{
     143    // Extract the integer part of the time (seconds) and the fractional part (microseconds). Attempt to
     144    // round the microseconds so no floating point precision is lost and we can perform an accurate seek.
     145    float seconds;
     146    float microSeconds = modf(time, &seconds) * 1000000;
     147    GTimeVal timeValue;
     148    timeValue.tv_sec = static_cast<glong>(seconds);
     149    timeValue.tv_usec = static_cast<glong>(roundf(microSeconds / 10000) * 10000);
     150    return GST_TIMEVAL_TO_TIME(timeValue);
     151}
     152
    141153void MediaPlayerPrivateGStreamer::setAudioStreamProperties(GObject* object)
    142154{
     
    200212    , m_paused(true)
    201213    , m_seeking(false)
     214    , m_seekIsPending(false)
     215    , m_timeOfOverlappingSeek(-1)
    202216    , m_buffering(false)
    203217    , m_playbackRate(1)
     
    334348        if (m_mediaDuration)
    335349            return m_mediaDuration;
    336     }
    337 
    338     float ret = 0.0f;
    339 
    340     GstQuery* query = gst_query_new_position(GST_FORMAT_TIME);
    341     if (!gst_element_query(m_playBin.get(), query)) {
    342         LOG_MEDIA_MESSAGE("Position query failed...");
    343         gst_query_unref(query);
    344         return ret;
    345     }
    346 
    347     gint64 position;
    348     gst_query_parse_position(query, 0, &position);
    349 
    350     // Position is available only if the pipeline is not in GST_STATE_NULL or
    351     // GST_STATE_READY state.
    352     if (position != static_cast<gint64>(GST_CLOCK_TIME_NONE))
    353         ret = static_cast<double>(position) / GST_SECOND;
     350        return 0;
     351    }
     352
     353    // Position is only available if no async state change is going on and the state is either paused or playing.
     354    gint64 position = GST_CLOCK_TIME_NONE;
     355    GstQuery* query= gst_query_new_position(GST_FORMAT_TIME);
     356    if (gst_element_query(m_playBin.get(), query))
     357        gst_query_parse_position(query, 0, &position);
     358
     359    float result = 0.0f;
     360    if (static_cast<GstClockTime>(position) != GST_CLOCK_TIME_NONE)
     361        result = static_cast<double>(position) / GST_SECOND;
     362    else if (m_canFallBackToLastFinishedSeekPositon)
     363        result = m_seekTime;
    354364
    355365    LOG_MEDIA_MESSAGE("Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position));
     
    357367    gst_query_unref(query);
    358368
    359     return ret;
     369    return result;
    360370}
    361371
     
    388398void MediaPlayerPrivateGStreamer::prepareToPlay()
    389399{
    390     m_isEndReached = false;
    391     m_seeking = false;
    392 
    393400    if (m_delayingLoad) {
    394401        m_delayingLoad = false;
     
    468475
    469476    return playbackPosition();
    470 
    471477}
    472478
     
    479485        return;
    480486
    481     LOG_MEDIA_MESSAGE("Seek attempt to %f secs", time);
     487    LOG_MEDIA_MESSAGE("[Seek] seek attempt to %f secs", time);
    482488
    483489    // Avoid useless seeking.
     
    485491        return;
    486492
    487     // Extract the integer part of the time (seconds) and the
    488     // fractional part (microseconds). Attempt to round the
    489     // microseconds so no floating point precision is lost and we can
    490     // perform an accurate seek.
    491     float seconds;
    492     float microSeconds = modf(time, &seconds) * 1000000;
    493     GTimeVal timeValue;
    494     timeValue.tv_sec = static_cast<glong>(seconds);
    495     timeValue.tv_usec = static_cast<glong>(roundf(microSeconds / 10000) * 10000);
    496 
    497     GstClockTime clockTime = GST_TIMEVAL_TO_TIME(timeValue);
    498     LOG_MEDIA_MESSAGE("Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(clockTime));
    499 
    500     if (!gst_element_seek(m_playBin.get(), m_player->rate(),
    501             GST_FORMAT_TIME,
    502             (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
    503             GST_SEEK_TYPE_SET, clockTime,
    504             GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
    505         LOG_MEDIA_MESSAGE("Seek to %f failed", time);
    506     else {
    507         m_seeking = true;
    508         m_seekTime = time;
    509     }
     493    if (isLiveStream())
     494        return;
     495
     496    GstClockTime clockTime = toGstClockTime(time);
     497    LOG_MEDIA_MESSAGE("[Seek] seeking to %" GST_TIME_FORMAT " (%f)", GST_TIME_ARGS(clockTime), time);
     498
     499    if (m_seeking) {
     500        if (m_seekIsPending) {
     501            m_seekTime = time;
     502            return;
     503        }
     504        m_timeOfOverlappingSeek = time;
     505    }
     506
     507    GstState state;
     508    GstStateChangeReturn getStateResult = gst_element_get_state(m_playBin.get(), &state, 0, 0);
     509    if (getStateResult == GST_STATE_CHANGE_FAILURE || getStateResult == GST_STATE_CHANGE_NO_PREROLL) {
     510        LOG_MEDIA_MESSAGE("[Seek] cannot seek, current state change is %s", gst_element_state_change_return_get_name(getStateResult));
     511        return;
     512    }
     513    if (getStateResult == GST_STATE_CHANGE_ASYNC || state < GST_STATE_PAUSED || m_isEndReached) {
     514        m_seekIsPending = true;
     515        if (m_isEndReached) {
     516            LOG_MEDIA_MESSAGE("[Seek] reset pipeline");
     517            m_resetPipeline = true;
     518            changePipelineState(GST_STATE_PAUSED);
     519        }
     520    } else {
     521        // We can seek now.
     522        if (!gst_element_seek(m_playBin.get(), m_player->rate(), GST_FORMAT_TIME, static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
     523            GST_SEEK_TYPE_SET, clockTime, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
     524            LOG_MEDIA_MESSAGE("[Seek] seeking to %f failed", time);
     525            return;
     526        }
     527    }
     528
     529    m_seeking = true;
     530    m_seekTime = time;
     531    m_isEndReached = false;
    510532}
    511533
     
    681703    GstState requestedState, currentState;
    682704
     705    m_canFallBackToLastFinishedSeekPositon = false;
     706
    683707    if (structure) {
    684708        const gchar* messageTypeName = gst_structure_get_name(structure);
     
    692716    }
    693717
    694     LOG_MEDIA_MESSAGE("Message received from element %s", GST_MESSAGE_SRC_NAME(message));
     718    // We ignore state changes from internal elements. They are forwarded to playbin2 anyway.
     719    bool messageSourceIsPlaybin = GST_MESSAGE_SRC(message) == reinterpret_cast<GstObject*>(m_playBin.get());
     720
     721    LOG_MEDIA_MESSAGE("Message %s received from element %s", GST_MESSAGE_TYPE_NAME(message), GST_MESSAGE_SRC_NAME(message));
    695722    switch (GST_MESSAGE_TYPE(message)) {
    696723    case GST_MESSAGE_ERROR:
     
    730757        break;
    731758    case GST_MESSAGE_EOS:
    732         LOG_MEDIA_MESSAGE("End of Stream");
    733759        didEnd();
    734760        break;
    735     case GST_MESSAGE_STATE_CHANGED:
    736         // Ignore state changes if load is delayed (preload=none). The
    737         // player state will be updated once commitLoad() is called.
    738         if (m_delayingLoad) {
    739             LOG_MEDIA_MESSAGE("Media load has been delayed. Ignoring state changes for now");
     761    case GST_MESSAGE_ASYNC_DONE:
     762        if (!messageSourceIsPlaybin || m_delayingLoad)
    740763            break;
    741         }
    742 
    743         // Ignore state changes from internal elements. They are
    744         // forwarded to playbin2 anyway.
    745         if (GST_MESSAGE_SRC(message) == reinterpret_cast<GstObject*>(m_playBin.get())) {
    746             updateStates();
    747 
    748             // Construct a filename for the graphviz dot file output.
    749             GstState newState;
    750             gst_message_parse_state_changed(message, &currentState, &newState, 0);
    751 
    752             CString dotFileName = String::format("webkit-video.%s_%s",
    753                 gst_element_state_get_name(currentState),
    754                 gst_element_state_get_name(newState)).utf8();
    755 
    756             GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_playBin.get()), GST_DEBUG_GRAPH_SHOW_ALL, dotFileName.data());
    757         }
     764        asyncStateChangeDone();
    758765        break;
     766    case GST_MESSAGE_STATE_CHANGED: {
     767        if (!messageSourceIsPlaybin || m_delayingLoad)
     768            break;
     769        updateStates();
     770
     771        // Construct a filename for the graphviz dot file output.
     772        GstState newState;
     773        gst_message_parse_state_changed(message, &currentState, &newState, 0);
     774        CString dotFileName = String::format("webkit-video.%s_%s", gst_element_state_get_name(currentState), gst_element_state_get_name(newState)).utf8();
     775        GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_playBin.get()), GST_DEBUG_GRAPH_SHOW_ALL, dotFileName.data());
     776
     777        break;
     778    }
    759779    case GST_MESSAGE_BUFFERING:
    760780        processBufferingStats(message);
     
    765785    case GST_MESSAGE_DURATION:
    766786#endif
    767         LOG_MEDIA_MESSAGE("Duration changed");
    768         durationChanged();
     787        if (messageSourceIsPlaybin)
     788            durationChanged();
    769789        break;
    770790    case GST_MESSAGE_REQUEST_STATE:
     
    10341054}
    10351055
     1056void MediaPlayerPrivateGStreamer::asyncStateChangeDone()
     1057{
     1058    if (!m_playBin || m_errorOccured)
     1059        return;
     1060
     1061    if (m_seeking) {
     1062        if (m_seekIsPending)
     1063            updateStates();
     1064        else {
     1065            LOG_MEDIA_MESSAGE("[Seek] seeked to %f", m_seekTime);
     1066            m_seeking = false;
     1067            if (m_timeOfOverlappingSeek != -1) {
     1068                seek(m_timeOfOverlappingSeek);
     1069                m_timeOfOverlappingSeek = -1;
     1070                return;
     1071            }
     1072
     1073            // The pipeline can still have a pending state. In this case a position query will fail.
     1074            // Right now we can use m_seekTime as a fallback.
     1075            m_canFallBackToLastFinishedSeekPositon = true;
     1076            timeChanged();
     1077        }
     1078    } else
     1079        updateStates();
     1080}
     1081
    10361082void MediaPlayerPrivateGStreamer::updateStates()
    10371083{
     
    10471093    GstState pending;
    10481094
    1049     GstStateChangeReturn ret = gst_element_get_state(m_playBin.get(),
    1050         &state, &pending, 250 * GST_NSECOND);
    1051 
    1052     bool shouldUpdateAfterSeek = false;
     1095    GstStateChangeReturn getStateResult = gst_element_get_state(m_playBin.get(), &state, &pending, 250 * GST_NSECOND);
     1096
    10531097    bool shouldUpdatePlaybackState = false;
    1054     switch (ret) {
     1098    switch (getStateResult) {
    10551099    case GST_STATE_CHANGE_SUCCESS:
    1056         LOG_MEDIA_MESSAGE("State: %s, pending: %s",
    1057             gst_element_state_get_name(state),
    1058             gst_element_state_get_name(pending));
     1100        LOG_MEDIA_MESSAGE("State: %s, pending: %s", gst_element_state_get_name(state), gst_element_state_get_name(pending));
    10591101
    10601102        m_resetPipeline = state <= GST_STATE_READY;
     
    11331175        }
    11341176
    1135         if (m_seeking) {
    1136             shouldUpdateAfterSeek = true;
    1137             m_seeking = false;
    1138         }
    1139 
    11401177        if (m_requestedState == GST_STATE_PAUSED && state == GST_STATE_PAUSED) {
    11411178            shouldUpdatePlaybackState = true;
     
    11451182        break;
    11461183    case GST_STATE_CHANGE_ASYNC:
    1147         LOG_MEDIA_MESSAGE("Async: State: %s, pending: %s",
    1148             gst_element_state_get_name(state),
    1149             gst_element_state_get_name(pending));
     1184        LOG_MEDIA_MESSAGE("Async: State: %s, pending: %s", gst_element_state_get_name(state), gst_element_state_get_name(pending));
    11501185        // Change in progress
    11511186
     
    11651200        }
    11661201
    1167         if (!isLiveStream() && !m_buffering)
    1168             return;
    1169 
    1170         if (m_seeking) {
    1171             shouldUpdateAfterSeek = true;
    1172             m_seeking = false;
    1173         }
    11741202        break;
    11751203    case GST_STATE_CHANGE_FAILURE:
    1176         LOG_MEDIA_MESSAGE("Failure: State: %s, pending: %s",
    1177             gst_element_state_get_name(state),
    1178             gst_element_state_get_name(pending));
     1204        LOG_MEDIA_MESSAGE("Failure: State: %s, pending: %s", gst_element_state_get_name(state), gst_element_state_get_name(pending));
    11791205        // Change failed
    11801206        return;
    11811207    case GST_STATE_CHANGE_NO_PREROLL:
    1182         LOG_MEDIA_MESSAGE("No preroll: State: %s, pending: %s",
    1183             gst_element_state_get_name(state),
    1184             gst_element_state_get_name(pending));
     1208        LOG_MEDIA_MESSAGE("No preroll: State: %s, pending: %s", gst_element_state_get_name(state), gst_element_state_get_name(pending));
    11851209
    11861210        if (state == GST_STATE_READY)
     
    11941218            m_paused = false;
    11951219
    1196         if (m_seeking) {
    1197             shouldUpdateAfterSeek = true;
    1198             m_seeking = false;
    1199             if (!m_paused)
    1200                 gst_element_set_state(m_playBin.get(), GST_STATE_PLAYING);
    1201         } else if (!m_paused)
     1220        if (!m_paused)
    12021221            gst_element_set_state(m_playBin.get(), GST_STATE_PLAYING);
    12031222
     
    12051224        break;
    12061225    default:
    1207         LOG_MEDIA_MESSAGE("Else : %d", ret);
     1226        LOG_MEDIA_MESSAGE("Else : %d", getStateResult);
    12081227        break;
    12091228    }
    12101229
    12111230    m_requestedState = GST_STATE_VOID_PENDING;
    1212 
    1213     if (seeking())
    1214         m_readyState = MediaPlayer::HaveNothing;
    1215 
    1216     if (shouldUpdateAfterSeek)
    1217         timeChanged();
    12181231
    12191232    if (shouldUpdatePlaybackState)
     
    12211234
    12221235    if (m_networkState != oldNetworkState) {
    1223         LOG_MEDIA_MESSAGE("Network State Changed from %u to %u",
    1224             oldNetworkState, m_networkState);
     1236        LOG_MEDIA_MESSAGE("Network State Changed from %u to %u", oldNetworkState, m_networkState);
    12251237        m_player->networkStateChanged();
    12261238    }
    12271239    if (m_readyState != oldReadyState) {
    1228         LOG_MEDIA_MESSAGE("Ready State Changed from %u to %u",
    1229             oldReadyState, m_readyState);
     1240        LOG_MEDIA_MESSAGE("Ready State Changed from %u to %u", oldReadyState, m_readyState);
    12301241        m_player->readyStateChanged();
     1242    }
     1243
     1244    if (m_seekIsPending && getStateResult == GST_STATE_CHANGE_SUCCESS && (state == GST_STATE_PAUSED || state == GST_STATE_PLAYING)) {
     1245        LOG_MEDIA_MESSAGE("[Seek] committing pending seek to %f", m_seekTime);
     1246        m_seekIsPending = false;
     1247        m_seeking = gst_element_seek(m_playBin.get(), m_player->rate(), GST_FORMAT_TIME, static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
     1248            GST_SEEK_TYPE_SET, toGstClockTime(m_seekTime), GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
     1249        if (!m_seeking)
     1250            LOG_MEDIA_MESSAGE("[Seek] seeking to %f failed", m_seekTime);
    12311251    }
    12321252}
     
    13621382    // And re-cache it if possible.
    13631383    GstState state;
    1364     gst_element_get_state(m_playBin.get(), &state, 0, 0);
     1384    GstStateChangeReturn getStateResult = gst_element_get_state(m_playBin.get(), &state, 0, 0);
    13651385    float newDuration = duration();
    13661386
    1367     if (state <= GST_STATE_READY) {
     1387    if (state > GST_STATE_READY && getStateResult == GST_STATE_CHANGE_SUCCESS) {
    13681388        // Don't set m_mediaDurationKnown yet if the pipeline is not
    1369         // paused. This allows duration() query to fail at least once
     1389        // stable. This allows duration() query to fail at least once
    13701390        // before playback starts and duration becomes known.
    1371         if (!std::isinf(newDuration))
    1372             m_mediaDuration = newDuration;
    1373     } else {
    13741391        m_mediaDurationKnown = !std::isinf(newDuration);
    1375         if (m_mediaDurationKnown)
    1376             m_mediaDuration = newDuration;
    13771392    }
    13781393
  • trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h

    r150031 r150066  
    115115    void cacheDuration();
    116116    void updateStates();
     117    void asyncStateChangeDone();
    117118
    118119    void createGSTPlayBin();
     
    141142    bool m_paused;
    142143    bool m_seeking;
     144    bool m_seekIsPending;
     145    float m_timeOfOverlappingSeek;
     146    bool m_canFallBackToLastFinishedSeekPositon;
    143147    bool m_buffering;
    144148    float m_playbackRate;
Note: See TracChangeset for help on using the changeset viewer.