Semiplanar pixel format (source code)

= Semiplanar pixel format

A \b[semiplanar pixel format] combines a separate sample plane with another plane containing interleaved components. A common <YCbCr> arrangement stores <luma (video)> samples in one plane and pairs of colour-difference samples in another. It therefore has two planes while representing three components. Linux's video API distinguishes this from the three separate planes of a fully <planar pixel format>.<Planar YUV formats in the Linux Kernel documentation>[§2.7.1.2, planar and semiplanar definitions]{ref}

In <NV12>, one <byte> represents each sample. <Chroma subsampling> halves the colour-difference sampling count in both directions, and the second plane stores Cb followed by Cr in each pair. <NV21> reverses that pair order. For even width $W$ and height $H$, tightly stored active samples occupy
$$
WH+2\left(\frac W2\frac H2\right)=\frac32WH\ \mathrm{bytes}.
$$
Thus a stipulated $4\times2$ image contains eight Y samples and two Cb/Cr pairs: 12 active <bytes>. The eight Y bytes can be followed by `Cb00 Cr00 Cb01 Cr01`. The component names identify stored codes; their colour interpretation also requires the declared <YCbCr> conventions.<Planar YUV formats in the Linux Kernel documentation>[Semi-Planar overview table and NV12/NV21 layout subsection]{ref}

Active sample count differs from allocated storage. With an eight-byte <framebuffer stride> for both planes in this example, two Y rows and one interleaved row occupy $2(8)+1(8)=24$ bytes including padding. A consumer needs dimensions, strides, component order and whether planes are adjacent or separately allocated. Reinterpreting <NV21> as <NV12> swaps the two colour-difference components; it does not recover the intended colours merely because the buffer size matches.