Source code
Revision control
Copy as Markdown
Other Tools
<!-- This was created from the demo of webcodecs-blogpost-demo.glitch.me, and added the webgl support for test only purpose. -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="origin-trial"
content="AoSY6Q4OOuuZVXTqOwJlfk4n77EL0esumtLRHj+9V97JoFfLq4AKsWlza8A8HmxTx1PU7SSzpjWK6F62bwWLPQYAAAB3eyJvcmlnaW4iOiJodHRwczovL3dlYmNvZGVjcy1ibG9ncG9zdC1kZW1vLmdsaXRjaC5tZTo0NDMiLCJmZWF0dXJlIjoiV2ViQ29kZWNzIiwiZXhwaXJ5IjoxNjA1NDc0OTQ4LCJpc1N1YmRvbWFpbiI6dHJ1ZX0=">
<title>WebCodecs API demo: Encoding and Decoding</title>
<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>
<script src="../../../../extensions/proposals/WEBGL_webcodecs_video_frame/webgl_webcodecs_video_frame.js"></script>
</head>
<body>
<canvas id="src" width="640" height="480"></canvas>
<button onclick="playPause()">Pause</button>
<canvas id="dst" width="640" height="480"></canvas>
<script>
let codec_string = "vp8";
let keep_going = true;
function playPause() {
keep_going = !keep_going;
let btn = document.querySelector("button");
if (keep_going) {
btn.innerText = "Pause";
} else {
btn.innerText = "Play";
}
}
async function startDrawing() {
let cnv = document.getElementById("src");
var ctx = cnv.getContext('2d', { alpha: false });
ctx.fillStyle = "white";
let width = cnv.width;
let height = cnv.height;
let cx = width / 2;
let cy = height / 2;
let r = Math.min(width, height) / 5;
let drawOneFrame = function (time) {
let angle = Math.PI * 2 * (time / 5000);
let scale = 1 + 0.3 * Math.sin(Math.PI * 2 * (time / 7000));
ctx.save();
ctx.fillRect(0, 0, width, height);
ctx.translate(cx, cy);
ctx.rotate(angle);
ctx.scale(scale, scale);
ctx.font = '30px Verdana';
ctx.fillStyle = 'black';
const text = "๐๐น๐ทHello WEBGL_webcodecs_video_frame๐ฅ๐๏ธ๐";
const size = ctx.measureText(text).width;
ctx.fillText(text, -size / 2, 0);
ctx.restore();
window.requestAnimationFrame(drawOneFrame);
}
window.requestAnimationFrame(drawOneFrame);
}
function captureAndEncode(processChunk) {
let cnv = document.getElementById("src");
let fps = 30;
let pending_outputs = 0;
let frame_counter = 0;
let stream = cnv.captureStream(fps);
let processor = new MediaStreamTrackProcessor(stream.getVideoTracks()[0]);
const init = {
output: (chunk) => {
pending_outputs--;
processChunk(chunk);
},
error: (e) => {
console.log(e.message);
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) {
// Too many frames in flight, encoder is overwhelmed
// let's drop this frame.
value.close();
frame_reader.read().then(processFrame);
return;
}
if(!keep_going) {
value.close();
frame_reader.read().then(processFrame);
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) => {
console.log(e.message);
}
};
const config = {
codec: codec_string,
codedWidth: cnv.width,
codedHeight: cnv.height
};
let decoder = new VideoDecoder(init);
decoder.configure(config);
return decoder;
}
function main() {
if (!("VideoEncoder" in window)) {
document.body.innerHTML = "<h1>WebCodecs API is not supported.</h1>";
return;
}
let cnv = document.getElementById("dst");
let handleFrame = requestWebGLVideoFrameHandler(cnv);
if (handleFrame === null) {
document.body.innerHTML =
"<h1>Unable to request WebGL to render video frames.</h1>";
return;
}
startDrawing();
let decoder = startDecodingAndRendering(cnv, handleFrame);
captureAndEncode((chunk) => {
decoder.decode(chunk);
});
}
document.body.onload = main;
</script>
</body>
</html>