chromium/third_party/blink/web_tests/external/wpt/webcodecs/videoFrame-canvasImageSource.html

<title>Test VideoFrame creation from CanvasImageSource.</title>
<style>
button {
  display: inline-block;
  min-height: 100px; min-width: 100px;
  background: no-repeat 5% center url(four-colors.png);
}
</style>
<video preload="auto"></video>
<img src="four-colors.png"/>
<canvas id=""></canvas>
<svg width="320" height="240" xmlns="http://www.w3.org/2000/svg">
<image href="four-colors.png" height="320" width="240"/>
</svg>
<button></button>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/webcodecs/image-decoder-utils.js"></script>
<script>
async_test(t => {
  let video = document.querySelector('video');
  video.onerror = t.unreached_func();
  video.requestVideoFrameCallback(t.step_func(_ => {
    let frame = new VideoFrame(video);
    assert_true(!!frame);
    assert_equals(frame.displayWidth, video.videoWidth);
    assert_equals(frame.displayHeight, video.videoHeight);

    let canvas = new OffscreenCanvas(frame.displayWidth, frame.displayHeight);
    let ctx = canvas.getContext('2d');
    ctx.drawImage(video, 0, 0);
    verifyFourColorsImage(video.videoWidth, video.videoHeight, ctx);
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.drawImage(frame, 0, 0);
    verifyFourColorsImage(frame.displayWidth, frame.displayHeight, ctx);

    let frame_copy = new VideoFrame(frame, {duration: 1234});
    assert_equals(frame.timestamp, frame_copy.timestamp);
    assert_equals(frame_copy.duration, 1234);
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.drawImage(frame_copy, 0, 0);
    verifyFourColorsImage(frame_copy.displayWidth, frame_copy.displayHeight,
                          ctx);
    frame_copy.close();

    frame_copy = new VideoFrame(frame, {timestamp: 1234, duration: 456});
    assert_equals(frame_copy.timestamp, 1234);
    assert_equals(frame_copy.duration, 456);
    frame_copy.close();

    frame_copy = new VideoFrame(frame);
    assert_equals(frame.format, frame_copy.format);
    assert_equals(frame.timestamp, frame_copy.timestamp);
    assert_equals(frame.codedWidth, frame_copy.codedWidth);
    assert_equals(frame.codedHeight, frame_copy.codedHeight);
    assert_equals(frame.displayWidth, frame_copy.displayWidth);
    assert_equals(frame.displayHeight, frame_copy.displayHeight);
    assert_equals(frame.duration, frame_copy.duration);
    frame_copy.close();

    frame.close();
    t.done();
  }));

  const mediaConfig = {
    type: 'file',
    video: {
      contentType: 'video/mp4; codecs="av01.0.04M.08"',
      width: 320,
      height: 240,
      bitrate: 1000000,
      framerate: '30'
    }
  };
  navigator.mediaCapabilities.decodingInfo(mediaConfig).then(t.step_func(result => {
    assert_implements_optional(result.supported, "AV.1 file streaming unsupported");
    video.src = 'four-colors.mp4';
  }));
}, '<video> and VideoFrame constructed VideoFrame');

test(t => {
  let button = document.querySelector('button');
  let bgImage = button.computedStyleMap().get('background-image');
  assert_throws_dom('SecurityError', _ => { new VideoFrame(bgImage, {timestamp: 0}); },
                    'CSSImageValues are currently always tainted');
}, 'CSSImageValue constructed VideoFrame');

promise_test(() => {
  return new Promise(resolve => onload = resolve);
}, "Wait for onload event to get access to image data");

promise_test(async t => {
  let frame = new VideoFrame(document.querySelector('img'), {timestamp: 0});
  let canvas = new OffscreenCanvas(frame.displayWidth, frame.displayHeight);
  let ctx = canvas.getContext('2d');
  ctx.drawImage(frame, 0, 0);
  verifyFourColorsImage(frame.displayWidth, frame.displayHeight, ctx);
  frame.close();
}, 'Image element constructed VideoFrame');

promise_test(async t => {
  let frame = new VideoFrame(document.querySelector('image'), {timestamp: 0});
  let canvas = new OffscreenCanvas(frame.displayWidth, frame.displayHeight);
  let ctx = canvas.getContext('2d');
  ctx.drawImage(frame, 0, 0);
  verifyFourColorsImage(frame.displayWidth, frame.displayHeight, ctx);
  frame.close();
}, 'SVGImageElement constructed VideoFrame');

function drawFourColors(canvas) {
  let ctx = canvas.getContext('2d');
  ctx.fillStyle = '#FFFF00'; // yellow
  ctx.fillRect(0, 0, canvas.width / 2, canvas.height / 2);
  ctx.fillStyle = '#FF0000'; // red
  ctx.fillRect(canvas.width / 2, 0, canvas.width / 2, canvas.height / 2);
  ctx.fillStyle = '#0000FF'; // blue
  ctx.fillRect(0, canvas.height / 2, canvas.width / 2, canvas.height / 2);
  ctx.fillStyle = '#00FF00'; // green
  ctx.fillRect(canvas.width / 2, canvas.height / 2, canvas.width / 2,
               canvas.height / 2);
}

test(t => {
  let canvas = document.querySelector('canvas');
  canvas.width = 320;
  canvas.height = 240;

  // Draw and verify four colors image.
  drawFourColors(canvas);
  let ctx = canvas.getContext('2d');
  verifyFourColorsImage(canvas.width, canvas.height, ctx);

  let frame = new VideoFrame(canvas, {timestamp: 0});
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.drawImage(frame, 0, 0);
  verifyFourColorsImage(canvas.width, canvas.height, ctx);
  frame.close();
}, 'Canvas element constructed VideoFrame');

test(t => {
  let canvas = document.querySelector('canvas');
  canvas.width = 320;
  canvas.height = 240;

  // Draw and verify four colors image.
  drawFourColors(canvas);
  let ctx = canvas.getContext('2d');
  verifyFourColorsImage(canvas.width, canvas.height, ctx);

  // Set a different timestamp to try and ensure the same frame isn't reused.
  let frame = new VideoFrame(canvas, {timestamp: 0});
  let frame_copy = new VideoFrame(frame, {timestamp: 1});
  frame.close();

  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.drawImage(frame_copy, 0, 0);
  verifyFourColorsImage(canvas.width, canvas.height, ctx);
  frame_copy.close();
}, 'Copy of canvas element constructed VideoFrame');
</script>