12#include <promeki/config.h>
13#if PROMEKI_ENABLE_CORE
22PROMEKI_NAMESPACE_BEGIN
26#define PROMEKI_WELL_KNOWN_FRAME_RATES \
27 X(FPS_Invalid, "INV", 0, 1) \
28 X(FPS_120, "120", 120, 1) \
29 X(FPS_119_88, "119.88", 120000, 1001) \
30 X(FPS_100, "100", 100, 1) \
31 X(FPS_96, "96", 96, 1) \
32 X(FPS_95_90, "95.90", 96000, 1001) \
33 X(FPS_60, "60", 60, 1) \
34 X(FPS_59_94, "59.94", 60000, 1001) \
35 X(FPS_50, "50", 50, 1) \
36 X(FPS_48, "48", 48, 1) \
37 X(FPS_47_95, "47.95", 48000, 1001) \
38 X(FPS_30, "30", 30, 1) \
39 X(FPS_29_97, "29.97", 30000, 1001) \
40 X(FPS_25, "25", 25, 1) \
41 X(FPS_24, "24", 24, 1) \
42 X(FPS_23_98, "23.98", 24000, 1001)
112 PROMEKI_DATATYPE(FrameRate, DataTypeFrameRate, 1)
115 Error writeToStream(DataStream &s) const;
117 template <uint32_t V> static Result<FrameRate> readFromStream(DataStream &s);
120 using RationalType = Rational<
unsigned int>;
122#define X(type, string, num, den) type,
125 FPS_NotWellKnown = 0,
126 PROMEKI_WELL_KNOWN_FRAME_RATES
151 static List<WellKnown> wellKnownRates();
154 FrameRate() =
default;
160 FrameRate(WellKnownRate rate);
166 FrameRate(
const RationalType &r);
172 bool isValid()
const {
return _fps.numerator() > 0; }
175 unsigned int numerator()
const {
return _fps.numerator(); }
178 unsigned int denominator()
const {
return _fps.denominator(); }
184 double toDouble()
const {
return _fps.toDouble(); }
205 static Result<FrameRate> fromDouble(
double val);
223 Duration frameDuration()
const {
224 if (!isValid())
return Duration();
227 int64_t num =
static_cast<int64_t
>(_fps.numerator());
228 int64_t den =
static_cast<int64_t
>(_fps.denominator());
229 int64_t ns = (den * INT64_C(1'000'000'000) + num / 2) / num;
230 return Duration::fromNanoseconds(ns);
284 int64_t cumulativeTicks(int64_t tickRate, int64_t frameIndex)
const {
285 if (!isValid() || tickRate <= 0 || frameIndex < 0)
return 0;
286 const int64_t num =
static_cast<int64_t
>(_fps.numerator());
287 const int64_t den =
static_cast<int64_t
>(_fps.denominator());
288 return (frameIndex * tickRate * den) / num;
314 size_t samplesPerFrame(int64_t sampleRate, int64_t frameIndex)
const {
315 if (!isValid() || sampleRate <= 0 || frameIndex < 0)
return 0;
316 const int64_t cumNow = cumulativeTicks(sampleRate, frameIndex);
317 const int64_t cumNext = cumulativeTicks(sampleRate, frameIndex + 1);
318 return static_cast<size_t>(cumNext - cumNow);
325 String toString()
const {
return _fps.toString(); }
331 bool isWellKnownRate()
const {
return wellKnownRate() != FPS_NotWellKnown; }
350 WellKnownRate wellKnownRate()
const;
356 const RationalType &rational()
const {
return _fps; }
369 static Result<FrameRate> fromString(
const String &str);
372 bool operator==(
const FrameRate &other)
const {
return _fps == other._fps; }
375 bool operator!=(
const FrameRate &other)
const {
return _fps != other._fps; }
393struct FrameRate::WellKnown {
400PROMEKI_FORMAT_VIA_TOSTRING(promeki::FrameRate);