moq_video/decode/
consumer.rs1use std::collections::VecDeque;
4
5use hang::catalog::VideoConfig;
6
7use super::decoder::Config;
8use super::sink::Sink;
9use crate::Error;
10use crate::Frame;
11
12pub struct Consumer {
17 decoder: Sink,
22 track: moq_mux::container::Consumer<moq_mux::catalog::hang::Container>,
23 pending: VecDeque<Frame>,
27}
28
29impl Consumer {
30 pub async fn new(
33 broadcast: &moq_net::broadcast::Consumer,
34 catalog: &VideoConfig,
35 name: impl Into<String>,
36 config: Config,
37 ) -> Result<Self, Error> {
38 let decoder = Sink::open(catalog, &config).await?;
39
40 let name = name.into();
41 let track = broadcast
42 .track(&name)?
43 .subscribe(moq_net::track::Subscription::default().with_priority(hang::catalog::PRIORITY.video))
44 .await?;
45 let container = moq_mux::catalog::hang::Container::try_from(&catalog.container)?;
49 let mut track = moq_mux::container::Consumer::new(track, container);
50 if let Some(latency) = config.latency_max {
51 track = track.with_latency(latency);
52 }
53
54 Ok(Self {
55 decoder,
56 track,
57 pending: VecDeque::new(),
58 })
59 }
60
61 pub fn name(&self) -> &str {
63 self.decoder.name()
64 }
65
66 pub async fn read(&mut self) -> Result<Option<Frame>, Error> {
68 loop {
69 if let Some(frame) = self.pending.pop_front() {
70 return Ok(Some(frame));
71 }
72
73 let Some(mux_frame) = self.track.read().await? else {
74 return Ok(None);
75 };
76
77 self.pending.extend(
78 self.decoder
79 .decode(mux_frame.payload, mux_frame.timestamp, mux_frame.keyframe)
80 .await?,
81 );
82 }
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use crate::decode::Kind;
90 use crate::encode::{Config as EncodeConfig, Encoder, Kind as EncodeKind, Producer as EncodeProducer};
91
92 #[tokio::test]
93 async fn reads_cmaf_container_declared_by_catalog() {
94 let mut source_broadcast = moq_net::broadcast::Info::new().produce();
95 let source_subscriber = source_broadcast.consume();
96 let source_catalog = moq_mux::catalog::Producer::new(&mut source_broadcast).unwrap();
97 let config = EncodeConfig {
98 kind: EncodeKind::Software,
99 ..EncodeConfig::new(320, 240, 30)
100 };
101 let rendition = config.probe().await.unwrap();
102 let mut producer = EncodeProducer::new(source_broadcast, source_catalog, rendition).unwrap();
103 let mut encoder = Encoder::new(&config).unwrap();
104 let rgba = vec![0x80u8; 320 * 240 * 4];
105 for index in 0..2 {
106 encoder.keyframe();
107 let surface = crate::Surface::rgba(&rgba, crate::Size::new(320, 240)).unwrap();
108 let frame = crate::Frame::new(surface, moq_net::Timestamp::from_micros(index * 33_333).unwrap());
109 producer.publish(&encoder.encode(&frame).unwrap()).unwrap();
110 }
111
112 let origin = moq_net::Origin::random().produce();
113 let mut requests = origin.dynamic();
114 let served = source_subscriber.clone();
115 tokio::spawn(async move {
116 while let Ok(request) = requests.requested_broadcast().await {
117 request.accept(served.clone());
118 }
119 });
120 let catalog = moq_mux::catalog::Consumer::<()>::new(&source_subscriber, moq_mux::catalog::CatalogFormat::Hang)
121 .await
122 .unwrap();
123 let source = moq_mux::Source::new(origin.consume(), "test");
124 let mut export = moq_mux::container::fmp4::Export::new(source, catalog);
125 let init = export.next().await.unwrap().expect("CMAF init");
126 let fragment = export.next().await.unwrap().expect("CMAF fragment");
127
128 let mut broadcast = moq_net::broadcast::Info::new().produce();
129 let subscriber = broadcast.consume();
130 let catalog = moq_mux::catalog::Producer::new(&mut broadcast).unwrap();
131 let mut import = moq_mux::container::fmp4::Import::new(broadcast, catalog.reserve());
132 import.decode(&init).unwrap();
133 import.decode(&fragment).unwrap();
134
135 let snapshot = catalog.snapshot();
136 let (name, config) = snapshot.video.renditions.iter().next().expect("video rendition");
137 assert!(matches!(config.container, hang::catalog::Container::Cmaf { .. }));
138 let mut consumer = Consumer::new(
139 &subscriber,
140 config,
141 name,
142 Config {
143 kind: Kind::Software,
144 ..Config::new()
145 },
146 )
147 .await
148 .unwrap();
149
150 let frame = consumer.read().await.unwrap().expect("decoded frame");
151 assert_eq!(frame.size(), crate::Size::new(320, 240));
152 }
153}