Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test has a WPT meta file that expects 7 subtest issues.
- This WPT test may be referenced by the following Test IDs:
- /webcodecs/transfering.https.any.html - WPT Dashboard Interop Dashboard
- /webcodecs/transfering.https.any.worker.html - WPT Dashboard Interop Dashboard
// 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.');