Bug 1219711 - Refactor captureStream_common.js to accept generic pixel testing method. r=jib

This commit is contained in:
Andreas Pehrson 2015-11-09 23:17:41 +08:00
parent 1bf22c83b2
commit 378e2b660c
6 changed files with 142 additions and 71 deletions

View File

@ -25,6 +25,7 @@ function CaptureStreamTestHelper(width, height) {
CaptureStreamTestHelper.prototype = {
/* Predefined colors for use in the methods below. */
black: { data: [0, 0, 0, 255], name: "black" },
blackTransparent: { data: [0, 0, 0, 0], name: "blackTransparent" },
green: { data: [0, 255, 0, 255], name: "green" },
red: { data: [255, 0, 0, 255], name: "red" },
@ -52,55 +53,90 @@ CaptureStreamTestHelper.prototype = {
video.srcObject.requestFrame();
},
/* Tests the top left pixel of |video| against |refData|. Format [R,G,B,A]. */
testPixel: function (video, refData, threshold) {
/*
* Returns the pixel at (|offsetX|, |offsetY|) (from top left corner) of
* |video| as an array of the pixel's color channels: [R,G,B,A].
*/
getPixel: function (video, offsetX, offsetY) {
offsetX = offsetX || 0; // Set to 0 if not passed in.
offsetY = offsetY || 0; // Set to 0 if not passed in.
var ctxout = this.cout.getContext('2d');
ctxout.drawImage(video, 0, 0);
var pixel = ctxout.getImageData(0, 0, 1, 1).data;
return pixel.every((val, i) => Math.abs(val - refData[i]) <= threshold);
return ctxout.getImageData(offsetX, offsetY, 1, 1).data;
},
/*
* Returns a promise that resolves when the pixel matches. Use |threshold|
* for fuzzy matching the color on each channel, in the range [0,255].
* Returns true if px lies within the per-channel |threshold| of the
* referenced color for all channels. px is on the form of an array of color
* channels, [R,G,B,A]. Each channel is in the range [0, 255].
*/
waitForPixel: function (video, refColor, threshold, infoString) {
isPixel: function (px, refColor, threshold) {
threshold = threshold || 0; // Default to 0 (exact match) if not passed in.
return px.every((ch, i) => Math.abs(ch - refColor.data[i]) <= threshold);
},
/*
* Returns true if px lies further away than |threshold| of the
* referenced color for any channel. px is on the form of an array of color
* channels, [R,G,B,A]. Each channel is in the range [0, 255].
*/
isPixelNot: function (px, refColor, threshold) {
if (threshold === undefined) {
// Default to 127 (should be sufficiently far away) if not passed in.
threshold = 127;
}
return px.some((ch, i) => Math.abs(ch - refColor.data[i]) > threshold);
},
/*
* Returns a promise that resolves when the provided function |test|
* returns true.
*/
waitForPixel: function (video, offsetX, offsetY, test, timeout) {
return new Promise(resolve => {
info("Testing " + video.id + " against [" + refColor.data.join(',') + "]");
const startTime = video.currentTime;
CaptureStreamTestHelper2D.prototype.clear.call(this, this.cout);
video.ontimeupdate = () => {
if (this.testPixel(video, refColor.data, threshold)) {
ok(true, video.id + " " + infoString);
video.ontimeupdate = null;
resolve();
var ontimeupdate = () => {
const pixelMatch = test(this.getPixel(video, offsetX, offsetY));
if (!pixelMatch &&
(!timeout || video.currentTime < startTime + (timeout / 1000.0))) {
// No match yet and,
// No timeout (waiting indefinitely) or |timeout| has not passed yet.
return;
}
video.removeEventListener("timeupdate", ontimeupdate);
resolve(pixelMatch);
};
video.addEventListener("timeupdate", ontimeupdate);
});
},
/*
* Returns a promise that resolves after |timeout| ms of playback or when a
* pixel of |video| becomes the color |refData|. The test is failed if the
* Returns a promise that resolves when the top left pixel of |video| matches
* on all channels. Use |threshold| for fuzzy matching the color on each
* channel, in the range [0,255].
*/
waitForPixelColor: function (video, refColor, threshold, infoString) {
info("Waiting for video " + video.id + " to match [" +
refColor.data.join(',') + "] - " + refColor.name +
" (" + infoString + ")");
return this.waitForPixel(video, 0, 0,
px => this.isPixel(px, refColor, threshold))
.then(() => ok(true, video.id + " " + infoString));
},
/*
* Returns a promise that resolves after |timeout| ms of playback or when the
* top left pixel of |video| becomes |refColor|. The test is failed if the
* timeout is not reached.
*/
waitForPixelToTimeout: function (video, refColor, threshold, timeout, infoString) {
return new Promise(resolve => {
info("Waiting for " + video.id + " to time out after " + timeout +
"ms against [" + refColor.data.join(',') + "] - " + refColor.name);
CaptureStreamTestHelper2D.prototype.clear.call(this, this.cout);
var startTime = video.currentTime;
video.ontimeupdate = () => {
if (this.testPixel(video, refColor.data, threshold)) {
ok(false, video.id + " " + infoString);
video.ontimeupdate = null;
resolve();
} else if (video.currentTime > startTime + (timeout / 1000.0)) {
ok(true, video.id + " " + infoString);
video.ontimeupdate = null;
resolve();
}
};
});
waitForPixelColorTimeout: function (video, refColor, threshold, timeout, infoString) {
info("Waiting for " + video.id + " to time out after " + timeout +
"ms against [" + refColor.data.join(',') + "] - " + refColor.name);
return this.waitForPixel(video, 0, 0,
px => this.isPixel(px, refColor, threshold),
timeout)
.then(result => ok(!result, video.id + " " + infoString));
},
/* Create an element of type |type| with id |id| and append it to the body. */

View File

@ -23,15 +23,21 @@ function checkDrawColorInitialRed() {
vmanual.srcObject = c.captureStream(0);
vrate.srcObject = c.captureStream(10);
ok(h.testPixel(vauto, [0, 0, 0, 0], 0), "vauto hould not be drawn to before stable state");
ok(h.testPixel(vrate, [0, 0, 0, 0], 0), "vrate Should not be drawn to before stable state");
ok(h.testPixel(vmanual, [0, 0, 0, 0], 0), "vmanual Should not be drawn to before stable state");
ok(h.isPixel(h.getPixel(vauto), h.blackTransparent, 0),
"vauto should not be drawn to before stable state");
ok(h.isPixel(h.getPixel(vrate), h.blackTransparent, 0),
"vrate should not be drawn to before stable state");
ok(h.isPixel(h.getPixel(vmanual), h.blackTransparent, 0),
"vmanual should not be drawn to before stable state");
return Promise.resolve()
.then(() => h.waitForPixel(vauto, h.red, 0, "should become red automatically"))
.then(() => h.waitForPixel(vrate, h.red, 0, "should become red automatically"))
.then(() => h.waitForPixel(vmanual, h.red, 0, "should become red when we get" +
" to stable state (first frame)"));
.then(() => h.waitForPixelColor(vauto, h.red, 0,
"should become red automatically"))
.then(() => h.waitForPixelColor(vrate, h.red, 0,
"should become red automatically"))
.then(() => h.waitForPixelColor(vmanual, h.red, 0,
"should become red when we get" +
" to stable state (first frame)"));
}
function checkDrawColorGreen() {
@ -40,11 +46,15 @@ function checkDrawColorGreen() {
var drawing = h.startDrawing(() => h.drawColor(c, h.green));
return Promise.resolve()
.then(() => h.waitForPixel(vauto, h.green, 0, "should become green automatically"))
.then(() => h.waitForPixel(vrate, h.green, 0, "should become green automatically"))
.then(() => h.waitForPixel(vmanual, h.red, 0, "should still be red"))
.then(() => h.waitForPixelColor(vauto, h.green, 0,
"should become green automatically"))
.then(() => h.waitForPixelColor(vrate, h.green, 0,
"should become green automatically"))
.then(() => h.waitForPixelColor(vmanual, h.red, 0,
"should still be red"))
.then(() => h.requestFrame(vmanual))
.then(() => h.waitForPixel(vmanual, h.green, 0, "should become green after requstFrame()"))
.then(() => h.waitForPixelColor(vmanual, h.green, 0,
"should become green after requstFrame()"))
.catch(err => ok(false, "checkDrawColorGreen failed: ", err))
.then(() => drawing.stop());
}
@ -54,10 +64,12 @@ function checkRequestFrameOrderGuarantee() {
"call results in the expected frame seen in the stream.");
return Promise.resolve()
.then(() => h.waitForPixel(vmanual, h.green, 0, "should still be green"))
.then(() => h.waitForPixelColor(vmanual, h.green, 0,
"should still be green"))
.then(() => h.drawColor(c, h.red)) // 1. Draw canvas red
.then(() => h.requestFrame(vmanual)) // 2. Immediately request a frame
.then(() => h.waitForPixel(vmanual, h.red, 0, "should become red after call order test"))
.then(() => h.waitForPixelColor(vmanual, h.red, 0,
"should become red after call order test"))
}
function checkDrawImageNotCleanRed() {
@ -74,11 +86,14 @@ function checkDrawImageNotCleanRed() {
})
.then(() => drawing = h.startDrawing(() => ctx.drawImage(notCleanRed, 0, 0, c.width, c.height)))
.then(() => h.testNotClean(c))
.then(() => h.waitForPixelToTimeout(vauto, h.red, 0, 1000, "should not become red"))
.then(() => h.waitForPixelToTimeout(vrate, h.red, 0, 0, "should not become red"))
.then(() => h.waitForPixel(vmanual, h.green, 0, "should still be green"))
.then(() => h.waitForPixelColorTimeout(vauto, h.red, 0, 1000,
"should not become red"))
.then(() => h.isPixelNot(h.getPixel(vrate), h.red, 250,
"should not have become red"))
.then(() => h.waitForPixelColor(vmanual, h.green, 0, "should still be green"))
.then(() => h.requestFrame(vmanual))
.then(() => h.waitForPixelToTimeout(vmanual, h.red, 0, 1000, "should not become red"))
.then(() => h.waitForPixelColorTimeout(vmanual, h.red, 0, 1000,
"should not become red"))
.catch(err => ok(false, "checkDrawImageNotCleanRed failed: ", err))
.then(() => drawing.stop());
}

View File

@ -54,14 +54,21 @@ function checkClearColorInitialRed() {
vmanual.srcObject = c.captureStream(0);
vrate.srcObject = c.captureStream(10);
ok(h.testPixel(vauto, [0, 0, 0, 0], 0), "Should not be drawn to before stable state");
ok(h.testPixel(vrate, [0, 0, 0, 0], 0), "Should not be drawn to before stable state");
ok(h.testPixel(vmanual, [0, 0, 0, 0], 0), "Should not be drawn to before stable state");
ok(h.isPixel(h.getPixel(vauto), h.blackTransparent, 0,
"vauto should not be drawn to before stable state"));
ok(h.isPixel(h.getPixel(vrate), h.blackTransparent, 0,
"vrate should not be drawn to before stable state"));
ok(h.isPixel(h.getPixel(vmanual), h.blackTransparent, 0,
"vmanual should not be drawn to before stable state"));
return Promise.resolve()
.then(() => h.waitForPixel(vauto, h.red, 0, "should become red automatically"))
.then(() => h.waitForPixel(vrate, h.red, 0, "should become red automatically"))
.then(() => h.waitForPixel(vmanual, h.red, 0, "should become red when we get to stable state (first frame)"))
.then(() => h.waitForPixelColor(vauto, h.red, 0,
"should become red automatically"))
.then(() => h.waitForPixelColor(vrate, h.red, 0,
"should become red automatically"))
.then(() => h.waitForPixelColor(vmanual, h.red, 0,
"should become red when we get to stable " +
"state (first frame)"))
}
function checkDrawColorGreen() {
@ -69,11 +76,15 @@ function checkDrawColorGreen() {
var drawing = h.startDrawing(h.drawColor.bind(h, c, h.green));
checkGLError('after DrawColor');
return Promise.resolve()
.then(() => h.waitForPixel(vauto, h.green, 0, "should become green automatically"))
.then(() => h.waitForPixel(vrate, h.green, 0, "should become green automatically"))
.then(() => h.waitForPixel(vmanual, h.red, 0, "should still be red"))
.then(() => h.waitForPixelColor(vauto, h.green, 0,
"should become green automatically"))
.then(() => h.waitForPixelColor(vrate, h.green, 0,
"should become green automatically"))
.then(() => h.waitForPixelColor(vmanual, h.red, 0,
"should still be red"))
.then(() => h.requestFrame(vmanual))
.then(() => h.waitForPixel(vmanual, h.green, 0, "should become green after requstFrame()"))
.then(() => h.waitForPixelColor(vmanual, h.green, 0,
"should become green after requstFrame()"))
.then(() => drawing.stop());
}
@ -81,11 +92,15 @@ function checkClearColorRed() {
info("Checking that clearing to red works.");
var drawing = h.startDrawing(h.clearColor.bind(h, c, h.red));
return Promise.resolve()
.then(() => h.waitForPixel(vauto, h.red, 0, "should become red automatically"))
.then(() => h.waitForPixel(vrate, h.red, 0, "should become red automatically"))
.then(() => h.waitForPixel(vmanual, h.green, 0, "should still be green"))
.then(() => h.waitForPixelColor(vauto, h.red, 0,
"should become red automatically"))
.then(() => h.waitForPixelColor(vrate, h.red, 0,
"should become red automatically"))
.then(() => h.waitForPixelColor(vmanual, h.green, 0,
"should still be green"))
.then(() => h.requestFrame(vmanual))
.then(() => h.waitForPixel(vmanual, h.red, 0, "should become red after requestFrame()"))
.then(() => h.waitForPixelColor(vmanual, h.red, 0,
"should become red after requestFrame()"))
.then(() => drawing.stop());
}
@ -93,10 +108,11 @@ function checkRequestFrameOrderGuarantee() {
info("Checking that requestFrame() immediately after a draw " +
"call results in the expected frame seen in the stream.");
return Promise.resolve()
.then(() => h.waitForPixel(vmanual, h.red, 0, "should still be red"))
.then(() => h.waitForPixelColor(vmanual, h.red, 0, "should still be red"))
.then(() => h.drawColor(c, h.green)) // 1. Draw canvas green
.then(() => h.requestFrame(vmanual)) // 2. Immediately request a frame
.then(() => h.waitForPixel(vmanual, h.green, 0, "should become green after call order test"))
.then(() => h.waitForPixelColor(vmanual, h.green, 0,
"should become green after call order test"))
}
function finish() {

View File

@ -56,7 +56,7 @@ function startTest() {
SimpleTest.finish();
};
document.getElementById("content").appendChild(video);
helper.waitForPixel(video, helper.red, 128, "Should become red")
helper.waitForPixelColor(video, helper.red, 128, "Should become red")
.then(SimpleTest.finish);
};

View File

@ -39,7 +39,8 @@ runNetworkTest(() => {
ok(!!vremote, "Should have remote video element for pcRemote");
},
function WAIT_FOR_REMOTE_GREEN() {
return h.waitForPixel(vremote, h.green, 128, "pcRemote's remote should become green");
return h.waitForPixelColor(vremote, h.green, 128,
"pcRemote's remote should become green");
},
function DRAW_LOCAL_RED() {
// After requesting a frame it will be captured at the time of next render.
@ -49,7 +50,8 @@ runNetworkTest(() => {
h.drawColor(canvas, h.red);
},
function WAIT_FOR_REMOTE_RED() {
return h.waitForPixel(vremote, h.red, 128, "pcRemote's remote should become red");
return h.waitForPixelColor(vremote, h.red, 128,
"pcRemote's remote should become red");
}
]);
test.run();

View File

@ -89,7 +89,8 @@ runNetworkTest(() => {
ok(!!vremote, "Should have remote video element for pcRemote");
},
function WAIT_FOR_REMOTE_GREEN() {
return h.waitForPixel(vremote, h.green, 128, "pcRemote's remote should become green");
return h.waitForPixelColor(vremote, h.green, 128,
"pcRemote's remote should become green");
},
function REQUEST_FRAME(test) {
// After requesting a frame it will be captured at the time of next render.
@ -101,7 +102,8 @@ runNetworkTest(() => {
h.drawColor(canvas, h.red);
},
function WAIT_FOR_REMOTE_RED() {
return h.waitForPixel(vremote, h.red, 128, "pcRemote's remote should become red");
return h.waitForPixelColor(vremote, h.red, 128,
"pcRemote's remote should become red");
}
]);
test.run();