<!DOCTYPE html>
<html>
<title>Test the VideoTrackReader API.</title>
<body>
  <img id='frame_image' src="pattern.png">
</body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/media.js"></script>
<script src="/webcodecs/utils.js"></script>
<script>

const defaultConfig = {
  codec: 'vp8',
  framerate: 25,
  width: 640,
  height: 480
};

async function generateBitmap(width, height) {
  return createImageBitmap(document.getElementById('frame_image'),
                                  { resizeWidth: width,
                                    resizeHeight: height });
}

async function createVideoFrame(width, height, timestamp) {
  let bitmap = await generateBitmap(width, height);
  return new VideoFrame(bitmap, { timestamp: timestamp });
}

promise_test(t => {
  // VideoEncoderInit lacks required fields.
  assert_throws_js(TypeError, () => { new VideoEncoder({}); });

  // VideoEncoderInit has required fields.
  let encoder = new VideoEncoder(getDefaultCodecInit(t));

  assert_equals(encoder.state, "unconfigured");

  encoder.close();

  return endAfterEventLoopTurn();
}, 'Test VideoEncoder construction');

promise_test(t => {
  let encoder = new VideoEncoder(getDefaultCodecInit(t));

  let badCodecsList = [
    '',                         // Empty codec
    'bogus',                    // Non exsitent codec
    'vorbis',                   // Audio codec
    'vp9',                      // Ambiguous codec
    'video/webm; codecs="vp9"'  // Codec with mime type
  ]

  testConfigurations(encoder, defaultConfig, badCodecsList);

  return endAfterEventLoopTurn();
}, 'Test VideoEncoder.configure()');

promise_test(async t => {
  let output_chunks = [];
  let codecInit = getDefaultCodecInit(t);
  codecInit.output = chunk => output_chunks.push(chunk);

  let encoder = new VideoEncoder(codecInit);

  // No encodes yet.
  assert_equals(encoder.encodeQueueSize, 0);

  encoder.configure(defaultConfig);

  // Still no encodes.
  assert_equals(encoder.encodeQueueSize, 0);

  let frame1 = await createVideoFrame(640, 480, 0);
  let frame2 = await createVideoFrame(640, 480, 33333);

  encoder.encode(frame1.clone());
  encoder.encode(frame2.clone());

  // Could be 0, 1, or 2. We can't guarantee this check runs before the UA has
  // processed the encodes.
  assert_true(encoder.encodeQueueSize >= 0 && encoder.encodeQueueSize <= 2)

  await encoder.flush();

  // We can guarantee that all encodes are processed after a flush.
  assert_equals(encoder.encodeQueueSize, 0);

  assert_equals(output_chunks.length, 2);
  assert_equals(output_chunks[0].timestamp, frame1.timestamp);
  assert_equals(output_chunks[1].timestamp, frame2.timestamp);
}, 'Test successful configure(), encode(), and flush()');

promise_test(async t => {
  let output_chunks = [];
  let codecInit = getDefaultCodecInit(t);
  codecInit.output = chunk => output_chunks.push(chunk);

  let encoder = new VideoEncoder(codecInit);

  // No encodes yet.
  assert_equals(encoder.encodeQueueSize, 0);

  let config = defaultConfig;

  encoder.configure(config);

  let frame1 = await createVideoFrame(640, 480, 0);
  let frame2 = await createVideoFrame(640, 480, 33333);

  encoder.encode(frame1.clone());
  encoder.configure(config);

  encoder.encode(frame2.clone());

  await encoder.flush();

  // We can guarantee that all encodes are processed after a flush.
  assert_equals(encoder.encodeQueueSize, 0);

  // The first frame may have been dropped when reconfiguring.
  // This shouldn't happen, and should be fixed/called out in the spec, but
  // this is preptively added to prevent flakiness.
  // TODO: Remove these checks when implementations handle this correctly.
  assert_true(output_chunks.length == 1 || output_chunks.length == 2);

  if (output_chunks.length == 1) {
    // If we only have one chunk frame, make sure we droped the frame that was
    // in flight when we reconfigured.
    assert_equals(output_chunks[0].timestamp, frame2.timestamp);
  } else {
    assert_equals(output_chunks[0].timestamp, frame1.timestamp);
    assert_equals(output_chunks[1].timestamp, frame2.timestamp);
  }

  output_chunks = [];

  let frame3 = await createVideoFrame(640, 480, 66666);
  let frame4 = await createVideoFrame(640, 480, 100000);

  encoder.encode(frame3.clone());

  // Verify that a failed call to configure does not change the encoder's state.
  let badConfig = {...defaultConfig};
  badConfig.codec = 'bogus';
  assert_throws_js(TypeError, () => encoder.configure(badConfig));

  encoder.encode(frame4.clone());

  await encoder.flush();

  assert_equals(output_chunks[0].timestamp, frame3.timestamp);
  assert_equals(output_chunks[1].timestamp, frame4.timestamp);
}, 'Test successful encode() after re-configure().');

promise_test(async t => {
  let output_chunks = [];
  let codecInit = getDefaultCodecInit(t);
  codecInit.output = chunk => output_chunks.push(chunk);

  let encoder = new VideoEncoder(codecInit);

  let timestamp = 33333;
  let frame = await createVideoFrame(640, 480, timestamp);

  encoder.configure(defaultConfig);
  assert_equals(encoder.state, "configured");

  encoder.encode(frame);

  // |frame| is not longer valid since it has been destroyed.
  assert_not_equals(frame.timestamp, timestamp);
  assert_throws_dom("InvalidStateError", () => frame.clone());

  encoder.close();

  return endAfterEventLoopTurn();
}, 'Test encoder consumes (destroys) frames.');

promise_test(async t => {
  let encoder = new VideoEncoder(getDefaultCodecInit(t));

  let frame = await createVideoFrame(640, 480, 0);

  return testClosedCodec(t, encoder, defaultConfig, frame);
}, 'Verify closed VideoEncoder operations');

promise_test(async t => {
  let encoder = new VideoEncoder(getDefaultCodecInit(t));

  let frame = await createVideoFrame(640, 480, 0);

  return testUnconfiguredCodec(t, encoder, frame);
}, 'Verify unconfigured VideoEncoder operations');

promise_test(async t => {
  let encoder = new VideoEncoder(getDefaultCodecInit(t));

  let frame = await createVideoFrame(640, 480, 0);
  frame.destroy();

  encoder.configure(defaultConfig);

  frame.destroy();
  assert_throws_dom("OperationError", () => {
    encoder.encode(frame)
  });
}, 'Verify encoding destroyed frames throws.');

</script>
</html>
