| // META: global=window,dedicatedworker |
| |
| promise_test(async t => { |
| let fmt = 'RGBA'; |
| const rgb_plane = [ |
| 0xBA, 0xDF, 0x00, 0xD0, 0xBA, 0xDF, 0x01, 0xD0, 0xBA, 0xDF, 0x02, 0xD0, |
| 0xBA, 0xDF, 0x03, 0xD0 |
| ]; |
| let data = new Uint8Array(rgb_plane); |
| let unused_buffer = new ArrayBuffer(123); |
| let init = { |
| format: fmt, |
| timestamp: 1234, |
| codedWidth: 2, |
| codedHeight: 2, |
| visibleRect: {x: 0, y: 0, width: 2, height: 2}, |
| transfer: [data.buffer, unused_buffer] |
| }; |
| assert_equals(data.length, 16, 'data.length'); |
| assert_equals(unused_buffer.byteLength, 123, 'unused_buffer.byteLength'); |
| |
| let frame = new VideoFrame(data, init); |
| assert_equals(frame.format, fmt, 'format'); |
| assert_equals(data.length, 0, 'data.length after detach'); |
| assert_equals(unused_buffer.byteLength, 0, 'unused_buffer after detach'); |
| |
| const options = { |
| rect: {x: 0, y: 0, width: init.codedWidth, height: init.codedHeight} |
| }; |
| let size = frame.allocationSize(options); |
| let output_data = new Uint8Array(size); |
| let layout = await frame.copyTo(output_data, options); |
| let expected_data = new Uint8Array(rgb_plane); |
| assert_equals(expected_data.length, size, 'expected_data size'); |
| for (let i = 0; i < size; i++) { |
| assert_equals(expected_data[i], output_data[i], `expected_data[${i}]`); |
| } |
| |
| frame.close(); |
| }, 'Test transfering ArrayBuffer to VideoFrame'); |
| |
| |
| promise_test(async t => { |
| let fmt = 'I420'; |
| const i420_planes = [0xAA, 0xBB, 0xCC]; |
| let data = new Uint8Array(i420_planes); |
| let init = { |
| format: fmt, |
| timestamp: 1234, |
| codedWidth: 1, |
| codedHeight: 1, |
| visibleRect: {x: 0, y: 0, width: 1, height: 1}, |
| transfer: [data.buffer] |
| }; |
| |
| let frame = new VideoFrame(data, init); |
| assert_equals(data.length, 0, 'data.length after detach'); |
| |
| const options = { |
| rect: {x: 0, y: 0, width: init.codedWidth, height: init.codedHeight} |
| }; |
| let size = frame.allocationSize(options); |
| let output_data = new Uint8Array(size); |
| let layout = await frame.copyTo(output_data, options); |
| let expected_data = new Uint8Array(i420_planes); |
| assert_equals(expected_data.length, size, 'expected_data size'); |
| assert_equals(layout[0].stride, 1, 'layout[0].stride'); |
| assert_equals(layout[0].offset, 0, 'layout[0].offset'); |
| assert_equals(layout[1].stride, 1, 'layout[1].stride'); |
| assert_equals(layout[1].offset, 1, 'layout[1].offset'); |
| assert_equals(layout[2].stride, 1, 'layout[2].stride'); |
| assert_equals(layout[2].offset, 2, 'layout[2].offset'); |
| assert_equals(expected_data.length, size, 'expected_data size'); |
| for (let i = 0; i < size; i++) { |
| assert_equals(expected_data[i], output_data[i], `expected_data[${i}]`); |
| } |
| |
| frame.close(); |
| }, 'Test transfering buffers to VideoFrame with uneven samples'); |
| |
| promise_test(async t => { |
| const rgb_plane = [ |
| 0xBA, 0xDF, 0x00, 0xD0, 0xBA, 0xDF, 0x01, 0xD0, 0xBA, 0xDF, 0x02, 0xD0, |
| 0xBA, 0xDF, 0x03, 0xD0 |
| ]; |
| let data = new Uint8Array(rgb_plane); |
| let detached_buffer = new ArrayBuffer(123); |
| |
| // Detach `detached_buffer` |
| structuredClone({x: detached_buffer}, {transfer: [detached_buffer]}); |
| |
| let init = { |
| format: 'RGBA', |
| timestamp: 1234, |
| codedWidth: 2, |
| codedHeight: 2, |
| visibleRect: {x: 0, y: 0, width: 2, height: 2}, |
| transfer: [data.buffer, detached_buffer] |
| }; |
| |
| try { |
| new VideoFrame(data, init); |
| } catch (error) { |
| assert_equals(error.name, 'DataCloneError', 'error.name'); |
| } |
| // `data.buffer` didn't get detached |
| assert_equals(data.length, 16, 'data.length'); |
| }, 'Test transfering detached buffer to VideoFrame'); |
| |
| |
| promise_test(async t => { |
| const rgb_plane = [ |
| 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, |
| 0xEE, 0xEE, 0xEE, 0xEE |
| ]; |
| const padding_size = 6; |
| let arraybuffer = new ArrayBuffer(padding_size + 16 /* pixels */); |
| let data = new Uint8Array(arraybuffer, padding_size); |
| data.set(rgb_plane); |
| |
| let init = { |
| format: 'RGBA', |
| timestamp: 1234, |
| codedWidth: 2, |
| codedHeight: 2, |
| visibleRect: {x: 0, y: 0, width: 2, height: 2}, |
| transfer: [arraybuffer] |
| }; |
| |
| let frame = new VideoFrame(data, init); |
| assert_equals(data.length, 0, 'data.length after detach'); |
| assert_equals(arraybuffer.byteLength, 0, 'arraybuffer after detach'); |
| |
| const options = { |
| rect: {x: 0, y: 0, width: init.codedWidth, height: init.codedHeight} |
| }; |
| let size = frame.allocationSize(options); |
| let output_data = new Uint8Array(size); |
| let layout = await frame.copyTo(output_data, options); |
| for (let i = 0; i < size; i++) { |
| assert_equals(output_data[i], 0xEE, `output_data[${i}]`); |
| } |
| }, 'Test transfering view of an ArrayBuffer to VideoFrame'); |
| |
| promise_test(async t => { |
| const rgb_plane = [ |
| 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, |
| 0xEE, 0xEE, 0xEE, 0xEE |
| ]; |
| const padding_size = 6; |
| let arraybuffer = new ArrayBuffer(padding_size + 16 /* pixels */); |
| let data = new Uint8Array(arraybuffer, padding_size); |
| data.set(rgb_plane); |
| |
| let init = { |
| format: 'RGBA', |
| timestamp: 1234, |
| codedWidth: 2, |
| codedHeight: 2, |
| visibleRect: {x: 0, y: 0, width: 2, height: 2}, |
| transfer: [arraybuffer, arraybuffer] |
| }; |
| |
| try { |
| new VideoFrame(data, init); |
| } catch (error) { |
| assert_equals(error.name, 'DataCloneError', 'error.name'); |
| } |
| // `data.buffer` didn't get detached |
| assert_equals(data.length, 16, 'data.length'); |
| }, 'Test transfering same array buffer twice'); |
| |
| promise_test(async t => { |
| const bytes = [ 0xBA, 0xDF, 0x00, 0xD0, 0xBA, 0xDF, 0x01, 0xD0, 0xBA, 0xDF ]; |
| let data = new Uint8Array(bytes); |
| let unused_buffer = new ArrayBuffer(123); |
| let init = { |
| type: 'key', |
| timestamp: 0, |
| data: data, |
| transfer: [data.buffer, unused_buffer] |
| }; |
| |
| assert_equals(data.length, 10, 'data.length'); |
| assert_equals(unused_buffer.byteLength, 123, 'unused_buffer.byteLength'); |
| |
| let chunk = new EncodedAudioChunk(init); |
| assert_equals(data.length, 0, 'data.length after detach'); |
| assert_equals(unused_buffer.byteLength, 0, 'unused_buffer after detach'); |
| |
| let output_data = new Uint8Array(chunk.byteLength); |
| chunk.copyTo(output_data); |
| let expected_data = new Uint8Array(bytes); |
| assert_equals(expected_data.length, chunk.byteLength, 'expected_data size'); |
| for (let i = 0; i < chunk.byteLength; i++) { |
| assert_equals(expected_data[i], output_data[i], `expected_data[${i}]`); |
| } |
| }, 'Test transfering ArrayBuffer to EncodedAudioChunk'); |
| |
| promise_test(async t => { |
| const bytes = [ 0xBA, 0xDF, 0x00, 0xD0, 0xBA, 0xDF, 0x01, 0xD0, 0xBA, 0xDF ]; |
| let data = new Uint8Array(bytes); |
| let unused_buffer = new ArrayBuffer(123); |
| let init = { |
| type: 'key', |
| timestamp: 0, |
| data: data, |
| transfer: [data.buffer, unused_buffer] |
| }; |
| |
| assert_equals(data.length, 10, 'data.length'); |
| assert_equals(unused_buffer.byteLength, 123, 'unused_buffer.byteLength'); |
| |
| let chunk = new EncodedVideoChunk(init); |
| assert_equals(data.length, 0, 'data.length after detach'); |
| assert_equals(unused_buffer.byteLength, 0, 'unused_buffer after detach'); |
| |
| let output_data = new Uint8Array(chunk.byteLength); |
| chunk.copyTo(output_data); |
| let expected_data = new Uint8Array(bytes); |
| assert_equals(expected_data.length, chunk.byteLength, 'expected_data size'); |
| for (let i = 0; i < chunk.byteLength; i++) { |
| assert_equals(expected_data[i], output_data[i], `expected_data[${i}]`); |
| } |
| }, 'Test transfering ArrayBuffer to EncodedVideoChunk'); |
| |
| promise_test(async t => { |
| const bytes = [0xBA, 0xDF, 0x00, 0xD0, 0xBA, 0xDF, 0x01, 0xD0, 0xBA, 0xDF]; |
| let data = new Uint8Array(bytes); |
| let unused_buffer = new ArrayBuffer(123); |
| let init = { |
| type: 'key', |
| timestamp: 0, |
| numberOfFrames: data.length, |
| numberOfChannels: 1, |
| sampleRate: 10000, |
| format: 'u8', |
| data: data, |
| transfer: [data.buffer, unused_buffer] |
| }; |
| |
| assert_equals(data.length, 10, 'data.length'); |
| assert_equals(unused_buffer.byteLength, 123, 'unused_buffer.byteLength'); |
| |
| let audio_data = new AudioData(init); |
| assert_equals(data.length, 0, 'data.length after detach'); |
| assert_equals(unused_buffer.byteLength, 0, 'unused_buffer after detach'); |
| |
| let readback_data = new Uint8Array(bytes.length); |
| audio_data.copyTo(readback_data, {planeIndex: 0, format: 'u8'}); |
| let expected_data = new Uint8Array(bytes); |
| for (let i = 0; i < expected_data.length; i++) { |
| assert_equals(expected_data[i], readback_data[i], `expected_data[${i}]`); |
| } |
| }, 'Test transfering ArrayBuffer to AudioData'); |
| |
| promise_test(async t => { |
| let sample_rate = 48000; |
| let total_duration_s = 1; |
| let data_count = 10; |
| let chunks = []; |
| |
| let encoder_init = { |
| error: t.unreached_func('Encoder error'), |
| output: (chunk, metadata) => { |
| chunks.push(chunk); |
| } |
| }; |
| let encoder = new AudioEncoder(encoder_init); |
| let config = { |
| codec: 'opus', |
| sampleRate: sample_rate, |
| numberOfChannels: 2, |
| bitrate: 256000, // 256kbit |
| }; |
| encoder.configure(config); |
| |
| let timestamp_us = 0; |
| const data_duration_s = total_duration_s / data_count; |
| const frames = data_duration_s * config.sampleRate; |
| for (let i = 0; i < data_count; i++) { |
| let buffer = new Float32Array(frames * config.numberOfChannels); |
| let data = new AudioData({ |
| timestamp: timestamp_us, |
| data: buffer, |
| numberOfChannels: config.numberOfChannels, |
| numberOfFrames: frames, |
| sampleRate: config.sampleRate, |
| format: 'f32-planar', |
| transfer: [buffer.buffer] |
| }); |
| timestamp_us += data_duration_s * 1_000_000; |
| assert_equals(buffer.length, 0, 'buffer.length after detach'); |
| encoder.encode(data); |
| } |
| await encoder.flush(); |
| encoder.close(); |
| assert_greater_than(chunks.length, 0); |
| }, 'Encoding from AudioData with transferred buffer'); |
| |
| |
| promise_test(async t => { |
| let unused_buffer = new ArrayBuffer(123); |
| let support = await ImageDecoder.isTypeSupported('image/png'); |
| assert_implements_optional( |
| support, 'Optional codec image/png not supported.'); |
| let buffer = await fetch('four-colors.png').then(response => { |
| return response.arrayBuffer(); |
| }); |
| |
| let decoder = new ImageDecoder( |
| {data: buffer, type: 'image/png', transfer: [buffer, unused_buffer]}); |
| assert_equals(buffer.byteLength, 0, 'buffer.byteLength after detach'); |
| assert_equals(unused_buffer.byteLength, 0, 'unused_buffer after detach'); |
| |
| let result = await decoder.decode(); |
| assert_equals(result.image.displayWidth, 320); |
| assert_equals(result.image.displayHeight, 240); |
| }, 'Test transfering ArrayBuffer to ImageDecoder.'); |