libpromeki 1.0.0-alpha
PROfessional MEdia toolKIt
 
Loading...
Searching...
No Matches
pixelformat.h
Go to the documentation of this file.
1
8#pragma once
9
10
11#include <promeki/config.h>
12#if PROMEKI_ENABLE_PROAV
13#include <promeki/namespace.h>
14#include <promeki/string.h>
15#include <promeki/list.h>
16#include <promeki/error.h>
17#include <promeki/result.h>
18#include <promeki/fourcc.h>
19#include <promeki/colormodel.h>
21#include <promeki/videocodec.h>
22#include <promeki/enums.h>
23#include <promeki/datatype.h>
24
25PROMEKI_NAMESPACE_BEGIN
26
27class DataStream;
28
29class Image;
30class ImageDesc;
31class UncompressedVideoPayload;
32class PaintEngine;
33
137class PixelFormat {
138 public:
139 PROMEKI_DATATYPE(PixelFormat, DataTypePixelFormat, 1)
140
141
142 Error writeToStream(DataStream &s) const;
144 template <uint32_t V> static Result<PixelFormat> readFromStream(DataStream &s);
145
146 static constexpr size_t MaxComps = PixelMemLayout::MaxComps;
147
154 enum ID {
155 Invalid = 0,
156
157 // -- RGB/RGBA uncompressed (8-bit, byte-aligned) --
158 RGBA8_sRGB = 1,
159 RGB8_sRGB = 2,
160
161 // -- RGB DPX packed --
162 RGB10_DPX_sRGB = 3,
163
164 // -- YCbCr 4:2:2 interleaved YUYV --
165 YUV8_422_Rec709 = 4,
166 YUV10_422_Rec709 = 5,
167
168 // -- JPEG compressed --
169 JPEG_RGBA8_sRGB = 6,
170 JPEG_RGB8_sRGB = 7,
171 JPEG_YUV8_422_Rec709 =
172 8,
173 JPEG_YUV8_420_Rec709 =
174 9,
175
176 // -- YCbCr 4:2:2 UYVY --
177 YUV8_422_UYVY_Rec709 = 10,
178 YUV10_422_UYVY_LE_Rec709 = 11,
179 YUV10_422_UYVY_BE_Rec709 = 12,
180 YUV12_422_UYVY_LE_Rec709 = 13,
181 YUV12_422_UYVY_BE_Rec709 = 14,
182
183 // -- YCbCr 4:2:2 v210 --
184 YUV10_422_v210_Rec709 = 15,
185
186 // -- YCbCr 4:2:2 planar --
187 YUV8_422_Planar_Rec709 = 16,
188 YUV10_422_Planar_LE_Rec709 = 17,
189 YUV10_422_Planar_BE_Rec709 = 18,
190 YUV12_422_Planar_LE_Rec709 = 19,
191 YUV12_422_Planar_BE_Rec709 = 20,
192
193 // -- YCbCr 4:2:0 planar --
194 YUV8_420_Planar_Rec709 = 21,
195 YUV10_420_Planar_LE_Rec709 = 22,
196 YUV10_420_Planar_BE_Rec709 = 23,
197 YUV12_420_Planar_LE_Rec709 = 24,
198 YUV12_420_Planar_BE_Rec709 = 25,
199
200 // -- YCbCr 4:2:0 semi-planar (NV12) --
201 YUV8_420_SemiPlanar_Rec709 = 26,
202 YUV10_420_SemiPlanar_LE_Rec709 = 27,
203 YUV10_420_SemiPlanar_BE_Rec709 = 28,
204 YUV12_420_SemiPlanar_LE_Rec709 = 29,
205 YUV12_420_SemiPlanar_BE_Rec709 = 30,
206
207 // -- RGB/RGBA 10/12/16-bit in 16-bit words --
208 RGBA10_LE_sRGB = 31,
209 RGBA10_BE_sRGB = 32,
210 RGB10_LE_sRGB = 33,
211 RGB10_BE_sRGB = 34,
212 RGBA12_LE_sRGB = 35,
213 RGBA12_BE_sRGB = 36,
214 RGB12_LE_sRGB = 37,
215 RGB12_BE_sRGB = 38,
216 RGBA16_LE_sRGB = 39,
217 RGBA16_BE_sRGB = 40,
218 RGB16_LE_sRGB = 41,
219 RGB16_BE_sRGB = 42,
220
221 // -- YCbCr 4:4:4 DPX packed --
222 YUV10_DPX_Rec709 = 43,
223
224 // -- BGRA/BGR (reversed component order) --
225 BGRA8_sRGB = 44,
226 BGR8_sRGB = 45,
227 BGRA10_LE_sRGB = 46,
228 BGRA10_BE_sRGB = 47,
229 BGR10_LE_sRGB = 48,
230 BGR10_BE_sRGB = 49,
231 BGRA12_LE_sRGB = 50,
232 BGRA12_BE_sRGB = 51,
233 BGR12_LE_sRGB = 52,
234 BGR12_BE_sRGB = 53,
235 BGRA16_LE_sRGB = 54,
236 BGRA16_BE_sRGB = 55,
237 BGR16_LE_sRGB = 56,
238 BGR16_BE_sRGB = 57,
239
240 // -- ARGB (alpha-first) --
241 ARGB8_sRGB = 58,
242 ARGB10_LE_sRGB = 59,
243 ARGB10_BE_sRGB = 60,
244 ARGB12_LE_sRGB = 61,
245 ARGB12_BE_sRGB = 62,
246 ARGB16_LE_sRGB = 63,
247 ARGB16_BE_sRGB = 64,
248
249 // -- ABGR (alpha-first, blue-first) --
250 ABGR8_sRGB = 65,
251 ABGR10_LE_sRGB = 66,
252 ABGR10_BE_sRGB = 67,
253 ABGR12_LE_sRGB = 68,
254 ABGR12_BE_sRGB = 69,
255 ABGR16_LE_sRGB = 70,
256 ABGR16_BE_sRGB = 71,
257
258 // -- Monochrome (sRGB luminance) --
259 Mono8_sRGB = 72,
260 Mono10_LE_sRGB = 73,
261 Mono10_BE_sRGB = 74,
262 Mono12_LE_sRGB = 75,
263 Mono12_BE_sRGB = 76,
264 Mono16_LE_sRGB = 77,
265 Mono16_BE_sRGB = 78,
266
267 // -- Float RGBA/RGB/Mono (linear Rec.709 primaries) --
268 RGBAF16_LE_LinearRec709 = 79,
269 RGBAF16_BE_LinearRec709 = 80,
270 RGBF16_LE_LinearRec709 = 81,
271 RGBF16_BE_LinearRec709 = 82,
272 MonoF16_LE_LinearRec709 = 83,
273 MonoF16_BE_LinearRec709 = 84,
274 RGBAF32_LE_LinearRec709 = 85,
275 RGBAF32_BE_LinearRec709 = 86,
276 RGBF32_LE_LinearRec709 = 87,
277 RGBF32_BE_LinearRec709 = 88,
278 MonoF32_LE_LinearRec709 = 89,
279 MonoF32_BE_LinearRec709 = 90,
280
281 // -- 10:10:10:2 packed (3x10 + 1x2 in 32 bits) --
282 RGB10A2_LE_sRGB = 91,
283 RGB10A2_BE_sRGB = 92,
284 BGR10A2_LE_sRGB = 93,
285 BGR10A2_BE_sRGB = 94,
286
287 // -- YCbCr 4:4:4 (non-DPX, Rec.709) --
288 YUV8_Rec709 = 95,
289 YUV10_LE_Rec709 = 96,
290 YUV10_BE_Rec709 = 97,
291 YUV12_LE_Rec709 = 98,
292 YUV12_BE_Rec709 = 99,
293 YUV16_LE_Rec709 = 100,
294 YUV16_BE_Rec709 = 101,
295
296 // -- Rec.2020 YCbCr --
297 YUV10_422_UYVY_LE_Rec2020 = 102,
298 YUV10_422_UYVY_BE_Rec2020 = 103,
299 YUV12_422_UYVY_LE_Rec2020 = 104,
300 YUV12_422_UYVY_BE_Rec2020 = 105,
301 YUV10_420_Planar_LE_Rec2020 = 106,
302 YUV10_420_Planar_BE_Rec2020 = 107,
303 YUV12_420_Planar_LE_Rec2020 = 108,
304 YUV12_420_Planar_BE_Rec2020 = 109,
305
306 // -- BT.2100 PQ / HLG HDR --
307 // Memory layout identical to the SDR
308 // BT.2020 entries above; the distinction is
309 // entirely the EOTF / transfer claim, so
310 // these IDs anchor a different ColorModel
311 // (Rec2020_PQ / Rec2020_HLG /
312 // YCbCr_Rec2020_PQ / YCbCr_Rec2020_HLG)
313 // whose @ref ColorModel::toH273 reports the
314 // matching H.273 transfer codepoint
315 // (16 = PQ, 18 = HLG). Includes only the
316 // memory layouts that practically carry HDR
317 // (V210, P010, P216, 10-bit RGB packed, 16-
318 // bit RGB) — the combinatorial sweep across
319 // every layout × {PQ, HLG} would inflate
320 // the catalog without practical benefit.
321 // SDI / NDI HDR (PQ + HLG):
322 YUV10_422_UYVY_LE_Rec2020_PQ = 200,
323 YUV10_422_UYVY_LE_Rec2020_HLG = 201,
324 YUV12_422_UYVY_LE_Rec2020_PQ = 202,
325 YUV12_422_UYVY_LE_Rec2020_HLG = 203,
326 // Codec / NVDEC HDR output (4:2:0 PQ / HLG):
327 YUV10_420_Planar_LE_Rec2020_PQ = 204,
328 YUV10_420_Planar_LE_Rec2020_HLG = 205,
329 YUV12_420_Planar_LE_Rec2020_PQ = 206,
330 YUV12_420_Planar_LE_Rec2020_HLG = 207,
331 // NV12 / P010 semi-planar HDR (NVDEC, Intel QSV, AMD UVD):
332 YUV10_420_SemiPlanar_LE_Rec2020_PQ = 208,
333 YUV10_420_SemiPlanar_LE_Rec2020_HLG = 209,
334 // P216 (NDI 16-bit HDR):
335 YUV16_422_SemiPlanar_LE_Rec2020_PQ = 210,
336 YUV16_422_SemiPlanar_LE_Rec2020_HLG = 211,
337 // 10-bit RGB packed (RGB10A2):
338 RGB10A2_LE_Rec2020_PQ = 212,
339 RGB10A2_LE_Rec2020_HLG = 213,
340 // 16-bit RGB (host order):
341 RGB16_LE_Rec2020_PQ = 214,
342 RGB16_LE_Rec2020_HLG = 215,
343 // Half-float scene-referred linear (cinema HDR working space):
344 RGBAF16_LE_LinearRec2020 = 216,
345 RGBF16_LE_LinearRec2020 = 217,
346 // DCI-P3 PQ (cinema):
347 RGB16_LE_DCI_P3_PQ = 218,
348
349 // -- Rec.601 YCbCr --
350 YUV8_422_Rec601 = 110,
351 YUV8_422_UYVY_Rec601 = 111,
352 YUV8_420_Planar_Rec601 = 112,
353 YUV8_420_SemiPlanar_Rec601 = 113,
354
355 // -- NV21 (semi-planar 4:2:0, CrCb order, Rec.709) --
356 YUV8_420_NV21_Rec709 = 114,
357 YUV10_420_NV21_LE_Rec709 = 115,
358 YUV10_420_NV21_BE_Rec709 = 116,
359 YUV12_420_NV21_LE_Rec709 = 117,
360 YUV12_420_NV21_BE_Rec709 = 118,
361
362 // -- Semi-planar 4:2:2 (NV16, Rec.709) --
363 YUV8_422_SemiPlanar_Rec709 = 119,
364 YUV10_422_SemiPlanar_LE_Rec709 = 120,
365 YUV10_422_SemiPlanar_BE_Rec709 = 121,
366 YUV12_422_SemiPlanar_LE_Rec709 = 122,
367 YUV12_422_SemiPlanar_BE_Rec709 = 123,
368
369 // -- Planar 4:1:1 (Rec.709) --
370 YUV8_411_Planar_Rec709 = 124,
371
372 // -- 16-bit YCbCr (Rec.709) --
373 YUV16_422_UYVY_LE_Rec709 = 125,
374 YUV16_422_UYVY_BE_Rec709 = 126,
375 YUV16_422_Planar_LE_Rec709 = 127,
376 YUV16_422_Planar_BE_Rec709 = 128,
377 YUV16_420_Planar_LE_Rec709 = 129,
378 YUV16_420_Planar_BE_Rec709 = 130,
379 YUV16_420_SemiPlanar_LE_Rec709 = 131,
380 YUV16_420_SemiPlanar_BE_Rec709 = 132,
381 YUV16_422_SemiPlanar_LE_Rec709 = 164,
382 YUV16_422_SemiPlanar_BE_Rec709 = 165,
383
384 // -- DPX additional packed formats --
385 RGB10_DPX_LE_sRGB = 133,
386 YUV10_DPX_B_Rec709 = 134,
387
388 // ----- Video codec compressed formats (QuickTime/MP4 family) ------------
389 H264 = 135,
390 HEVC = 136,
391 AV1 = 161,
392 ProRes_422_Proxy = 137,
393 ProRes_422_LT = 138,
394 ProRes_422 = 139,
395 ProRes_422_HQ = 140,
396 ProRes_4444 = 141,
397 ProRes_4444_XQ = 142,
398
399 // -- Full-range uncompressed YCbCr --
400 //
401 // The library-wide YCbCr naming convention is that
402 // the unsuffixed form (e.g. YUV8_422_Rec709) is
403 // limited-range (16..235 Y, 16..240 Cb/Cr) to match
404 // broadcast / SDI / ST 2110 defaults. The explicit
405 // "_Full" suffix opts in to full-range 0..255 Y and
406 // 0..255 Cb/Cr, which is what JPEG / JFIF uses and
407 // what most consumer video decoders (ffplay,
408 // browsers, libjpeg-turbo) expect. These
409 // PixelFormats exist both as general-purpose
410 // full-range YCbCr storage and as encode-source
411 // intermediates for the full-range JPEG variants
412 // below.
413 YUV8_422_Rec709_Full = 143,
414 YUV8_422_Rec601_Full = 144,
415 YUV8_420_Planar_Rec709_Full = 145,
416 YUV8_420_Planar_Rec601_Full = 146,
417
418 // -- Full complement of JPEG YCbCr variants (matrix × range) --
419 //
420 // Following the library-wide YCbCr convention: the
421 // unsuffixed JPEG names (existing
422 // JPEG_YUV8_422_Rec709 / JPEG_YUV8_420_Rec709) are
423 // limited-range to stay consistent with the
424 // uncompressed YCbCr defaults. Full-range variants
425 // take the explicit "_Full" suffix. All eight
426 // combinations (matrix × range × subsampling) are
427 // provided; pick the one that matches what the
428 // downstream decoder expects to interpret:
429 //
430 // - Rec.601 + full range (strict JFIF) → ffplay,
431 // browsers, libjpeg-turbo, most consumer apps
432 // - Rec.709 + full range → modern cameras with
433 // an ICC profile; good for high-quality still
434 // storage that a colour-managed viewer honours
435 // - Rec.709 + limited range (existing default) →
436 // broadcast / SDI JPEG pipelines (ST 2110 JPEG XS
437 // style)
438 // - Rec.601 + limited range → legacy broadcast
439 JPEG_YUV8_422_Rec601 =
440 147,
441 JPEG_YUV8_420_Rec601 =
442 148,
443 JPEG_YUV8_422_Rec709_Full =
444 149,
445 JPEG_YUV8_420_Rec709_Full =
446 150,
447 JPEG_YUV8_422_Rec601_Full =
448 151,
449 JPEG_YUV8_420_Rec601_Full =
450 152,
451
452 // -- JPEG XS (ISO/IEC 21122) compressed variants --
453 //
454 // Modern low-complexity intra-only codec. JPEG XS
455 // carries matrix / range out-of-band (in the MP4 sample
456 // entry or RTP SDP — see RFC 9134) rather than inside
457 // the bitstream, so the compressed PixelFormats only
458 // distinguish bit depth and subsampling; Rec.709 is the
459 // canonical broadcast default and the one wired up
460 // here. 10- and 12-bit variants are first-class
461 // citizens since JPEG XS targets high-bit-depth
462 // contribution workflows.
463 JPEG_XS_YUV8_422_Rec709 =
464 153,
465 JPEG_XS_YUV10_422_Rec709 =
466 154,
467 JPEG_XS_YUV12_422_Rec709 =
468 155,
469 JPEG_XS_YUV8_420_Rec709 =
470 156,
471 JPEG_XS_YUV10_420_Rec709 =
472 157,
473 JPEG_XS_YUV12_420_Rec709 =
474 158,
475 JPEG_XS_RGB8_sRGB = 159,
476
477 // -- Planar RGB --
478 RGB8_Planar_sRGB = 160,
479
480 // -- Planar 4:4:4 YCbCr --
481 YUV8_444_Planar_Rec709 = 162,
482 YUV10_444_Planar_LE_Rec709 = 163,
483
484 UserDefined = 1024
485 };
486
488 using IDList = ::promeki::List<ID>;
489
491 struct CompSemantic {
492 String name;
493 String abbrev;
494 float rangeMin = 0;
495 float rangeMax = 0;
496 };
497
499 struct Data {
500 ID id = Invalid;
501 String name;
502 String desc;
503 PixelMemLayout memLayout;
504 ColorModel colorModel;
505 bool hasAlpha = false;
506 int alphaCompIndex = -1;
507 bool compressed = false;
508 VideoCodec
509 videoCodec;
510 List<ID> encodeSources;
511 List<ID> decodeTargets;
512 FourCC::List fourccList;
513 CompSemantic compSemantics[MaxComps] = {};
514 VideoRange
515 videoRange;
516
523 PaintEngine (*createPaintEngineFunc)(const Data *d,
524 const UncompressedVideoPayload &payload) = nullptr;
525 };
526
532 static ID registerType();
533
539 static void registerData(Data &&data);
540
548 static IDList registeredIDs();
549
563 static PixelFormat lookup(const String &name);
564
584 static PixelFormat lookup(const String &name, Error *err);
585
593 static Result<PixelFormat> fromString(const String &name) {
594 Error err;
595 PixelFormat p = lookup(name, &err);
596 if (err.isError()) return makeError<PixelFormat>(err);
597 return makeResult(p);
598 }
599
604 inline PixelFormat(ID id = Invalid);
605
607 bool isValid() const { return d != nullptr && d->id != Invalid; }
608
610 ID id() const { return d->id; }
611
613 const String &name() const { return d->name; }
614
616 String toString() const { return d->name; }
617
619 const String &desc() const { return d->desc; }
620
622 const PixelMemLayout &memLayout() const { return d->memLayout; }
623
625 const ColorModel &colorModel() const { return d->colorModel; }
626
644 VideoRange videoRange() const { return d->videoRange; }
645
647 bool hasAlpha() const { return d->hasAlpha; }
648
650 int alphaCompIndex() const { return d->alphaCompIndex; }
651
653 bool isCompressed() const { return d->compressed; }
654
662 const VideoCodec &videoCodec() const { return d->videoCodec; }
663
673 const List<ID> &encodeSources() const { return d->encodeSources; }
674
684 const List<ID> &decodeTargets() const { return d->decodeTargets; }
685
687 const FourCC::List &fourccList() const { return d->fourccList; }
688
690 size_t compCount() const { return d->memLayout.compCount(); }
691
697 const CompSemantic &compSemantic(size_t index) const { return d->compSemantics[index]; }
698
700 size_t planeCount() const { return d->memLayout.planeCount(); }
701
702 // The following methods depend on proav types (ImageDesc, Image,
703 // PaintEngine) — defined in pixelformat.cpp.
704
711 size_t lineStride(size_t planeIndex, const ImageDesc &desc) const;
712
722 size_t planeSize(size_t planeIndex, const ImageDesc &desc) const;
723
732 PaintEngine createPaintEngine(const UncompressedVideoPayload &payload) const;
733
748 bool hasPaintEngine() const { return d != nullptr && d->createPaintEngineFunc != nullptr; }
749
751 bool operator==(const PixelFormat &o) const { return d == o.d; }
752
754 bool operator!=(const PixelFormat &o) const { return d != o.d; }
755
757 const Data *data() const { return d; }
758
759 private:
760 const Data *d = nullptr;
761 static const Data *lookupData(ID id);
762};
763
764inline PixelFormat::PixelFormat(ID id) : d(lookupData(id)) {}
765
766PROMEKI_NAMESPACE_END
767
768#endif // PROMEKI_ENABLE_PROAV