1use crate::dropframe::frames_to_components;
2use crate::framerate::FrameRate;
3
4pub fn format_timecode(total_frames: i64, rate: FrameRate) -> [u8; 11] {
5 let (h, m, s, f) = frames_to_components(total_frames, rate);
6 let sep = if rate.is_drop_frame() { b';' } else { b':' };
7
8 [
9 b'0' + h / 10,
10 b'0' + h % 10,
11 b':',
12 b'0' + m / 10,
13 b'0' + m % 10,
14 b':',
15 b'0' + s / 10,
16 b'0' + s % 10,
17 sep,
18 b'0' + f / 10,
19 b'0' + f % 10,
20 ]
21}
22
23pub fn format_timecode_str(total_frames: i64, rate: FrameRate, buf: &mut [u8; 11]) {
24 *buf = format_timecode(total_frames, rate);
25}
26
27#[cfg(test)]
28mod tests {
29 use super::*;
30
31 fn fmt(frames: i64, rate: FrameRate) -> &'static str {
32 let bytes = format_timecode(frames, rate);
33 let s: &str = core::str::from_utf8(&bytes).unwrap();
34 Box::leak(s.to_string().into_boxed_str())
36 }
37
38 #[test]
39 fn zero() {
40 assert_eq!(fmt(0, FrameRate::Fps24), "00:00:00:00");
41 }
42
43 #[test]
44 fn one_hour() {
45 assert_eq!(fmt(86400, FrameRate::Fps24), "01:00:00:00");
46 }
47
48 #[test]
49 fn half_second_24fps() {
50 assert_eq!(fmt(12, FrameRate::Fps24), "00:00:00:12");
51 }
52
53 #[test]
54 fn drop_frame_uses_semicolon() {
55 let bytes = format_timecode(1800, FrameRate::Fps29_97Df);
56 assert_eq!(bytes[8], b';');
57 }
58
59 #[test]
60 fn non_drop_uses_colon() {
61 let bytes = format_timecode(0, FrameRate::Fps24);
62 assert_eq!(bytes[8], b':');
63 }
64}