blob: 6b8af266f2907b359d0399ac10672a6634ec8b1b [file] [log] [blame]
<!DOCTYPE html>
<!--
Take frames coming from various sources and read them using copyTo().
-->
<title>copyTo() test</title>
<script src="webcodecs_common.js"></script>
<script type="text/javascript">
'use strict';
function yuv_to_rgb(y, u, v) {
let b = 1.164 * (y - 16) + 2.018 * (u - 128);
let g = 1.164 * (y - 16) - 0.813 * (v - 128) - 0.391 * (u - 128);
let r = 1.164 * (y - 16) + 1.596 * (v - 128);
return { r: r, g: g, b: b };
}
async function validateFourColorsBytes(frame) {
const m = 4;
const tolerance = 8;
let expected_xy_color = [
// Left-top yellow
{ x: m, y: m, r: 255, g: 255, b: 0 },
// Right-top red
{ x: frame.displayWidth - m, y: m, r: 255, g: 0, b: 0 },
// Left-bottom blue
{ x: m, y: frame.displayHeight - m, r: 0, g: 0, b: 255 },
// Right-bottom green
{ x: frame.displayWidth - m, y: frame.displayHeight - m,
r: 0, g: 255, b: 0 },
]
for (let test of expected_xy_color) {
const options = {
rect: { x: test.x, y: test.y, width: 2, height: 2 }
}
let size = frame.allocationSize(options);
let buffer = new ArrayBuffer(size);
let layout = await frame.copyTo(buffer, options);
let view = new DataView(buffer);
let rgb = null;
switch (frame.format) {
case "I420":
case "I420A":
rgb = yuv_to_rgb(view.getUint8(layout[0].offset), // Y
view.getUint8(layout[1].offset), // U
view.getUint8(layout[2].offset)); // V
break;
case "NV12":
rgb = yuv_to_rgb(view.getUint8(layout[0].offset), // Y
view.getUint8(layout[1].offset), // U
view.getUint8(layout[1].offset + 1)); // V
break;
case "RGBX":
case "RGBA":
rgb = {
r: view.getUint8(layout[0].offset),
g: view.getUint8(layout[0].offset + 1),
b: view.getUint8(layout[0].offset + 2)
};
break;
case "BGRX":
case "BGRA":
rgb = {
r: view.getUint8(layout[0].offset + 2),
g: view.getUint8(layout[0].offset + 1),
b: view.getUint8(layout[0].offset)
};
break;
default:
TEST.reportFailure("Unexpected frame format: " + frame.format);
return;
}
let message =
`Test ${frame.format} ${JSON.stringify(test)} ${JSON.stringify(rgb)}`;
TEST.assert(Math.abs(rgb.r - test.r) < tolerance, message);
TEST.assert(Math.abs(rgb.g - test.g) < tolerance, message);
TEST.assert(Math.abs(rgb.b - test.b) < tolerance, message);
}
}
async function main(arg) {
let source_type = arg.source_type;
let source = await createFrameSource(source_type, 320, 240);
if (!source) {
TEST.skip('Unsupported source: ' + source_type);
return;
}
let frame = await source.getNextFrame();
if (!arg.validate_camera_frames && source_type == 'camera') {
TEST.log("Skip copyTo result validation");
let size = frame.allocationSize();
let buf = new ArrayBuffer(size);
let layout = await frame.copyTo(buf);
TEST.assert(layout, "layout is empty");
} else {
await validateFourColorsBytes(frame);
}
frame.close();
source.close();
}
</script>