Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions contrib/opentimelineio_contrib/adapters/ale.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,19 +290,19 @@ def val_for_column(column, clip):
if not clip.source_range:
return ""
return otio.opentime.to_timecode(
clip.source_range.start_time, fps
clip.source_range.start_time.rescaled_to(fps)
)
elif column == "Duration":
if not clip.source_range:
return ""
return otio.opentime.to_timecode(
clip.source_range.duration, fps
clip.source_range.duration.rescaled_to(fps)
)
elif column == "End":
if not clip.source_range:
return ""
return otio.opentime.to_timecode(
clip.source_range.end_time_exclusive(), fps
clip.source_range.end_time_exclusive().rescaled_to(fps)
)
else:
return clip.metadata.get("ALE", {}).get(column)
Expand Down
5 changes: 3 additions & 2 deletions contrib/opentimelineio_contrib/adapters/ffmpeg_burnins.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,9 @@ def add_timecode(self, align, options=None):
:param dict options: recommended to use TimeCodeOptions
"""
options = options or TimeCodeOptions()
timecode = _frames_to_timecode(options['frame_offset'],
self.frame_rate)
timecode = _frames_to_timecode(
options['frame_offset'].rescaled_to(self.frame_rate)
)
options = options.copy()
if not options.get('fps'):
options['fps'] = self.frame_rate
Expand Down
5 changes: 3 additions & 2 deletions src/opentime/rationalTime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,18 +187,19 @@ RationalTime::from_time_string(std::string const& time_string, double rate, Erro

std::string
RationalTime::to_timecode(
double rate,
IsDropFrameRate drop_frame,
ErrorStatus* error_status
) const {

*error_status = ErrorStatus();

if (_value < 0) {
*error_status = ErrorStatus(ErrorStatus::NEGATIVE_VALUE);
return std::string();
}

double rate = _rate;

if (!is_valid_timecode_rate(rate)) {
*error_status = ErrorStatus(ErrorStatus::INVALID_TIMECODE_RATE);
return std::string();
Expand Down
3 changes: 1 addition & 2 deletions src/opentime/rationalTime.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,12 @@ class RationalTime {
}

std::string to_timecode(
double rate,
IsDropFrameRate drop_frame,
ErrorStatus *error_status
) const;

std::string to_timecode(ErrorStatus *error_status) const {
return to_timecode(_rate, IsDropFrameRate::InferFromRate, error_status);
return to_timecode(IsDropFrameRate::InferFromRate, error_status);
}

std::string to_time_string() const;
Expand Down
12 changes: 4 additions & 8 deletions src/opentimelineview/track_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,25 +153,21 @@ def _set_labels_timecode(self):
self.source_in_label.setText(
'{timeline}\n{source}'.format(
timeline=otio.opentime.to_timecode(
self.timeline_range.start_time,
self.timeline_range.start_time.rate
self.timeline_range.start_time
),
source=otio.opentime.to_timecode(
self.item.trimmed_range.start_time,
self.item.trimmed_range.start_time.rate
self.item.trimmed_range.start_time
)
)
)

self.source_out_label.setText(
'{timeline}\n{source}'.format(
timeline=otio.opentime.to_timecode(
self.timeline_range.end_time_exclusive(),
self.timeline_range.end_time_exclusive().rate
self.timeline_range.end_time_exclusive()
),
source=otio.opentime.to_timecode(
self.item.trimmed_range.end_time_exclusive(),
self.item.trimmed_range.end_time_exclusive().rate
self.item.trimmed_range.end_time_exclusive()
)
)
)
Expand Down
13 changes: 2 additions & 11 deletions src/py-opentimelineio/opentime-bindings/opentime_rationalTime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,23 +84,14 @@ void opentime_rationalTime_bindings(py::module m) {
.def("to_frames", (int (RationalTime::*)() const) &RationalTime::to_frames)
.def("to_frames", (int (RationalTime::*)(double) const) &RationalTime::to_frames, "rate"_a)
.def("to_seconds", &RationalTime::to_seconds)
.def("to_timecode", [](RationalTime rt, double rate, py::object drop_frame) {
.def("to_timecode", [](RationalTime rt, py::object drop_frame) {
return rt.to_timecode(
rate,
df_enum_converter(drop_frame),
ErrorStatusConverter()
);
}, "rate"_a, "drop_frame"_a)
.def("to_timecode", [](RationalTime rt, double rate) {
return rt.to_timecode(
rate,
IsDropFrameRate::InferFromRate,
ErrorStatusConverter()
);
}, "rate"_a)
}, "drop_frame"_a)
.def("to_timecode", [](RationalTime rt) {
return rt.to_timecode(
rt.rate(),
IsDropFrameRate::InferFromRate,
ErrorStatusConverter());
})
Expand Down
17 changes: 7 additions & 10 deletions src/py-opentimelineio/opentimelineio/adapters/cmx_3600.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,8 +556,7 @@ def parse(self, line):
opentime.from_frames(
int(getattr(self, prop)),
self.edl_rate
),
self.edl_rate
)
)
)

Expand Down Expand Up @@ -1124,10 +1123,10 @@ def to_edl_format(self, edit_number):
'edit': edit_number,
'reel': self.reel,
'kind': self._kind,
'src_in': opentime.to_timecode(self.source_in, self._rate),
'src_out': opentime.to_timecode(self.source_out, self._rate),
'rec_in': opentime.to_timecode(self.record_in, self._rate),
'rec_out': opentime.to_timecode(self.record_out, self._rate),
'src_in': opentime.to_timecode(self.source_in.rescaled_to(self._rate)),
'src_out': opentime.to_timecode(self.source_out.rescaled_to(self._rate)),
'rec_in': opentime.to_timecode(self.record_in.rescaled_to(self._rate)),
'rec_out': opentime.to_timecode(self.record_out.rescaled_to(self._rate)),
'diss': int(
opentime.to_frames(self.dissolve_length, self._rate)
),
Expand Down Expand Up @@ -1182,8 +1181,7 @@ def _generate_comment_lines(
clip.name,
timing_effect.time_scalar * edl_rate,
opentime.to_timecode(
clip.trimmed_range().start_time,
edl_rate
clip.trimmed_range().start_time.rescaled_to(edl_rate)
)
)
)
Expand Down Expand Up @@ -1241,8 +1239,7 @@ def _generate_comment_lines(
# Output any markers on this clip
for marker in clip.markers:
timecode = opentime.to_timecode(
marker.marked_range.start_time,
edl_rate
marker.marked_range.start_time.rescaled_to(edl_rate)
)

color = marker.color
Expand Down
2 changes: 1 addition & 1 deletion src/py-opentimelineio/opentimelineio/adapters/fcp_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -1360,7 +1360,7 @@ def _build_timecode(time, fps, drop_frame=False, additional_metadata=None):

# Get the time values
tc_time = opentime.RationalTime(time.value_rescaled_to(fps), tc_fps)
tc_string = opentime.to_timecode(tc_time, tc_fps, drop_frame)
tc_string = opentime.to_timecode(tc_time.rescaled_to(tc_fps), drop_frame)

_append_new_sub_element(tc_element, "string", text=tc_string)

Expand Down
2 changes: 1 addition & 1 deletion src/py-opentimelineio/opentimelineio/console/otiostat.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def _total_duration(input):
def _total_duration_timecode(input):
try:
d = input.tracks.duration()
return otio.opentime.to_timecode(d, d.rate)
return otio.opentime.to_timecode(d)
except AttributeError:
return "n/a"

Expand Down
6 changes: 3 additions & 3 deletions src/py-opentimelineio/opentimelineio/opentime.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
duration_from_start_end_time = RationalTime.duration_from_start_end_time


def to_timecode(rt, rate=None, drop_frame=None):
def to_timecode(rt, drop_frame=None):
return (
rt.to_timecode()
if rate is None and drop_frame is None
else rt.to_timecode(rate, drop_frame)
if drop_frame is None
else rt.to_timecode(drop_frame)
)


Expand Down
2 changes: 1 addition & 1 deletion src/swift-opentimelineio/opentime.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ bool rational_time_is_valid_timecode_rate(double);

CxxRationalTime rational_time_from_timecode(NSString* timecode, double rate, CxxErrorStruct* err);
CxxRationalTime rational_time_from_timestring(NSString* timestring, double rate, CxxErrorStruct* err);
NSString* rational_time_to_timecode(CxxRationalTime, double rate, CxxErrorStruct* err);
NSString* rational_time_to_timecode(CxxRationalTime, CxxErrorStruct* err);
NSString* rational_time_to_timestring(CxxRationalTime);
CxxRationalTime rational_time_add(CxxRationalTime, CxxRationalTime);
CxxRationalTime rational_time_subtract(CxxRationalTime, CxxRationalTime);
Expand Down
4 changes: 2 additions & 2 deletions src/swift-opentimelineio/opentime.mm
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ CxxRationalTime rational_time_from_timestring(NSString* timestring, double rate,
return result;
}

NSString* rational_time_to_timecode(CxxRationalTime rt, double rate, CxxErrorStruct* err) {
NSString* rational_time_to_timecode(CxxRationalTime rt, CxxErrorStruct* err) {
opentime::ErrorStatus error_status;
std::string result = otioRationalTime(rt).to_timecode(rate, &error_status);
std::string result = otioRationalTime(rt).to_timecode(&error_status);
deal_with_error(error_status, err);
return [NSString stringWithUTF8String: result.c_str()];
}
Expand Down
44 changes: 26 additions & 18 deletions tests/test_opentime.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
import copy


# @TODO: replace "29.97" and similar strings with the correct NTSC values:
# 30000/1001


class TestTime(unittest.TestCase):

def test_create(self):
Expand Down Expand Up @@ -137,7 +141,7 @@ def test_plus_equals(self):
def test_time_timecode_zero(self):
t = otio.opentime.RationalTime()
timecode = "00:00:00:00"
self.assertEqual(timecode, otio.opentime.to_timecode(t, 24))
self.assertEqual(timecode, otio.opentime.to_timecode(t.rescaled_to(24)))
self.assertEqual(t, otio.opentime.from_timecode(timecode, 24))

def test_long_running_timecode_24(self):
Expand Down Expand Up @@ -195,7 +199,7 @@ def test_timecode_23976_fps(self):
def test_converting_negative_values_to_timecode(self):
t = otio.opentime.RationalTime(value=-1, rate=25)
with self.assertRaises(ValueError):
otio.opentime.to_timecode(t, 25)
otio.opentime.to_timecode(t.rescaled_to(25))

def test_dropframe_timecode_2997fps(self):
"""Test drop frame in action. Focused on minute roll overs
Expand Down Expand Up @@ -289,9 +293,8 @@ def test_dropframe_timecode_2997fps(self):
for value, tc in time_values:
t = otio.opentime.RationalTime(value, 29.97)
self.assertEqual(
tc, otio.opentime.to_timecode(
t, rate=29.97, drop_frame=True
)
tc,
otio.opentime.to_timecode(t.rescaled_to(29.97), True)
)
t1 = otio.opentime.from_timecode(tc, rate=29.97)
self.assertEqual(t, t1)
Expand All @@ -301,21 +304,19 @@ def test_timecode_ntsc_2997fps(self):
rate_float = (30000 / 1001.0)
t = otio.opentime.RationalTime(frames, rate_float)

dftc = otio.opentime.to_timecode(t, rate_float, drop_frame=True)
dftc = otio.opentime.to_timecode(t.rescaled_to(rate_float), drop_frame=True)
self.assertEqual(dftc, '10:03:00;05')

tc = otio.opentime.to_timecode(t, rate_float, drop_frame=False)
tc = otio.opentime.to_timecode(t.rescaled_to(rate_float), drop_frame=False)
self.assertEqual(tc, '10:02:23:29')

# Detect DFTC from rate for backward compatability with old versions
tc_auto = otio.opentime.to_timecode(t, rate_float)
tc_auto = otio.opentime.to_timecode(t.rescaled_to(rate_float))
self.assertEqual(tc_auto, '10:03:00;05')

invalid_df_rate = otio.opentime.RationalTime(30, (24000 / 1001.0))
with self.assertRaises(ValueError):
otio.opentime.to_timecode(
invalid_df_rate, (24000 / 1001.0), drop_frame=True
)
otio.opentime.to_timecode(invalid_df_rate, drop_frame=True)

def test_timecode_2997(self):
ref_values = [
Expand All @@ -329,9 +330,9 @@ def test_timecode_2997(self):

for value, tc, dftc in ref_values:
t = otio.opentime.RationalTime(value, 29.97)
to_dftc = otio.opentime.to_timecode(t, rate=29.97, drop_frame=True)
to_tc = otio.opentime.to_timecode(t, rate=29.97, drop_frame=False)
to_auto_tc = otio.opentime.to_timecode(t, rate=29.97)
to_dftc = otio.opentime.to_timecode(t, drop_frame=True)
to_tc = otio.opentime.to_timecode(t, drop_frame=False)
to_auto_tc = otio.opentime.to_timecode(t)

# 29.97 should auto-detect dftc for backward compatability
self.assertEqual(to_dftc, to_auto_tc)
Expand All @@ -355,7 +356,7 @@ def test_invalid_rate_to_timecode_functions(self):
t = otio.opentime.RationalTime(100, 29.98)

with self.assertRaises(ValueError):
otio.opentime.to_timecode(t, 29.98)
otio.opentime.to_timecode(t.rescaled_to(29.98))

with self.assertRaises(ValueError):
otio.opentime.to_timecode(t)
Expand Down Expand Up @@ -632,7 +633,7 @@ def test_passing_ndf_tc_at_df_rate(self):

tc2 = otio.opentime.to_timecode(
otio.opentime.RationalTime(frames, 29.97),
30
drop_frame=False
)
self.assertEqual(tc2, NDF_TC)

Expand Down Expand Up @@ -990,8 +991,15 @@ def test_to_timecode_mixed_rates(self):
timecode = "00:06:56:17"
t = otio.opentime.from_timecode(timecode, 24)
self.assertEqual(timecode, otio.opentime.to_timecode(t))
self.assertEqual(timecode, otio.opentime.to_timecode(t, 24))
self.assertNotEqual(timecode, otio.opentime.to_timecode(t, 12))
self.assertEqual(timecode, otio.opentime.to_timecode(t.rescaled_to(24)))
self.assertNotEqual(timecode, otio.opentime.to_timecode(t.rescaled_to(12)))

time1 = otio.opentime.RationalTime(24.0, 24.0)
time2 = otio.opentime.RationalTime(1.0, 1.0)
self.assertEqual(
otio.opentime.to_timecode(time1.rescaled_to(24.0)),
otio.opentime.to_timecode(time2.rescaled_to(24.0))
)

def test_to_frames_mixed_rates(self):
frame = 100
Expand Down