<!--
Copyright 2022 The Chromium Authors
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<html>
<head>
<title>WebGL MxN Video playbacks</title>
<style>
#message {
position: absolute;
width: 1600px;
height: 900px;
top: 200px;
left: 400px;
}
</style>
<script src="../third_party/stats-js/stats.js"></script>
<script src="video_utils.js"></script>
<script src="webgl_video.js"></script>
<script>
const _defaultRows = 7;
const _defaultColumns = 7;
const _totalVideoWidth = 1600;
const _totalVideoHeight = 900;
let hasUIOnTop = true;
let hasFPSOnTop = true;
let capUIFPS = true;
let useLargeSizeVideo = false;
let codec = 'vp9';
let useLocalCamera = false;
async function startMxNVideos() {
const container = document.getElementById('container');
const p = document.getElementById('message');
// Initialize WebGL
const gl = await webglInit(_totalVideoWidth, _totalVideoHeight);
if (!gl) {
p.innerHTML = "WebGL not supported!";
return;
}
// Get the UI rendering options from the string.
const uiOption = parsedString['ui'];
if (uiOption === 'none') {
hasUIOnTop = false;
}
const fpsOption = parsedString['fps'];
if (fpsOption === 'none') {
hasFPSOnTop = false;
}
codecString = parsedString['codec'];
if (codecString === 'vp8') {
codec = 'vp8';
} else if (codecString !== 'vp9' && codecString !== undefined) {
console.warn('Unsupported video codec format! Switch to default VP9.');
}
const capFPSOption = parsedString['cap_ui_fps'];
if (capFPSOption === '0') {
capUIFPS = false;
} else if (capFPSOption === '1') {
capUIFPS = true;
}
const useLargeSizeVideoOption = parsedString['use_large_size_video'];
if (useLargeSizeVideoOption === '0') {
useLargeSizeVideo = false;
} else if (useLargeSizeVideoOption === '1') {
useLargeSizeVideo = true;
}
const useLocalCameraOption = parsedString['use_local_camera'];
if (useLocalCameraOption === '0') {
useLocalCamera = false;
} else if (useLocalCameraOption === '1') {
useLocalCamera = true;
}
// Get the number of video rows and columns from the string.
let videoRows = parsedString['rows'];
let videoColumns = parsedString['columns'];
if (videoRows === undefined) {
videoRows = _defaultRows;
}
if (videoColumns === undefined) {
videoColumns = _defaultColumns;
}
// Limit the number of videos to 20x20.
// The video will not load when the number is too big.
const maxColRow = Math.max(videoRows, videoColumns);
if (maxColRow > 20) {
p.innerHTML = "Cannot support videos more than 20 x 20 !" + "<br />" +
"Please change the number of rows/columns.";
return;
}
// Calculate the video onscreen size
const videoWidth = _totalVideoWidth / maxColRow;
const videoHeight = _totalVideoHeight / maxColRow;
// Create MxN videos and a small video (size = 89x50) at the upper right
// corner to similate the one from the local camera.
p.innerHTML = "Uploading videos...";
const videos = [];
const videoCount = videoRows * videoColumns;
for (let i = 0; i < videoCount + 1; i++) {
const video = document.createElement('video');
video.id = i;
video.loop = true;
video.autoplay = true;
video.muted = true;
video.display = "none";
video.src = GetVideoSource(videoCount, i, codec, useLargeSizeVideo);
video.width = videoWidth;
video.height = videoHeight;
video.crossorigin = "anonymous";
videos.push(video);
}
// For the small video at the upper right corner.
videos[videoRows * videoColumns].width = videoWidth / 3;
videos[videoRows * videoColumns].height = videoHeight / 3;
if (useLocalCamera) {
const video = videos[videoRows * videoColumns];
video.src = "";
const constraints = {
audio: false,
video: { width: 640, height: 360 }
};
await navigator.mediaDevices.getUserMedia(constraints)
.then((mediaStream) => {
video.srcObject = mediaStream;
video.onloadedmetadata = () => {
video.play();
};
})
.catch((err) => {
console.error(`${err.name}: ${err.message}`);
});
} else {
// Use the 640x360 source to simulate the local camera.
videos[videoRows * videoColumns].src = GetVideoSource(1, 1, codec);
}
await Promise.all(videos.map(video => video.play()));
p.remove();
// Simulate video playback by WebGL rendering.
webglDrawVideoFrames(gl, videos, videoRows, videoColumns,
hasUIOnTop, hasFPSOnTop, capUIFPS);
}
</script>
</head>
<body>
<div id="container" style="position:absolute; top:0px; left:0px">
<p id="message"></p>
</div>
<script>startMxNVideos();</script>
</body>
</html>