1use crate::{Result, codec};
7
8pub struct Bridge {
10 catalog: moq_mux::catalog::Producer,
11 track: moq_mux::container::Producer<moq_mux::catalog::hang::Container>,
12 announced: bool,
13}
14
15impl Bridge {
16 pub fn new(mut broadcast: moq_net::BroadcastProducer, catalog: moq_mux::catalog::Producer) -> Result<Self> {
18 let track = broadcast.unique_track(".vp9")?;
19 let producer = catalog.media_producer(track, moq_mux::catalog::hang::Container::Legacy);
20 Ok(Self {
21 catalog,
22 track: producer,
23 announced: false,
24 })
25 }
26
27 fn announce(&mut self) {
28 if self.announced {
29 return;
30 }
31 let name = self.track.track().name.clone();
32 let mut config = hang::catalog::VideoConfig::new(hang::catalog::VP9::default());
33 config.container = hang::catalog::Container::Legacy;
34 config.timeline = Some(self.catalog.timeline_section(&name));
35 self.catalog.lock().video.renditions.insert(name, config);
36 self.announced = true;
37 }
38}
39
40impl codec::Bridge for Bridge {
41 fn push(&mut self, frame: codec::Frame) -> Result<()> {
42 self.announce();
43 let pts = moq_mux::container::Timestamp::from_micros(frame.timestamp_us)
44 .map_err(|err| crate::Error::Other(anyhow::anyhow!("invalid timestamp: {err}")))?;
45 let keyframe = is_keyframe(&frame.payload);
46 self.track
47 .write(moq_mux::container::Frame {
48 timestamp: pts,
49 payload: frame.payload,
50 keyframe,
51 duration: None,
52 })
53 .map_err(|err| crate::Error::Other(anyhow::anyhow!("vp9 track write failed: {err}")))?;
54 Ok(())
55 }
56}
57
58fn is_keyframe(payload: &[u8]) -> bool {
64 let Some(&b) = payload.first() else {
65 return false;
66 };
67 let profile = (((b >> 4) & 1) << 1) | ((b >> 5) & 1); let mut pos = 4;
70 if profile == 3 {
71 pos += 1;
72 }
73 let show_existing_frame = (b >> (7 - pos)) & 1;
74 if show_existing_frame == 1 {
75 return false;
76 }
77 pos += 1;
78 let frame_type = (b >> (7 - pos)) & 1;
79 frame_type == 0
80}
81
82impl Drop for Bridge {
83 fn drop(&mut self) {
84 self.catalog.lock().video.renditions.remove(&self.track.track().name);
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::is_keyframe;
91
92 #[test]
94 fn profile0_keyframe_and_interframe() {
95 assert!(is_keyframe(&[0b1000_0010]));
97 assert!(!is_keyframe(&[0b1000_0110]));
98 }
99
100 #[test]
101 fn profile0_show_existing_frame_is_not_keyframe() {
102 assert!(!is_keyframe(&[0b1000_1000]));
104 }
105
106 #[test]
107 fn profile3_keyframe_and_interframe() {
108 assert!(is_keyframe(&[0b1011_0000])); assert!(!is_keyframe(&[0b1011_0010])); }
113
114 #[test]
115 fn empty_payload_is_not_keyframe() {
116 assert!(!is_keyframe(&[]));
117 }
118}