rskit_media/stream/
time.rs1use std::collections::HashMap;
4use std::time::Duration;
5
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
13pub struct Timestamp(pub u64);
14
15impl Timestamp {
16 pub fn from_millis(ms: u64) -> Self {
18 Self(ms.saturating_mul(1000))
19 }
20
21 pub fn from_micros(us: u64) -> Self {
23 Self(us)
24 }
25
26 pub fn from_seconds(s: f64) -> Self {
28 Self((s * 1_000_000.0) as u64)
29 }
30
31 pub fn from_hms(h: u32, m: u32, s: f64) -> Self {
33 let total_secs = (h as f64) * 3600.0 + (m as f64) * 60.0 + s;
34 Self::from_seconds(total_secs)
35 }
36
37 pub fn as_millis(&self) -> u64 {
39 self.0 / 1000
40 }
41
42 pub fn as_micros(&self) -> u64 {
44 self.0
45 }
46
47 pub fn as_seconds(&self) -> f64 {
49 self.0 as f64 / 1_000_000.0
50 }
51
52 pub fn as_duration(&self) -> Duration {
54 Duration::from_micros(self.0)
55 }
56
57 pub fn to_ffmpeg_time(&self) -> String {
59 let total_us = self.0;
60 let ms = (total_us / 1000) % 1000;
61 let total_secs = total_us / 1_000_000;
62 let secs = total_secs % 60;
63 let total_mins = total_secs / 60;
64 let mins = total_mins % 60;
65 let hours = total_mins / 60;
66 format!("{hours:02}:{mins:02}:{secs:02}.{ms:03}")
67 }
68}
69
70impl std::fmt::Display for Timestamp {
71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72 f.write_str(&self.to_ffmpeg_time())
73 }
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
78pub struct TimeRange {
79 pub start: Timestamp,
81 pub end: Timestamp,
83}
84
85impl TimeRange {
86 pub fn new(start: Timestamp, end: Timestamp) -> Self {
88 Self { start, end }
89 }
90
91 pub fn from_millis(start_ms: u64, end_ms: u64) -> Self {
93 Self {
94 start: Timestamp::from_millis(start_ms),
95 end: Timestamp::from_millis(end_ms),
96 }
97 }
98
99 pub fn from_seconds(start: f64, end: f64) -> Self {
101 Self {
102 start: Timestamp::from_seconds(start),
103 end: Timestamp::from_seconds(end),
104 }
105 }
106
107 pub fn duration(&self) -> Duration {
109 Duration::from_micros(self.end.0.saturating_sub(self.start.0))
110 }
111
112 pub fn duration_ms(&self) -> u64 {
114 self.end.as_millis().saturating_sub(self.start.as_millis())
115 }
116
117 pub fn contains(&self, ts: Timestamp) -> bool {
119 ts >= self.start && ts <= self.end
120 }
121
122 pub fn overlaps(&self, other: &TimeRange) -> bool {
124 self.start < other.end && other.start < self.end
125 }
126
127 pub fn merge(&self, other: &TimeRange) -> Option<TimeRange> {
129 if self.overlaps(other) {
130 Some(TimeRange {
131 start: std::cmp::min(self.start, other.start),
132 end: std::cmp::max(self.end, other.end),
133 })
134 } else {
135 None
136 }
137 }
138
139 pub fn split_at(&self, ts: Timestamp) -> (Option<TimeRange>, Option<TimeRange>) {
141 if ts <= self.start {
142 (None, Some(*self))
143 } else if ts >= self.end {
144 (Some(*self), None)
145 } else {
146 (
147 Some(TimeRange::new(self.start, ts)),
148 Some(TimeRange::new(ts, self.end)),
149 )
150 }
151 }
152
153 pub fn shift(&self, offset_ms: i64) -> Self {
155 let offset_us = offset_ms * 1000;
156 let shift = |ts: Timestamp| {
157 if offset_us >= 0 {
158 Timestamp(ts.0.saturating_add(offset_us as u64))
159 } else {
160 Timestamp(ts.0.saturating_sub(offset_us.unsigned_abs()))
161 }
162 };
163 Self {
164 start: shift(self.start),
165 end: shift(self.end),
166 }
167 }
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize)]
172pub struct Segment {
173 pub range: TimeRange,
175 pub label: Option<String>,
177 pub confidence: Option<f32>,
179 pub metadata: HashMap<String, serde_json::Value>,
181}
182
183impl Segment {
184 pub fn new(range: TimeRange) -> Self {
186 Self {
187 range,
188 label: None,
189 confidence: None,
190 metadata: HashMap::new(),
191 }
192 }
193
194 #[must_use]
196 pub fn with_label(mut self, label: impl Into<String>) -> Self {
197 self.label = Some(label.into());
198 self
199 }
200
201 #[must_use]
203 pub fn with_confidence(mut self, c: f32) -> Self {
204 self.confidence = Some(c.clamp(0.0, 1.0));
205 self
206 }
207
208 #[must_use]
210 pub fn with_meta(mut self, key: impl Into<String>, val: impl Into<serde_json::Value>) -> Self {
211 self.metadata.insert(key.into(), val.into());
212 self
213 }
214}