1use bytes::{Buf, Bytes, BytesMut};
29
30const PROP_TIMESTAMP: u64 = 0x06;
32const PROP_TIMESCALE: u64 = 0x08;
33
34const VARINT_MAX: u64 = (1u64 << 62) - 1;
36
37#[derive(Clone, Debug)]
39pub struct Frame {
40 pub timestamp: u64,
42
43 pub timescale: Option<u64>,
48
49 pub payload: Bytes,
51}
52
53#[derive(Debug, thiserror::Error)]
55#[non_exhaustive]
56pub enum Error {
57 #[error("loc frame missing required timestamp property")]
59 MissingTimestamp,
60
61 #[error("malformed loc properties")]
63 MalformedProperties,
64
65 #[error("short buffer")]
67 ShortBuffer,
68
69 #[error("value out of range")]
71 OutOfRange,
72}
73
74pub fn decode(mut buf: Bytes) -> Result<Frame, Error> {
79 let properties_length = read_varint(&mut buf)?;
80 let properties_length: usize = properties_length.try_into().map_err(|_| Error::MalformedProperties)?;
81
82 if properties_length > buf.remaining() {
83 return Err(Error::MalformedProperties);
84 }
85
86 let mut props = buf.split_to(properties_length);
87
88 let mut timestamp: Option<u64> = None;
89 let mut timescale: Option<u64> = None;
90 let mut prev_type: u64 = 0;
91 let mut first = true;
92
93 while props.has_remaining() {
94 let delta = read_varint(&mut props)?;
95 let abs = if first {
96 first = false;
97 delta
98 } else {
99 prev_type.checked_add(delta).ok_or(Error::MalformedProperties)?
100 };
101 prev_type = abs;
102
103 if abs % 2 == 0 {
104 let value = read_varint(&mut props)?;
105 match abs {
106 PROP_TIMESTAMP => timestamp = Some(value),
107 PROP_TIMESCALE => {
108 if value == 0 {
109 return Err(Error::MalformedProperties);
110 }
111 timescale = Some(value);
112 }
113 _ => {}
114 }
115 } else {
116 let len = read_varint(&mut props)?;
117 let len: usize = len.try_into().map_err(|_| Error::MalformedProperties)?;
118 if len > props.remaining() {
119 return Err(Error::MalformedProperties);
120 }
121 props.advance(len);
124 }
125 }
126
127 let timestamp = timestamp.ok_or(Error::MissingTimestamp)?;
128
129 Ok(Frame {
130 timestamp,
131 timescale,
132 payload: buf,
133 })
134}
135
136pub fn encode(timestamp: u64, payload: &[u8]) -> Result<Bytes, Error> {
141 let mut props = BytesMut::with_capacity(16);
142 write_varint(&mut props, PROP_TIMESTAMP)?;
143 write_varint(&mut props, timestamp)?;
144
145 let mut out = BytesMut::with_capacity(props.len() + payload.len() + 8);
146 write_varint(&mut out, props.len() as u64)?;
147 out.extend_from_slice(&props);
148 out.extend_from_slice(payload);
149
150 Ok(out.freeze())
151}
152
153fn read_varint<B: Buf>(buf: &mut B) -> Result<u64, Error> {
155 if !buf.has_remaining() {
156 return Err(Error::ShortBuffer);
157 }
158 let b = buf.get_u8();
159 let tag = b >> 6;
160 let mut bytes = [0u8; 8];
161 bytes[0] = b & 0b0011_1111;
162 let value = match tag {
163 0b00 => u64::from(bytes[0]),
164 0b01 => {
165 if buf.remaining() < 1 {
166 return Err(Error::ShortBuffer);
167 }
168 buf.copy_to_slice(&mut bytes[1..2]);
169 u64::from(u16::from_be_bytes(bytes[..2].try_into().unwrap()))
170 }
171 0b10 => {
172 if buf.remaining() < 3 {
173 return Err(Error::ShortBuffer);
174 }
175 buf.copy_to_slice(&mut bytes[1..4]);
176 u64::from(u32::from_be_bytes(bytes[..4].try_into().unwrap()))
177 }
178 0b11 => {
179 if buf.remaining() < 7 {
180 return Err(Error::ShortBuffer);
181 }
182 buf.copy_to_slice(&mut bytes[1..8]);
183 u64::from_be_bytes(bytes)
184 }
185 _ => unreachable!(),
186 };
187 Ok(value)
188}
189
190fn write_varint<B: bytes::BufMut>(buf: &mut B, value: u64) -> Result<(), Error> {
192 if value > VARINT_MAX {
193 return Err(Error::OutOfRange);
194 }
195 if value < (1u64 << 6) {
196 if buf.remaining_mut() < 1 {
197 return Err(Error::ShortBuffer);
198 }
199 buf.put_u8(value as u8);
200 } else if value < (1u64 << 14) {
201 if buf.remaining_mut() < 2 {
202 return Err(Error::ShortBuffer);
203 }
204 buf.put_u16(value as u16 | 0b01 << 14);
205 } else if value < (1u64 << 30) {
206 if buf.remaining_mut() < 4 {
207 return Err(Error::ShortBuffer);
208 }
209 buf.put_u32(value as u32 | 0b10 << 30);
210 } else {
211 if buf.remaining_mut() < 8 {
212 return Err(Error::ShortBuffer);
213 }
214 buf.put_u64(value | 0b11 << 62);
215 }
216 Ok(())
217}
218
219#[cfg(test)]
220mod tests {
221 use super::*;
222
223 #[test]
224 fn roundtrip() {
225 let payload = Bytes::from_static(b"hello world");
226 let encoded = encode(12345, &payload).unwrap();
227
228 let frame = decode(encoded).unwrap();
229 assert_eq!(frame.timestamp, 12345);
230 assert_eq!(frame.timescale, None);
231 assert_eq!(frame.payload, payload);
232 }
233
234 #[test]
235 fn decode_per_frame_timescale() {
236 let mut props = BytesMut::new();
238 write_varint(&mut props, PROP_TIMESTAMP).unwrap();
239 write_varint(&mut props, 96_000).unwrap();
240 write_varint(&mut props, PROP_TIMESCALE - PROP_TIMESTAMP).unwrap(); write_varint(&mut props, 48_000).unwrap();
242
243 let mut frame = BytesMut::new();
244 write_varint(&mut frame, props.len() as u64).unwrap();
245 frame.extend_from_slice(&props);
246 frame.extend_from_slice(b"payload");
247
248 let decoded = decode(frame.freeze()).unwrap();
249 assert_eq!(decoded.timestamp, 96_000);
250 assert_eq!(decoded.timescale, Some(48_000));
251 assert_eq!(decoded.payload, Bytes::from_static(b"payload"));
252 }
253
254 #[test]
255 fn decode_skips_video_config() {
256 let mut props = BytesMut::new();
258 write_varint(&mut props, PROP_TIMESTAMP).unwrap();
259 write_varint(&mut props, 10).unwrap();
260 write_varint(&mut props, 0x0d - PROP_TIMESTAMP).unwrap(); write_varint(&mut props, 3).unwrap(); props.extend_from_slice(&[0x01, 0x02, 0x03]);
263
264 let mut frame = BytesMut::new();
265 write_varint(&mut frame, props.len() as u64).unwrap();
266 frame.extend_from_slice(&props);
267 frame.extend_from_slice(b"data");
268
269 let decoded = decode(frame.freeze()).unwrap();
270 assert_eq!(decoded.timestamp, 10);
271 assert_eq!(decoded.timescale, None);
272 assert_eq!(decoded.payload, Bytes::from_static(b"data"));
273 }
274
275 #[test]
276 fn decode_missing_timestamp_errors() {
277 let mut props = BytesMut::new();
279 write_varint(&mut props, PROP_TIMESCALE).unwrap();
280 write_varint(&mut props, 1000).unwrap();
281
282 let mut frame = BytesMut::new();
283 write_varint(&mut frame, props.len() as u64).unwrap();
284 frame.extend_from_slice(&props);
285 frame.extend_from_slice(b"x");
286
287 assert!(matches!(decode(frame.freeze()), Err(Error::MissingTimestamp)));
288 }
289
290 #[test]
291 fn decode_empty_properties_errors() {
292 let mut frame = BytesMut::new();
293 write_varint(&mut frame, 0).unwrap();
294 frame.extend_from_slice(b"payload");
295
296 assert!(matches!(decode(frame.freeze()), Err(Error::MissingTimestamp)));
297 }
298
299 #[test]
300 fn decode_rejects_zero_timescale() {
301 let mut props = BytesMut::new();
303 write_varint(&mut props, PROP_TIMESTAMP).unwrap();
304 write_varint(&mut props, 10).unwrap();
305 write_varint(&mut props, PROP_TIMESCALE - PROP_TIMESTAMP).unwrap();
306 write_varint(&mut props, 0).unwrap();
307
308 let mut frame = BytesMut::new();
309 write_varint(&mut frame, props.len() as u64).unwrap();
310 frame.extend_from_slice(&props);
311 frame.extend_from_slice(b"x");
312
313 assert!(matches!(decode(frame.freeze()), Err(Error::MalformedProperties)));
314 }
315
316 #[test]
317 fn decode_overflowing_properties_length_errors() {
318 let mut frame = BytesMut::new();
319 write_varint(&mut frame, 100).unwrap(); frame.extend_from_slice(&[0x06]); assert!(matches!(decode(frame.freeze()), Err(Error::MalformedProperties)));
323 }
324}