libpromeki 1.0.0-alpha
PROfessional MEdia toolKIt
 
Loading...
Searching...
No Matches
videoformat.h
Go to the documentation of this file.
1
9#pragma once
10
11
12#include <promeki/config.h>
13#if PROMEKI_ENABLE_PROAV
14#include <promeki/namespace.h>
15#include <promeki/size2d.h>
16#include <promeki/framerate.h>
17#include <promeki/enums.h>
18#include <promeki/list.h>
19#include <promeki/result.h>
20#include <promeki/string.h>
21#include <promeki/datatype.h>
22
23PROMEKI_NAMESPACE_BEGIN
24
25class DataStream;
26
39#define PROMEKI_WELL_KNOWN_RASTERS \
40 X(Raster_Invalid, "INV", 0, 0) \
41 X(Raster_SD525, "SD525", 720, 486) \
42 X(Raster_SD625, "SD625", 720, 576) \
43 X(Raster_HD720, "HD720", 1280, 720) \
44 X(Raster_HD, "HD", 1920, 1080) \
45 X(Raster_2K, "2K", 2048, 1080) \
46 X(Raster_QHD, "QHD", 2560, 1440) \
47 X(Raster_UHD, "UHD", 3840, 2160) \
48 X(Raster_4K, "4K", 4096, 2160) \
49 X(Raster_UHD8K, "UHD8K", 7680, 4320) \
50 X(Raster_8K, "8K", 8192, 4320)
51
73#define PROMEKI_WELL_KNOWN_VIDEO_FORMATS \
74 X(Smpte486i59_94, Raster_SD525, FPS_29_97, Interlaced, FormatFlag_Smpte | FormatFlag_Ntsc | FormatFlag_Sd) \
75 X(Smpte576i50, Raster_SD625, FPS_25, Interlaced, FormatFlag_Smpte | FormatFlag_Pal | FormatFlag_Sd) \
76 X(Smpte720p50, Raster_HD720, FPS_50, Progressive, FormatFlag_Smpte | FormatFlag_Pal | FormatFlag_Hd) \
77 X(Smpte720p59_94, Raster_HD720, FPS_59_94, Progressive, FormatFlag_Smpte | FormatFlag_Ntsc | FormatFlag_Hd) \
78 X(Smpte720p60, Raster_HD720, FPS_60, Progressive, FormatFlag_Smpte | FormatFlag_Hd) \
79 X(Smpte1080i50, Raster_HD, FPS_25, Interlaced, FormatFlag_Smpte | FormatFlag_Pal | FormatFlag_Hd) \
80 X(Smpte1080i59_94, Raster_HD, FPS_29_97, Interlaced, FormatFlag_Smpte | FormatFlag_Ntsc | FormatFlag_Hd) \
81 X(Smpte1080i60, Raster_HD, FPS_30, Interlaced, FormatFlag_Smpte | FormatFlag_Hd) \
82 X(Smpte1080p23_98, Raster_HD, FPS_23_98, Progressive, FormatFlag_Smpte | FormatFlag_Ntsc | FormatFlag_Hd) \
83 X(Smpte1080p24, Raster_HD, FPS_24, Progressive, FormatFlag_Smpte | FormatFlag_Hd) \
84 X(Smpte1080p25, Raster_HD, FPS_25, Progressive, FormatFlag_Smpte | FormatFlag_Pal | FormatFlag_Hd) \
85 X(Smpte1080p29_97, Raster_HD, FPS_29_97, Progressive, FormatFlag_Smpte | FormatFlag_Ntsc | FormatFlag_Hd) \
86 X(Smpte1080p30, Raster_HD, FPS_30, Progressive, FormatFlag_Smpte | FormatFlag_Hd) \
87 X(Smpte1080p50, Raster_HD, FPS_50, Progressive, FormatFlag_Smpte | FormatFlag_Pal | FormatFlag_Hd) \
88 X(Smpte1080p59_94, Raster_HD, FPS_59_94, Progressive, FormatFlag_Smpte | FormatFlag_Ntsc | FormatFlag_Hd) \
89 X(Smpte1080p60, Raster_HD, FPS_60, Progressive, FormatFlag_Smpte | FormatFlag_Hd) \
90 X(Smpte1080psf23_98, Raster_HD, FPS_23_98, PsF, FormatFlag_Smpte | FormatFlag_Ntsc | FormatFlag_Hd) \
91 X(Smpte1080psf24, Raster_HD, FPS_24, PsF, FormatFlag_Smpte | FormatFlag_Hd) \
92 X(Smpte1080psf25, Raster_HD, FPS_25, PsF, FormatFlag_Smpte | FormatFlag_Pal | FormatFlag_Hd) \
93 X(Smpte1080psf29_97, Raster_HD, FPS_29_97, PsF, FormatFlag_Smpte | FormatFlag_Ntsc | FormatFlag_Hd) \
94 X(Smpte1080psf30, Raster_HD, FPS_30, PsF, FormatFlag_Smpte | FormatFlag_Hd) \
95 X(Smpte2160p23_98, Raster_UHD, FPS_23_98, Progressive, FormatFlag_Smpte | FormatFlag_Ntsc | FormatFlag_Uhd) \
96 X(Smpte2160p24, Raster_UHD, FPS_24, Progressive, FormatFlag_Smpte | FormatFlag_Uhd) \
97 X(Smpte2160p25, Raster_UHD, FPS_25, Progressive, FormatFlag_Smpte | FormatFlag_Pal | FormatFlag_Uhd) \
98 X(Smpte2160p29_97, Raster_UHD, FPS_29_97, Progressive, FormatFlag_Smpte | FormatFlag_Ntsc | FormatFlag_Uhd) \
99 X(Smpte2160p30, Raster_UHD, FPS_30, Progressive, FormatFlag_Smpte | FormatFlag_Uhd) \
100 X(Smpte2160p50, Raster_UHD, FPS_50, Progressive, FormatFlag_Smpte | FormatFlag_Pal | FormatFlag_Uhd) \
101 X(Smpte2160p59_94, Raster_UHD, FPS_59_94, Progressive, FormatFlag_Smpte | FormatFlag_Ntsc | FormatFlag_Uhd) \
102 X(Smpte2160p60, Raster_UHD, FPS_60, Progressive, FormatFlag_Smpte | FormatFlag_Uhd) \
103 X(Smpte4320p23_98, Raster_UHD8K, FPS_23_98, Progressive, \
104 FormatFlag_Smpte | FormatFlag_Ntsc | FormatFlag_Uhd8k) \
105 X(Smpte4320p24, Raster_UHD8K, FPS_24, Progressive, FormatFlag_Smpte | FormatFlag_Uhd8k) \
106 X(Smpte4320p25, Raster_UHD8K, FPS_25, Progressive, FormatFlag_Smpte | FormatFlag_Pal | FormatFlag_Uhd8k) \
107 X(Smpte4320p29_97, Raster_UHD8K, FPS_29_97, Progressive, \
108 FormatFlag_Smpte | FormatFlag_Ntsc | FormatFlag_Uhd8k) \
109 X(Smpte4320p30, Raster_UHD8K, FPS_30, Progressive, FormatFlag_Smpte | FormatFlag_Uhd8k) \
110 X(Smpte4320p50, Raster_UHD8K, FPS_50, Progressive, FormatFlag_Smpte | FormatFlag_Pal | FormatFlag_Uhd8k) \
111 X(Smpte4320p59_94, Raster_UHD8K, FPS_59_94, Progressive, \
112 FormatFlag_Smpte | FormatFlag_Ntsc | FormatFlag_Uhd8k) \
113 X(Smpte4320p60, Raster_UHD8K, FPS_60, Progressive, FormatFlag_Smpte | FormatFlag_Uhd8k) \
114 X(Dci2Kp24, Raster_2K, FPS_24, Progressive, FormatFlag_Dci) \
115 X(Dci2Kp25, Raster_2K, FPS_25, Progressive, FormatFlag_Dci) \
116 X(Dci2Kp30, Raster_2K, FPS_30, Progressive, FormatFlag_Dci) \
117 X(Dci2Kp48, Raster_2K, FPS_48, Progressive, FormatFlag_Dci) \
118 X(Dci2Kp50, Raster_2K, FPS_50, Progressive, FormatFlag_Dci) \
119 X(Dci2Kp60, Raster_2K, FPS_60, Progressive, FormatFlag_Dci) \
120 X(Dci4Kp24, Raster_4K, FPS_24, Progressive, FormatFlag_Dci) \
121 X(Dci4Kp25, Raster_4K, FPS_25, Progressive, FormatFlag_Dci) \
122 X(Dci4Kp30, Raster_4K, FPS_30, Progressive, FormatFlag_Dci) \
123 X(Dci4Kp48, Raster_4K, FPS_48, Progressive, FormatFlag_Dci) \
124 X(Dci4Kp50, Raster_4K, FPS_50, Progressive, FormatFlag_Dci) \
125 X(Dci4Kp60, Raster_4K, FPS_60, Progressive, FormatFlag_Dci)
126
198class VideoFormat {
199 public:
200 PROMEKI_DATATYPE(VideoFormat, DataTypeVideoFormat, 1)
201
202
203 Error writeToStream(DataStream &s) const;
205 template <uint32_t V> static Result<VideoFormat> readFromStream(DataStream &s);
206
208 enum WellKnownRaster {
209 Raster_NotWellKnown = 0,
210#define X(id, name, w, h) id,
211 PROMEKI_WELL_KNOWN_RASTERS
212#undef X
213 };
214
223 enum WellKnownFormatFlag : uint32_t {
224 FormatFlag_Smpte = 1u << 0,
225 FormatFlag_Dci = 1u << 1,
226 FormatFlag_Ntsc = 1u << 2,
227 FormatFlag_Pal = 1u << 3,
228 FormatFlag_Sd = 1u << 4,
229 FormatFlag_Hd = 1u << 5,
230 FormatFlag_Uhd = 1u << 6,
231 FormatFlag_Uhd8k = 1u << 7,
232 };
233
249 enum WellKnownFormat {
250 Invalid = 0,
251 NotWellKnown,
252#define X(id, raster, rate, scan, flags) id,
253 PROMEKI_WELL_KNOWN_VIDEO_FORMATS
254#undef X
255 };
256
258 using WellKnownFormatList = ::promeki::List<WellKnownFormat>;
259
261 struct StringOptions {
272 bool useNamedRaster = false;
273 };
274
276 struct ParseOptions {
295 bool strictInterlacedFieldRate = true;
296 };
297
299 VideoFormat() = default;
300
307 VideoFormat(const Size2Du32 &raster, const FrameRate &rate,
308 VideoScanMode scanMode = VideoScanMode::Progressive);
309
319 VideoFormat(WellKnownRaster raster, const FrameRate &rate,
320 VideoScanMode scanMode = VideoScanMode::Progressive);
321
332 VideoFormat(WellKnownFormat fmt);
333
335 bool isValid() const { return _raster.isValid() && _rate.isValid(); }
336
338 const Size2Du32 &raster() const { return _raster; }
339
341 const FrameRate &frameRate() const { return _rate; }
342
344 VideoScanMode videoScanMode() const { return _scanMode; }
345
350 WellKnownRaster wellKnownRaster() const;
351
353 bool isWellKnownRaster() const { return wellKnownRaster() != Raster_NotWellKnown; }
354
364 WellKnownFormat wellKnownFormat() const;
365
367 bool isWellKnownFormat() const {
368 const WellKnownFormat id = wellKnownFormat();
369 return id != Invalid && id != NotWellKnown;
370 }
371
378 uint32_t wellKnownFormatFlags() const;
379
381 bool isSmpteFormat() const { return (wellKnownFormatFlags() & FormatFlag_Smpte) != 0; }
382
384 bool isDciFormat() const { return (wellKnownFormatFlags() & FormatFlag_Dci) != 0; }
385
387 bool isNtscFormat() const { return (wellKnownFormatFlags() & FormatFlag_Ntsc) != 0; }
388
390 bool isPalFormat() const { return (wellKnownFormatFlags() & FormatFlag_Pal) != 0; }
391
393 bool isSdFormat() const { return (wellKnownFormatFlags() & FormatFlag_Sd) != 0; }
394
396 bool isHdFormat() const { return (wellKnownFormatFlags() & FormatFlag_Hd) != 0; }
397
399 bool isUhdFormat() const { return (wellKnownFormatFlags() & FormatFlag_Uhd) != 0; }
400
402 bool isUhd8kFormat() const { return (wellKnownFormatFlags() & FormatFlag_Uhd8k) != 0; }
403
412 bool isBroadcastFormat() const {
413 const uint32_t f = wellKnownFormatFlags();
414 return (f & FormatFlag_Smpte) != 0 && (f & FormatFlag_Dci) == 0;
415 }
416
425 bool isCinemaFormat() const { return isDciFormat(); }
426
436 bool isIntegerCadence() const { return _rate.isValid() && _rate.denominator() == 1; }
437
445 static uint32_t formatFlags(WellKnownFormat fmt);
446
463 static WellKnownFormatList allWellKnownFormats(uint32_t requiredFlags = 0);
464
473 String rasterString() const { return rasterString(StringOptions()); }
478 String rasterString(const StringOptions &opts) const;
479
493 String frameRateString() const;
494
500 String toString() const { return toString(StringOptions()); }
505 String toString(const StringOptions &opts) const;
506
513 static Result<VideoFormat> fromString(const String &str) { return fromString(str, ParseOptions()); }
521 static Result<VideoFormat> fromString(const String &str, const ParseOptions &opts);
522
524 bool operator==(const VideoFormat &o) const {
525 return _raster == o._raster && _rate == o._rate && _scanMode == o._scanMode;
526 }
527
529 bool operator!=(const VideoFormat &o) const { return !(*this == o); }
530
540 bool operator==(WellKnownFormat fmt) const { return wellKnownFormat() == fmt; }
541
543 bool operator!=(WellKnownFormat fmt) const { return wellKnownFormat() != fmt; }
544
546 friend bool operator==(WellKnownFormat fmt, const VideoFormat &vf) { return vf == fmt; }
547
549 friend bool operator!=(WellKnownFormat fmt, const VideoFormat &vf) { return vf != fmt; }
550
551 private:
552 Size2Du32 _raster;
553 FrameRate _rate;
554 VideoScanMode _scanMode{VideoScanMode::Progressive};
555};
556
557PROMEKI_NAMESPACE_END
558
581template <> struct std::formatter<promeki::VideoFormat> {
582 enum class Style {
583 Smpte,
584 Named,
585 };
586
587 Style _style = Style::Smpte;
588 std::formatter<std::string_view> _base;
589
590 constexpr auto parse(std::format_parse_context &ctx) {
591 auto it = ctx.begin();
592 auto end = ctx.end();
593
594 // Match a style keyword at the start of the spec. Each
595 // candidate stops at end-of-spec or a ':' separator so
596 // trailing std-spec forwarding still works.
597 auto tryKeyword = [&](const char *kw, Style s) {
598 auto p = it;
599 while (*kw && p != end && *p == *kw) {
600 ++p;
601 ++kw;
602 }
603 if (*kw == 0 && (p == end || *p == '}' || *p == ':')) {
604 it = p;
605 _style = s;
606 return true;
607 }
608 return false;
609 };
610
611 if (!tryKeyword("smpte", Style::Smpte) && !tryKeyword("named", Style::Named)) {
612 // No keyword — leave _style at default and let
613 // the base parser consume the entire remaining spec.
614 }
615
616 // Separating ':' between the style hint and a standard
617 // string format spec is consumed here so the base parser
618 // sees a bare ">16" rather than ":>16".
619 if (it != end && *it == ':') ++it;
620
621 ctx.advance_to(it);
622 return _base.parse(ctx);
623 }
624
625 template <typename FormatContext>
626 auto format(const promeki::VideoFormat &vf, FormatContext &ctx) const {
627 promeki::VideoFormat::StringOptions opts;
628 opts.useNamedRaster = (_style == Style::Named);
629 const promeki::String s = vf.toString(opts);
630 return _base.format(std::string_view(s.cstr(), s.byteCount()), ctx);
631 }
632};
633
634#endif // PROMEKI_ENABLE_PROAV