1use std::collections::VecDeque;
11use std::sync::Arc;
12
13use alpha2_model::{LinearPrimaries, MissingFrames};
14use alpha2_time::{FrameRate, MediaTime};
15
16use crate::api::{
17 Diagnostic, ExtensionError, Format, FramePixels, LinearColor, ProbeReport, SharedResolver,
18 Timing, VisualFrame, VisualSource, premultiply,
19};
20use crate::budget::{DEFAULT_FRAME_BUDGET, check_canvas};
21use crate::raster::decode_png;
22
23pub fn open_sequence(
31 frames: &[Option<String>],
32 rate: FrameRate,
33 missing: MissingFrames,
34 primaries: Option<LinearPrimaries>,
35 resolver: SharedResolver,
36) -> Result<Box<dyn VisualSource>, ExtensionError> {
37 open_within(
38 frames,
39 rate,
40 missing,
41 primaries,
42 resolver,
43 DEFAULT_FRAME_BUDGET,
44 )
45}
46
47pub(crate) fn open_within(
50 frames: &[Option<String>],
51 rate: FrameRate,
52 missing: MissingFrames,
53 primaries: Option<LinearPrimaries>,
54 resolver: SharedResolver,
55 budget: usize,
56) -> Result<Box<dyn VisualSource>, ExtensionError> {
57 let first = frames
58 .first()
59 .and_then(Option::as_ref)
60 .ok_or_else(|| ExtensionError::Malformed("the sequence's first frame is missing".into()))?;
61 if missing == MissingFrames::Reject && frames.iter().any(Option::is_none) {
62 return Err(ExtensionError::Mismatch(
63 "the sequence has a gap and refuses missing frames".into(),
64 ));
65 }
66 let first = decode(&resolver.bytes(first)?, None, primaries)?;
67 if first.color.is_none() && primaries.is_some() {
68 return Err(ExtensionError::Mismatch(
69 "primaries apply to OpenEXR frames, and these are PNGs".into(),
70 ));
71 }
72 check_canvas(first.width, first.height)?;
73 let report = ProbeReport {
74 format: first.format,
75 width: first.width,
76 height: first.height,
77 timing: Timing::Rate {
78 rate,
79 frames: frames.len(),
80 },
81 loop_count: None,
82 items: Vec::new(),
83 item: None,
84 color: first.color.clone(),
85 diagnostics: first.diagnostics.clone(),
86 };
87 let mut source = SequenceSource {
88 frames: frames.to_vec(),
89 resolver,
90 missing,
91 report,
92 kept: VecDeque::new(),
93 kept_bytes: 0,
94 budget,
95 };
96 source.keep(0, Arc::new(first));
97 Ok(Box::new(source))
98}
99
100struct Decoded {
102 format: Format,
103 width: u32,
104 height: u32,
105 pixels: FramePixels,
106 color: Option<LinearColor>,
108 diagnostics: Vec<Diagnostic>,
109}
110
111impl Decoded {
112 fn bytes(&self) -> usize {
114 match &self.pixels {
115 FramePixels::Rgba8(pixels) => pixels.len(),
116 FramePixels::LinearF16(pixels) => pixels.len() * 2,
117 }
118 }
119}
120
121fn decode(
124 bytes: &[u8],
125 color: Option<&LinearColor>,
126 primaries: Option<LinearPrimaries>,
127) -> Result<Decoded, ExtensionError> {
128 #[cfg(feature = "exr")]
129 if crate::exr::is_exr(bytes) {
130 let color = color
131 .cloned()
132 .or_else(|| primaries.map(crate::exr::project_color));
133 let image = crate::exr::decode_exr(bytes, color)?;
134 return Ok(Decoded {
135 format: Format::ExrSequence,
136 width: image.width,
137 height: image.height,
138 pixels: FramePixels::LinearF16(image.pixels.into()),
139 color: Some(image.color),
140 diagnostics: image.diagnostics,
141 });
142 }
143 let _ = (color, primaries);
144 if bytes.starts_with(&[0x76, 0x2f, 0x31, 0x01]) {
145 return Err(ExtensionError::Unsupported(
146 "this build reads no OpenEXR frames".into(),
147 ));
148 }
149 let (width, height, mut pixels) = decode_png(bytes)?;
150 premultiply(&mut pixels);
151 Ok(Decoded {
152 format: Format::PngSequence,
153 width,
154 height,
155 pixels: FramePixels::Rgba8(pixels.into()),
156 color: None,
157 diagnostics: Vec::new(),
158 })
159}
160
161struct SequenceSource {
163 frames: Vec<Option<String>>,
165 resolver: SharedResolver,
166 missing: MissingFrames,
167 report: ProbeReport,
168 kept: VecDeque<(usize, Arc<Decoded>)>,
170 kept_bytes: usize,
172 budget: usize,
175}
176
177impl SequenceSource {
178 fn shown(&self, time: MediaTime) -> (usize, MediaTime, Option<MediaTime>, usize) {
182 let (index, start, end) = self.report.timing.frame_at(time);
183 let shown = match self.missing {
184 MissingFrames::Hold => (0..=index)
185 .rev()
186 .find(|at| self.frames[*at].is_some())
187 .unwrap_or(0),
188 MissingFrames::Blank | MissingFrames::Reject => index,
189 };
190 (index, start, end, shown)
191 }
192
193 fn keep(&mut self, index: usize, decoded: Arc<Decoded>) {
194 self.kept_bytes += decoded.bytes();
195 self.kept.push_back((index, decoded));
196 while self.kept.len() > 1 && self.kept_bytes > self.budget {
197 if let Some((_, oldest)) = self.kept.pop_front() {
198 self.kept_bytes -= oldest.bytes();
199 }
200 }
201 }
202
203 fn decoded(&mut self, index: usize) -> Result<Arc<Decoded>, ExtensionError> {
204 if let Some((_, decoded)) = self.kept.iter().find(|(kept, _)| *kept == index) {
205 return Ok(Arc::clone(decoded));
206 }
207 let (width, height) = (self.report.width, self.report.height);
208 let decoded = if let Some(locator) = &self.frames[index] {
209 let decoded = decode(
210 &self.resolver.bytes(locator)?,
211 self.report.color.as_ref(),
212 None,
213 )?;
214 if decoded.format != self.report.format {
215 return Err(ExtensionError::Mismatch(format!(
216 "frame {index} is not in the first frame's format"
217 )));
218 }
219 if (decoded.width, decoded.height) != (width, height) {
220 return Err(ExtensionError::Mismatch(format!(
221 "frame {index} is {}x{}; the sequence is {width}x{height}",
222 decoded.width, decoded.height
223 )));
224 }
225 decoded
226 } else {
227 let samples = width as usize * height as usize * 4;
228 Decoded {
229 format: self.report.format,
230 width,
231 height,
232 pixels: if self.report.color.is_some() {
233 FramePixels::LinearF16(vec![0; samples].into())
234 } else {
235 FramePixels::Rgba8(vec![0; samples].into())
236 },
237 color: self.report.color.clone(),
238 diagnostics: Vec::new(),
239 }
240 };
241 let decoded = Arc::new(decoded);
242 self.keep(index, Arc::clone(&decoded));
243 Ok(decoded)
244 }
245}
246
247impl VisualSource for SequenceSource {
248 fn report(&self) -> &ProbeReport {
249 &self.report
250 }
251
252 fn render(&mut self, time: MediaTime, _fit: (u32, u32)) -> Result<VisualFrame, ExtensionError> {
253 let (index, start, end, shown) = self.shown(time);
254 let decoded = self.decoded(shown)?;
255 Ok(VisualFrame {
256 width: self.report.width,
257 height: self.report.height,
258 pixels: decoded.pixels.clone(),
259 index,
260 start,
261 end,
262 diagnostics: decoded.diagnostics.clone(),
263 })
264 }
265
266 fn needs(&self, time: MediaTime) -> Vec<String> {
267 let (.., shown) = self.shown(time);
268 if self.kept.iter().any(|(kept, _)| *kept == shown) {
269 return Vec::new();
270 }
271 self.frames[shown].iter().cloned().collect()
272 }
273
274 fn resident_bytes(&self) -> usize {
275 self.kept_bytes
276 }
277}