forked from mirrors/gecko-dev
		
	Automatic update from web-platform-tests [webcodecs] Deprecate VideoFrame.destroy(). This CL adds VideoFrame.close() as an alias for VideoFrame.destroy(), adds a deprecation message for VideoFrame.destroy(), and changes all callsites to use close(). Bug: 1166930 Change-Id: I39b9c68262553a6814f6bb0b6b81c02012c2d026 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2631405 Commit-Queue: Dan Sanders <sandersd@chromium.org> Reviewed-by: Jeremy Roman <jbroman@chromium.org> Reviewed-by: Eugene Zemtsov <eugene@chromium.org> Reviewed-by: Guido Urdaneta <guidou@chromium.org> Cr-Commit-Position: refs/heads/master@{#844250} -- wpt-commits: 1895256f46deb64c491bff1d5bc2e4372dd35731 wpt-pr: 27194
		
			
				
	
	
		
			261 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			261 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
// META: global=window,dedicatedworker
 | 
						|
// META: script=/common/media.js
 | 
						|
// META: script=/webcodecs/utils.js
 | 
						|
 | 
						|
const defaultConfig = {
 | 
						|
  codec: 'vp8',
 | 
						|
  framerate: 25,
 | 
						|
  width: 640,
 | 
						|
  height: 480
 | 
						|
};
 | 
						|
 | 
						|
async function generateBitmap(width, height) {
 | 
						|
  const src = "pattern.png";
 | 
						|
 | 
						|
  var size = {
 | 
						|
    resizeWidth: width,
 | 
						|
    resizeHeight: height
 | 
						|
  };
 | 
						|
 | 
						|
  return fetch(src)
 | 
						|
      .then(response => response.blob())
 | 
						|
      .then(blob => createImageBitmap(blob, size));
 | 
						|
}
 | 
						|
 | 
						|
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 callbacks_before_reset = 0;
 | 
						|
  let callbacks_after_reset = 0;
 | 
						|
  let codecInit = getDefaultCodecInit(t);
 | 
						|
  codecInit.output = chunk => {
 | 
						|
    if (chunk.timestamp % 2 == 0) {
 | 
						|
      // pre-reset frames have even timestamp
 | 
						|
      callbacks_before_reset++;
 | 
						|
    } else {
 | 
						|
      // after-reset frames have odd timestamp
 | 
						|
      callbacks_after_reset++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  let encoder = new VideoEncoder(codecInit);
 | 
						|
  encoder.configure(defaultConfig);
 | 
						|
  await encoder.flush();
 | 
						|
 | 
						|
  let frames = [];
 | 
						|
  for (let i = 0; i < 200; i++) {
 | 
						|
    let frame = await createVideoFrame(640, 480, i * 40_000);
 | 
						|
    frames.push(frame);
 | 
						|
  }
 | 
						|
 | 
						|
  for (frame of frames)
 | 
						|
    encoder.encode(frame);
 | 
						|
 | 
						|
  // Wait for the first frame to be encoded
 | 
						|
  await t.step_wait(() => callbacks_before_reset > 0,
 | 
						|
    "Encoded outputs started coming", 10000, 1);
 | 
						|
 | 
						|
  let saved_callbacks_before_reset = callbacks_before_reset;
 | 
						|
  assert_greater_than(callbacks_before_reset, 0);
 | 
						|
  assert_less_than_equal(callbacks_before_reset, frames.length);
 | 
						|
 | 
						|
  encoder.reset();
 | 
						|
  assert_equals(encoder.encodeQueueSize, 0);
 | 
						|
 | 
						|
  let newConfig = { ...defaultConfig };
 | 
						|
  newConfig.width = 800;
 | 
						|
  newConfig.height = 600;
 | 
						|
  encoder.configure(newConfig);
 | 
						|
 | 
						|
  for (let i = frames.length; i < frames.length + 5; i++) {
 | 
						|
    let frame = await createVideoFrame(800, 600, i * 40_000 + 1);
 | 
						|
    encoder.encode(frame);
 | 
						|
  }
 | 
						|
  await encoder.flush();
 | 
						|
  assert_equals(callbacks_after_reset, 5);
 | 
						|
  assert_equals(saved_callbacks_before_reset, callbacks_before_reset);
 | 
						|
  assert_equals(encoder.encodeQueueSize, 0);
 | 
						|
}, 'Test successful reset() and re-confiugre()');
 | 
						|
 | 
						|
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 closed.
 | 
						|
  assert_not_equals(frame.timestamp, timestamp);
 | 
						|
  assert_throws_dom("InvalidStateError", () => frame.clone());
 | 
						|
 | 
						|
  encoder.close();
 | 
						|
 | 
						|
  return endAfterEventLoopTurn();
 | 
						|
}, 'Test encoder consumes (closes) 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.close();
 | 
						|
 | 
						|
  encoder.configure(defaultConfig);
 | 
						|
 | 
						|
  assert_throws_dom("OperationError", () => {
 | 
						|
    encoder.encode(frame)
 | 
						|
  });
 | 
						|
}, 'Verify encoding closed frames throws.');
 |