chromium/third_party/blink/web_tests/wpt_internal/webcodecs/avc_encoder_config.https.any.js

// META: global=window,dedicatedworker
// META: script=/wpt_internal/webcodecs/encoder_utils.js

const defaultWidth = 640;
const defaultHeight = 360;

let frameNumber = 0;

async function configureAndEncode(encoder, config) {
  encoder.configure(config);

  let frame = createFrame(defaultWidth, defaultHeight, ++frameNumber);
  encoder.encode(frame, { keyFrame : true });
  frame.close();
  return encoder.flush()
}

promise_test(async t => {
  var output = undefined;

  let encoderInit = {
    error: () => t.unreached_func("Unexpected error"),
    output: (chunk, metadata) => {
      let config = metadata.decoderConfig;
      assert_equals(output, undefined, "output undefined sanity");
      output = {
        chunk: chunk,
        config: config,
      };
    },
  };

  let encoder = new VideoEncoder(encoderInit);

  let encoderConfig = {
    codec: "avc1.42001E",
    width: defaultWidth,
    height: defaultHeight,
  };

  // Configure an encoder with no avcOptions (should default to avc format).
  await configureAndEncode(encoder, encoderConfig);

  // avc chunks should output a config with an avcC description.
  assert_not_equals(output, undefined, "output default");
  assert_not_equals(output.chunk, null, "chunk default");
  assert_not_equals(output.config, null, "config default");
  assert_not_equals(output.config.description, null, "desc default");

  output = undefined;

  // Configure with annex-b.
  encoderConfig.avc = { format: "annexb" };
  await configureAndEncode(encoder, encoderConfig);

  // annexb chunks should start with a start code.
  assert_not_equals(output, undefined, "output annexb");
  assert_not_equals(output.chunk, null, "chunk annexb");
  assert_greater_than(output.chunk.byteLength, 4, "chunk annexb data");

  let chunkData = new Uint8Array(output.chunk.byteLength);
  output.chunk.copyTo(chunkData);

  let startCode = new Int8Array(chunkData.buffer, 0, 4);
  assert_equals(startCode[0], 0x00, "startCode [0]");
  assert_equals(startCode[1], 0x00, "startCode [1]");
  assert_equals(startCode[2], 0x00, "startCode [2]");
  assert_equals(startCode[3], 0x01, "startCode [3]");

  // There should not be an avcC 'description' with annexb.
  assert_not_equals(output.config, null, "config annexb");
  assert_equals(output.config.description, undefined, "desc annexb");

  output = undefined;

  // Configure with avc.
  encoderConfig.avc = { format: "avc" };
  await configureAndEncode(encoder, encoderConfig);

  // avc should output a config with an avcC description.
  assert_not_equals(output, undefined, "output avc");
  assert_not_equals(output.chunk, null, "chunk avc");
  assert_not_equals(output.config, null, "config avc");
  assert_not_equals(output.config.description, null, "desc avc");

  encoder.close();
}, "Test AvcConfig supports 'avc' and 'annexb'");

promise_test(async t => {
  let goodEncoderConfig = {codec: 'avc1.42001E', width: 128, height: 128};
  let support = await VideoEncoder.isConfigSupported(goodEncoderConfig);
  assert_true(support.supported);

  let badEncoderConfig = {codec: 'avc1.42001E', width: 129, height: 129};
  support = await VideoEncoder.isConfigSupported(badEncoderConfig);
  assert_false(support.supported);
}, 'Test H.264 only supports even sizes');

promise_test(async t => {
  // Spot test a few levels.

  // level 3.0.
  const LEVEL_30 = 'avc1.42001E';
  let support = await VideoEncoder.isConfigSupported(
      {codec: LEVEL_30, width: 720, height: 576});
  assert_true(support.supported);
  support = await VideoEncoder.isConfigSupported(
      {codec: LEVEL_30, width: 722, height: 576});
  assert_false(support.supported);
  support = await VideoEncoder.isConfigSupported(
      {codec: LEVEL_30, width: 720, height: 578});
  assert_false(support.supported);

  // level 4.0.
  const LEVEL_40 = 'avc1.420028';
  support = await VideoEncoder.isConfigSupported(
      {codec: LEVEL_40, width: 2048, height: 1024});
  if (support.supported) {
    support = await VideoEncoder.isConfigSupported(
        {codec: LEVEL_40, width: 2050, height: 1024});
    assert_false(support.supported);
    support = await VideoEncoder.isConfigSupported(
        {codec: LEVEL_40, width: 2048, height: 1026});
    assert_false(support.supported);
  }

  // level 5.1.
  const LEVEL_51 = 'avc1.420033';
  support = await VideoEncoder.isConfigSupported(
      {codec: LEVEL_51, width: 4096, height: 2304});
  if (support.supported) {
    support = await VideoEncoder.isConfigSupported(
        {codec: LEVEL_51, width: 4098, height: 2304});
    assert_false(support.supported);
    support = await VideoEncoder.isConfigSupported(
        {codec: LEVEL_51, width: 4096, height: 2306});
    assert_false(support.supported);
  }

  // level 6.0.
  const LEVEL_60 = 'avc1.42003C';
  support = await VideoEncoder.isConfigSupported(
      {codec: LEVEL_60, width: 8192, height: 4320});
  if (support.supported) {
    support = await VideoEncoder.isConfigSupported(
        {codec: LEVEL_60, width: 8194, height: 4320});
    assert_false(support.supported);
    support = await VideoEncoder.isConfigSupported(
        {codec: LEVEL_60, width: 8192, height: 4322});
    assert_false(support.supported);
  }
}, 'Resolutions exceeding H.264 level are rejected');