Last active
October 27, 2022 14:57
-
-
Save Vanilagy/7fe8f98cf1563c73a070657d922266b2 to your computer and use it in GitHub Desktop.
Canvas RGBA image data to packed planar YUV 4:2:0 using the BT.709 color matrix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const RGBAToYUV420 = ({ width, height, data }: ImageData) => { | |
// Assume both width and height are even | |
let yuv = new Uint8Array(width * height * 1.5); | |
// Use loop tiling as a cache optimization | |
const tileSize = 64; | |
for (let y0 = 0; y0 < height; y0 += tileSize) { | |
for (let x0 = 0; x0 < width; x0 += tileSize) { | |
let limitX = Math.min(width, x0 + tileSize); | |
let limitY = Math.min(height, y0 + tileSize); | |
for (let y = y0; y < limitY; y++) { | |
for (let x = x0; x < limitX; x++) { | |
let R = data[4*(y*width + x) + 0]; | |
let G = data[4*(y*width + x) + 1]; | |
let B = data[4*(y*width + x) + 2]; | |
// Uses the matrix given in https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.709_conversion, then adds 128 to the chroma channels, then remaps full range to the condensed, broadcast range (also explained in that article). This entire transformation is condensed into a single matrix, used here: | |
let Y = 0.182586*R + 0.614231*G + 0.0620071*B + 16; | |
let U = -0.100668*R - 0.338547*G + 0.439216*B + 128.439; | |
let V = 0.439216*R - 0.398984*G - 0.0426039*B + 128.439; | |
yuv[y*width + x] = Y; | |
if (x % 2 === 0 && y % 2 === 0) { | |
yuv[1*width*height + (y*width/4 + x/2)] = U; | |
yuv[1.25*width*height + (y*width/4 + x/2)] = V; | |
} | |
} | |
} | |
} | |
} | |
return yuv; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment