tor-browser

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

video-encoder-utils.js (3861B)


      1 async function checkEncoderSupport(test, config) {
      2  assert_equals("function", typeof VideoEncoder.isConfigSupported);
      3  let supported = false;
      4  try {
      5    const support = await VideoEncoder.isConfigSupported(config);
      6    supported = support.supported;
      7  } catch (e) {}
      8 
      9  assert_implements_optional(supported, 'Unsupported config: ' +
     10                             JSON.stringify(config));
     11 }
     12 
     13 function fourColorsFrame(ctx, width, height, text) {
     14  const kYellow = "#FFFF00";
     15  const kRed = "#FF0000";
     16  const kBlue = "#0000FF";
     17  const kGreen = "#00FF00";
     18 
     19  ctx.fillStyle = kYellow;
     20  ctx.fillRect(0, 0, width / 2, height / 2);
     21 
     22  ctx.fillStyle = kRed;
     23  ctx.fillRect(width / 2, 0, width / 2, height / 2);
     24 
     25  ctx.fillStyle = kBlue;
     26  ctx.fillRect(0, height / 2, width / 2, height / 2);
     27 
     28  ctx.fillStyle = kGreen;
     29  ctx.fillRect(width / 2, height / 2, width / 2, height / 2);
     30 
     31  ctx.fillStyle = 'white';
     32  ctx.font = (height / 10) + 'px sans-serif';
     33  ctx.fillText(text, width / 2, height / 2);
     34 }
     35 
     36 // Paints |count| black dots on the |ctx|, so their presence can be validated
     37 // later. This is an analog of the most basic bar code.
     38 function putBlackDots(ctx, width, height, count) {
     39  ctx.fillStyle = 'black';
     40  const dot_size = 20;
     41  const step = dot_size * 2;
     42 
     43  for (let i = 1; i <= count; i++) {
     44    let x = i * step;
     45    let y = step * (x / width + 1);
     46    x %= width;
     47    ctx.fillRect(x, y, dot_size, dot_size);
     48  }
     49 }
     50 
     51 // Validates that frame has |count| black dots in predefined places.
     52 function validateBlackDots(frame, count) {
     53  const width = frame.displayWidth;
     54  const height = frame.displayHeight;
     55  let cnv = new OffscreenCanvas(width, height);
     56  var ctx = cnv.getContext('2d', {willReadFrequently: true});
     57  ctx.drawImage(frame, 0, 0);
     58  const dot_size = 20;
     59  const step = dot_size * 2;
     60 
     61  for (let i = 1; i <= count; i++) {
     62    let x = i * step + dot_size / 2;
     63    let y = step * (x / width + 1) + dot_size / 2;
     64    x %= width;
     65 
     66    if (x)
     67      x = x -1;
     68    if (y)
     69      y = y -1;
     70 
     71    let rgba = ctx.getImageData(x, y, 2, 2).data;
     72    const tolerance = 60;
     73    if ((rgba[0] > tolerance || rgba[1] > tolerance || rgba[2] > tolerance)
     74      && (rgba[4] > tolerance || rgba[5] > tolerance || rgba[6] > tolerance)
     75      && (rgba[8] > tolerance || rgba[9] > tolerance || rgba[10] > tolerance)
     76      && (rgba[12] > tolerance || rgba[13] > tolerance || rgba[14] > tolerance)) {
     77      // The dot is too bright to be a black dot.
     78      return false;
     79    }
     80  }
     81  return true;
     82 }
     83 
     84 function createFrame(width, height, ts = 0, additionalOptions = {}) {
     85  let duration = 33333;  // 30fps
     86  let text = ts.toString();
     87  let cnv = new OffscreenCanvas(width, height);
     88  var ctx = cnv.getContext('2d');
     89  fourColorsFrame(ctx, width, height, text);
     90 
     91  // Merge the default options with the provided additionalOptions
     92  const videoFrameOptions = {
     93    timestamp: ts,
     94    duration,
     95    ...additionalOptions, // Spread the additional options to merge them
     96  };
     97 
     98  return new VideoFrame(cnv, videoFrameOptions);
     99 }
    100 
    101 function createDottedFrame(width, height, dots, ts) {
    102  if (ts === undefined)
    103    ts = dots;
    104  let duration = 33333;  // 30fps
    105  let text = ts.toString();
    106  let cnv = new OffscreenCanvas(width, height);
    107  var ctx = cnv.getContext('2d');
    108  fourColorsFrame(ctx, width, height, text);
    109  putBlackDots(ctx, width, height, dots);
    110  return new VideoFrame(cnv, { timestamp: ts, duration });
    111 }
    112 
    113 function createVideoEncoder(t, callbacks) {
    114  return new VideoEncoder({
    115    output(chunk, metadata) {
    116      if (callbacks && callbacks.output) {
    117        t.step(() => callbacks.output(chunk, metadata));
    118      } else {
    119        t.unreached_func('unexpected output()');
    120      }
    121    },
    122    error(e) {
    123      if (callbacks && callbacks.error) {
    124        t.step(() => callbacks.error(e));
    125      } else {
    126        t.unreached_func('unexpected error()');
    127      }
    128    }
    129  });
    130 }