Skip to content

Commit

Permalink
Add nearest_valid_timecode_rate (AcademySoftwareFoundation#1181)
Browse files Browse the repository at this point in the history
Added useful nearest_valid_timecode_rate in lieu of access to the list in Python.
  • Loading branch information
splidje authored Jan 11, 2022
1 parent a79bc1e commit 1e44ca2
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 15 deletions.
50 changes: 35 additions & 15 deletions src/opentime/rationalTime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,19 @@ static constexpr std::array<double, 4> dropframe_timecode_rates{ {
60000.0 / 1001.0,
} };

// currently unused:
/*
static constexpr std::array<double, 10> non_dropframe_timecode_rates
{{ 1,
12,
23.976,
23.98,
24,
25,
30,
48,
50,
60
}};
*/
static constexpr std::array<double, 11> smpte_timecode_rates{
{ 1.0,
12.0,
24000.0 / 1001.0,
24.0,
25.0,
30000.0 / 1001.0,
30.0,
48.0,
50.0,
60000.0 / 1001.0,
60.0 }
};

static constexpr std::array<double, 16> valid_timecode_rates{
{ 1.0,
Expand Down Expand Up @@ -63,6 +61,28 @@ RationalTime::is_valid_timecode_rate(double fps)
return std::find(b, e, fps) != e;
}

double
RationalTime::nearest_valid_timecode_rate(double rate)
{
double nearest_rate = 0;
double min_diff = std::numeric_limits<double>::max();
for (auto valid_rate : smpte_timecode_rates)
{
if (valid_rate == rate)
{
return rate;
}
auto diff = std::abs(rate - valid_rate);
if (diff >= min_diff)
{
continue;
}
min_diff = diff;
nearest_rate = valid_rate;
}
return nearest_rate;
}

static bool
is_dropframe_rate(double rate)
{
Expand Down
2 changes: 2 additions & 0 deletions src/opentime/rationalTime.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ class RationalTime

static bool is_valid_timecode_rate(double rate);

static double nearest_valid_timecode_rate(double rate);

static constexpr RationalTime
from_frames(double frame, double rate) noexcept
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ void opentime_rationalTime_bindings(py::module m) {
.def_static("duration_from_start_end_time_inclusive", &RationalTime::duration_from_start_end_time_inclusive,
"start_time"_a, "end_time_inclusive"_a)
.def_static("is_valid_timecode_rate", &RationalTime::is_valid_timecode_rate, "rate"_a)
.def_static("nearest_valid_timecode_rate", &RationalTime::nearest_valid_timecode_rate, "rate"_a,
R"docstring(Returns the first valid timecode rate that has the least difference from the given value.)docstring")
.def_static("from_frames", &RationalTime::from_frames, "frame"_a, "rate"_a)
.def_static("from_seconds", static_cast<RationalTime (*)(double, double)> (&RationalTime::from_seconds), "seconds"_a, "rate"_a)
.def_static("from_seconds", static_cast<RationalTime (*)(double)> (&RationalTime::from_seconds), "seconds"_a)
Expand Down
23 changes: 23 additions & 0 deletions tests/test_opentime.py
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,29 @@ def test_passing_ndf_tc_at_df_rate(self):
t2 = otio.opentime.from_timecode(NDF_TC, 29.97)
self.assertEqual(t2.value, frames)

def test_nearest_valid_timecode_rate(self):
invalid_valid_rates = (
(23.97602397602397, 24000.0 / 1001.0),
(23.97, 24000.0 / 1001.0),
(23.976, 24000.0 / 1001.0),
(23.98, 24000.0 / 1001.0),
(29.97, 30000.0 / 1001.0),
(59.94, 60000.0 / 1001.0),
)

for invalid_rate, nearest_valid_rate in invalid_valid_rates:
self.assertTrue(
otio.opentime.RationalTime.is_valid_timecode_rate(
nearest_valid_rate
)
)
self.assertEqual(
otio.opentime.RationalTime.nearest_valid_timecode_rate(
invalid_rate
),
nearest_valid_rate,
)


class TestTimeTransform(unittest.TestCase):

Expand Down

0 comments on commit 1e44ca2

Please sign in to comment.