blob: 1b5c15d6d219eef00dd432c522b2bc7d391b4fb2 [file] [log] [blame]
<!--
Copyright (c) 2021 The Khronos Group Inc.
Use of this source code is governed by an MIT-style license that can be
found in the LICENSE.txt file.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="../../resources/js-test-style.css" />
<script src="../../js/js-test-pre.js"></script>
<script src="../../js/webgl-test-utils.js"></script>
<script src="../../js/tests/out-of-bounds-test.js"></script>
<script src="../../../../extensions/proposals/WEBGL_webcodecs_video_frame/webgl_webcodecs_video_frame.js"></script>
<style>
canvas {
padding: 10px;
background: gold;
}
button {
background-color: #555555;
border: none;
color: white;
padding: 15px 32px;
width: 150px;
text-align: center;
display: block;
font-size: 16px;
}
</style>
</head>
<body>
<canvas id="src" width="640" height="480"></canvas>
<canvas id="dst" width="640" height="480"></canvas>
<p id="info"></p>
<div id="description"></div>
<div id="console"></div>
<script>
"use strict";
description("Test of importing Videoframe from Webcodecs to Webgl");
const kIsRunningTest = true;
const kMaxFrame = 10;
const kTestPixel = [255, 128, 0, 255];
// Sum of pixel difference of R/G/B channel. Use to decide whether a
// pixel is matched with another.
const codec_string = "vp09.00.51.08.00";
let wtu = WebGLTestUtils;
let cnv = document.getElementById("src");
let src_width = cnv.width;
let src_height = cnv.height;
let src_color = "rgba(" + kTestPixel[0].toString() + "," + kTestPixel[1].toString() + ","
+ kTestPixel[2].toString() + "," + kTestPixel[3].toString() + ")";
let frame_counter = 0;
let pixelCompareTolerance = 5;
function getQueryVariable(variable) {
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
if (pair[0] == variable) { return pair[1]; }
}
return false;
}
let th = parseInt(getQueryVariable('threshold'));
if (!isNaN(th))
pixelCompareTolerance = th;
async function startDrawing() {
let cnv = document.getElementById("src");
var ctx = cnv.getContext('2d', { alpha: false });
ctx.fillStyle = src_color;
let drawOneFrame = function (time) {
ctx.fillStyle = src_color;
ctx.fillRect(0, 0, src_width, src_height);
window.requestAnimationFrame(drawOneFrame);
}
window.requestAnimationFrame(drawOneFrame);
}
function captureAndEncode(processChunk) {
let cnv = document.getElementById("src");
let fps = 60;
let pending_outputs = 0;
let stream = cnv.captureStream(fps);
let processor = new MediaStreamTrackProcessor(stream.getVideoTracks()[0]);
const init = {
output: (chunk) => {
testPassed("Encode frame successfully.");
pending_outputs--;
processChunk(chunk);
},
error: (e) => {
testFailed("Failed to encode frame.");
finishTest();
vtr.stop();
}
};
const config = {
codec: codec_string,
width: cnv.width,
height: cnv.height,
bitrate: 10e6,
framerate: fps,
};
let encoder = new VideoEncoder(init);
encoder.configure(config);
const frame_reader = processor.readable.getReader();
frame_reader.read().then(function processFrame({done, value}) {
if (done)
return;
if (pending_outputs > 30) {
console.log("drop this frame");
// Too many frames in flight, encoder is overwhelmed
// let's drop this frame.
value.close();
frame_reader.read().then(processFrame);
return;
}
if(frame_counter == kMaxFrame) {
frame_reader.releaseLock();
processor.readable.cancel();
value.close();
return;
}
frame_counter++;
pending_outputs++;
const insert_keyframe = (frame_counter % 150) == 0;
encoder.encode(value, { keyFrame: insert_keyframe });
frame_reader.read().then(processFrame);
});
}
function startDecodingAndRendering(cnv, handleFrame) {
const init = {
output: handleFrame,
error: (e) => {
testFailed("Failed to decode frame.");
finishTest();
}
};
const config = {
codec: codec_string,
codedWidth: cnv.width,
codedHeight: cnv.height,
acceleration: "deny",
};
let decoder = new VideoDecoder(init);
decoder.configure(config);
return decoder;
}
function isFramePixelMatched(gl, th_per_pixel = pixelCompareTolerance) {
WebGLTestUtils.checkCanvasRect(gl, 0, 0, src_width, src_width, kTestPixel, "should be orange", pixelCompareTolerance)
}
function main() {
if (!("VideoEncoder" in window)) {
testPassed("WebCodecs API is not supported.");
finishTest();
return;
}
let cnv = document.getElementById("dst");
let webgl_webcodecs_test_context = {
maxFrameTested: kMaxFrame,
displayed_frame: 0,
isFramePixelMatched: isFramePixelMatched,
testFailed: testFailed,
testPassed: testPassed,
finishTest: finishTest
};
setTestMode(webgl_webcodecs_test_context);
let handleFrame = requestWebGLVideoFrameHandler(cnv);
if (handleFrame === null) {
finishTest();
return;
}
startDrawing();
let decoder = startDecodingAndRendering(cnv, handleFrame);
captureAndEncode((chunk) => {
decoder.decode(chunk);
});
}
document.body.onload = main;
</script>
</body>
</html>