9个版本

0.1.13 2023年7月23日
0.1.12 2023年3月25日
0.1.9 2021年5月26日

#21 in 视频

Download history 75/week @ 2024-03-07 84/week @ 2024-03-14 60/week @ 2024-03-21 62/week @ 2024-03-28 18/week @ 2024-04-04 8/week @ 2024-05-02 147/week @ 2024-05-09 51/week @ 2024-05-16 17/week @ 2024-05-23 64/week @ 2024-05-30 6/week @ 2024-06-06 74/week @ 2024-06-13 39/week @ 2024-06-20

190 每月下载量

MIT 协议

1.5MB
4.5K SLoC

Rust 3.5K SLoC // 0.2% comments Python 1K SLoC // 0.2% comments Forge Config 5 SLoC

包含 (Cab文件,3MB) Many Basic Edits.aaf

vtc-rs

Rust的SMPTE时间码库

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

PyPI version Documentation

概述

vtc-rs 受到好莱坞剪辑室多年脚本解决方案的启发。它旨在捕捉整个行业中所有时间码的使用方式,以便用户可以将更多时间花在他们的工作流程逻辑上,而不是处理解析和计算时间码的边缘情况。

演示

让我们快速了解一下vtc-rs可以做什么

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

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

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

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

// Parsing is flexible

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

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

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

// Premiere Ticks:
let parsed = Timecode::with_premiere_ticks(254016000000i64, rates::F23_98).unwrap();
assert_eq!(parsed.timecode(), "00:00:01:00");

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

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

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

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

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

assert_eq!(sorted[0].timecode(), "02:00:00:00");
assert_eq!(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;

assert_eq!(dividend.timecode(), "11:35:28:17");
assert_eq!(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 drop_frame = Timecode::with_frames(15000, rates::F29_97_DF).unwrap();
assert_eq!(drop_frame.timecode(), "00:08:20;18");
assert_eq!(drop_frame.rate().ntsc(), Ntsc::DropFrame);

// We can make new timecodes with arbitrary framerates if we want:
let arbitrary = Timecode::with_frames(
    "01:00:00:00",
    Framerate::with_playback(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::with_frames(
    "01:00:00:00",
    Framerate::with_timebase(120, Ntsc::NonDropFrame).unwrap(),
).unwrap();
assert_eq!(ntsc.rate().playback(), Rational64::new(120000, 1001));
assert_eq!(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::F59_94_NDF);
assert_eq!(ntsc.timecode(), "02:00:00:00");

功能

  • SMPTE约定
    • NTSC
    • Drop-Frame
    • 交错时间码
  • 时间码表示
    • 时间码 | '01:00:00:00'
    • 帧 | 86400
    • 秒 | 3600.0
    • 运行时间 | '01:00:00.0'
    • 有理数 | 18018/5
    • 英尺+帧 | '5400+00'
      • 35mm, 4-perf
      • 35mm, 3-perf
      • 35mm, 2-perf
      • 16mm
    • 首演时间戳 | 15240960000000
  • 操作
    • 比较运算符(==, <, <=, >, >=)
    • 加法
    • 减法
    • 缩放(乘法和除法)
    • 除余
    • 取模
    • 负数
    • 绝对值
    • 重新计算帧计数(以新的帧率)
  • 灵活解析
    • 部分时间码 | '1:12'
    • 部分运行时间 | '1.5'
    • 负字符串值 | '-1:12', '-3+00'
    • 格式不正确的tc | '1:13:4'
  • 内置常量用于常见帧率

目标

  • 解析和获取所有时间码表示
  • 干净、简洁的API
  • 支持所有对时间码有意义的应用程序

非目标

  • 实时时间码生成器

致谢

Drop-Frame计算借鉴自 David Heidelberger的博客
Logo由 Freepik(来自 www.flaticon.com)制作

作者

  • Billy Peake:初始工作
  • Jamie Hardt:35mm, 3perf & 16mm格式支持

依赖

~2.5–3.5MB
~62K SLoC