Skip to main content

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}