Loading...
Searching...
No Matches
VideoPixelFormat.hpp
Go to the documentation of this file.
1#pragma once
2
38#include <score_plugin_gfx_export.h>
39
40#include <cstddef>
41#include <cstdint>
42
43namespace score::gfx::interop
44{
45
48enum class ColorModel : uint8_t
49{
50 Unknown = 0,
51 RGB,
52 YUV,
53 Grey,
54 Bayer,
55};
56
60enum class ByteOrder : uint8_t
61{
62 NA = 0,
63 Little,
64 Big,
65};
66
67// ---------------------------------------------------------------------------
68// The single declarative table. One row per format; nothing else in this
69// vocabulary is maintained by hand.
70//
71// X(Name, Value, Model, Planes, Hsub, Vsub, BlockPixels, BlockBytes,
72// Alpha, Order, Align)
73//
74// `Value` is the serialized wire value and is FROZEN: rows may be reordered
75// freely, but a value must never change without a serialization migration.
76//
77// BlockPixels/BlockBytes describe the PRIMARY plane: a horizontal run of
78// BlockPixels pixels occupies exactly BlockBytes bytes. Packed formats put a
79// whole pixel group there (BGRA8 = 1px/4B, UYVY = 2px/4B, v210 = 48px/128B per
80// SMPTE ST 2110-20); planar formats put one luma sample there (NV12 = 1px/1B,
81// P010 = 1px/2B). An averaged bits-per-pixel cannot express v210 at all
82// (128 bytes / 48 pixels = 21.33 bits) and over-computes planar strides, so a
83// new packed layout needs a table row rather than another branch.
84//
85// `Align` is a PREFERRED stride alignment, used only by callers that have no
86// constraint of their own. It is not a property of the pixel format: a device or
87// allocator with a real requirement -- D3D12's 256-byte row pitch, a DeckLink
88// rowBytes, a V4L2 bytesperline -- must pass its own to alignedRowBytes.
89// ---------------------------------------------------------------------------
90#define SCORE_VIDEO_PIXEL_FORMATS(X) \
91 /* -- Packed 8-bit RGB -------------------------------------------------- */ \
92 /* BGRA8 matches QRhi BGRA8 + DeckLink bmdFormat8BitBGRA. The X-variants */ \
93 /* are the same bytes with the 4th/1st channel undefined: forced opaque. */ \
94 X(BGRA8, 1, RGB, 1, 1, 1, 1, 4, true, NA, 256) \
95 X(RGBA8, 2, RGB, 1, 1, 1, 1, 4, true, NA, 256) \
96 X(ARGB8, 3, RGB, 1, 1, 1, 1, 4, true, NA, 256) \
97 X(ABGR8, 4, RGB, 1, 1, 1, 1, 4, true, NA, 256) \
98 X(RGB24, 5, RGB, 1, 1, 1, 1, 3, false, NA, 64) \
99 X(BGR24, 6, RGB, 1, 1, 1, 1, 3, false, NA, 64) \
100 X(BGRX8, 7, RGB, 1, 1, 1, 1, 4, false, NA, 256) \
101 X(RGBX8, 8, RGB, 1, 1, 1, 1, 4, false, NA, 256) \
102 X(XRGB8, 9, RGB, 1, 1, 1, 1, 4, false, NA, 256) \
103 X(XBGR8, 19, RGB, 1, 1, 1, 1, 4, false, NA, 256) \
104 /* -- Packed 10/12-bit RGB ----------------------------------------------- */ \
105 /* R210 is DeckLink r210 / AV_CODEC_ID_R210: (R<<20)|(G<<10)|B, big-endian. */ \
106 /* Its 64-pixel/256-byte row is mandatory, not padding, so it belongs in the */ \
107 /* block like v210 s: a tight row would not be a legal r210 frame. */ \
108 /* RGB10 is AJA NTV2_FBF_10BIT_RGB: (B<<20)|(G<<10)|R, little-endian. */ \
109 /* R12B/R12L/RGB12P all carry 36 bits per pixel, which is exactly 2 pixels */ \
110 /* per 9 bytes; they differ only in component and byte order. */ \
111 X(R210, 10, RGB, 1, 1, 1, 64, 256, false, Big, 256) \
112 X(R12B, 11, RGB, 1, 1, 1, 2, 9, false, Big, 256) \
113 X(R12L, 12, RGB, 1, 1, 1, 2, 9, false, Little, 256) \
114 X(ARGB10, 13, RGB, 1, 1, 1, 1, 5, true, Little, 256) \
115 X(DPX10, 14, RGB, 1, 1, 1, 1, 4, false, Big, 256) \
116 X(DPX10LE, 15, RGB, 1, 1, 1, 1, 4, false, Little, 256) \
117 X(RGB12P, 16, RGB, 1, 1, 1, 2, 9, false, Little, 256) \
118 X(RGB48, 17, RGB, 1, 1, 1, 1, 6, false, Little, 256) \
119 X(RGB10, 18, RGB, 1, 1, 1, 1, 4, false, Little, 256) \
120 /* X2RGB10/X2BGR10 hold two padding bits plus three 10-bit components in a */ \
121 /* 32-bit little-endian word; the pad is not alpha. These are the DRM */ \
122 /* ARGB2101010/ABGR2101010 layouts. */ \
123 X(X2RGB10, 120, RGB, 1, 1, 1, 1, 4, false, Little, 256) \
124 X(X2BGR10, 121, RGB, 1, 1, 1, 1, 4, false, Little, 256) \
125 /* -- Packed sub-byte RGB / YUV (legacy, embedded, V4L2 cameras) --------- */ \
126 X(RGB332, 90, RGB, 1, 1, 1, 1, 1, false, NA, 64) \
127 X(RGB565, 91, RGB, 1, 1, 1, 1, 2, false, Little, 64) \
128 X(RGB565BE, 92, RGB, 1, 1, 1, 1, 2, false, Big, 64) \
129 X(RGB555, 93, RGB, 1, 1, 1, 1, 2, false, Little, 64) \
130 X(RGB555BE, 94, RGB, 1, 1, 1, 1, 2, false, Big, 64) \
131 X(ARGB1555, 95, RGB, 1, 1, 1, 1, 2, true, Little, 64) \
132 X(RGB444, 96, RGB, 1, 1, 1, 1, 2, false, Little, 64) \
133 X(ARGB4444, 97, RGB, 1, 1, 1, 1, 2, true, Little, 64) \
134 X(AYUV4444, 98, YUV, 1, 1, 1, 1, 2, true, Little, 64) \
135 X(AYUV1555, 99, YUV, 1, 1, 1, 1, 2, true, Little, 64) \
136 X(YUV565, 100, YUV, 1, 1, 1, 1, 2, false, Little, 64) \
137 /* -- Packed 8-bit YUV 4:2:2 (two pixels share one chroma pair) ---------- */ \
138 X(UYVY422, 20, YUV, 1, 2, 1, 2, 4, false, NA, 256) \
139 X(YUYV422, 21, YUV, 1, 2, 1, 2, 4, false, NA, 256) \
140 X(YVYU422, 22, YUV, 1, 2, 1, 2, 4, false, NA, 256) \
141 X(VYUY422, 23, YUV, 1, 2, 1, 2, 4, false, NA, 256) \
142 /* -- Packed 10/16-bit YUV 4:2:2 ----------------------------------------- */ \
143 /* v210 packs 48 pixels into 128 bytes; that block IS the SMPTE stride */ \
144 /* rule, so it needs no special case here. */ \
145 X(V210, 30, YUV, 1, 2, 1, 48, 128, false, Little, 128) \
146 X(V216, 31, YUV, 1, 2, 1, 2, 8, false, Little, 256) \
147 /* Y210/Y216 carry YUYV component order in 16-bit lanes (Y210 uses the high */ \
148 /* 10 bits); V216 differs from Y216 only in that order. */ \
149 X(Y210, 106, YUV, 1, 2, 1, 2, 8, false, Little, 256) \
150 X(Y216, 107, YUV, 1, 2, 1, 2, 8, false, Little, 256) \
151 /* -- Planar / semi-planar 4:2:0 ----------------------------------------- */ \
152 X(NV12, 40, YUV, 2, 2, 2, 1, 1, false, NA, 256) \
153 X(P010, 41, YUV, 2, 2, 2, 1, 2, false, Little, 256) \
154 X(YUV420P, 42, YUV, 3, 2, 2, 1, 1, false, NA, 256) \
155 X(YUV420P10, 43, YUV, 3, 2, 2, 1, 2, false, Little, 256) \
156 X(NV21, 44, YUV, 2, 2, 2, 1, 1, false, NA, 256) \
157 X(YVU420P, 45, YUV, 3, 2, 2, 1, 1, false, NA, 256) \
158 /* -- Planar / semi-planar 4:2:2 ----------------------------------------- */ \
159 X(P210, 50, YUV, 2, 2, 1, 1, 2, false, Little, 256) \
160 X(YUV422P, 51, YUV, 3, 2, 1, 1, 1, false, NA, 256) \
161 X(YUV422P10, 52, YUV, 3, 2, 1, 1, 2, false, Little, 256) \
162 X(NV16, 53, YUV, 2, 2, 1, 1, 1, false, NA, 256) \
163 X(NV61, 54, YUV, 2, 2, 1, 1, 1, false, NA, 256) \
164 X(YUV422P12, 55, YUV, 3, 2, 1, 1, 2, false, Little, 256) \
165 X(YUV422P16, 110, YUV, 3, 2, 1, 1, 2, false, Little, 256) \
166 X(YVU422P, 104, YUV, 3, 2, 1, 1, 1, false, NA, 256) \
167 X(P216, 108, YUV, 2, 2, 1, 1, 2, false, Little, 256) \
168 /* -- Planar 4:1:1 and 4:1:0 (webcams, legacy capture) ------------------- */ \
169 X(YUV411P, 101, YUV, 3, 4, 1, 1, 1, false, NA, 256) \
170 X(YUV410P, 102, YUV, 3, 4, 4, 1, 1, false, NA, 256) \
171 X(YVU410P, 103, YUV, 3, 4, 4, 1, 1, false, NA, 256) \
172 X(UYYVYY411, 105, YUV, 1, 4, 1, 4, 6, false, NA, 256) \
173 /* -- Planar / semi-planar / packed 4:4:4 -------------------------------- */ \
174 X(YUV444P, 60, YUV, 3, 1, 1, 1, 1, false, NA, 256) \
175 X(YUV444P10, 61, YUV, 3, 1, 1, 1, 2, false, Little, 256) \
176 X(YUV444P12, 62, YUV, 3, 1, 1, 1, 2, false, Little, 256) \
177 X(NV24, 63, YUV, 2, 1, 1, 1, 1, false, NA, 256) \
178 X(NV42, 64, YUV, 2, 1, 1, 1, 1, false, NA, 256) \
179 X(VUYA, 65, YUV, 1, 1, 1, 1, 4, true, NA, 256) \
180 X(VUYX, 66, YUV, 1, 1, 1, 1, 4, false, NA, 256) \
181 X(AYUV, 67, YUV, 1, 1, 1, 1, 4, true, NA, 256) \
182 X(XYUV, 68, YUV, 1, 1, 1, 1, 4, false, NA, 256) \
183 X(YUVA, 69, YUV, 1, 1, 1, 1, 4, true, NA, 256) \
184 X(YUVX, 73, YUV, 1, 1, 1, 1, 4, false, NA, 256) \
185 X(YUVA444P, 111, YUV, 4, 1, 1, 1, 1, true, NA, 256) \
186 X(P416, 109, YUV, 2, 1, 1, 1, 2, false, Little, 256) \
187 /* XV30 packs 2 padding bits + three 10-bit components into 32 bits; the pad */ \
188 /* is not alpha. AYUV64 is the same geometry at 16 bits with real alpha. */ \
189 X(XV30, 112, YUV, 1, 1, 1, 1, 4, false, Little, 256) \
190 X(AYUV64, 113, YUV, 1, 1, 1, 1, 8, true, Little, 256) \
191 /* -- High-precision RGB ------------------------------------------------- */ \
192 X(RGBA16, 70, RGB, 1, 1, 1, 1, 8, true, Little, 256) \
193 X(RGBA16F, 71, RGB, 1, 1, 1, 1, 8, true, Little, 256) \
194 X(RGBA32F, 72, RGB, 1, 1, 1, 1, 16, true, Little, 256) \
195 /* -- Greyscale / Bayer (industrial cameras) ----------------------------- */ \
196 X(Mono8, 80, Grey, 1, 1, 1, 1, 1, false, NA, 64) \
197 X(Mono10, 81, Grey, 1, 1, 1, 1, 2, false, Little, 64) \
198 X(Mono12, 82, Grey, 1, 1, 1, 1, 2, false, Little, 64) \
199 X(Mono16, 83, Grey, 1, 1, 1, 1, 2, false, Little, 64) \
200 /* BayerRG8/BayerRG12 are the GenICam PFNC spellings of the RGGB order, so */ \
201 /* they name the same bytes as BayerRGGB8/BayerRGGB16. They are kept because */ \
202 /* their values are serialized, and deliberately left unbridged: mapping two */ \
203 /* enumerators onto one AVPixelFormat would make the round-trip ambiguous. */ \
204 /* Prefer the explicit orders. */ \
205 X(BayerRG8, 84, Bayer, 1, 1, 1, 1, 1, false, NA, 64) \
206 X(BayerRG12, 85, Bayer, 1, 1, 1, 1, 2, false, Little, 64) \
207 /* The CFA order decides how a demosaic reads the mosaic, so the four 8-bit */ \
208 /* orders are distinct formats rather than one generic Bayer. */ \
209 X(BayerBGGR8, 114, Bayer, 1, 1, 1, 1, 1, false, NA, 64) \
210 X(BayerGBRG8, 115, Bayer, 1, 1, 1, 1, 1, false, NA, 64) \
211 X(BayerGRBG8, 116, Bayer, 1, 1, 1, 1, 1, false, NA, 64) \
212 X(BayerRGGB8, 117, Bayer, 1, 1, 1, 1, 1, false, NA, 64) \
213 X(BayerBGGR16, 118, Bayer, 1, 1, 1, 1, 2, false, Little, 64) \
214 X(BayerRGGB16, 119, Bayer, 1, 1, 1, 1, 2, false, Little, 64) \
215 /* The 10-bit CFA orders occupy a 16-bit little-endian container, so they are */ \
216 /* two bytes per sample like the 16-bit orders. V4L2 defines the ten */ \
217 /* significant bits as right-aligned; a producer that left-aligns them */ \
218 /* (the Tegra VI does) is a sixty-fourfold scale a demosaic must be told */ \
219 /* about, not a distinct layout. */ \
220 X(BayerBGGR10, 123, Bayer, 1, 1, 1, 1, 2, false, Little, 64) \
221 X(BayerGBRG10, 124, Bayer, 1, 1, 1, 1, 2, false, Little, 64) \
222 X(BayerGRBG10, 125, Bayer, 1, 1, 1, 1, 2, false, Little, 64) \
223 X(BayerRGGB10, 126, Bayer, 1, 1, 1, 1, 2, false, Little, 64) \
224 X(Mono16BE, 86, Grey, 1, 1, 1, 1, 2, false, Big, 64)
225
228enum class VideoPixelFormat : uint16_t
229{
230 Unknown = 0,
231#define SCORE_VPF_ENUM_ROW(Name, Value, ...) Name = Value,
232 SCORE_VIDEO_PIXEL_FORMATS(SCORE_VPF_ENUM_ROW)
233#undef SCORE_VPF_ENUM_ROW
234};
235
237constexpr std::size_t formatCount() noexcept
238{
239#define SCORE_VPF_COUNT_ROW(...) +1
240 return std::size_t(0 SCORE_VIDEO_PIXEL_FORMATS(SCORE_VPF_COUNT_ROW));
241#undef SCORE_VPF_COUNT_ROW
242}
243
253{
254 const char* name{"unknown"};
255 VideoPixelFormat format{VideoPixelFormat::Unknown};
256 ColorModel colorModel{ColorModel::Unknown};
257 uint8_t planeCount{1};
262 uint16_t blockPixels{1};
263 uint16_t blockBytes{};
264 bool hasAlpha{};
265 ByteOrder byteOrder{ByteOrder::NA};
269
272 constexpr bool isPlanar() const noexcept { return planeCount > 1; }
273 constexpr bool isYuv() const noexcept { return colorModel == ColorModel::YUV; }
274 constexpr bool isRgb() const noexcept { return colorModel == ColorModel::RGB; }
276 constexpr bool isAchromatic() const noexcept
277 {
278 return colorModel == ColorModel::Grey || colorModel == ColorModel::Bayer;
279 }
281 constexpr bool valid() const noexcept { return blockBytes != 0; }
282};
283
286constexpr std::size_t alignUp(std::size_t v, std::size_t a) noexcept
287{
288 return a <= 1 ? v : ((v + a - 1) / a) * a;
289}
290
293SCORE_PLUGIN_GFX_EXPORT
294const VideoPixelFormatInfo& formatInfo(VideoPixelFormat f) noexcept;
295
297SCORE_PLUGIN_GFX_EXPORT
298const char* formatName(VideoPixelFormat f) noexcept;
299
308SCORE_PLUGIN_GFX_EXPORT
309VideoPixelFormat chromaSwappedTwin(VideoPixelFormat f) noexcept;
310
313SCORE_PLUGIN_GFX_EXPORT
314const VideoPixelFormatInfo* allFormats(std::size_t& count) noexcept;
315
317SCORE_PLUGIN_GFX_EXPORT
318std::size_t rowBytes(VideoPixelFormat f, uint32_t width) noexcept;
319
322SCORE_PLUGIN_GFX_EXPORT
323std::size_t
324alignedRowBytes(VideoPixelFormat f, uint32_t width, std::size_t alignment) noexcept;
325
328SCORE_PLUGIN_GFX_EXPORT
329std::size_t defaultStride(VideoPixelFormat f, uint32_t width) noexcept;
330
333SCORE_PLUGIN_GFX_EXPORT
334std::size_t
335bytesPerFrame(VideoPixelFormat f, uint32_t width, uint32_t height) noexcept;
336
337} // namespace score::gfx::interop
ColorModel
Definition VideoPixelFormat.hpp:49
VideoPixelFormat
Definition VideoPixelFormat.hpp:229
constexpr std::size_t formatCount() noexcept
Definition VideoPixelFormat.hpp:237
ByteOrder
Definition VideoPixelFormat.hpp:61
constexpr std::size_t alignUp(std::size_t v, std::size_t a) noexcept
Definition VideoPixelFormat.hpp:286
Definition VideoPixelFormat.hpp:253
uint16_t preferredStrideAlignment
Definition VideoPixelFormat.hpp:268
constexpr bool isAchromatic() const noexcept
Definition VideoPixelFormat.hpp:276
constexpr bool isPlanar() const noexcept
Definition VideoPixelFormat.hpp:272
uint8_t verticalSubsampling
Definition VideoPixelFormat.hpp:259
uint8_t horizontalSubsampling
Definition VideoPixelFormat.hpp:258
uint16_t blockPixels
Definition VideoPixelFormat.hpp:262
constexpr bool valid() const noexcept
Definition VideoPixelFormat.hpp:281