chromium/content/test/data/gpu/vc/webgl2_videos_mxn.html

<!--
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>WebGL2 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;
    let fixedTextureSize = false;

    async function startMxNVideos() {
      const container = document.getElementById('container');
      const p = document.getElementById('message');

      // Initialize WebGL

      const gl = await webglInit(_totalVideoWidth, _totalVideoHeight, 'webgl2');
      if (!gl) {
        p.innerHTML = "WebGL2 not supported!";
        return;
      }

      const fixedTextureSizeOption = parsedString['fixed_texture_size'];
      if (fixedTextureSizeOption === '0') {
        fixedTextureSize = false;
      } else if (fixedTextureSizeOption === '1') {
        fixedTextureSize = true;
      }

      // 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, fixedTextureSize);
    }

  </script>
</head>

<body>
  <div id="container" style="position:absolute; top:0px; left:0px">
    <p id="message"></p>
  </div>
  <script>startMxNVideos();</script>
</body>

</html>