| <!DOCTYPE html> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="resources/videoframe-utilities.js"></script> |
| <style> |
| body { margin: 0 } |
| canvas { image-rendering: pixelated } |
| </style> |
| <canvas style="display: none" id="referenceCanvas"></canvas> |
| <canvas style="display: none" id="resultCanvas"></canvas> |
| <script> |
| // Tests that VideoFrame constructed from I420, BT709 data is has correct RGBA pixel values |
| // when drawn to 2D canvas. |
| // 1. Create sRGB RGBA test pattern. |
| // 2. Convert that to I420 BT709 data with a reference JS implementation. |
| // 3. Create VideoFrame of this I420 BT709 data and draw it to result canvas. |
| // Expect that the drawn image is correct. |
| // To verify that the image is correct: |
| // V1. Convert the I420 BT709 to sRGB RGBA data with a reference JS implementation. |
| // V2. Create VideoFrame out of that and draw it to reference canvas. |
| // V3. Expect that reference and result match. |
| let colors = [[255, 0, 0, 255], [0, 255, 0, 255], [0, 255, 255, 255], [30, 30, 230, 255], [3, 3, 77, 255]]; |
| let subtests = []; |
| for (let fullRange of [true, false]) { |
| for (let color of colors) |
| subtests.push({fullRange, color}); |
| } |
| |
| for (let subtest of subtests) { |
| test(() => { |
| runTest(subtest.color, subtest.fullRange); |
| }, `VideoFrame from I420, BT709 data has correct RGBA pixel values. fullRange: ${subtest.fullRange} color:${subtest.color}`); |
| } |
| |
| function runTest(color, fullRange) { |
| const pattern = createTestImageData(referenceCanvas.width, referenceCanvas.height, color); |
| const i420Data = sRGBImageDataToI420BT709(pattern, fullRange); |
| const videoFrame = new VideoFrame(i420Data.data, { |
| format: i420Data.format, |
| colorSpace: i420Data.colorSpace, |
| codedWidth: i420Data.width, |
| codedHeight: i420Data.height, |
| layout: i420Data.layout, |
| timestamp: 0 |
| }); |
| // This is being tested. |
| resultCanvas.getContext('2d').drawImage(videoFrame, 0, 0); |
| videoFrame.close(); |
| |
| // For clarity, convert the data also with JS-based reference implementation and |
| // compare that against the above native implementation. |
| const referenceSRGBData = I420BT709ToSRGB(i420Data, fullRange); |
| const referenceVideoFrame = new VideoFrame(referenceSRGBData.data, { |
| format: referenceSRGBData.format, |
| colorSpace: referenceSRGBData.colorSpace, |
| codedWidth: referenceSRGBData.width, |
| codedHeight: referenceSRGBData.height, |
| layout: referenceSRGBData.layout, |
| timestamp: 0 |
| }); |
| referenceCanvas.getContext("2d").drawImage(referenceVideoFrame, 0, 0); |
| referenceVideoFrame.close(); |
| |
| let referenceColor = referenceCanvas.getContext("2d").getImageData(0, 0, 1, 1).data; |
| let resultColor = resultCanvas.getContext("2d").getImageData(0, 0, 1, 1).data; |
| assert_array_approx_equals(resultColor, referenceColor, 20); |
| assert_array_approx_equals(resultColor, color, 20); |
| } |
| </script> |