tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

webgl-webcodecs-video-frame.html (6114B)


      1 <!--
      2 Copyright (c) 2021 The Khronos Group Inc.
      3 Use of this source code is governed by an MIT-style license that can be
      4 found in the LICENSE.txt file.
      5 -->
      6 
      7 <!DOCTYPE html>
      8 <html>
      9 
     10 <head>
     11  <meta charset="UTF-8">
     12  <link rel="stylesheet" href="../../resources/js-test-style.css" />
     13  <script src="../../js/js-test-pre.js"></script>
     14  <script src="../../js/webgl-test-utils.js"></script>
     15  <script src="../../js/tests/out-of-bounds-test.js"></script>
     16  <script src="../../../../extensions/proposals/WEBGL_webcodecs_video_frame/webgl_webcodecs_video_frame.js"></script>
     17  <style>
     18    canvas {
     19      padding: 10px;
     20      background: gold;
     21    }
     22 
     23    button {
     24      background-color: #555555;
     25      border: none;
     26      color: white;
     27      padding: 15px 32px;
     28      width: 150px;
     29      text-align: center;
     30      display: block;
     31      font-size: 16px;
     32    }
     33  </style>
     34 </head>
     35 
     36 <body>
     37  <canvas id="src" width="640" height="480"></canvas>
     38  <canvas id="dst" width="640" height="480"></canvas>
     39  <p id="info"></p>
     40  <div id="description"></div>
     41  <div id="console"></div>
     42  <script>
     43    "use strict";
     44    description("Test of importing Videoframe from Webcodecs to Webgl");
     45 
     46    const kIsRunningTest = true;
     47    const kMaxFrame = 10;
     48    const kTestPixel = [255, 128, 0, 255];
     49    // Sum of pixel difference of R/G/B channel. Use to decide whether a
     50    // pixel is matched with another.
     51    const codec_string = "vp09.00.51.08.00";
     52 
     53    let wtu = WebGLTestUtils;
     54    let cnv = document.getElementById("src");
     55    let src_width = cnv.width;
     56    let src_height = cnv.height;
     57    let src_color = "rgba(" + kTestPixel[0].toString() + "," + kTestPixel[1].toString() + ","
     58      + kTestPixel[2].toString() + "," + kTestPixel[3].toString() + ")";
     59    let frame_counter = 0;
     60    let pixelCompareTolerance = 5;
     61 
     62    function getQueryVariable(variable) {
     63      var query = window.location.search.substring(1);
     64      var vars = query.split("&");
     65      for (var i = 0; i < vars.length; i++) {
     66        var pair = vars[i].split("=");
     67        if (pair[0] == variable) { return pair[1]; }
     68      }
     69      return false;
     70    }
     71 
     72    let th = parseInt(getQueryVariable('threshold'));
     73    if (!isNaN(th))
     74      pixelCompareTolerance = th;
     75 
     76    async function startDrawing() {
     77      let cnv = document.getElementById("src");
     78      var ctx = cnv.getContext('2d', { alpha: false });
     79 
     80      ctx.fillStyle = src_color;
     81      let drawOneFrame = function (time) {
     82        ctx.fillStyle = src_color;
     83        ctx.fillRect(0, 0, src_width, src_height);
     84        window.requestAnimationFrame(drawOneFrame);
     85      }
     86      window.requestAnimationFrame(drawOneFrame);
     87    }
     88 
     89    function captureAndEncode(processChunk) {
     90      let cnv = document.getElementById("src");
     91      let fps = 60;
     92      let pending_outputs = 0;
     93      let stream = cnv.captureStream(fps);
     94      let processor = new MediaStreamTrackProcessor(stream.getVideoTracks()[0]);
     95 
     96      const init = {
     97        output: (chunk) => {
     98          testPassed("Encode frame successfully.");
     99          pending_outputs--;
    100          processChunk(chunk);
    101        },
    102        error: (e) => {
    103          testFailed("Failed to encode frame.");
    104          finishTest();
    105          vtr.stop();
    106        }
    107      };
    108 
    109      const config = {
    110        codec: codec_string,
    111        width: cnv.width,
    112        height: cnv.height,
    113        bitrate: 10e6,
    114        framerate: fps,
    115      };
    116 
    117      let encoder = new VideoEncoder(init);
    118      encoder.configure(config);
    119 
    120      const frame_reader = processor.readable.getReader();
    121      frame_reader.read().then(function processFrame({done, value}) {
    122        if (done)
    123          return;
    124 
    125        if (pending_outputs > 30) {
    126          console.log("drop this frame");
    127          // Too many frames in flight, encoder is overwhelmed
    128          // let's drop this frame.
    129          value.close();
    130          frame_reader.read().then(processFrame);
    131          return;
    132        }
    133 
    134        if(frame_counter == kMaxFrame) {
    135          frame_reader.releaseLock();
    136          processor.readable.cancel();
    137          value.close();
    138          return;
    139        }
    140 
    141        frame_counter++;
    142        pending_outputs++;
    143        const insert_keyframe = (frame_counter % 150) == 0;
    144        encoder.encode(value, { keyFrame: insert_keyframe });
    145 
    146        frame_reader.read().then(processFrame);
    147      });
    148    }
    149 
    150    function startDecodingAndRendering(cnv, handleFrame) {
    151      const init = {
    152        output: handleFrame,
    153        error: (e) => {
    154          testFailed("Failed to decode frame.");
    155          finishTest();
    156        }
    157      };
    158 
    159      const config = {
    160        codec: codec_string,
    161        codedWidth: cnv.width,
    162        codedHeight: cnv.height,
    163        acceleration: "deny",
    164 
    165      };
    166 
    167      let decoder = new VideoDecoder(init);
    168      decoder.configure(config);
    169      return decoder;
    170    }
    171 
    172    function isFramePixelMatched(gl, th_per_pixel = pixelCompareTolerance) {
    173      WebGLTestUtils.checkCanvasRect(gl, 0, 0, src_width, src_width, kTestPixel, "should be orange", pixelCompareTolerance)
    174    }
    175 
    176    function main() {
    177      if (!("VideoEncoder" in window)) {
    178        testPassed("WebCodecs API is not supported.");
    179        finishTest();
    180        return;
    181      }
    182      let cnv = document.getElementById("dst");
    183 
    184      let webgl_webcodecs_test_context = {
    185        maxFrameTested: kMaxFrame,
    186        displayed_frame: 0,
    187        isFramePixelMatched: isFramePixelMatched,
    188        testFailed: testFailed,
    189        testPassed: testPassed,
    190        finishTest: finishTest
    191      };
    192      setTestMode(webgl_webcodecs_test_context);
    193      let handleFrame = requestWebGLVideoFrameHandler(cnv);
    194      if (handleFrame === null) {
    195        finishTest();
    196        return;
    197      }
    198 
    199      startDrawing();
    200      let decoder = startDecodingAndRendering(cnv, handleFrame);
    201      captureAndEncode((chunk) => {
    202        decoder.decode(chunk);
    203      });
    204    }
    205 
    206    document.body.onload = main;
    207  </script>
    208 
    209 </body>
    210 
    211 </html>