Unreviewed, rolling out r150022.

http://trac.webkit.org/changeset/150022
https://bugs.webkit.org/show_bug.cgi?id=114044

Causes assertions in media tests

Source/WebCore:

* platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
(WebCore::MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer):
(WebCore::MediaPlayerPrivateGStreamer::playbackPosition):
(WebCore::MediaPlayerPrivateGStreamer::prepareToPlay):
(WebCore::MediaPlayerPrivateGStreamer::currentTime):
(WebCore::MediaPlayerPrivateGStreamer::seek):
(WebCore::MediaPlayerPrivateGStreamer::handleMessage):
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:
(MediaPlayerPrivateGStreamer):

LayoutTests:

* media/video-seek-after-end-expected.txt: Removed.
* media/video-seek-after-end.html: Removed.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@150031 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 59d47873
2013-05-13 Christophe Dumez <ch.dumez@sisa.samsung.com>
Unreviewed, rolling out r150022.
http://trac.webkit.org/changeset/150022
https://bugs.webkit.org/show_bug.cgi?id=114044
Causes assertions in media tests
* media/video-seek-after-end-expected.txt: Removed.
* media/video-seek-after-end.html: Removed.
2013-05-13 Bem Jones-Bey <bjonesbe@adobe.com>
Fix the float logic to not return an anonymous block ancestor
......
Test that we can seek after reached the end of the video.
EVENT(playing)
EVENT(ended)
EVENT(seeked)
EVENT(playing)
EXPECTED (video.currentTime.toFixed(2) == '3') OK
END OF TEST
<!DOCTYPE HTML>
<html>
<head>
<script src=media-file.js></script>
<script src=video-test.js></script>
<script>
function start()
{
findMediaElement();
var countPlaying = 0;
waitForEvent('playing', function() {
if (++countPlaying > 2) {
logResult(false, 'FAIL: playing fired more then twice.');
endTest();
return;
}
var seekTarget = 3;
if (countPlaying == 2) {
testExpected('video.currentTime.toFixed(2)', seekTarget, '==');
endTest();
return;
}
waitForEventOnce('ended', function() {
video.currentTime = seekTarget;
waitForEventOnce('seeked', function() { video.play(); })
});
video.currentTime = video.duration - 0.2;
});
video.src = findMediaFile('video', 'content/test');
video.play();
setTimeout(function() {
logResult(false, 'FAIL: timeout');
endTest();
}, 1000);
}
</script>
</head>
<body onload="start()">
<p>Test that we can seek after reached the end of the video.</p>
<video controls></video>
</body>
</html>
2013-05-13 Christophe Dumez <ch.dumez@sisa.samsung.com>
Unreviewed, rolling out r150022.
http://trac.webkit.org/changeset/150022
https://bugs.webkit.org/show_bug.cgi?id=114044
Causes assertions in media tests
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
(WebCore::MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer):
(WebCore::MediaPlayerPrivateGStreamer::playbackPosition):
(WebCore::MediaPlayerPrivateGStreamer::prepareToPlay):
(WebCore::MediaPlayerPrivateGStreamer::currentTime):
(WebCore::MediaPlayerPrivateGStreamer::seek):
(WebCore::MediaPlayerPrivateGStreamer::handleMessage):
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:
(MediaPlayerPrivateGStreamer):
2013-05-13 Bem Jones-Bey <bjonesbe@adobe.com>
Floats should not overhang from flex items
......
......@@ -138,18 +138,6 @@ static void mediaPlayerPrivatePluginInstallerResultFunction(GstInstallPluginsRet
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 @@ MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer(MediaPlayer* player)
, 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 @@ float MediaPlayerPrivateGStreamer::playbackPosition() const
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;
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);
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;
// 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 @@ bool MediaPlayerPrivateGStreamer::changePipelineState(GstState newState)
void MediaPlayerPrivateGStreamer::prepareToPlay()
{
m_isEndReached = false;
m_seeking = false;
if (m_delayingLoad) {
m_delayingLoad = false;
commitLoad();
......@@ -474,6 +467,7 @@ float MediaPlayerPrivateGStreamer::currentTime() const
return 0.0f;
return playbackPosition();
}
void MediaPlayerPrivateGStreamer::seek(float time)
......@@ -484,52 +478,35 @@ void MediaPlayerPrivateGStreamer::seek(float time)
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;
GstClockTime clockTime = toGstClockTime(time);
LOG_MEDIA_MESSAGE("[Seek] seeking to %" GST_TIME_FORMAT " (%f)", GST_TIME_ARGS(clockTime), 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);
if (m_seeking) {
if (m_seekIsPending) {
m_seekTime = time;
return;
}
m_timeOfOverlappingSeek = time;
GstClockTime clockTime = GST_TIMEVAL_TO_TIME(timeValue);
LOG_MEDIA_MESSAGE("Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(clockTime));
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 @@ gboolean MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message)
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 @@ gboolean MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message)
}
}
// 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 @@ gboolean MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message)
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();
}
// 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, &currentState, &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());
// Construct a filename for the graphviz dot file output.
GstState newState;
gst_message_parse_state_changed(message, &currentState, &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 @@ gboolean MediaPlayerPrivateGStreamer::handleMessage(GstMessage* message)
#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 @@ void MediaPlayerPrivateGStreamer::cancelLoad()
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 @@ void MediaPlayerPrivateGStreamer::updateStates()
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 @@ void MediaPlayerPrivateGStreamer::updateStates()
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 @@ void MediaPlayerPrivateGStreamer::updateStates()
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 @@ void MediaPlayerPrivateGStreamer::updateStates()
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 @@ void MediaPlayerPrivateGStreamer::updateStates()
} 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 @@ void MediaPlayerPrivateGStreamer::cacheDuration()
// 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))
......
......@@ -114,7 +114,6 @@ private:
void cacheDuration();
void updateStates();
void asyncStateChangeDone();
void createGSTPlayBin();
bool changePipelineState(GstState);
......@@ -141,9 +140,6 @@ private:
bool m_resetPipeline;
bool m_paused;
bool m_seeking;
bool m_seekIsPending;
float m_timeOfOverlappingSeek;
bool m_canFallBackToLastFinishedSeekPositon;
bool m_buffering;
float m_playbackRate;
bool m_errorOccured;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment