Bug 1686838 [wpt PR 27194] - [webcodecs] Deprecate VideoFrame.destroy()., a=testonly
[gecko.git] / testing / web-platform / tests / webcodecs / video-encoder.any.js
blobd86e6b61f2039acdf882f7551c7027967eec3ce2
1 // META: global=window,dedicatedworker
2 // META: script=/common/media.js
3 // META: script=/webcodecs/utils.js
5 const defaultConfig = {
6   codec: 'vp8',
7   framerate: 25,
8   width: 640,
9   height: 480
12 async function generateBitmap(width, height) {
13   const src = "pattern.png";
15   var size = {
16     resizeWidth: width,
17     resizeHeight: height
18   };
20   return fetch(src)
21       .then(response => response.blob())
22       .then(blob => createImageBitmap(blob, size));
25 async function createVideoFrame(width, height, timestamp) {
26   let bitmap = await generateBitmap(width, height);
27   return new VideoFrame(bitmap, { timestamp: timestamp });
30 promise_test(t => {
31   // VideoEncoderInit lacks required fields.
32   assert_throws_js(TypeError, () => { new VideoEncoder({}); });
34   // VideoEncoderInit has required fields.
35   let encoder = new VideoEncoder(getDefaultCodecInit(t));
37   assert_equals(encoder.state, "unconfigured");
39   encoder.close();
41   return endAfterEventLoopTurn();
42 }, 'Test VideoEncoder construction');
44 promise_test(t => {
45   let encoder = new VideoEncoder(getDefaultCodecInit(t));
47   let badCodecsList = [
48     '',                         // Empty codec
49     'bogus',                    // Non exsitent codec
50     'vorbis',                   // Audio codec
51     'vp9',                      // Ambiguous codec
52     'video/webm; codecs="vp9"'  // Codec with mime type
53   ]
55   testConfigurations(encoder, defaultConfig, badCodecsList);
57   return endAfterEventLoopTurn();
58 }, 'Test VideoEncoder.configure()');
60 promise_test(async t => {
61   let output_chunks = [];
62   let codecInit = getDefaultCodecInit(t);
63   codecInit.output = chunk => output_chunks.push(chunk);
65   let encoder = new VideoEncoder(codecInit);
67   // No encodes yet.
68   assert_equals(encoder.encodeQueueSize, 0);
70   encoder.configure(defaultConfig);
72   // Still no encodes.
73   assert_equals(encoder.encodeQueueSize, 0);
75   let frame1 = await createVideoFrame(640, 480, 0);
76   let frame2 = await createVideoFrame(640, 480, 33333);
78   encoder.encode(frame1.clone());
79   encoder.encode(frame2.clone());
81   // Could be 0, 1, or 2. We can't guarantee this check runs before the UA has
82   // processed the encodes.
83   assert_true(encoder.encodeQueueSize >= 0 && encoder.encodeQueueSize <= 2)
85   await encoder.flush();
87   // We can guarantee that all encodes are processed after a flush.
88   assert_equals(encoder.encodeQueueSize, 0);
90   assert_equals(output_chunks.length, 2);
91   assert_equals(output_chunks[0].timestamp, frame1.timestamp);
92   assert_equals(output_chunks[1].timestamp, frame2.timestamp);
93 }, 'Test successful configure(), encode(), and flush()');
95 promise_test(async t => {
96   let callbacks_before_reset = 0;
97   let callbacks_after_reset = 0;
98   let codecInit = getDefaultCodecInit(t);
99   codecInit.output = chunk => {
100     if (chunk.timestamp % 2 == 0) {
101       // pre-reset frames have even timestamp
102       callbacks_before_reset++;
103     } else {
104       // after-reset frames have odd timestamp
105       callbacks_after_reset++;
106     }
107   }
109   let encoder = new VideoEncoder(codecInit);
110   encoder.configure(defaultConfig);
111   await encoder.flush();
113   let frames = [];
114   for (let i = 0; i < 200; i++) {
115     let frame = await createVideoFrame(640, 480, i * 40_000);
116     frames.push(frame);
117   }
119   for (frame of frames)
120     encoder.encode(frame);
122   // Wait for the first frame to be encoded
123   await t.step_wait(() => callbacks_before_reset > 0,
124     "Encoded outputs started coming", 10000, 1);
126   let saved_callbacks_before_reset = callbacks_before_reset;
127   assert_greater_than(callbacks_before_reset, 0);
128   assert_less_than_equal(callbacks_before_reset, frames.length);
130   encoder.reset();
131   assert_equals(encoder.encodeQueueSize, 0);
133   let newConfig = { ...defaultConfig };
134   newConfig.width = 800;
135   newConfig.height = 600;
136   encoder.configure(newConfig);
138   for (let i = frames.length; i < frames.length + 5; i++) {
139     let frame = await createVideoFrame(800, 600, i * 40_000 + 1);
140     encoder.encode(frame);
141   }
142   await encoder.flush();
143   assert_equals(callbacks_after_reset, 5);
144   assert_equals(saved_callbacks_before_reset, callbacks_before_reset);
145   assert_equals(encoder.encodeQueueSize, 0);
146 }, 'Test successful reset() and re-confiugre()');
148 promise_test(async t => {
149   let output_chunks = [];
150   let codecInit = getDefaultCodecInit(t);
151   codecInit.output = chunk => output_chunks.push(chunk);
153   let encoder = new VideoEncoder(codecInit);
155   // No encodes yet.
156   assert_equals(encoder.encodeQueueSize, 0);
158   let config = defaultConfig;
160   encoder.configure(config);
162   let frame1 = await createVideoFrame(640, 480, 0);
163   let frame2 = await createVideoFrame(640, 480, 33333);
165   encoder.encode(frame1.clone());
166   encoder.configure(config);
168   encoder.encode(frame2.clone());
170   await encoder.flush();
172   // We can guarantee that all encodes are processed after a flush.
173   assert_equals(encoder.encodeQueueSize, 0);
175   // The first frame may have been dropped when reconfiguring.
176   // This shouldn't happen, and should be fixed/called out in the spec, but
177   // this is preptively added to prevent flakiness.
178   // TODO: Remove these checks when implementations handle this correctly.
179   assert_true(output_chunks.length == 1 || output_chunks.length == 2);
181   if (output_chunks.length == 1) {
182     // If we only have one chunk frame, make sure we droped the frame that was
183     // in flight when we reconfigured.
184     assert_equals(output_chunks[0].timestamp, frame2.timestamp);
185   } else {
186     assert_equals(output_chunks[0].timestamp, frame1.timestamp);
187     assert_equals(output_chunks[1].timestamp, frame2.timestamp);
188   }
190   output_chunks = [];
192   let frame3 = await createVideoFrame(640, 480, 66666);
193   let frame4 = await createVideoFrame(640, 480, 100000);
195   encoder.encode(frame3.clone());
197   // Verify that a failed call to configure does not change the encoder's state.
198   let badConfig = { ...defaultConfig };
199   badConfig.codec = 'bogus';
200   assert_throws_js(TypeError, () => encoder.configure(badConfig));
202   encoder.encode(frame4.clone());
204   await encoder.flush();
206   assert_equals(output_chunks[0].timestamp, frame3.timestamp);
207   assert_equals(output_chunks[1].timestamp, frame4.timestamp);
208 }, 'Test successful encode() after re-configure().');
210 promise_test(async t => {
211   let output_chunks = [];
212   let codecInit = getDefaultCodecInit(t);
213   codecInit.output = chunk => output_chunks.push(chunk);
215   let encoder = new VideoEncoder(codecInit);
217   let timestamp = 33333;
218   let frame = await createVideoFrame(640, 480, timestamp);
220   encoder.configure(defaultConfig);
221   assert_equals(encoder.state, "configured");
223   encoder.encode(frame);
225   // |frame| is not longer valid since it has been closed.
226   assert_not_equals(frame.timestamp, timestamp);
227   assert_throws_dom("InvalidStateError", () => frame.clone());
229   encoder.close();
231   return endAfterEventLoopTurn();
232 }, 'Test encoder consumes (closes) frames.');
234 promise_test(async t => {
235   let encoder = new VideoEncoder(getDefaultCodecInit(t));
237   let frame = await createVideoFrame(640, 480, 0);
239   return testClosedCodec(t, encoder, defaultConfig, frame);
240 }, 'Verify closed VideoEncoder operations');
242 promise_test(async t => {
243   let encoder = new VideoEncoder(getDefaultCodecInit(t));
245   let frame = await createVideoFrame(640, 480, 0);
247   return testUnconfiguredCodec(t, encoder, frame);
248 }, 'Verify unconfigured VideoEncoder operations');
250 promise_test(async t => {
251   let encoder = new VideoEncoder(getDefaultCodecInit(t));
253   let frame = await createVideoFrame(640, 480, 0);
254   frame.close();
256   encoder.configure(defaultConfig);
258   assert_throws_dom("OperationError", () => {
259     encoder.encode(frame)
260   });
261 }, 'Verify encoding closed frames throws.');