Skip to content

Commit c2a7752

Browse files
committed
[MSE][GStreamer] Pause after seek is not working
https://bugs.webkit.org/show_bug.cgi?id=263317 Reviewed by Philippe Normand. When issuing seeks and play or pauses close to each other, there can be race conditions. To solve then first we need to avoid changing the pipeline state while seeking. Then we need to ensure we know if the pipeline change was rejected or failed, so the function signature was changed. We also need to consider that when a pause is requested by the element and the player issues it to the pipeline, we are paused because it can take some time for the pipeline to pause and if the element queries too fast, it can lead to more race conditions. * LayoutTests/media/media-controller-play-then-pause-expected.txt: * LayoutTests/media/media-controller-play-then-pause.html: * LayoutTests/media/media-source/media-controller-media-source-play-then-pause-expected.txt: Added. * LayoutTests/media/media-source/media-controller-media-source-play-then-pause.html: Added. * LayoutTests/media/media-source/media-source-seek-and-play-expected.txt: Added. * LayoutTests/media/media-source/media-source-seek-and-play.html: Added. * LayoutTests/media/media-source/media-source-video-seek-pause-expected.txt: Added. * LayoutTests/media/media-source/media-source-video-seek-pause.html: Added. * LayoutTests/media/video-seek-pause-expected.txt: Added. * LayoutTests/media/video-seek-pause.html: Added. * LayoutTests/media/video-test.js: (return.new.Promise): * LayoutTests/platform/glib/TestExpectations: * LayoutTests/platform/ios/TestExpectations: * Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp: (WebCore::MediaPlayerPrivateGStreamer::isPipelineSeeking const): (WebCore::MediaPlayerPrivateGStreamer::play): (WebCore::MediaPlayerPrivateGStreamer::pause): (WebCore::MediaPlayerPrivateGStreamer::paused const): (WebCore::MediaPlayerPrivateGStreamer::seekToTarget): (WebCore::MediaPlayerPrivateGStreamer::changePipelineState): (WebCore::MediaPlayerPrivateGStreamer::handleMessage): * Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h: * Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp: (WebCore::MediaPlayerPrivateGStreamerMSE::updateStates): * Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.h: * Source/WebCore/testing/Internals.cpp: (WebCore::Internals::isPlayerPaused const): * Source/WebCore/testing/Internals.h: * Source/WebCore/testing/Internals.idl: Canonical link: https://commits.webkit.org/273977@main
1 parent 9622aa7 commit c2a7752

20 files changed

Lines changed: 1572 additions & 271 deletions
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
2+
RUN(controller = video.controller)
3+
EVENT(canplaythrough)
4+
RUN(controller.play())
5+
EVENT(playing)
6+
RUN(controller.pause())
7+
EVENT(pause)
8+
RUN(controller.play())
9+
EVENT(play)
10+
EXPECTED (controller.playbackState == 'playing') OK
11+
EXPECTED (!internals.isPlayerPaused(video)) OK
12+
EXPECTED (!internals.isPlayerPaused(video2)) OK
13+
END OF TEST
14+
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta name="timeout" content="long">
5+
<script src=media-file.js></script>
6+
<script src=video-test.js></script>
7+
<script>
8+
var controller;
9+
var video2;
10+
11+
async function start() {
12+
var videos = document.getElementsByTagName('video');
13+
video = videos[0];
14+
video2 = videos[1];
15+
run('controller = video.controller');
16+
var src = findMediaFile('video', 'content/test');
17+
video.src = src;
18+
video2.src = src;
19+
await waitFor(controller, 'canplaythrough');
20+
21+
run('controller.play()');
22+
await waitFor(controller, 'playing');
23+
24+
run('controller.pause()');
25+
await waitFor(controller, 'pause');
26+
27+
run('controller.play()');
28+
await waitFor(controller, 'play');
29+
30+
testExpected('controller.playbackState', 'playing');
31+
await waitForConditionOrTimeout('!internals.isPlayerPaused(video)');
32+
await waitForConditionOrTimeout('!internals.isPlayerPaused(video2)');
33+
endTest();
34+
}
35+
</script>
36+
</head>
37+
<body onload="start()">
38+
<video mediaGroup="group" controls></video>
39+
<video mediaGroup="group" controls></video>
40+
</body>
41+
</html>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
2+
RUN(controller = video.controller)
3+
RUN(video.src = URL.createObjectURL(source))
4+
EVENT(sourceopen)
5+
RUN(sourceBuffer = source.addSourceBuffer(loader.type()))
6+
RUN(sourceBuffer.appendBuffer(loader.initSegment()))
7+
EVENT(update)
8+
Append all media segments
9+
RUN(video2.src = URL.createObjectURL(source2))
10+
EVENT(sourceopen)
11+
RUN(sourceBuffer2 = source2.addSourceBuffer(loader.type()))
12+
RUN(sourceBuffer2.appendBuffer(loader.initSegment()))
13+
EVENT(update)
14+
Append all media segments
15+
RUN(controller.play())
16+
EVENT(playing)
17+
EXPECTED (!internals.isPlayerPaused(video)) OK
18+
EXPECTED (!internals.isPlayerPaused(video2)) OK
19+
RUN(controller.pause())
20+
EVENT(pause)
21+
EXPECTED (internals.isPlayerPaused(video)) OK
22+
EXPECTED (internals.isPlayerPaused(video2)) OK
23+
RUN(controller.play())
24+
EVENT(play)
25+
EXPECTED (controller.playbackState == 'playing') OK
26+
EXPECTED (!internals.isPlayerPaused(video)) OK
27+
EXPECTED (!internals.isPlayerPaused(video2)) OK
28+
END OF TEST
29+
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta name="timeout" content="long">
5+
<script src="media-source-loader.js"></script>
6+
<script src="../video-test.js"></script>
7+
<script>
8+
var loader;
9+
var source;
10+
var source2;
11+
var sourceBuffer;
12+
var sourceBuffer2;
13+
var controller;
14+
var video2;
15+
var i;
16+
17+
function loaderPromise(loader) {
18+
return new Promise((resolve, reject) => {
19+
loader.onload = resolve;
20+
loader.onerror = reject;
21+
});
22+
}
23+
24+
async function start() {
25+
loader = new MediaSourceLoader('content/test-fragmented-manifest.json');
26+
await loaderPromise(loader);
27+
28+
var videos = document.getElementsByTagName('video');
29+
video = videos[0];
30+
video2 = videos[1];
31+
run('controller = video.controller');
32+
33+
source = new MediaSource();
34+
run('video.src = URL.createObjectURL(source)');
35+
await waitFor(source, 'sourceopen');
36+
waitFor(video, 'error').then(failTest);
37+
38+
run('sourceBuffer = source.addSourceBuffer(loader.type())');
39+
run('sourceBuffer.appendBuffer(loader.initSegment())');
40+
await waitFor(sourceBuffer, 'update');
41+
42+
consoleWrite('Append all media segments')
43+
for (i = 0; i < loader.mediaSegmentsLength(); i++) {
44+
sourceBuffer.appendBuffer(loader.mediaSegment(i));
45+
await waitFor(sourceBuffer, 'update', true);
46+
}
47+
48+
source2 = new MediaSource();
49+
run('video2.src = URL.createObjectURL(source2)');
50+
await waitFor(source2, 'sourceopen');
51+
waitFor(video2, 'error').then(failTest);
52+
53+
run('sourceBuffer2 = source2.addSourceBuffer(loader.type())');
54+
run('sourceBuffer2.appendBuffer(loader.initSegment())');
55+
await waitFor(sourceBuffer2, 'update');
56+
57+
consoleWrite('Append all media segments')
58+
for (i = 0; i < loader.mediaSegmentsLength(); i++) {
59+
sourceBuffer2.appendBuffer(loader.mediaSegment(i));
60+
await waitFor(sourceBuffer2, 'update', true);
61+
}
62+
63+
run('controller.play()');
64+
await waitFor(controller, 'playing');
65+
await waitForConditionOrTimeout('!internals.isPlayerPaused(video)', false, 5000);
66+
await waitForConditionOrTimeout('!internals.isPlayerPaused(video2)', false, 5000);
67+
68+
run('controller.pause()');
69+
await waitFor(controller, 'pause');
70+
await waitForConditionOrTimeout('internals.isPlayerPaused(video)', false, 5000);
71+
await waitForConditionOrTimeout('internals.isPlayerPaused(video2)', false, 5000);
72+
73+
run('controller.play()');
74+
await waitFor(controller, 'play');
75+
76+
testExpected('controller.playbackState', 'playing');
77+
await waitForConditionOrTimeout('!internals.isPlayerPaused(video)', false, 5000);
78+
await waitForConditionOrTimeout('!internals.isPlayerPaused(video2)', false, 5000);
79+
80+
endTest();
81+
}
82+
</script>
83+
</head>
84+
<body onload="start()">
85+
<video mediaGroup="group" controls></video>
86+
<video mediaGroup="group" controls></video>
87+
</body>
88+
</html>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
RUN(video.src = URL.createObjectURL(source))
3+
EVENT(sourceopen)
4+
RUN(sourceBuffer = source.addSourceBuffer(loader.type()))
5+
RUN(sourceBuffer.appendBuffer(loader.initSegment()))
6+
EVENT(update)
7+
Appended all media segments
8+
RUN(video.currentTime = 0)
9+
RUN(video.play())
10+
EVENT(playing)
11+
EXPECTED (video.paused == 'false') OK
12+
RUN(video.pause())
13+
EVENT(pause)
14+
EXPECTED (video.paused == 'true') OK
15+
RUN(video.currentTime = 1)
16+
RUN(video.play())
17+
EVENT(play)
18+
EXPECTED (video.paused == 'false') OK
19+
EXPECTED (!internals.isPlayerPaused(video)) OK
20+
END OF TEST
21+
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta name="timeout" content="long">
5+
<script src="media-source-loader.js"></script>
6+
<script src="../video-test.js"></script>
7+
<script>
8+
var loader;
9+
var source;
10+
var sourceBuffer;
11+
var i;
12+
13+
function loaderPromise(loader) {
14+
return new Promise((resolve, reject) => {
15+
loader.onload = resolve;
16+
loader.onerror = reject;
17+
});
18+
}
19+
20+
async function start() {
21+
22+
findMediaElement();
23+
24+
let isTestEnded = false;
25+
let numberOfInitiatedSeeks = 0;
26+
let numberOfCompletedSeeks = 0;
27+
28+
async function finalCheck() {
29+
if (!isTestEnded || numberOfInitiatedSeeks < 2 || numberOfCompletedSeeks < 1) {
30+
return;
31+
}
32+
33+
await waitForConditionOrTimeout('!internals.isPlayerPaused(video)', false, 5000, 1000);
34+
endTest();
35+
}
36+
37+
video.addEventListener('seeking', event => {
38+
numberOfInitiatedSeeks++;
39+
});
40+
41+
video.addEventListener('seeked', event => {
42+
numberOfCompletedSeeks++;
43+
finalCheck();
44+
});
45+
46+
loader = new MediaSourceLoader('content/test-fragmented-manifest.json');
47+
await loaderPromise(loader);
48+
49+
source = new MediaSource();
50+
run('video.src = URL.createObjectURL(source)');
51+
await waitFor(source, 'sourceopen');
52+
waitFor(video, 'error').then(failTest);
53+
54+
run('sourceBuffer = source.addSourceBuffer(loader.type())');
55+
run('sourceBuffer.appendBuffer(loader.initSegment())');
56+
await waitFor(sourceBuffer, 'update');
57+
58+
for (i = 0; i < loader.mediaSegmentsLength(); i++) {
59+
sourceBuffer.appendBuffer(loader.mediaSegment(i));
60+
await waitFor(sourceBuffer, 'update', true);
61+
}
62+
consoleWrite('Appended all media segments')
63+
64+
run('video.currentTime = 0');
65+
run('video.play()');
66+
await waitFor(video, 'playing');
67+
testExpected('video.paused', false);
68+
69+
run('video.pause()');
70+
await waitFor(video, 'pause');
71+
testExpected('video.paused', true);
72+
73+
run('video.currentTime = 1');
74+
run('video.play()');
75+
await waitFor(video, 'play');
76+
testExpected('video.paused', false);
77+
78+
isTestEnded = true;
79+
finalCheck();
80+
}
81+
</script>
82+
</head>
83+
<body onload="start()">
84+
<video></video>
85+
</body>
86+
</html>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
RUN(video.src = URL.createObjectURL(source))
3+
EVENT(sourceopen)
4+
RUN(sourceBuffer = source.addSourceBuffer(loader.type()))
5+
RUN(sourceBuffer.appendBuffer(loader.initSegment()))
6+
EVENT(update)
7+
Append all media segments
8+
RUN('video.play()')
9+
EXPECTED (video.paused == 'false') OK
10+
RUN(video.currentTime = 2)
11+
RUN(video.pause())
12+
EXPECTED (internals.isPlayerPaused(video)) OK
13+
EXPECTED (video.paused == 'true') OK
14+
END OF TEST
15+
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>media-source-video-seek-pause</title>
5+
<script src="../video-test.js"></script>
6+
<script src="media-source-loader.js"></script>
7+
<script>
8+
var loader;
9+
var source;
10+
var sourceBuffer;
11+
12+
function loaderPromise(loader) {
13+
return new Promise((resolve, reject) => {
14+
loader.onload = resolve;
15+
loader.onerror = reject;
16+
});
17+
}
18+
19+
async function startTest()
20+
{
21+
findMediaElement();
22+
23+
loader = new MediaSourceLoader('content/test-fragmented-manifest.json');
24+
await loaderPromise(loader);
25+
26+
source = new MediaSource();
27+
run('video.src = URL.createObjectURL(source)');
28+
await waitFor(source, 'sourceopen');
29+
waitFor(video, 'error').then(failTest);
30+
31+
run('sourceBuffer = source.addSourceBuffer(loader.type())');
32+
run('sourceBuffer.appendBuffer(loader.initSegment())');
33+
await waitFor(sourceBuffer, 'update');
34+
35+
consoleWrite('Append all media segments')
36+
for (i = 0; i < loader.mediaSegmentsLength(); i++) {
37+
sourceBuffer.appendBuffer(loader.mediaSegment(i));
38+
await waitFor(sourceBuffer, 'update', true);
39+
}
40+
41+
consoleWrite("RUN('video.play()')");
42+
await video.play();
43+
testExpected('video.paused', false);
44+
run('video.currentTime = 2');
45+
await sleepFor(5);
46+
run('video.pause()');
47+
await waitForConditionOrTimeout('internals.isPlayerPaused(video)');
48+
testExpected('video.paused', true);
49+
endTest();
50+
}
51+
</script>
52+
</head>
53+
<body onload="startTest()">
54+
<video controls></video>
55+
</body>
56+
</html>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
EVENT(canplaythrough)
3+
RUN('video.play()')
4+
EXPECTED (video.paused == 'false') OK
5+
EXPECTED (internals.isPlayerPaused(video) == 'false') OK
6+
RUN(video.currentTime = 2)
7+
RUN(video.pause())
8+
EXPECTED (internals.isPlayerPaused(video)) OK
9+
EXPECTED (video.paused == 'true') OK
10+
END OF TEST
11+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>video-seek-pause</title>
5+
<script src="video-test.js"></script>
6+
<script src="media-file.js"></script>
7+
<script>
8+
async function startTest()
9+
{
10+
findMediaElement();
11+
video.src = findMediaFile('video', 'content/test');
12+
await waitFor(video, 'canplaythrough');
13+
consoleWrite("RUN('video.play()')");
14+
await video.play();
15+
testExpected('video.paused', false);
16+
testExpected('internals.isPlayerPaused(video)', false);
17+
run('video.currentTime = 2');
18+
await sleepFor(5);
19+
run('video.pause()');
20+
await waitForConditionOrTimeout('internals.isPlayerPaused(video)', false, 2000);
21+
testExpected('video.paused', true);
22+
endTest();
23+
}
24+
</script>
25+
</head>
26+
<body onload="startTest()">
27+
<video controls></video>
28+
</body>
29+
</html>

0 commit comments

Comments
 (0)