Expand description
SMPTE ST 12-1:2014 “Time and Control Code” — the §9 Linear Time Code (LTC) 80-bit logical codeword.
This crate implements exactly the wire structure described in the curated
spec transcription at st12-1/docs/st12-1.md (fetched directly from
https://pub.smpte.org/pub/st12-1/st0012-1-2014.pdf) — cite that file,
not this doc comment, as the field-semantics oracle.
LtcFrame— the 80-bit LTC codeword (§9.2): BCD hours/minutes/ seconds/frames, the drop-frame and color-frame flags, four rate-dependent flag bits (resolved viaFrameRate), eight 4-bit binary groups (“user bits”), and the fixed synchronization word.FrameRate— which of ST 12-1 Table 3’s three flag-bit-position columns (30-frame / 25-frame / 24-frame) applies; the codeword itself carries no self-describing frame-rate field.BinaryGroupUsage/BinaryGroupFlags— Table 1’s classification of what the binary groups contain, from the three binary group flag bits.
Scope: this crate models only the already-demodulated logical 80-bit
codeword — never the §9.3 biphase-mark-encoded physical/analog audio
waveform LTC is carried as on a wire. That line-encoding/clock-recovery
layer is out of scope for this project, the same way it never decodes PCM
or AC-3 audio samples. See docs/st12-1.md’s “Scope” section.
Depends only on broadcast-common. #![no_std] when the std feature
is disabled (this crate needs no heap allocation at all — every field is
a fixed-size scalar).
§Examples
Build a frame and round-trip it:
use broadcast_common::{Parse, Serialize};
use st12_1::LtcFrame;
let frame = LtcFrame {
hours: 1,
minutes: 23,
seconds: 45,
frames: 13,
drop_frame_flag: false,
color_frame_flag: true,
flag_bit_27: true,
flag_bit_43: true,
flag_bit_58: false,
flag_bit_59: true,
user_bits: [1, 2, 3, 4, 5, 6, 7, 8],
};
let mut bytes = [0u8; st12_1::FRAME_LEN];
frame.serialize_into(&mut bytes).unwrap();
assert_eq!(LtcFrame::parse(&bytes).unwrap(), frame);§Runnable examples
Run with cargo run -p st12-1 --example <name>.
§build_frame
//! Build an LTC codeword from typed fields and serialize it to wire bytes —
//! SMPTE ST 12-1:2014 §9.2.
//!
//! Run with `cargo run -p st12-1 --example build_frame`.
use broadcast_common::Serialize;
use st12_1::LtcFrame;
fn main() {
let frame = LtcFrame {
hours: 1,
minutes: 23,
seconds: 45,
frames: 13,
drop_frame_flag: false,
color_frame_flag: true,
flag_bit_27: true,
flag_bit_43: true,
flag_bit_58: false,
flag_bit_59: true,
user_bits: [1, 2, 3, 4, 5, 6, 7, 8],
};
let mut bytes = [0u8; st12_1::FRAME_LEN];
frame.serialize_into(&mut bytes).expect("serialize");
println!("serialized {} bytes:", bytes.len());
println!(
"{}",
bytes
.iter()
.map(|b| format!("{b:02x}"))
.collect::<Vec<_>>()
.join(" ")
);
println!(
"time address: {:02}:{:02}:{:02}:{:02}",
frame.hours, frame.minutes, frame.seconds, frame.frames
);
println!("drop_frame_flag: {}", frame.drop_frame_flag);
println!("color_frame_flag: {}", frame.color_frame_flag);
println!("user bits: {:X?}", frame.user_bits);
}§parse_frame
//! Parse a spec-derived LTC codeword (see `docs/st12-1.md`'s "Worked vector"
//! section), print its decoded fields — including the `FrameRate`-dependent
//! polarity-correction and binary-group-flag bits — then round-trip it back
//! to bytes and confirm the output is byte-identical.
//!
//! Run with `cargo run -p st12-1 --example parse_frame`.
use broadcast_common::{Parse, Serialize};
use st12_1::{FrameRate, LtcFrame};
fn main() {
// Time Address = 01:23:45:13 (docs/st12-1.md's worked example), computed
// independently from ST 12-1 Tables 2-5, not by round-tripping through
// this crate's own serializer.
#[rustfmt::skip]
let bytes: [u8; st12_1::FRAME_LEN] =
[0x13, 0x29, 0x35, 0x4C, 0x53, 0x6A, 0x71, 0x88, 0xFC, 0xBF];
let frame = LtcFrame::parse(&bytes).expect("parse LTC codeword");
println!(
"time address: {:02}:{:02}:{:02}:{:02}",
frame.hours, frame.minutes, frame.seconds, frame.frames
);
println!("drop_frame_flag: {}", frame.drop_frame_flag);
println!("color_frame_flag: {}", frame.color_frame_flag);
println!("user bits: {:X?}", frame.user_bits);
for rate in [FrameRate::Fps30, FrameRate::Fps25, FrameRate::Fps24] {
let bgf = frame.binary_group_flags(rate);
println!(
"{rate}: polarity_correction={} binary_group_usage={}",
frame.polarity_correction(rate),
bgf.usage()
);
}
let mut out = [0u8; st12_1::FRAME_LEN];
frame.serialize_into(&mut out).expect("serialize");
assert_eq!(out, bytes, "byte-identical round trip");
println!("round trip byte-identical: OK ({} bytes)", out.len());
}Structs§
- Binary
Group Flags - The three binary group flag bits (§8.3.3), resolved from an
LtcFrameagainst a chosenFrameRate(seeLtcFrame::binary_group_flags). - LtcFrame
- A parsed (or to-be-serialized) 80-bit LTC codeword (§9.2): the BCD time
address, drop/color frame flags, the four rate-dependent flag bits
(polarity correction / BGF0 / BGF1 / BGF2 — see
FrameRate), the eight 4-bit binary groups (“user bits”, §8.1), and the fixed synchronization word (alwaysSYNC_WORDon serialize; validated on parse).
Enums§
- Binary
Group Usage - The meaning of the eight binary groups (“user bits”), per the three binary group flag bits BGF2/BGF1/BGF0 (§8.3.3, Table 1).
- Error
- An LTC codeword parse / serialize error.
- Frame
Rate - Which of ST 12-1 Table 3’s three flag-bit-position columns applies.
Constants§
- FRAME_
LEN - Length of the LTC codeword: 80 bits (§9.1) packed 8 bits/byte.
- MAX_
BINARY_ GROUP - Maximum value of one 4-bit binary group (“user bits”) nibble (§8.1/Table 4).
- MAX_
FRAMES - Maximum frame value across all supported frame rates: 30-frame counting
(drop or non-drop, §5.2.1/§5.2.2) numbers frames
00through29, the widest of the three per-rate bounds (25-frame:00-24per §6.2; 24-frame:00-23per §7.2). The 80-bit codeword carries no self-describing frame-rate field, so this crate validates against the widest bound and leaves the tighter per-rate bound to a caller that knows its stream’s frame rate (seedocs/st12-1.md§8.2). - MAX_
HOURS - Maximum hour value — “24-hour clock … to 23 hours” (§5.2/§6.2/§7.2).
- MAX_
MINUTES_ SECONDS - Maximum minute/second value — “… 59 minutes, and 59 seconds”.
- SYNC_
WORD - The fixed synchronization word (§9.2.5, Table 5), as the two bytes it
occupies under this crate’s bit-to-byte packing (
docs/st12-1.md’s “Byte packing convention”): byte 8 holds bits 64-71, byte 9 holds bits 72-79. This is the well-known LTC sync-word byte pair.
Type Aliases§
- Result
- Result alias for
st12-1parsing/serialization.