blob: a8e4fce89796a2d5c28a754be456e4876da9283f [file] [log] [blame]
<style>
canvas {
width: 300px;
height: 300px;
}
</style>
</head>
<script id="vertexShaderSource" type="text/glsl">
attribute vec4 a_position;
varying vec2 v_texturePosition;
void main() {
v_texturePosition = vec2((a_position.x + 1.0) / 2.0, (a_position.y + 1.0) / 2.0);
gl_Position = a_position;
}
</script>
<script id="fragmentShaderSource" type="text/glsl">
precision mediump float;
varying vec2 v_texturePosition;
uniform sampler2D texture;
void main() {
gl_FragColor = texture2D(texture, v_texturePosition);
}
</script>
<script>
if (window.testRunner) {
testRunner.waitUntilDone();
testRunner.dumpAsText();
}
const width = 300;
const height = 300;
let canvas;
let gl;
let animationFrame = null;
let tested = false;
let drawFunction = null;
let video;
function output(msg) {
const div = document.getElementById("output");
div.innerHTML += `${msg}<br>`;
}
function isMostlyRed(buffer, x, y) {
let offset = (y * width + x) * 4;
return buffer[offset] > 240 && buffer[offset+1] < 25 && buffer[offset+2] < 25 && buffer[offset+3] > 240;
}
function isMostlyBlue(buffer, x, y) {
let offset = (y * width + x) * 4;
return buffer[offset] < 25 && buffer[offset+1] < 25 && buffer[offset+2] > 240 && buffer[offset+3] > 240;
}
function runTest() {
output("Checking the canvas pixels.");
drawFunction();
let pixels = new Uint8Array(width * height * 4);
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
if (isMostlyRed(pixels, 2, 2))
output("PASS: Bottom edge is red.");
else
output("FAIL: Bottom edge is not red.");
if (isMostlyBlue(pixels, 2, height - 2))
output("PASS: Top edge is blue.");
else
output("FAIL: Top edge is not blue.");
cancelAnimationFrame(animationFrame);
video.pause();
if (window.testRunner)
testRunner.notifyDone();
}
function init() {
canvas = document.querySelector("canvas");
canvas.width = width;
canvas.height = height;
gl = canvas.getContext("webgl");
gl.clearColor(0, 0, 0, 1);
let vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, document.getElementById("vertexShaderSource").textContent);
gl.compileShader(vertexShader);
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
console.error("Vertex Shader failed to compile.");
console.log(gl.getShaderInfoLog(vertexShader));
return;
}
let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, document.getElementById("fragmentShaderSource").textContent);
gl.compileShader(fragmentShader);
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
console.error("Fragment Shader failed to compile.");
console.log(gl.getShaderInfoLog(fragmentShader));
return;
}
let program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error("Unable to link shaders into program.");
return;
}
gl.useProgram(program);
let textureUniform = gl.getUniformLocation(program, "texture");
let positionAttribute = gl.getAttribLocation(program, "a_position");
gl.enableVertexAttribArray(positionAttribute);
// Unlike the corresponding texImage2D-video-flipY-false test, draw a quad using
// four points in a triangle strip, with 3 floats per point. This way we're doing
// something different from the WebCore code that renders the video into a texture,
// ensuring that state restoration is correctly restored.
let vertices = new Float32Array([-1.0, -1.0, 0.0, 1.0, -1.0, 0.0, -1.0, 1.0, 0.0, 1.0, 1.0, 0.0]);
let buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.vertexAttribPointer(positionAttribute, 3, gl.FLOAT, false, 0, 0);
let updateTexture = function (texture, data) {
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, data);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.bindTexture(gl.TEXTURE_2D, null);
}
let texture = gl.createTexture();
video = document.createElement("video");
video.loop = true;
video.playsInline = true;
video.addEventListener("canplay", function () {
output("Video can play.");
}, false);
video.addEventListener("timeupdate", function () {
// If we've just started, jump forward to 3 seconds. If we've played a bit after
// that, check the pixels.
if (video.currentTime < 1) {
video.currentTime = 3;
return;
} else if (video.currentTime > 3.1) {
if (!tested)
runTest();
tested = true;
}
}, false);
output("Setting video src.");
window.source = new MediaSource();
source.addEventListener('sourceopen', async event => {
var buffer = source.addSourceBuffer('video/mp4');
var response = await fetch('resources/orientation-normal-fragmented.mp4');
buffer.appendBuffer(await response.arrayBuffer());
});
video.srcObject = source;
video.play();
drawFunction = function () {
gl.clear(gl.COLOR_BUFFER_BIT);
if (video.currentTime > 0) {
updateTexture(texture, video);
}
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.uniform1i(textureUniform, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
animationFrame = requestAnimationFrame(drawFunction);
};
drawFunction();
}
window.addEventListener("load", init, false);
</script>
<body>
<canvas></canvas>
<div id="output">
</div>
</body>