From<(u32, FrameRate)> for Timecode computes the field split with fps as u32, which truncates 29.97 to 29 frames per second (and 59.94 to 59). The resulting timecode drifts immediately and the error grows without bound; drop-frame is also hardcoded to false.
Repro (timecode 0.7.5):
use timecode::{Timecode, FrameRate};
for f in [1798u32, 17982, 107892, 2589407] {
println!("{}", Timecode::from((f, FrameRate::_29_97)));
}
| frames |
expected NDF |
expected DF |
actual |
| 1798 |
00:00:59:28 |
00:00:59;29 |
00:01:02:00 |
| 17982 (= 10 min DF) |
00:09:59:12 |
00:10:00;00 |
00:10:20:02 |
| 107892 (= 1 h DF) |
00:59:56:12 |
01:00:00;00 |
01:02:00:12 |
| 2589407 (= 24 h DF) |
23:58:33:17 |
24:00:00;00 |
24:48:09:26 |
Cause in src/lib.rs (From<(u32, FrameRate)>): let hours = number_of_frames / (60 * 60 * fps as u32); etc. — 23.97/24.97 are remapped to their integer timebases first, but 29.97/59.94 are not, so the f32 rate is truncated to 29/59.
Suggested fix: use the integer timebase (30 for 29.97, 60 for 59.94) for the field split, and either implement the drop-frame adjustment or document that output is NDF only.
🤖 Generated with Claude Code
https://claude.ai/code/session_01F7LQ1CdoDbQ8WHpRqQ1AwK
From<(u32, FrameRate)> for Timecodecomputes the field split withfps as u32, which truncates 29.97 to 29 frames per second (and 59.94 to 59). The resulting timecode drifts immediately and the error grows without bound; drop-frame is also hardcoded tofalse.Repro (timecode 0.7.5):
Cause in
src/lib.rs(From<(u32, FrameRate)>):let hours = number_of_frames / (60 * 60 * fps as u32);etc. — 23.97/24.97 are remapped to their integer timebases first, but 29.97/59.94 are not, so the f32 rate is truncated to 29/59.Suggested fix: use the integer timebase (30 for 29.97, 60 for 59.94) for the field split, and either implement the drop-frame adjustment or document that output is NDF only.
🤖 Generated with Claude Code
https://claude.ai/code/session_01F7LQ1CdoDbQ8WHpRqQ1AwK