Modified: trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp (150030 => 150031)
--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp 2013-05-13 19:31:04 UTC (rev 150030)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp 2013-05-13 19:35:32 UTC (rev 150031)
@@ -138,18 +138,6 @@
player->handlePluginInstallerResult(result);
}
-static GstClockTime toGstClockTime(float time)
-{
- // Extract the integer part of the time (seconds) and the fractional part (microseconds). Attempt to
- // round the microseconds so no floating point precision is lost and we can perform an accurate seek.
- float seconds;
- float microSeconds = modf(time, &seconds) * 1000000;
- GTimeVal timeValue;
- timeValue.tv_sec = static_cast<glong>(seconds);
- timeValue.tv_usec = static_cast<glong>(roundf(microSeconds / 10000) * 10000);
- return GST_TIMEVAL_TO_TIME(timeValue);
-}
-
void MediaPlayerPrivateGStreamer::setAudioStreamProperties(GObject* object)
{
if (g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstPulseSink"))
@@ -211,8 +199,6 @@
, m_resetPipeline(false)
, m_paused(true)
, m_seeking(false)
- , m_seekIsPending(false)
- , m_timeOfOverlappingSeek(-1)
, m_buffering(false)
, m_playbackRate(1)
, m_errorOccured(false)
@@ -347,26 +333,30 @@
return m_seekTime;
if (m_mediaDuration)
return m_mediaDuration;
- return 0;
}
- // Position is only available if no async state change is going on and the state is either paused or playing.
- gint64 position = GST_CLOCK_TIME_NONE;
- GstQuery* query= gst_query_new_position(GST_FORMAT_TIME);
- if (gst_element_query(m_playBin.get(), query))
- gst_query_parse_position(query, 0, &position);
+ float ret = 0.0f;
- float result = 0.0f;
- if (static_cast<GstClockTime>(position) != GST_CLOCK_TIME_NONE)
- result = static_cast<double>(position) / GST_SECOND;
- else if (m_canFallBackToLastFinishedSeekPositon)
- result = m_seekTime;
+ GstQuery* query = gst_query_new_position(GST_FORMAT_TIME);
+ if (!gst_element_query(m_playBin.get(), query)) {
+ LOG_MEDIA_MESSAGE("Position query failed...");
+ gst_query_unref(query);
+ return ret;
+ }
+ gint64 position;
+ gst_query_parse_position(query, 0, &position);
+
+ // Position is available only if the pipeline is not in GST_STATE_NULL or
+ // GST_STATE_READY state.
+ if (position != static_cast<gint64>(GST_CLOCK_TIME_NONE))
+ ret = static_cast<double>(position) / GST_SECOND;
+
LOG_MEDIA_MESSAGE("Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position));
gst_query_unref(query);
- return result;
+ return ret;
}
bool MediaPlayerPrivateGStreamer::changePipelineState(GstState newState)
@@ -397,6 +387,9 @@
void MediaPlayerPrivateGStreamer::prepareToPlay()
{
+ m_isEndReached = false;
+ m_seeking = false;
+
if (m_delayingLoad) {
m_delayingLoad = false;
commitLoad();
@@ -474,6 +467,7 @@
return 0.0f;
return playbackPosition();
+
}
void MediaPlayerPrivateGStreamer::seek(float time)
@@ -484,52 +478,35 @@
if (m_errorOccured)
return;
- LOG_MEDIA_MESSAGE("[Seek] seek attempt to %f secs", time);
+ LOG_MEDIA_MESSAGE("Seek attempt to %f secs", time);
// Avoid useless seeking.
if (time == currentTime())
return;
- if (isLiveStream())
- return;
+ // Extract the integer part of the time (seconds) and the
+ // fractional part (microseconds). Attempt to round the
+ // microseconds so no floating point precision is lost and we can
+ // perform an accurate seek.
+ float seconds;
+ float microSeconds = modf(time, &seconds) * 1000000;
+ GTimeVal timeValue;
+ timeValue.tv_sec = static_cast<glong>(seconds);
+ timeValue.tv_usec = static_cast<glong>(roundf(microSeconds / 10000) * 10000);
- GstClockTime clockTime = toGstClockTime(time);
- LOG_MEDIA_MESSAGE("[Seek] seeking to %" GST_TIME_FORMAT " (%f)", GST_TIME_ARGS(clockTime), time);
+ GstClockTime clockTime = GST_TIMEVAL_TO_TIME(timeValue);
+ LOG_MEDIA_MESSAGE("Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(clockTime));
- if (m_seeking) {
- if (m_seekIsPending) {
- m_seekTime = time;
- return;
- }
- m_timeOfOverlappingSeek = time;
+ if (!gst_element_seek(m_playBin.get(), m_player->rate(),
+ GST_FORMAT_TIME,
+ (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
+ GST_SEEK_TYPE_SET, clockTime,
+ GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
+ LOG_MEDIA_MESSAGE("Seek to %f failed", time);
+ else {
+ m_seeking = true;
+ m_seekTime = time;
}
-
- GstState state;
- GstStateChangeReturn getStateResult = gst_element_get_state(m_playBin.get(), &state, 0, 0);
- if (getStateResult == GST_STATE_CHANGE_FAILURE || getStateResult == GST_STATE_CHANGE_NO_PREROLL) {
- LOG_MEDIA_MESSAGE("[Seek] cannot seek, current state change is %s", gst_element_state_change_return_get_name(getStateResult));
- return;
- }
- if (getStateResult == GST_STATE_CHANGE_ASYNC || state < GST_STATE_PAUSED || m_isEndReached) {
- m_seekIsPending = true;
- if (m_isEndReached) {
- LOG_MEDIA_MESSAGE("[Seek] reset pipeline");
- ASSERT(state == GST_STATE_NULL);
- m_resetPipeline = true;
- changePipelineState(GST_STATE_PAUSED);
- }
- } else {
- // We can seek now.
- if (!gst_element_seek(m_playBin.get(), m_player->rate(), GST_FORMAT_TIME, static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
- GST_SEEK_TYPE_SET, clockTime, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
- LOG_MEDIA_MESSAGE("[Seek] seeking to %f failed", time);
- return;
- }
- }
-
- m_seeking = true;
- m_seekTime = time;
- m_isEndReached = false;
}
bool MediaPlayerPrivateGStreamer::paused() const
@@ -703,8 +680,6 @@
const GstStructure* structure = gst_message_get_structure(message);
GstState requestedState, currentState;
- m_canFallBackToLastFinishedSeekPositon = false;
-
if (structure) {
const gchar* messageTypeName = gst_structure_get_name(structure);
@@ -716,10 +691,7 @@
}
}
- // We ignore state changes from internal elements. They are forwarded to playbin2 anyway.
- bool messageSourceIsPlaybin = GST_MESSAGE_SRC(message) == reinterpret_cast<GstObject*>(m_playBin.get());
-
- LOG_MEDIA_MESSAGE("Message %s received from element %s", GST_MESSAGE_TYPE_NAME(message), GST_MESSAGE_SRC_NAME(message));
+ LOG_MEDIA_MESSAGE("Message received from element %s", GST_MESSAGE_SRC_NAME(message));
switch (GST_MESSAGE_TYPE(message)) {
case GST_MESSAGE_ERROR:
if (m_resetPipeline)
@@ -757,26 +729,33 @@
loadingFailed(error);
break;
case GST_MESSAGE_EOS:
+ LOG_MEDIA_MESSAGE("End of Stream");
didEnd();
break;
- case GST_MESSAGE_ASYNC_DONE:
- if (!messageSourceIsPlaybin || m_delayingLoad)
+ case GST_MESSAGE_STATE_CHANGED:
+ // Ignore state changes if load is delayed (preload=none). The
+ // player state will be updated once commitLoad() is called.
+ if (m_delayingLoad) {
+ LOG_MEDIA_MESSAGE("Media load has been delayed. Ignoring state changes for now");
break;
- asyncStateChangeDone();
- break;
- case GST_MESSAGE_STATE_CHANGED: {
- if (!messageSourceIsPlaybin || m_delayingLoad)
- break;
- updateStates();
+ }
- // Construct a filename for the graphviz dot file output.
- GstState newState;
- gst_message_parse_state_changed(message, ¤tState, &newState, 0);
- CString dotFileName = String::format("webkit-video.%s_%s", gst_element_state_get_name(currentState), gst_element_state_get_name(newState)).utf8();
- GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_playBin.get()), GST_DEBUG_GRAPH_SHOW_ALL, dotFileName.data());
+ // Ignore state changes from internal elements. They are
+ // forwarded to playbin2 anyway.
+ if (GST_MESSAGE_SRC(message) == reinterpret_cast<GstObject*>(m_playBin.get())) {
+ updateStates();
+ // Construct a filename for the graphviz dot file output.
+ GstState newState;
+ gst_message_parse_state_changed(message, ¤tState, &newState, 0);
+
+ CString dotFileName = String::format("webkit-video.%s_%s",
+ gst_element_state_get_name(currentState),
+ gst_element_state_get_name(newState)).utf8();
+
+ GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_playBin.get()), GST_DEBUG_GRAPH_SHOW_ALL, dotFileName.data());
+ }
break;
- }
case GST_MESSAGE_BUFFERING:
processBufferingStats(message);
break;
@@ -785,8 +764,8 @@
#else
case GST_MESSAGE_DURATION:
#endif
- if (messageSourceIsPlaybin)
- durationChanged();
+ LOG_MEDIA_MESSAGE("Duration changed");
+ durationChanged();
break;
case GST_MESSAGE_REQUEST_STATE:
gst_message_parse_request_state(message, &requestedState);
@@ -1054,32 +1033,6 @@
gst_element_set_state(m_playBin.get(), GST_STATE_NULL);
}
-void MediaPlayerPrivateGStreamer::asyncStateChangeDone()
-{
- if (!m_playBin || m_errorOccured)
- return;
-
- if (m_seeking) {
- if (m_seekIsPending)
- updateStates();
- else {
- LOG_MEDIA_MESSAGE("[Seek] seeked to %f", m_seekTime);
- m_seeking = false;
- if (m_timeOfOverlappingSeek != -1) {
- seek(m_timeOfOverlappingSeek);
- m_timeOfOverlappingSeek = -1;
- return;
- }
-
- // The pipeline can still have a pending state. In this case a position query will fail.
- // Right now we can use m_seekTime as a fallback.
- m_canFallBackToLastFinishedSeekPositon = true;
- timeChanged();
- }
- } else
- updateStates();
-}
-
void MediaPlayerPrivateGStreamer::updateStates()
{
if (!m_playBin)
@@ -1093,12 +1046,16 @@
GstState state;
GstState pending;
- GstStateChangeReturn getStateResult = gst_element_get_state(m_playBin.get(), &state, &pending, 250 * GST_NSECOND);
+ GstStateChangeReturn ret = gst_element_get_state(m_playBin.get(),
+ &state, &pending, 250 * GST_NSECOND);
+ bool shouldUpdateAfterSeek = false;
bool shouldUpdatePlaybackState = false;
- switch (getStateResult) {
+ switch (ret) {
case GST_STATE_CHANGE_SUCCESS:
- LOG_MEDIA_MESSAGE("State: %s, pending: %s", gst_element_state_get_name(state), gst_element_state_get_name(pending));
+ LOG_MEDIA_MESSAGE("State: %s, pending: %s",
+ gst_element_state_get_name(state),
+ gst_element_state_get_name(pending));
m_resetPipeline = state <= GST_STATE_READY;
@@ -1175,6 +1132,11 @@
m_changingRate = false;
}
+ if (m_seeking) {
+ shouldUpdateAfterSeek = true;
+ m_seeking = false;
+ }
+
if (m_requestedState == GST_STATE_PAUSED && state == GST_STATE_PAUSED) {
shouldUpdatePlaybackState = true;
LOG_MEDIA_MESSAGE("Requested state change to %s was completed", gst_element_state_get_name(state));
@@ -1182,7 +1144,9 @@
break;
case GST_STATE_CHANGE_ASYNC:
- LOG_MEDIA_MESSAGE("Async: State: %s, pending: %s", gst_element_state_get_name(state), gst_element_state_get_name(pending));
+ LOG_MEDIA_MESSAGE("Async: State: %s, pending: %s",
+ gst_element_state_get_name(state),
+ gst_element_state_get_name(pending));
// Change in progress
// On-disk buffering was attempted but the media is live. This
@@ -1200,13 +1164,24 @@
gst_element_set_state(m_playBin.get(), GST_STATE_PLAYING);
}
+ if (!isLiveStream() && !m_buffering)
+ return;
+
+ if (m_seeking) {
+ shouldUpdateAfterSeek = true;
+ m_seeking = false;
+ }
break;
case GST_STATE_CHANGE_FAILURE:
- LOG_MEDIA_MESSAGE("Failure: State: %s, pending: %s", gst_element_state_get_name(state), gst_element_state_get_name(pending));
+ LOG_MEDIA_MESSAGE("Failure: State: %s, pending: %s",
+ gst_element_state_get_name(state),
+ gst_element_state_get_name(pending));
// Change failed
return;
case GST_STATE_CHANGE_NO_PREROLL:
- LOG_MEDIA_MESSAGE("No preroll: State: %s, pending: %s", gst_element_state_get_name(state), gst_element_state_get_name(pending));
+ LOG_MEDIA_MESSAGE("No preroll: State: %s, pending: %s",
+ gst_element_state_get_name(state),
+ gst_element_state_get_name(pending));
if (state == GST_STATE_READY)
m_readyState = MediaPlayer::HaveNothing;
@@ -1218,38 +1193,42 @@
} else if (state == GST_STATE_PLAYING)
m_paused = false;
- if (!m_paused)
+ if (m_seeking) {
+ shouldUpdateAfterSeek = true;
+ m_seeking = false;
+ if (!m_paused)
+ gst_element_set_state(m_playBin.get(), GST_STATE_PLAYING);
+ } else if (!m_paused)
gst_element_set_state(m_playBin.get(), GST_STATE_PLAYING);
m_networkState = MediaPlayer::Loading;
break;
default:
- LOG_MEDIA_MESSAGE("Else : %d", getStateResult);
+ LOG_MEDIA_MESSAGE("Else : %d", ret);
break;
}
m_requestedState = GST_STATE_VOID_PENDING;
+ if (seeking())
+ m_readyState = MediaPlayer::HaveNothing;
+
+ if (shouldUpdateAfterSeek)
+ timeChanged();
+
if (shouldUpdatePlaybackState)
m_player->playbackStateChanged();
if (m_networkState != oldNetworkState) {
- LOG_MEDIA_MESSAGE("Network State Changed from %u to %u", oldNetworkState, m_networkState);
+ LOG_MEDIA_MESSAGE("Network State Changed from %u to %u",
+ oldNetworkState, m_networkState);
m_player->networkStateChanged();
}
if (m_readyState != oldReadyState) {
- LOG_MEDIA_MESSAGE("Ready State Changed from %u to %u", oldReadyState, m_readyState);
+ LOG_MEDIA_MESSAGE("Ready State Changed from %u to %u",
+ oldReadyState, m_readyState);
m_player->readyStateChanged();
}
-
- if (m_seekIsPending && getStateResult == GST_STATE_CHANGE_SUCCESS && (state == GST_STATE_PAUSED || state == GST_STATE_PLAYING)) {
- LOG_MEDIA_MESSAGE("[Seek] committing pending seek to %f", m_seekTime);
- m_seekIsPending = false;
- 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),
- GST_SEEK_TYPE_SET, toGstClockTime(m_seekTime), GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
- if (!m_seeking)
- LOG_MEDIA_MESSAGE("[Seek] seeking to %f failed", m_seekTime);
- }
}
void MediaPlayerPrivateGStreamer::mediaLocationChanged(GstMessage* message)
@@ -1382,14 +1361,19 @@
// And re-cache it if possible.
GstState state;
- GstStateChangeReturn getStateResult = gst_element_get_state(m_playBin.get(), &state, 0, 0);
+ gst_element_get_state(m_playBin.get(), &state, 0, 0);
float newDuration = duration();
- if (state > GST_STATE_READY && getStateResult == GST_STATE_CHANGE_SUCCESS) {
+ if (state <= GST_STATE_READY) {
// Don't set m_mediaDurationKnown yet if the pipeline is not
- // stable. This allows duration() query to fail at least once
+ // paused. This allows duration() query to fail at least once
// before playback starts and duration becomes known.
+ if (!std::isinf(newDuration))
+ m_mediaDuration = newDuration;
+ } else {
m_mediaDurationKnown = !std::isinf(newDuration);
+ if (m_mediaDurationKnown)
+ m_mediaDuration = newDuration;
}
if (!std::isinf(newDuration))