NV12 2026-11-05
NV12 is an eight-bit YCbCr semiplanar pixel format with 4:2:0 chroma subsampling. A full-resolution plane holds luma samples. The following plane stores alternating Cb and Cr samples, with half as many sample positions in each spatial direction. Linux specifies ordinary untiled NV12 with adjacent planes; the separately allocated variant is NV12M.[ref]
Planar YUV formats in the Linux Kernel documentation. Semi-Planar overview table; NV12/NV21/NV12M/NV21M subsection
For even dimensions , active samples occupy luma bytes plus interleaved colour-difference bytes. This is bytes, or an average of 12 bits per original pixel. It does not give every pixel its own three-component triple: neighbouring pixels share the lower-resolution colour-difference samples.
For an original address calculation, choose width six, height four and an eight-byte framebuffer stride in both planes. Put the first luma row at address 1000. The luma allocation occupies bytes, so the colour-difference plane starts at 1032 and occupies another bytes. There are 36 active bytes in 48 allocated bytes, including row padding.
With zero-based indices, luma position is at . Its associated subsampled grid cell has indices in this declared layout. That cell's Cb and Cr bytes are at 1044 and 1045. Colour reconstruction additionally needs a sampling-location and filtering convention; these address calculations alone do not specify it.
NV12M 2026-11-05
NV12M is the non-contiguous-memory variant of NV12 in the Linux video API. It stores eight-bit luma separately from an interleaved Cb, Cr plane, using 4:2:0 chroma subsampling. Its two image memory planes can occupy independent allocations; the second plane's address is not inferred by adding the first plane's size.[ref]
Planar YUV formats in the Linux Kernel documentation. Semi-Planar table and NV12/NV21/NV12M/NV21M subsection
For an original address example, stipulate an accepted width-six, height-four layout. Let the luma base be 1000 with framebuffer stride eight bytes, and the colour-difference base be 8000 with stride 12 bytes. The allocations occupy and bytes, respectively. Their 56 allocated bytes contain 36 active samples, with padding accounting for the difference.
At zero-based luma position , the address is . In the declared subsampling grid, its associated colour-difference cell is . The Cb address is , and Cr is at 8017. Substituting 1032 for the second base would access an unrelated region under these stipulated allocations.
The V4L2 multi-planar API describes each memory plane explicitly. It also supports single-planar formats, so using that API does not itself prove that a buffer is NV12M. The negotiated pixel format, plane addresses, sizes and strides must agree.[ref]
Single- and multi-planar APIs in the Linux Kernel documentation. §1.26, especially Multi-planar formats
This separation changes buffer organization, not the YCbCr matrix, code ranges or chroma sample location. Those remain additional information needed for colour interpretation and chroma reconstruction.
NV21 2026-11-05
NV21 is an eight-bit YCbCr semiplanar pixel format using 4:2:0 chroma subsampling. It has a full-resolution luma plane followed by interleaved colour-difference samples in Cr, Cb order. NV12 uses the reverse pair order, Cb, Cr. The separately allocated Linux variant is NV21M.[ref]
Planar YUV formats in the Linux Kernel documentation. Semi-Planar overview table; NV12/NV21/NV12M/NV21M subsection
An original tightly stored image has eight luma bytes followed by four colour-difference bytes. Suppose the latter are
200 40 150 90. Under NV21, the two pairs are and . Reading the same bytes as NV12 instead assigns and . The buffer length remains correct while its colour-difference channels are exchanged.Converting this declared NV21 buffer to NV12 requires swapping adjacent bytes in the interleaved plane, giving
40 200 90 150, while retaining the luma data. This is a layout conversion, not a conversion to the RGB color model. The numerical colour interpretation still depends on the declared YCbCr encoding.The active footprint is bytes for even width and height under eight-bit 4:2:0 sampling. Framebuffer stride can add padding, so the next row need not start immediately after the last active sample. A converter must apply the actual row and plane boundaries: swapping pairs across padding or across the luma plane would corrupt the image rather than exchange the intended channels.
NV21M 2026-11-05
NV21M is a two-memory-plane semiplanar pixel format for eight-bit YCbCr with 4:2:0 chroma subsampling. Like NV21, its colour-difference plane stores Cr before Cb in each pair. Unlike ordinary contiguous NV21, the two image memory planes can have independent allocations.[ref]
Planar YUV formats in the Linux Kernel documentation. Semi-Planar table and NV12/NV21/NV12M/NV21M subsection
For an original example, stipulate an accepted width-four, height-four layout whose luma plane begins at 1000 with an eight-byte framebuffer stride, while its Cr/Cb plane begins at 5000 with a four-byte stride. Luma position is at . The corresponding subsampled cell has Cr at and Cb at 5007. This ordering is the reverse of NV12M.
The active sample count is bytes. The declared allocation sizes are bytes because luma rows have padding. Neither 40 nor 24 is an offset that can replace the explicitly supplied second-plane base.
A layout conversion to NV12M can exchange the two bytes in each active colour-difference pair while respecting each plane's stride. It does not require changing luma values or reducing the colour sample count. By contrast, choosing a different YCbCr matrix would be a colour conversion.
The distinction between a multi-planar format and the V4L2 multi-planar API matters here: the interface can carry formats with different memory organizations, while the format identifies which organization the supplied descriptors represent.[ref]
Single- and multi-planar APIs in the Linux Kernel documentation. §1.26.1, API versus format
Semiplanar pixel format 2026-11-05
A semiplanar pixel format combines a separate sample plane with another plane containing interleaved components. A common YCbCr arrangement stores luma 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.[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 and height , tightly stored active samples occupyThus a stipulated 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.[ref]Planar YUV formats in the Linux Kernel documentation. Semi-Planar overview table and NV12/NV21 layout subsection
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 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.