Skip to content

Commit

Permalink
Update test utils to use video.rVFC (KhronosGroup#3065)
Browse files Browse the repository at this point in the history
* Update test utils to use video.rVFC

The startPlayingAndWaitForVideo function uses various heuristics to
determine whether or not a video has started playing. These heuristics
mostly rely on currentTime progress, but aren't necessarily
reliable when determining whether there is actually new video data to
be consumed.

This PR adds cross browser support for the
video.requestVideoFrameCallback API, which can be used to replace the
heuristics, and potentially deflake tests. It applies to the 1.0.1, 1.0.2, 1.0.3,
and 2.0.0 conformance test suite snapshots, as well as top-of-tree.
  • Loading branch information
tguilbert-google authored May 15, 2020
1 parent 3429e1b commit 5885bea
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 113 deletions.
68 changes: 42 additions & 26 deletions conformance-suites/1.0.1/conformance/resources/webgl-test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -1320,42 +1320,58 @@ var addShaderSource = function(element, label, source) {
element.appendChild(div);
}

/**
* Provides video.requestVideoFrameCallback in a cross browser way.
* Returns a property, or undefined if unsuported.
*/
var getRequestVidFrameCallback = function() {
return HTMLVideoElement.prototype["requestVideoFrameCallback"];
};

/**
* Starts playing a video and waits for it to be consumable.
* @param {!HTMLVideoElement} video An HTML5 Video element.
* @param {!function(!HTMLVideoElement): void>} callback. Function to call when
* video is ready.
*/
var startPlayingAndWaitForVideo = function(video, callback) {
var gotPlaying = false;
var gotTimeUpdate = false;

var maybeCallCallback = function() {
if (gotPlaying && gotTimeUpdate && callback) {
callback(video);
callback = undefined;
video.removeEventListener('playing', playingListener, true);
video.removeEventListener('timeupdate', timeupdateListener, true);
}
};

var playingListener = function() {
gotPlaying = true;
maybeCallCallback();
};
var rvfc = getRequestVidFrameCallback();

if(rvfc === undefined) {
var gotPlaying = false;
var gotTimeUpdate = false;

var maybeCallCallback = function() {
if (gotPlaying && gotTimeUpdate && callback) {
callback(video);
callback = undefined;
video.removeEventListener('playing', playingListener, true);
video.removeEventListener('timeupdate', timeupdateListener, true);
}
};

var timeupdateListener = function() {
// Checking to make sure the current time has advanced beyond
// the start time seems to be a reliable heuristic that the
// video element has data that can be consumed.
if (video.currentTime > 0.0) {
gotTimeUpdate = true;
var playingListener = function() {
gotPlaying = true;
maybeCallCallback();
}
};
};

var timeupdateListener = function() {
// Checking to make sure the current time has advanced beyond
// the start time seems to be a reliable heuristic that the
// video element has data that can be consumed.
if (video.currentTime > 0.0) {
gotTimeUpdate = true;
maybeCallCallback();
}
};

video.addEventListener('playing', playingListener, true);
video.addEventListener('timeupdate', timeupdateListener, true);
} else {
// Calls video.requestVideoFrameCallback(_ => { callback(video) })
rvfc.call(video, _ => { callback(video) });
}

video.addEventListener('playing', playingListener, true);
video.addEventListener('timeupdate', timeupdateListener, true);
video.loop = true;
video.muted = true;
video.play();
Expand Down
68 changes: 42 additions & 26 deletions conformance-suites/1.0.2/conformance/resources/webgl-test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -1968,6 +1968,14 @@ var cancelAnimFrame = (function() {
window.clearTimeout;
})();

/**
* Provides video.requestVideoFrameCallback in a cross browser way.
* Returns a property, or undefined if unsuported.
*/
var getRequestVidFrameCallback = function() {
return HTMLVideoElement.prototype["requestVideoFrameCallback"];
};

/**
* Waits for the browser to composite the canvas associated with
* the WebGL context passed in.
Expand All @@ -1992,35 +2000,43 @@ var waitForComposite = function(gl, callback) {
* video is ready.
*/
var startPlayingAndWaitForVideo = function(video, callback) {
var gotPlaying = false;
var gotTimeUpdate = false;

var maybeCallCallback = function() {
if (gotPlaying && gotTimeUpdate && callback) {
callback(video);
callback = undefined;
video.removeEventListener('playing', playingListener, true);
video.removeEventListener('timeupdate', timeupdateListener, true);
}
};

var playingListener = function() {
gotPlaying = true;
maybeCallCallback();
};
var rvfc = getRequestVidFrameCallback();

if(rvfc === undefined) {
var gotPlaying = false;
var gotTimeUpdate = false;

var maybeCallCallback = function() {
if (gotPlaying && gotTimeUpdate && callback) {
callback(video);
callback = undefined;
video.removeEventListener('playing', playingListener, true);
video.removeEventListener('timeupdate', timeupdateListener, true);
}
};

var timeupdateListener = function() {
// Checking to make sure the current time has advanced beyond
// the start time seems to be a reliable heuristic that the
// video element has data that can be consumed.
if (video.currentTime > 0.0) {
gotTimeUpdate = true;
var playingListener = function() {
gotPlaying = true;
maybeCallCallback();
}
};
};

var timeupdateListener = function() {
// Checking to make sure the current time has advanced beyond
// the start time seems to be a reliable heuristic that the
// video element has data that can be consumed.
if (video.currentTime > 0.0) {
gotTimeUpdate = true;
maybeCallCallback();
}
};

video.addEventListener('playing', playingListener, true);
video.addEventListener('timeupdate', timeupdateListener, true);
} else {
// Calls video.requestVideoFrameCallback(_ => { callback(video) })
rvfc.call(video, _ => { callback(video) });
}

video.addEventListener('playing', playingListener, true);
video.addEventListener('timeupdate', timeupdateListener, true);
video.loop = true;
video.muted = true;
video.play();
Expand Down
67 changes: 41 additions & 26 deletions conformance-suites/1.0.3/conformance/resources/webgl-test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2407,6 +2407,14 @@ var cancelAnimFrame = function(request) {
_cancelAnimFrame.call(window, request);
};

/**
* Provides video.requestVideoFrameCallback in a cross browser way.
* Returns a property, or undefined if unsuported.
*/
var getRequestVidFrameCallback = function() {
return HTMLVideoElement.prototype["requestVideoFrameCallback"];
};

/**
* Provides requestFullScreen in a cross browser way.
*/
Expand Down Expand Up @@ -2586,35 +2594,42 @@ var runSteps = function(steps) {
* video is ready.
*/
var startPlayingAndWaitForVideo = function(video, callback) {
var gotPlaying = false;
var gotTimeUpdate = false;

var maybeCallCallback = function() {
if (gotPlaying && gotTimeUpdate && callback) {
callback(video);
callback = undefined;
video.removeEventListener('playing', playingListener, true);
video.removeEventListener('timeupdate', timeupdateListener, true);
}
};

var playingListener = function() {
gotPlaying = true;
maybeCallCallback();
};
var rvfc = getRequestVidFrameCallback();
if (rvfc === undefined) {
var gotPlaying = false;
var gotTimeUpdate = false;

var maybeCallCallback = function() {
if (gotPlaying && gotTimeUpdate && callback) {
callback(video);
callback = undefined;
video.removeEventListener('playing', playingListener, true);
video.removeEventListener('timeupdate', timeupdateListener, true);
}
};

var timeupdateListener = function() {
// Checking to make sure the current time has advanced beyond
// the start time seems to be a reliable heuristic that the
// video element has data that can be consumed.
if (video.currentTime > 0.0) {
gotTimeUpdate = true;
var playingListener = function() {
gotPlaying = true;
maybeCallCallback();
}
};
};

var timeupdateListener = function() {
// Checking to make sure the current time has advanced beyond
// the start time seems to be a reliable heuristic that the
// video element has data that can be consumed.
if (video.currentTime > 0.0) {
gotTimeUpdate = true;
maybeCallCallback();
}
};

video.addEventListener('playing', playingListener, true);
video.addEventListener('timeupdate', timeupdateListener, true);
} else {
// Calls video.requestVideoFrameCallback(_ => { callback(video) })
rvfc.call(video, _ => { callback(video) });
}

video.addEventListener('playing', playingListener, true);
video.addEventListener('timeupdate', timeupdateListener, true);
video.loop = true;
video.muted = true;
video.play();
Expand Down
69 changes: 43 additions & 26 deletions conformance-suites/2.0.0/js/webgl-test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2694,6 +2694,14 @@ var cancelAnimFrame = function(request) {
_cancelAnimFrame.call(window, request);
};

/**
* Provides video.requestVideoFrameCallback in a cross browser way.
* Returns a property, or undefined if unsuported.
*/
var getRequestVidFrameCallback = function() {
return HTMLVideoElement.prototype["requestVideoFrameCallback"];
};

/**
* Provides requestFullScreen in a cross browser way.
*/
Expand Down Expand Up @@ -2875,37 +2883,46 @@ var runSteps = function(steps) {
* video is ready.
*/
var startPlayingAndWaitForVideo = function(video, callback) {
var gotPlaying = false;
var gotTimeUpdate = false;

var maybeCallCallback = function() {
if (gotPlaying && gotTimeUpdate && callback) {
callback(video);
callback = undefined;
video.removeEventListener('playing', playingListener, true);
video.removeEventListener('timeupdate', timeupdateListener, true);
}
};

var playingListener = function() {
gotPlaying = true;
maybeCallCallback();
};
var rvfc = getRequestVidFrameCallback();
if (rvfc === undefined) {
var gotPlaying = false;
var gotTimeUpdate = false;

var maybeCallCallback = function() {
if (gotPlaying && gotTimeUpdate && callback) {
callback(video);
callback = undefined;
video.removeEventListener('playing', playingListener, true);
video.removeEventListener('timeupdate', timeupdateListener, true);
}
};

var timeupdateListener = function() {
// Checking to make sure the current time has advanced beyond
// the start time seems to be a reliable heuristic that the
// video element has data that can be consumed.
if (video.currentTime > 0.0) {
gotTimeUpdate = true;
var playingListener = function() {
gotPlaying = true;
maybeCallCallback();
}
};
};

var timeupdateListener = function() {
// Checking to make sure the current time has advanced beyond
// the start time seems to be a reliable heuristic that the
// video element has data that can be consumed.
if (video.currentTime > 0.0) {
gotTimeUpdate = true;
maybeCallCallback();
}
};

video.addEventListener('playing', playingListener, true);
video.addEventListener('timeupdate', timeupdateListener, true);
} else {
// Calls video.requestVideoFrameCallback(_ => { callback(video) })
rvfc.call(video, _ => { callback(video) });
}

video.addEventListener('playing', playingListener, true);
video.addEventListener('timeupdate', timeupdateListener, true);
video.loop = true;
video.muted = true;
// See whether setting the preload flag de-flakes video-related tests.
video.preload = 'auto';
video.play();
};

Expand Down
32 changes: 23 additions & 9 deletions sdk/tests/js/webgl-test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2913,6 +2913,14 @@ var requestAnimFrame = function(callback) {
_requestAnimFrame.call(window, callback);
};

/**
* Provides video.requestVideoFrameCallback in a cross browser way.
* Returns a property, or undefined if unsuported.
*/
var getRequestVidFrameCallback = function() {
return HTMLVideoElement.prototype["requestVideoFrameCallback"];
};

var _cancelAnimFrame;

/**
Expand Down Expand Up @@ -3115,21 +3123,27 @@ var runSteps = function(steps) {
* video is ready.
*/
var startPlayingAndWaitForVideo = function(video, callback) {
var timeWatcher = function() {
if (video.currentTime > 0) {
callback(video);
} else {
requestAnimFrame.call(window, timeWatcher);
}
};
var rvfc = getRequestVidFrameCallback();
if (rvfc === undefined) {
var timeWatcher = function() {
if (video.currentTime > 0) {
callback(video);
} else {
requestAnimFrame.call(window, timeWatcher);
}
};

timeWatcher();
} else {
// Calls video.requestVideoFrameCallback(_ => { callback(video) })
rvfc.call(video, _ => { callback(video) });
}

video.loop = true;
video.muted = true;
// See whether setting the preload flag de-flakes video-related tests.
video.preload = 'auto';
video.play();

timeWatcher();
};

var getHost = function(url) {
Expand Down

0 comments on commit 5885bea

Please sign in to comment.