| // META: global=window,dedicatedworker |
| // META: script=/webcodecs/utils.js |
| // META: script=/webcodecs/videoFrame-utils.js |
| |
| test(t => { |
| let image = makeImageBitmap(32, 16); |
| let frame = new VideoFrame(image, {timestamp: 10}); |
| |
| assert_equals(frame.timestamp, 10, 'timestamp'); |
| assert_equals(frame.duration, null, 'duration'); |
| assert_equals(frame.visibleRect.width, 32, 'visibleRect.width'); |
| assert_equals(frame.visibleRect.height, 16, 'visibleRect.height'); |
| assert_equals(frame.displayWidth, 32, 'displayWidth'); |
| assert_equals(frame.displayHeight, 16, 'displayHeight'); |
| |
| frame.close(); |
| }, 'Test we can construct a VideoFrame.'); |
| |
| test(t => { |
| let image = makeImageBitmap(32, 16); |
| let frame = new VideoFrame(image, {timestamp: 10}); |
| frame.close(); |
| |
| assert_equals(frame.format, null, 'format') |
| assert_equals(frame.timestamp, null, 'timestamp'); |
| assert_equals(frame.duration, null, 'duration'); |
| assert_equals(frame.codedWidth, 0, 'codedWidth'); |
| assert_equals(frame.codedHeight, 0, 'codedHeight'); |
| assert_equals(frame.visibleRect, null, 'visibleRect'); |
| assert_equals(frame.displayWidth, 0, 'displayWidth'); |
| assert_equals(frame.displayHeight, 0, 'displayHeight'); |
| assert_equals(frame.colorSpace.primaries, null, 'colorSpace.primaries'); |
| assert_equals(frame.colorSpace.transfer, null, 'colorSpace.transfer'); |
| assert_equals(frame.colorSpace.matrix, null, 'colorSpace.matrix'); |
| assert_equals(frame.colorSpace.fullRange, null, 'colorSpace.fullRange'); |
| |
| assert_throws_dom('InvalidStateError', () => frame.clone()); |
| }, 'Test closed VideoFrame.'); |
| |
| test(t => { |
| let image = makeImageBitmap(32, 16); |
| let frame = new VideoFrame(image, {timestamp: -10}); |
| assert_equals(frame.timestamp, -10, 'timestamp'); |
| frame.close(); |
| }, 'Test we can construct a VideoFrame with a negative timestamp.'); |
| |
| test(t => { |
| let image = makeImageBitmap(1, 1); |
| let frame = new VideoFrame(image, {timestamp: 10}); |
| |
| assert_equals(frame.visibleRect.width, 1, 'visibleRect.width'); |
| assert_equals(frame.visibleRect.height, 1, 'visibleRect.height'); |
| assert_equals(frame.displayWidth, 1, 'displayWidth'); |
| assert_equals(frame.displayHeight, 1, 'displayHeight'); |
| |
| frame.close(); |
| }, 'Test we can construct an odd-sized VideoFrame.'); |
| |
| test(t => { |
| // Test only valid for Window contexts. |
| if (!('document' in self)) |
| return; |
| |
| let video = document.createElement('video'); |
| |
| assert_throws_dom('InvalidStateError', () => { |
| let frame = new VideoFrame(video, {timestamp: 10}); |
| }) |
| }, 'Test constructing w/ unusable image argument throws: HAVE_NOTHING <video>.'); |
| |
| test(t => { |
| let canvas = new OffscreenCanvas(0, 0); |
| |
| assert_throws_dom('InvalidStateError', () => { |
| let frame = new VideoFrame(canvas, {timestamp: 10}); |
| }) |
| }, 'Test constructing w/ unusable image argument throws: emtpy Canvas.'); |
| |
| test(t => { |
| let image = makeImageBitmap(32, 16); |
| image.close(); |
| |
| assert_throws_dom('InvalidStateError', () => { |
| let frame = new VideoFrame(image, {timestamp: 10}); |
| }) |
| }, 'Test constructing w/ unusable image argument throws: closed ImageBitmap.'); |
| |
| test(t => { |
| let image = makeImageBitmap(32, 16); |
| let frame = new VideoFrame(image, {timestamp: 10}); |
| frame.close(); |
| |
| assert_throws_dom('InvalidStateError', () => { |
| let newFrame = new VideoFrame(frame); |
| }) |
| }, 'Test constructing w/ unusable image argument throws: closed VideoFrame.'); |
| |
| test(t => { |
| let init = { |
| format: 'I420', |
| timestamp: 1234, |
| codedWidth: 4, |
| codedHeight: 2 |
| }; |
| let data = new Uint8Array([ |
| 1, 2, 3, 4, 5, 6, 7, 8, // y |
| 1, 2, // u |
| 1, 2, // v |
| ]); |
| let i420Frame = new VideoFrame(data, init); |
| let image = makeImageBitmap(32, 16); |
| |
| |
| assert_throws_js( |
| TypeError, |
| () => new VideoFrame(image, {timestamp: 10, visibleRect: {x: -1, y: 0, width: 10, height: 10}}), |
| 'negative visibleRect x'); |
| |
| assert_throws_js( |
| TypeError, |
| () => new VideoFrame(image, {timestamp: 10, visibleRect: {x: 0, y: 0, width: -10, height: 10}}), |
| 'negative visibleRect width'); |
| |
| assert_throws_js( |
| TypeError, |
| () => new VideoFrame(image, {timestamp: 10, visibleRect: {x: 0, y: 0, width: 10, height: 0}}), |
| 'zero visibleRect height'); |
| |
| assert_throws_js( |
| TypeError, |
| () => new VideoFrame(image, {timestamp: 10, visibleRect: {x: 0, y: Infinity, width: 10, height: 10}}), |
| 'non finite visibleRect y'); |
| |
| assert_throws_js( |
| TypeError, |
| () => new VideoFrame(image, {timestamp: 10, visibleRect: {x: 0, y: 0, width: 10, height: Infinity}}), |
| 'non finite visibleRect height'); |
| |
| assert_throws_js( |
| TypeError, |
| () => new VideoFrame(image, {timestamp: 10, visibleRect: {x: 0, y: 0, width: 33, height: 17}}), |
| 'visibleRect area exceeds coded size'); |
| |
| assert_throws_js( |
| TypeError, |
| () => new VideoFrame(image, {timestamp: 10, visibleRect: {x: 2, y: 2, width: 32, height: 16}}), |
| 'visibleRect outside coded size'); |
| |
| assert_throws_js( |
| TypeError, |
| () => new VideoFrame(image, {timestamp: 10, displayHeight: 10}), |
| 'displayHeight provided without displayWidth'); |
| |
| assert_throws_js( |
| TypeError, |
| () => new VideoFrame(image, {timestamp: 10, displayWidth: 10}), |
| 'displayWidth provided without displayHeight'); |
| |
| assert_throws_js( |
| TypeError, |
| () => new VideoFrame(image, {timestamp: 10, displayWidth: 0, displayHeight: 10}), |
| 'displayWidth is zero'); |
| |
| assert_throws_js( |
| TypeError, |
| () => new VideoFrame(image, {timestamp: 10, displayWidth: 10, displayHeight: 0}), |
| 'displayHeight is zero'); |
| |
| assert_throws_js( |
| TypeError, |
| () => new VideoFrame(i420Frame, {visibleRect: {x: 1, y: 0, width: 2, height: 2}}), |
| 'visibleRect x is not sample aligned'); |
| |
| assert_throws_js( |
| TypeError, |
| () => new VideoFrame(i420Frame, {visibleRect: {x: 0, y: 0, width: 1, height: 2}}), |
| 'visibleRect width is not sample aligned'); |
| |
| }, 'Test invalid CanvasImageSource constructed VideoFrames'); |
| |
| test(t => { |
| let init = { |
| format: 'I420', |
| timestamp: 1234, |
| codedWidth: 4, |
| codedHeight: 2 |
| }; |
| let data = new Uint8Array([ |
| 1, 2, 3, 4, 5, 6, 7, 8, // y |
| 1, 2, // u |
| 1, 2, // v |
| ]); |
| let origFrame = new VideoFrame(data, init); |
| |
| let cropLeftHalf = new VideoFrame(origFrame, {visibleRect : {x: 0, y: 0, width: 2, height: 2}}); |
| assert_equals(cropLeftHalf.codedWidth, origFrame.codedWidth); |
| assert_equals(cropLeftHalf.codedHeight, origFrame.codedHeight); |
| assert_equals(cropLeftHalf.visibleRect.x, 0); |
| assert_equals(cropLeftHalf.visibleRect.y, 0); |
| assert_equals(cropLeftHalf.visibleRect.width, 2); |
| assert_equals(cropLeftHalf.visibleRect.height, 2); |
| assert_equals(cropLeftHalf.displayWidth, 2); |
| assert_equals(cropLeftHalf.displayHeight, 2); |
| }, 'Test visibleRect metadata override where source display size = visible size'); |
| |
| test(t => { |
| let init = { |
| format: 'I420', |
| timestamp: 1234, |
| codedWidth: 4, |
| codedHeight: 2, |
| displayWidth: 8, |
| displayHeight: 2 |
| }; |
| let data = new Uint8Array([ |
| 1, 2, 3, 4, 5, 6, 7, 8, // y |
| 1, 2, // u |
| 1, 2, // v |
| ]); |
| let anamorphicFrame = new VideoFrame(data, init); |
| |
| let cropRightFrame = new VideoFrame(anamorphicFrame, {visibleRect : {x: 2, y: 0, width: 2, height: 2}}); |
| assert_equals(cropRightFrame.codedWidth, anamorphicFrame.codedWidth); |
| assert_equals(cropRightFrame.codedHeight, anamorphicFrame.codedHeight); |
| assert_equals(cropRightFrame.visibleRect.x, 2); |
| assert_equals(cropRightFrame.visibleRect.y, 0); |
| assert_equals(cropRightFrame.visibleRect.width, 2); |
| assert_equals(cropRightFrame.visibleRect.height, 2); |
| assert_equals(cropRightFrame.displayWidth, 4, 'cropRightFrame.displayWidth'); |
| assert_equals(cropRightFrame.displayHeight, 2, 'cropRightFrame.displayHeight'); |
| }, 'Test visibleRect metadata override where source display width = 2 * visible width (anamorphic)'); |
| |
| test(t => { |
| let init = { |
| format: 'I420', |
| timestamp: 1234, |
| codedWidth: 4, |
| codedHeight: 2, |
| displayWidth: 8, |
| displayHeight: 4 |
| }; |
| let data = new Uint8Array([ |
| 1, 2, 3, 4, 5, 6, 7, 8, // y |
| 1, 2, // u |
| 1, 2, // v |
| ]); |
| let scaledFrame = new VideoFrame(data, init); |
| |
| let cropRightFrame = new VideoFrame(scaledFrame, {visibleRect : {x: 2, y: 0, width: 2, height: 2}}); |
| assert_equals(cropRightFrame.codedWidth, scaledFrame.codedWidth); |
| assert_equals(cropRightFrame.codedHeight, scaledFrame.codedHeight); |
| assert_equals(cropRightFrame.visibleRect.x, 2); |
| assert_equals(cropRightFrame.visibleRect.y, 0); |
| assert_equals(cropRightFrame.visibleRect.width, 2); |
| assert_equals(cropRightFrame.visibleRect.height, 2); |
| assert_equals(cropRightFrame.displayWidth, 4, 'cropRightFrame.displayWidth'); |
| assert_equals(cropRightFrame.displayHeight, 4, 'cropRightFrame.displayHeight'); |
| }, 'Test visibleRect metadata override where source display size = 2 * visible size for both width and height'); |
| |
| test(t => { |
| let image = makeImageBitmap(32, 16); |
| |
| let scaledFrame = new VideoFrame(image, |
| { visibleRect : {x: 0, y: 0, width: 2, height: 2}, |
| displayWidth: 10, displayHeight: 20 |
| }); |
| assert_equals(scaledFrame.codedWidth, 32); |
| assert_equals(scaledFrame.codedHeight, 16); |
| assert_equals(scaledFrame.visibleRect.x, 0); |
| assert_equals(scaledFrame.visibleRect.y, 0); |
| assert_equals(scaledFrame.visibleRect.width, 2); |
| assert_equals(scaledFrame.visibleRect.height, 2); |
| assert_equals(scaledFrame.displayWidth, 10, 'scaledFrame.displayWidth'); |
| assert_equals(scaledFrame.displayHeight, 20, 'scaledFrame.displayHeight'); |
| }, 'Test visibleRect + display size metadata override'); |
| |
| test(t => { |
| let image = makeImageBitmap(32, 16); |
| |
| let scaledFrame = new VideoFrame(image, |
| { |
| displayWidth: 10, displayHeight: 20 |
| }); |
| assert_equals(scaledFrame.codedWidth, 32); |
| assert_equals(scaledFrame.codedHeight, 16); |
| assert_equals(scaledFrame.visibleRect.x, 0); |
| assert_equals(scaledFrame.visibleRect.y, 0); |
| assert_equals(scaledFrame.visibleRect.width, 32); |
| assert_equals(scaledFrame.visibleRect.height, 16); |
| assert_equals(scaledFrame.displayWidth, 10, 'scaledFrame.displayWidth'); |
| assert_equals(scaledFrame.displayHeight, 20, 'scaledFrame.displayHeight'); |
| }, 'Test display size metadata override'); |
| |
| test(t => { |
| assert_throws_js( |
| TypeError, |
| () => new VideoFrame( |
| new Uint8Array(1), |
| {format: 'ABCD', timestamp: 1234, codedWidth: 4, codedHeight: 2}), |
| 'invalid pixel format'); |
| |
| assert_throws_js( |
| TypeError, |
| () => |
| new VideoFrame(new Uint32Array(1), {format: 'RGBA', timestamp: 1234}), |
| 'missing coded size'); |
| |
| function constructFrame(init) { |
| let data = new Uint8Array([ |
| 1, 2, 3, 4, 5, 6, 7, 8, // y |
| 1, 2, // u |
| 1, 2, // v |
| ]); |
| return new VideoFrame(data, {...init, format: 'I420'}); |
| } |
| |
| assert_throws_js( |
| TypeError, () => constructFrame({ |
| timestamp: 1234, |
| codedWidth: Math.pow(2, 32) - 1, |
| codedHeight: Math.pow(2, 32) - 1, |
| }), |
| 'invalid coded size'); |
| assert_throws_js( |
| TypeError, |
| () => constructFrame({timestamp: 1234, codedWidth: 4, codedHeight: 0}), |
| 'invalid coded height'); |
| assert_throws_js( |
| TypeError, |
| () => constructFrame({timestamp: 1234, codedWidth: 0, codedHeight: 4}), |
| 'invalid coded width'); |
| assert_throws_js( |
| TypeError, () => constructFrame({ |
| timestamp: 1234, |
| codedWidth: 4, |
| codedHeight: 2, |
| visibleRect: {x: 100, y: 100, width: 1, height: 1} |
| }), |
| 'invalid visible left/right'); |
| assert_throws_js( |
| TypeError, () => constructFrame({ |
| timestamp: 1234, |
| codedWidth: 4, |
| codedHeight: 2, |
| visibleRect: {x: 0, y: 0, width: 0, height: 2} |
| }), |
| 'invalid visible width'); |
| assert_throws_js( |
| TypeError, () => constructFrame({ |
| timestamp: 1234, |
| codedWidth: 4, |
| codedHeight: 2, |
| visibleRect: {x: 0, y: 0, width: 2, height: 0} |
| }), |
| 'invalid visible height'); |
| assert_throws_js( |
| TypeError, () => constructFrame({ |
| timestamp: 1234, |
| codedWidth: 4, |
| codedHeight: 2, |
| visibleRect: {x: 0, y: 0, width: -100, height: -100} |
| }), |
| 'invalid negative visible size'); |
| assert_throws_js( |
| TypeError, () => constructFrame({ |
| timestamp: 1234, |
| codedWidth: 4, |
| codedHeight: 2, |
| displayWidth: Math.pow(2, 32), |
| }), |
| 'invalid display width'); |
| assert_throws_js( |
| TypeError, () => constructFrame({ |
| timestamp: 1234, |
| codedWidth: 4, |
| codedHeight: 2, |
| displayWidth: Math.pow(2, 32) - 1, |
| displayHeight: Math.pow(2, 32) |
| }), |
| 'invalid display height'); |
| }, 'Test invalid buffer constructed VideoFrames'); |
| |
| test(t => { |
| testBufferConstructedI420Frame('Uint8Array(ArrayBuffer)'); |
| }, 'Test Uint8Array(ArrayBuffer) constructed I420 VideoFrame'); |
| |
| test(t => { |
| testBufferConstructedI420Frame('ArrayBuffer'); |
| }, 'Test ArrayBuffer constructed I420 VideoFrame'); |
| |
| test(t => { |
| let fmt = 'I420'; |
| let vfInit = { |
| format: fmt, |
| timestamp: 1234, |
| codedWidth: 4, |
| codedHeight: 2, |
| colorSpace: { |
| primaries: 'smpte170m', |
| matrix: 'bt470bg', |
| }, |
| }; |
| let data = new Uint8Array([ |
| 1, 2, 3, 4, 5, 6, 7, 8, // y |
| 1, 2, // u |
| 1, 2, // v |
| ]); |
| let frame = new VideoFrame(data, vfInit); |
| assert_equals(frame.colorSpace.primaries, 'smpte170m', 'color primaries'); |
| assert_true(frame.colorSpace.transfer == null, 'color transfer'); |
| assert_equals(frame.colorSpace.matrix, 'bt470bg', 'color matrix'); |
| assert_true(frame.colorSpace.fullRange == null, 'color range'); |
| }, 'Test planar constructed I420 VideoFrame with colorSpace'); |
| |
| test(t => { |
| let fmt = 'I420A'; |
| let vfInit = {format: fmt, timestamp: 1234, codedWidth: 4, codedHeight: 2}; |
| let data = new Uint8Array([ |
| 1, 2, 3, 4, 5, 6, 7, 8, // y |
| 1, 2, // u |
| 1, 2, // v |
| 8, 7, 6, 5, 4, 3, 2, 1, // a |
| ]); |
| let frame = new VideoFrame(data, vfInit); |
| assert_equals(frame.format, fmt, 'plane format'); |
| assert_equals(frame.colorSpace.primaries, 'bt709', 'color primaries'); |
| assert_equals(frame.colorSpace.transfer, 'bt709', 'color transfer'); |
| assert_equals(frame.colorSpace.matrix, 'bt709', 'color matrix'); |
| assert_false(frame.colorSpace.fullRange, 'color range'); |
| frame.close(); |
| |
| // Most constraints are tested as part of I420 above. |
| |
| let y = {offset: 0, stride: 4}; |
| let u = {offset: 8, stride: 2}; |
| let v = {offset: 10, stride: 2}; |
| let a = {offset: 12, stride: 4}; |
| |
| assert_throws_js(TypeError, () => { |
| let a = {offset: 12, stride: 1}; |
| let frame = new VideoFrame(data, {...vfInit, layout: [y, u, v, a]}); |
| }, 'a stride too small'); |
| assert_throws_js(TypeError, () => { |
| let frame = new VideoFrame(data.slice(0, 12), vfInit); |
| }, 'data too small'); |
| }, 'Test buffer constructed I420+Alpha VideoFrame'); |
| |
| test(t => { |
| let fmt = 'NV12'; |
| let vfInit = {format: fmt, timestamp: 1234, codedWidth: 4, codedHeight: 2}; |
| let data = new Uint8Array([ |
| 1, 2, 3, 4, 5, 6, 7, 8, // y |
| 1, 2, 3, 4, // uv |
| ]); |
| let frame = new VideoFrame(data, vfInit); |
| assert_equals(frame.format, fmt, 'plane format'); |
| assert_equals(frame.colorSpace.primaries, 'bt709', 'color primaries'); |
| assert_equals(frame.colorSpace.transfer, 'bt709', 'color transfer'); |
| assert_equals(frame.colorSpace.matrix, 'bt709', 'color matrix'); |
| assert_false(frame.colorSpace.fullRange, 'color range'); |
| frame.close(); |
| |
| let y = {offset: 0, stride: 4}; |
| let uv = {offset: 8, stride: 4}; |
| |
| assert_throws_js(TypeError, () => { |
| let y = {offset: 0, stride: 1}; |
| let frame = new VideoFrame(data, {...vfInit, layout: [y, uv]}); |
| }, 'y stride too small'); |
| assert_throws_js(TypeError, () => { |
| let uv = {offset: 8, stride: 1}; |
| let frame = new VideoFrame(data, {...vfInit, layout: [y, uv]}); |
| }, 'uv stride too small'); |
| assert_throws_js(TypeError, () => { |
| let frame = new VideoFrame(data.slice(0, 8), vfInit); |
| }, 'data too small'); |
| }, 'Test buffer constructed NV12 VideoFrame'); |
| |
| test(t => { |
| let vfInit = {timestamp: 1234, codedWidth: 4, codedHeight: 2}; |
| let data = new Uint8Array([ |
| 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, |
| 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, |
| ]); |
| let frame = new VideoFrame(data, {...vfInit, format: 'RGBA'}); |
| assert_equals(frame.format, 'RGBA', 'plane format'); |
| assert_equals(frame.colorSpace.primaries, 'bt709', 'color primaries'); |
| assert_equals(frame.colorSpace.transfer, 'iec61966-2-1', 'color transfer'); |
| assert_equals(frame.colorSpace.matrix, 'rgb', 'color matrix'); |
| assert_true(frame.colorSpace.fullRange, 'color range'); |
| frame.close(); |
| |
| frame = new VideoFrame(data, {...vfInit, format: 'RGBX'}); |
| assert_equals(frame.format, 'RGBX', 'plane format'); |
| assert_equals(frame.colorSpace.primaries, 'bt709', 'color primaries'); |
| assert_equals(frame.colorSpace.transfer, 'iec61966-2-1', 'color transfer'); |
| assert_equals(frame.colorSpace.matrix, 'rgb', 'color matrix'); |
| assert_true(frame.colorSpace.fullRange, 'color range'); |
| frame.close(); |
| |
| frame = new VideoFrame(data, {...vfInit, format: 'BGRA'}); |
| assert_equals(frame.format, 'BGRA', 'plane format'); |
| assert_equals(frame.colorSpace.primaries, 'bt709', 'color primaries'); |
| assert_equals(frame.colorSpace.transfer, 'iec61966-2-1', 'color transfer'); |
| assert_equals(frame.colorSpace.matrix, 'rgb', 'color matrix'); |
| assert_true(frame.colorSpace.fullRange, 'color range'); |
| frame.close(); |
| |
| frame = new VideoFrame(data, {...vfInit, format: 'BGRX'}); |
| assert_equals(frame.format, 'BGRX', 'plane format'); |
| assert_equals(frame.colorSpace.primaries, 'bt709', 'color primaries'); |
| assert_equals(frame.colorSpace.transfer, 'iec61966-2-1', 'color transfer'); |
| assert_equals(frame.colorSpace.matrix, 'rgb', 'color matrix'); |
| assert_true(frame.colorSpace.fullRange, 'color range'); |
| frame.close(); |
| }, 'Test buffer constructed RGB VideoFrames'); |
| |
| test(t => { |
| let image = makeImageBitmap(32, 16); |
| let frame = new VideoFrame(image, {timestamp: 0}); |
| assert_true(!!frame); |
| |
| frame_copy = new VideoFrame(frame); |
| assert_equals(frame.format, frame_copy.format); |
| assert_equals(frame.timestamp, frame_copy.timestamp); |
| assert_equals(frame.codedWidth, frame_copy.codedWidth); |
| assert_equals(frame.codedHeight, frame_copy.codedHeight); |
| assert_equals(frame.displayWidth, frame_copy.displayWidth); |
| assert_equals(frame.displayHeight, frame_copy.displayHeight); |
| assert_equals(frame.duration, frame_copy.duration); |
| frame_copy.close(); |
| |
| frame_copy = new VideoFrame(frame, {duration: 1234}); |
| assert_equals(frame.timestamp, frame_copy.timestamp); |
| assert_equals(frame_copy.duration, 1234); |
| frame_copy.close(); |
| |
| frame_copy = new VideoFrame(frame, {timestamp: 1234, duration: 456}); |
| assert_equals(frame_copy.timestamp, 1234); |
| assert_equals(frame_copy.duration, 456); |
| frame_copy.close(); |
| |
| frame.close(); |
| }, 'Test VideoFrame constructed VideoFrame'); |
| |
| test(t => { |
| let canvas = makeOffscreenCanvas(16, 16); |
| let frame = new VideoFrame(canvas); |
| assert_equals(frame.displayWidth, 16); |
| assert_equals(frame.displayHeight, 16); |
| frame.close(); |
| }, 'Test we can construct a VideoFrame from an offscreen canvas.'); |
| |
| test(t => { |
| let fmt = 'I420A'; |
| let vfInit = {format: fmt, timestamp: 1234, codedWidth: 4, codedHeight: 2}; |
| let data = new Uint8Array([ |
| 1, 2, 3, 4, 5, 6, 7, 8, // y |
| 1, 2, // u |
| 1, 2, // v |
| 8, 7, 6, 5, 4, 3, 2, 1, // a |
| ]); |
| let frame = new VideoFrame(data, vfInit); |
| assert_equals(frame.format, fmt, 'plane format'); |
| |
| let alpha_frame_copy = new VideoFrame(frame, {alpha: 'keep'}); |
| assert_equals(alpha_frame_copy.format, 'I420A', 'plane format'); |
| |
| let opaque_frame_copy = new VideoFrame(frame, {alpha: 'discard'}); |
| assert_equals(opaque_frame_copy.format, 'I420', 'plane format'); |
| |
| frame.close(); |
| alpha_frame_copy.close(); |
| opaque_frame_copy.close(); |
| }, 'Test I420A VideoFrame and alpha={keep,discard}'); |
| |
| test(t => { |
| let vfInit = {timestamp: 1234, codedWidth: 4, codedHeight: 2}; |
| let data = new Uint8Array([ |
| 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, |
| 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, |
| ]); |
| let frame = new VideoFrame(data, {...vfInit, format: 'RGBA'}); |
| assert_equals(frame.format, 'RGBA', 'plane format'); |
| |
| let alpha_frame_copy = new VideoFrame(frame, {alpha: 'keep'}); |
| assert_equals(alpha_frame_copy.format, 'RGBA', 'plane format'); |
| |
| let opaque_frame_copy = new VideoFrame(frame, {alpha: 'discard'}); |
| assert_equals(opaque_frame_copy.format, 'RGBX', 'plane format'); |
| |
| alpha_frame_copy.close(); |
| opaque_frame_copy.close(); |
| frame.close(); |
| |
| frame = new VideoFrame(data, {...vfInit, format: 'BGRA'}); |
| assert_equals(frame.format, 'BGRA', 'plane format'); |
| |
| alpha_frame_copy = new VideoFrame(frame, {alpha: 'keep'}); |
| assert_equals(alpha_frame_copy.format, 'BGRA', 'plane format'); |
| |
| opaque_frame_copy = new VideoFrame(frame, {alpha: 'discard'}); |
| assert_equals(opaque_frame_copy.format, 'BGRX', 'plane format'); |
| |
| alpha_frame_copy.close(); |
| opaque_frame_copy.close(); |
| frame.close(); |
| }, 'Test RGBA, BGRA VideoFrames with alpha={keep,discard}'); |
| |
| test(t => { |
| let canvas = makeOffscreenCanvas(16, 16, {alpha: true}); |
| let frame = new VideoFrame(canvas); |
| assert_true( |
| frame.format == 'RGBA' || frame.format == 'BGRA' || |
| frame.format == 'I420A', |
| 'plane format should have alpha: ' + frame.format); |
| frame.close(); |
| |
| frame = new VideoFrame(canvas, {alpha: 'discard'}); |
| assert_true( |
| frame.format == 'RGBX' || frame.format == 'BGRX' || |
| frame.format == 'I420', |
| 'plane format should not have alpha: ' + frame.format); |
| frame.close(); |
| }, 'Test a VideoFrame constructed from canvas can drop the alpha channel.'); |