ebml_webm/types.rs
1//! Freestanding `WebM` track/frame types (no Mediaway dependency).
2
3#![forbid(unsafe_code)]
4
5pub use bytes::Bytes;
6
7/// Integer rational timebase (`num / den` seconds).
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub struct Rational {
10 /// Numerator.
11 pub num: u64,
12 /// Denominator (non-zero for valid timebases).
13 pub den: u32,
14}
15
16impl Rational {
17 /// Construct a rational.
18 #[must_use]
19 pub const fn new(num: u64, den: u32) -> Self {
20 Self { num, den }
21 }
22}
23
24/// Track metadata from `Tracks\TrackEntry` (v1 subset — see crate `adr/0001`).
25#[derive(Debug, Clone, PartialEq)]
26pub struct TrackInfo {
27 /// `TrackNumber` — referenced by `SimpleBlock`'s track number field.
28 pub track_number: u64,
29 /// Raw `TrackType` (1 = video, 2 = audio; other values pass through
30 /// unmapped in v1).
31 pub track_type: u8,
32 /// Raw `WebM` `CodecID` string (e.g. `"V_VP9"`, `"A_OPUS"`). Mapping to a
33 /// Mediaway `CodecKind` is the facade's job, not this crate's.
34 pub codec_id: String,
35 /// `TrackEntry\CodecPrivate` (codec-specific init data, e.g. `OpusHead`).
36 /// `None` when absent (VP8/VP9 without config, legacy files).
37 pub codec_private: Option<Bytes>,
38 /// Video width in pixels (`0` for non-video tracks or if absent).
39 pub width: u32,
40 /// Video height in pixels (`0` for non-video tracks or if absent).
41 pub height: u32,
42 /// `Audio\SamplingFrequency` in Hz (spec default `8000.0` when absent; `0.0`
43 /// only ever appears if a file explicitly encodes it, which spec forbids).
44 pub sample_rate: f64,
45 /// `Audio\Channels` (spec default `1` when absent).
46 pub channels: u32,
47}
48
49impl TrackInfo {
50 /// `TrackType == 1` (video), per the Matroska/`WebM` `TrackType` enum.
51 #[must_use]
52 pub const fn is_video(&self) -> bool {
53 self.track_type == 1
54 }
55}
56
57/// One demuxed `SimpleBlock`/`Block` frame.
58#[derive(Debug, Clone, PartialEq, Eq)]
59pub struct Frame {
60 /// Owning track's `TrackNumber`.
61 pub track_number: u64,
62 /// Absolute timecode in `TimecodeScale` ticks (`Cluster` timecode +
63 /// the block's signed relative timecode). Laced sub-frames within one
64 /// block share this same timecode — Matroska lacing does not encode a
65 /// distinct timecode per sub-frame (a real spec property, not a gap here).
66 pub timecode: i64,
67 /// Keyframe flag: `SimpleBlock`'s own flag bit, or (for a `BlockGroup`'s
68 /// `Block`) the *absence* of a sibling `ReferenceBlock`.
69 pub is_keyframe: bool,
70 /// `BlockGroup\BlockDuration` in `TimecodeScale` ticks, if present
71 /// (`None` for a bare `SimpleBlock`, which carries no duration).
72 pub duration_ticks: Option<u64>,
73 /// Frame payload bytes.
74 pub payload: Bytes,
75}
76
77/// One `Segment\Cues\CuePoint` entry — informational seek index; this crate
78/// does no seeking itself (sans-io: I/O and seeking belong to the adapter).
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub struct CuePoint {
81 /// `CueTime` in `TimecodeScale` ticks.
82 pub time_ticks: u64,
83 /// `CueClusterPosition` — byte offset from `Segment`'s data start.
84 pub cluster_position: u64,
85}
86
87/// One `Segment\SeekHead\Seek` entry.
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
89pub struct SeekEntry {
90 /// The referenced element's raw ID (same representation as [`crate::vint::decode_id`]).
91 pub id: u32,
92 /// Byte offset from `Segment`'s data start.
93 pub position: u64,
94}