vtc-rs

A SMPTE Timecode Library for Rust

click to see build pipeline click to see build pipeline click to see build pipeline

PyPI version Documentation

Overview

vtc-rs is inspired by years of scripting workflow solutions in a Hollywood cutting room. It aims to capture all the ways in which timecode is used throughout the industry so users can spend more time on their workflow logic, and less time handling the corner-cases of parsing and calculating timecode.

Demo

Let's take a quick high-level look at what you can do with vtc-rs:

```rust use vtc::{Timecode, Framerate, Ntsc, rates}; use num::Rational64;

// It's easy to make a new 23.98 NTSC timecode. We use the withframes constructor here since // timecode is really a human-readable way to represent frame count. let mut tc = Timecode::withframes("17:23:13:02", rates::F23_98).unwrap();

// We can get all sorts of ways to represent the timecode. asserteq!(tc.timecode(), "17:23:13:02"); asserteq!(tc.frames(), 1502234i64); asserteq!(tc.seconds(), Rational64::new(751868117, 12000)); asserteq!(tc.runtime(3), "17:24:15.676"); asserteq!(tc.premiereticks(), 15915544300656000i64); asserteq!(tc.feetand_frames(), "93889+10");

// We can inspect the framerate. asserteq!(tc.rate().playback(), Rational64::new(24000, 1001)); asserteq!(tc.rate().timebase(), Rational64::new(24, 1)); assert_eq!(tc.rate().ntsc(), Ntsc::NonDropFrame);

// Parsing is flexible

// Partial timecode: let parsed = Timecode::withframes("3:12", rates::F2398).unwrap(); assert_eq!(parsed.timecode(), "00:00:03:12");

// Frame count: let parsed = Timecode::withframes(24, rates::F2398).unwrap(); assert_eq!(parsed.timecode(), "00:00:01:00");

// Seconds: let parsed = Timecode::withseconds(1.5, rates::F2398).unwrap(); assert_eq!(parsed.timecode(), "00:00:01:12");

// Premiere Ticks: let parsed = Timecode::withpremiereticks(254016000000i64, rates::F2398).unwrap(); asserteq!(parsed.timecode(), "00:00:01:00");

// Feet + Frames: let parsed = Timecode::withframes("1+08", rates::F2398).unwrap(); assert_eq!(parsed.timecode(), "00:00:01:00");

// We can add two timecodes tc += Timecode::withframes("01:00:00:00", rates::F2398).unwrap(); assert_eq!(tc.timecode(), "18:23:13:02");

// We can subtract too. tc -= Timecode::withframes("01:00:00:00", rates::F2398).unwrap(); assert_eq!(tc.timecode(), "17:23:13:02");

// It's easy to compare two timecodes: assert!(tc > Timecode::withframes("02:00:00:00", rates::F2398).unwrap());

// And sort them: let mut sorted = vec![tc, Timecode::withframes("02:00:00:00", rates::F2398).unwrap()]; sorted.sort();

asserteq!(sorted[0].timecode(), "02:00:00:00"); asserteq!(sorted[1].timecode(), "17:23:13:02");

// We can multiply: tc *= 2; assert_eq!(tc.timecode(), "34:46:26:04");

// ...divide... : tc /= 2; assert_eq!(tc.timecode(), "17:23:13:02");

// ... and even get the remainder of division! let dividend = tc / 1.5; let remainder = tc % 1.5;

asserteq!(dividend.timecode(), "11:35:28:17"); asserteq!(remainder.timecode(), "00:00:00:01");

// We can make a timecode negative: tc = -tc; assert_eq!(tc.timecode(), "-17:23:13:02");

// Or get it's absolute value. tc = tc.abs(); assert_eq!(tc.timecode(), "17:23:13:02");

// We can make dropframe timecode for 29.97 or 59.94 using one of the pre-set framerates. // We can use an int to parse 15000 frames. let dropframe = Timecode::withframes(15000, rates::F2997DF).unwrap(); asserteq!(dropframe.timecode(), "00:08:20;18"); asserteq!(dropframe.rate().ntsc(), Ntsc::DropFrame);

// We can make new timecodes with arbitrary framerates if we want: let arbitrary = Timecode::withframes( "01:00:00:00", Framerate::withplayback(48, Ntsc::None).unwrap(), ).unwrap(); assert_eq!(arbitrary.frames(), 172800);

// We can make NTSC values for timebases and playback speeds that do not ship with this // crate: let mut ntsc = Timecode::withframes( "01:00:00:00", Framerate::withtimebase(120, Ntsc::NonDropFrame).unwrap(), ).unwrap(); asserteq!(ntsc.rate().playback(), Rational64::new(120000, 1001)); asserteq!(ntsc.rate().timebase(), Rational64::new(120, 1)); assert_eq!(ntsc.rate().ntsc(), Ntsc::NonDropFrame);

// We can also rebase them using another framerate: ntsc = ntsc.rebase(rates::F5994NDF); assert_eq!(ntsc.timecode(), "02:00:00:00"); ```

Features

Goals

Non-Goals

Attributions

Drop-frame calculations adapted from David Heidelberger's blog.
Logo made by Freepik from www.flaticon.com