summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webcodecs/video-encoder.https.any.js
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/webcodecs/video-encoder.https.any.js')
-rw-r--r--testing/web-platform/tests/webcodecs/video-encoder.https.any.js320
1 files changed, 320 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webcodecs/video-encoder.https.any.js b/testing/web-platform/tests/webcodecs/video-encoder.https.any.js
new file mode 100644
index 0000000000..b5c511d406
--- /dev/null
+++ b/testing/web-platform/tests/webcodecs/video-encoder.https.any.js
@@ -0,0 +1,320 @@
+// META: global=window,dedicatedworker
+// META: script=/common/media.js
+// META: script=/webcodecs/utils.js
+// META: script=/webcodecs/video-encoder-utils.js
+
+const defaultConfig = {
+ codec: 'vp8',
+ width: 640,
+ height: 480
+};
+
+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);
+ let decoderConfig = null;
+ let encoderConfig = {
+ codec: 'vp8',
+ width: 640,
+ height: 480,
+ displayWidth: 800,
+ displayHeight: 600,
+ };
+
+ codecInit.output = (chunk, metadata) => {
+ assert_not_equals(metadata, null);
+ if (metadata.decoderConfig)
+ decoderConfig = metadata.decoderConfig;
+ output_chunks.push(chunk);
+ }
+
+ let encoder = new VideoEncoder(codecInit);
+ encoder.configure(encoderConfig);
+
+ let frame1 = createFrame(640, 480, 0);
+ let frame2 = createFrame(640, 480, 33333);
+ t.add_cleanup(() => {
+ frame1.close();
+ frame2.close();
+ });
+
+ encoder.encode(frame1);
+ encoder.encode(frame2);
+
+ await encoder.flush();
+
+ // Decoder config should be given with the first chunk
+ assert_not_equals(decoderConfig, null);
+ assert_equals(decoderConfig.codec, encoderConfig.codec);
+ assert_greater_than_equal(decoderConfig.codedHeight, encoderConfig.height);
+ assert_greater_than_equal(decoderConfig.codedWidth, encoderConfig.width);
+ assert_equals(decoderConfig.displayAspectHeight, encoderConfig.displayHeight);
+ assert_equals(decoderConfig.displayAspectWidth, encoderConfig.displayWidth);
+ assert_not_equals(decoderConfig.colorSpace.primaries, null);
+ assert_not_equals(decoderConfig.colorSpace.transfer, null);
+ assert_not_equals(decoderConfig.colorSpace.matrix, null);
+ assert_not_equals(decoderConfig.colorSpace.fullRange, null);
+
+ assert_equals(output_chunks.length, 2);
+ assert_equals(output_chunks[0].timestamp, frame1.timestamp);
+ assert_equals(output_chunks[0].duration, frame1.duration);
+ assert_equals(output_chunks[1].timestamp, frame2.timestamp);
+ assert_equals(output_chunks[1].duration, frame2.duration);
+}, 'Test successful configure(), encode(), and flush()');
+
+promise_test(async t => {
+ let codecInit = getDefaultCodecInit(t);
+ let encoderConfig = {
+ codec: 'vp8',
+ width: 320,
+ height: 200
+ };
+
+ codecInit.output = (chunk, metadata) => {}
+
+ let encoder = new VideoEncoder(codecInit);
+
+ // No encodes yet.
+ assert_equals(encoder.encodeQueueSize, 0);
+
+ encoder.configure(encoderConfig);
+
+ // Still no encodes.
+ assert_equals(encoder.encodeQueueSize, 0);
+
+ const frames_count = 100;
+ let frames = [];
+ for (let i = 0; i < frames_count; i++) {
+ let frame = createFrame(320, 200, i * 16000);
+ frames.push(frame);
+ }
+
+ let lastDequeueSize = Infinity;
+ encoder.ondequeue = () => {
+ assert_greater_than(lastDequeueSize, 0, "Dequeue event after queue empty");
+ assert_greater_than(lastDequeueSize, encoder.encodeQueueSize,
+ "Dequeue event without decreased queue size");
+ lastDequeueSize = encoder.encodeQueueSize;
+ };
+
+ for (let frame of frames)
+ encoder.encode(frame);
+
+ assert_greater_than_equal(encoder.encodeQueueSize, 0);
+ assert_less_than_equal(encoder.encodeQueueSize, frames_count);
+
+ await encoder.flush();
+ // We can guarantee that all encodes are processed after a flush.
+ assert_equals(encoder.encodeQueueSize, 0);
+ // Last dequeue event should fire when the queue is empty.
+ assert_equals(lastDequeueSize, 0);
+
+ // Reset this to Infinity to track the decline of queue size for this next
+ // batch of encodes.
+ lastDequeueSize = Infinity;
+
+ for (let frame of frames) {
+ encoder.encode(frame);
+ frame.close();
+ }
+
+ assert_greater_than_equal(encoder.encodeQueueSize, 0);
+ encoder.reset();
+ assert_equals(encoder.encodeQueueSize, 0);
+}, 'encodeQueueSize test');
+
+
+promise_test(async t => {
+ let timestamp = 0;
+ let callbacks_before_reset = 0;
+ let callbacks_after_reset = 0;
+ const timestamp_step = 40000;
+ const expected_callbacks_before_reset = 3;
+ let codecInit = getDefaultCodecInit(t);
+ let original = createFrame(320, 200, 0);
+ let encoder = null;
+ let reset_completed = false;
+ codecInit.output = (chunk, metadata) => {
+ if (chunk.timestamp % 2 == 0) {
+ // pre-reset frames have even timestamp
+ callbacks_before_reset++;
+ if (callbacks_before_reset == expected_callbacks_before_reset) {
+ encoder.reset();
+ reset_completed = true;
+ }
+ } else {
+ // after-reset frames have odd timestamp
+ callbacks_after_reset++;
+ }
+ }
+
+ encoder = new VideoEncoder(codecInit);
+ encoder.configure(defaultConfig);
+ await encoder.flush();
+
+ // Send 10x frames to the encoder, call reset() on it after x outputs,
+ // and make sure no more chunks are emitted afterwards.
+ let encodes_before_reset = expected_callbacks_before_reset * 10;
+ for (let i = 0; i < encodes_before_reset; i++) {
+ let frame = new VideoFrame(original, { timestamp: timestamp });
+ timestamp += timestamp_step;
+ encoder.encode(frame);
+ frame.close();
+ }
+
+ await t.step_wait(() => reset_completed,
+ "Reset() should be called by output callback", 10000, 1);
+
+ assert_equals(callbacks_before_reset, expected_callbacks_before_reset);
+ assert_true(reset_completed);
+ assert_equals(encoder.encodeQueueSize, 0);
+
+ let newConfig = { ...defaultConfig };
+ newConfig.width = 800;
+ newConfig.height = 600;
+ encoder.configure(newConfig);
+
+ const frames_after_reset = 5;
+ for (let i = 0; i < frames_after_reset; i++) {
+ let frame = createFrame(800, 600, timestamp + 1);
+ timestamp += timestamp_step;
+ encoder.encode(frame);
+ frame.close();
+ }
+ await encoder.flush();
+
+ assert_equals(callbacks_after_reset, frames_after_reset,
+ "not all after-reset() outputs have been emitted");
+ assert_equals(callbacks_before_reset, expected_callbacks_before_reset,
+ "pre-reset() outputs were emitter after reset() and flush()");
+ 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 = createFrame(640, 480, 0);
+ let frame2 = createFrame(640, 480, 33333);
+
+ encoder.encode(frame1);
+ encoder.configure(config);
+
+ encoder.encode(frame2);
+
+ await encoder.flush();
+
+ // We can guarantee that all encodes are processed after a flush.
+ assert_equals(encoder.encodeQueueSize, 0, "queue size after encode");
+
+ assert_equals(output_chunks.length, 2, "number of chunks");
+ assert_equals(output_chunks[0].timestamp, frame1.timestamp);
+ assert_equals(output_chunks[1].timestamp, frame2.timestamp);
+
+ output_chunks = [];
+
+ let frame3 = createFrame(640, 480, 66666);
+ let frame4 = createFrame(640, 480, 100000);
+
+ encoder.encode(frame3);
+
+ // 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);
+
+ 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 encoder = new VideoEncoder(getDefaultCodecInit(t));
+
+ let frame = createFrame(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 = createFrame(640, 480, 0);
+
+ return testUnconfiguredCodec(t, encoder, frame);
+}, 'Verify unconfigured VideoEncoder operations');
+
+promise_test(async t => {
+ let encoder = new VideoEncoder(getDefaultCodecInit(t));
+
+ let frame = createFrame(640, 480, 0);
+ frame.close();
+
+ encoder.configure(defaultConfig);
+
+ assert_throws_dom("OperationError", () => {
+ encoder.encode(frame);
+ });
+}, 'Verify encoding closed frames throws.');
+
+promise_test(async t => {
+ let output_chunks = [];
+ let codecInit = getDefaultCodecInit(t);
+ codecInit.output = chunk => output_chunks.push(chunk);
+
+ let encoder = new VideoEncoder(codecInit);
+ let config = defaultConfig;
+ encoder.configure(config);
+
+ let frame = createFrame(640, 480, -10000);
+ encoder.encode(frame);
+ frame.close();
+ await encoder.flush();
+ encoder.close();
+ assert_equals(output_chunks.length, 1);
+ assert_equals(output_chunks[0].timestamp, -10000, "first chunk timestamp");
+ assert_greater_than(output_chunks[0].byteLength, 0);
+}, 'Encode video with negative timestamp');