summaryrefslogtreecommitdiff
path: root/src/lib/dcpomatic_time.cc
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2024-12-22 00:09:57 +0100
committerCarl Hetherington <cth@carlh.net>2025-09-02 22:40:13 +0200
commit33b0928b20618da5bc295711bfdf3d638863afa5 (patch)
tree24af21c6a7b863d914991ae837c36b6b9b50bcce /src/lib/dcpomatic_time.cc
parent6784eb8de2451afd2dedc15c05eac043011b5afb (diff)
Untested conversion to num/den DCPTime.arbitrary-hz
Summary of required changes: Replace ::from_frames with a constructor that takes num/den. Provide and use member to_debug_string() instead of to_string(). Provide and use member to_serializable_string() and string constructor instead of fmt::to_string on .get() and number constructor. Provide and use content_time() member instead of ContentTime constructor from DCPTime. Use frames_round(96000) instead of get() when comparing times to see if they are "close enough". Provide and use DCPTime(x, FrameRateChange) constructor when converting from ContentTime. Use .seconds() when calculating proportions or sometimes when dividing by HZ. Provide and use operator bool(). Pass explicit 96000 denominator in a lot of places. Add member max() and use it instead of static max() Change BOOST_CHECK_EQUAL to BOOST_CHECK Provide operator/ and use it instead of .get() / 2.
Diffstat (limited to 'src/lib/dcpomatic_time.cc')
-rw-r--r--src/lib/dcpomatic_time.cc294
1 files changed, 271 insertions, 23 deletions
diff --git a/src/lib/dcpomatic_time.cc b/src/lib/dcpomatic_time.cc
index 60fc5342a..a969f4c19 100644
--- a/src/lib/dcpomatic_time.cc
+++ b/src/lib/dcpomatic_time.cc
@@ -20,10 +20,13 @@
#include "dcpomatic_time.h"
+#include <dcp/raw_convert.h>
+#include <boost/algorithm/string.hpp>
#include <inttypes.h>
using std::string;
+using std::vector;
using namespace dcpomatic;
@@ -47,14 +50,6 @@ dcpomatic::operator<=(HMSF const& a, HMSF const& b)
template <>
-Time<ContentTimeDifferentiator, DCPTimeDifferentiator>::Time (DCPTime d, FrameRateChange f)
- : _t (llrint(d.get() * f.speed_up))
-{
-
-}
-
-
-template <>
Time<DCPTimeDifferentiator, ContentTimeDifferentiator>::Time (ContentTime d, FrameRateChange f)
: _t (llrint(d.get() / f.speed_up))
{
@@ -119,27 +114,280 @@ dcpomatic::to_string (ContentTime t)
}
+DCPTime::DCPTime(Type num)
+ : _num(num)
+ , _den(96000)
+{
+
+}
+
+
+DCPTime::DCPTime(Type num, Type den)
+ : _num(num)
+ , _den(den)
+{
+ DCPOMATIC_ASSERT(_den);
+}
+
+
+DCPTime::DCPTime(ContentTime time, FrameRateChange frc)
+ : _num(llrint(time.get() / frc.speed_up))
+ , _den(ContentTime::HZ)
+{
+
+}
+
+
+DCPTime::DCPTime(string const& serializable_string)
+{
+ vector<string> parts;
+ boost::algorithm::split(parts, serializable_string, boost::is_any_of("_"));
+ if (parts.size() == 1) {
+ _num = dcp::raw_convert<int64_t>(parts[0]);
+ _den = 96000;
+ } else {
+ _num = dcp::raw_convert<int64_t>(parts[0]);
+ _den = dcp::raw_convert<int64_t>(parts[1]);
+ }
+}
+
+
+DCPTime::DCPTime(HMSF const& hmsf, float fps)
+{
+ *this = from_seconds(hmsf.h * 3600)
+ + from_seconds(hmsf.m * 60)
+ + from_seconds(hmsf.s)
+ + DCPTime(hmsf.f * 1000, fps * 1000);
+}
+
+
string
-dcpomatic::to_string (DCPTime t)
+DCPTime::to_serialisable_string() const
{
- char buffer[64];
-#ifdef DCPOMATIC_WINDOWS
- __mingw_snprintf (buffer, sizeof(buffer), "[DCP %" PRId64 " %fs]", t.get(), t.seconds());
-#else
- snprintf (buffer, sizeof(buffer), "[DCP %" PRId64 " %fs]", t.get(), t.seconds());
-#endif
- return buffer;
+ return fmt::format("{}_{}", _num, _den);
}
string
-dcpomatic::to_string (DCPTimePeriod p)
+DCPTime::to_debug_string() const
{
- char buffer[64];
-#ifdef DCPOMATIC_WINDOWS
- __mingw_snprintf (buffer, sizeof(buffer), "[DCP %" PRId64 " %fs -> %" PRId64 " %fs]", p.from.get(), p.from.seconds(), p.to.get(), p.to.seconds());
-#else
- snprintf (buffer, sizeof(buffer), "[DCP %" PRId64 " %fs -> %" PRId64 " %fs]", p.from.get(), p.from.seconds(), p.to.get(), p.to.seconds());
-#endif
+ return fmt::format("[{}/{} {}]", _num, _den, seconds());
+}
+
+
+double
+DCPTime::seconds() const
+{
+ return static_cast<double>(_num) / _den;
+}
+
+bool
+DCPTime::operator<(DCPTime const& o) const
+{
+ DCPOMATIC_ASSERT(_den == o._den);
+ return _num < o._num;
+}
+
+
+bool
+DCPTime::operator<=(DCPTime const& o) const
+{
+ DCPOMATIC_ASSERT(_den == o._den);
+ return _num <= o._num;
+}
+
+
+bool
+DCPTime::operator==(DCPTime const& o) const
+{
+ DCPOMATIC_ASSERT(_den == o._den);
+ return _num == o._num;
+}
+
+
+bool
+DCPTime::operator!=(DCPTime const& o) const
+{
+ DCPOMATIC_ASSERT(_den == o._den);
+ return _num != o._num;
+}
+
+
+bool
+DCPTime::operator>=(DCPTime const& o) const
+{
+ DCPOMATIC_ASSERT(_den == o._den);
+ return _num >= o._num;
+}
+
+
+bool
+DCPTime::operator>(DCPTime const& o) const
+{
+ DCPOMATIC_ASSERT(_den == o._den);
+ return _num > o._num;
+}
+
+
+int64_t
+DCPTime::frames_floor(int r) const
+{
+ return (_num * r) / _den;
+}
+
+
+int64_t
+DCPTime::frames_round(int r) const
+{
+ return ((_num * r) + (r / 2)) / _den;
+}
+
+
+int64_t
+DCPTime::frames_ceil(int r) const
+{
+ return ((_num + 1) * r) / _den;
+}
+
+
+DCPTime
+DCPTime::operator+(DCPTime const& o) const
+{
+ DCPOMATIC_ASSERT(_den == o._den);
+ return DCPTime(_num + o._num, _den);
+}
+
+
+DCPTime&
+DCPTime::operator+=(DCPTime const& o)
+{
+ DCPOMATIC_ASSERT(_den == o._den);
+ _num += o._num;
+ return *this;
+}
+
+
+DCPTime
+DCPTime::operator-(DCPTime const& o) const
+{
+ DCPOMATIC_ASSERT(_den == o._den);
+ return DCPTime(_num - o._num, _den);
+}
+
+
+DCPTime
+DCPTime::operator-() const
+{
+ return DCPTime(-_num, _den);
+}
+
+
+DCPTime&
+DCPTime::operator-=(DCPTime const& o)
+{
+ DCPOMATIC_ASSERT(_den == o._den);
+ _num -= o._num;
+ return *this;
+}
+
+
+DCPTime
+DCPTime::operator*(int o) const
+{
+ return DCPTime(_num * o, _den);
+}
+
+
+DCPTime
+DCPTime::operator/(int o) const
+{
+ return DCPTime(_num, _den * o);
+}
+
+
+DCPTime::operator bool() const
+{
+ return _num != 0;
+}
+
+
+DCPTime
+DCPTime::max() const
+{
+ return DCPTime(INT64_MAX, _den);
+}
+
+
+DCPTime
+DCPTime::from_seconds(double s)
+{
+ return DCPTime(s * 96000, 96000);
+}
+
+
+DCPTime
+DCPTime::floor(int r) const
+{
+ return DCPTime(frames_floor(r), r);
+}
+
+
+DCPTime
+DCPTime::round(int r) const
+{
+ return DCPTime(frames_round(r), r);
+}
+
+
+DCPTime
+DCPTime::ceil(int r) const
+{
+ return DCPTime(frames_ceil(r), r);
+}
+
+
+DCPTime
+DCPTime::abs() const
+{
+ return DCPTime(std::abs(_num), _den);
+}
+
+
+HMSF
+DCPTime::splitX(int r) const
+{
+ /* Do this calculation with frames so that we can round
+ to a frame boundary at the start rather than the end.
+ */
+ auto ff = frames_round(r);
+ HMSF hmsf;
+
+ hmsf.h = ff / (3600 * r);
+ ff -= static_cast<int64_t>(hmsf.h) * 3600 * r;
+ hmsf.m = ff / (60 * r);
+ ff -= static_cast<int64_t>(hmsf.m) * 60 * r;
+ hmsf.s = ff / r;
+ ff -= static_cast<int64_t>(hmsf.s) * r;
+
+ hmsf.f = static_cast<int>(ff);
+ return hmsf;
+}
+
+
+string
+DCPTime::timecodeX(int r) const
+{
+ auto hmsf = splitX(r);
+
+ char buffer[128];
+ snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d:%02d", hmsf.h, hmsf.m, hmsf.s, hmsf.f);
return buffer;
}
+
+
+ContentTime
+DCPTime::content_time(FrameRateChange frc) const
+{
+ return ContentTime(frames_round(ContentTime::HZ) * frc.speed_up);
+}
+