-
Notifications
You must be signed in to change notification settings - Fork 317
Description
Problem
The ALE adapter fails to parse ALE files with trucated decimal framerates (e.g., 23.976, 29.97) in OpenTimelineIO v0.18.1, while the same files parse successfully in v0.17.0. I believe this is quite common for ALEs, as seen in the ALE adapter sample files.
Reproduction
Using uvx to execute OpenTimelineIO's otiocat command against the otio-ale-adapter plugin's test file:
Fails in v0.18.1:
$ uvx --with OpenTimelineIO-Plugins==0.18.1 --from OpenTimelineIO==0.18.1 \
otiocat ./otio-ale-adapter/tests/sample_data/sampleUHD.ale
ValueError: SMPTE timecode does not support this rate
ALEParseError: Invalid Start timecode: 14:40:02:11Works in v0.17.0:
$ uvx --with OpenTimelineIO-Plugins==0.17 --from OpenTimelineIO==0.17 \
otiocat ./otio-ale-adapter/tests/sample_data/sampleUHD.ale
{"OTIO_SCHEMA": "SerializableCollection.1", ...}$ grep FPS ./otio-ale-adapter/tests/sample_data/sampleUHD.ale
FPS 23.976Using the exact fractional value works:
$ grep FPS sampleUHD-long-fps.ale
FPS 23.976023976023978$ uvx --with OpenTimelineIO-Plugins==0.18.1 --from OpenTimelineIO==0.18.1 \
otiocat sampleUHD-long-fps.ale
{"OTIO_SCHEMA": "SerializableCollection.1", ...}Root Cause
Introduced by #1477. In rationalTime.cpp:195, from_timecode() validates rates using exact floating-point comparison:
RationalTime::from_timecode(std::string const& timecode, double rate, ...)
{
if (!RationalTime::is_smpte_timecode_rate(rate)) // Line 195
// Throws error
bool RationalTime::is_smpte_timecode_rate(double fps)
{
return std::find(smpte_timecode_rates.begin(), smpte_timecode_rates.end(), fps) != end;
}Since 23.976 != 24000.0/1001.0 (23.976023976...), validation fails. This exact equality check is fragile given the well-known issues with floating-point representation and comparison.
The codebase includes nearest_smpte_timecode_rate() for tolerance-based matching, but it's not used in from_timecode() and other helpers.
Proposed Solution
I think the best approach would be to modify from_timecode() and other helpers to go back to using tolerance-based matching instead of exact comparison.
The alternative is that every usage of from_timecode() (like these calls, and other plugins, and thirdparty code) needs to first call nearest_smpte_timecode_rate() and get a precise fps value.