1use crate::ljpeg::LjpegHeader;
17use crate::par_entropy::{self, EndCheck, SymbolStream};
18use flashraw_core::bits::{BitPumpMsb, BitRead};
19use flashraw_core::huffman::HuffTable;
20use flashraw_core::{Error, Result, par};
21
22pub(crate) const PARALLEL_MIN_SAMPLES: usize = 4 << 20;
24pub(crate) const LJPEG_PARALLEL_MIN_SAMPLES: usize = 1 << 20;
27const END_SLACK_BITS: u64 = 16;
30
31struct Scan<'a> {
33 stream: &'a [u8],
34 tables: &'a [HuffTable],
35 period: usize,
36}
37
38impl SymbolStream for Scan<'_> {
39 type Pump<'p>
40 = BitPumpMsb<'p>
41 where
42 Self: 'p;
43 const WIDTH: usize = 1;
44 fn cycle(&self) -> usize {
45 self.tables.len()
46 }
47 fn period(&self) -> usize {
48 self.period
49 }
50 fn total_bits(&self) -> u64 {
51 self.stream.len() as u64 * 8
52 }
53 fn end_check(&self, pos: u64) -> EndCheck {
54 if pos <= self.total_bits() + END_SLACK_BITS { EndCheck::Valid } else { EndCheck::Invalid }
56 }
57 fn pump_at(&self, bit: u64) -> BitPumpMsb<'_> {
58 BitPumpMsb::at_bit(self.stream, bit)
59 }
60 fn position(p: &BitPumpMsb<'_>) -> u64 {
61 p.bit_position()
62 }
63 #[inline(always)]
64 fn decode(&self, p: &mut BitPumpMsb<'_>, phase: usize, out: &mut [u16]) -> bool {
65 let before = p.bit_position();
66 p.fill();
67 let mut err = false;
68 out[0] = self.tables[phase].decode_diff_buffered(p, &mut err) as u16;
69 if err && p.bit_position() == before {
70 p.skip_no_fill(1);
71 }
72 !err
73 }
74}
75
76pub fn decode_frame_parallel(data: &[u8], hdr: &LjpegHeader, frame: &mut [u16]) -> Result<bool> {
83 decode_frame_chunked(data, hdr, hdr.height as usize, frame, None)
84}
85
86pub(crate) fn decode_frame_rows(data: &[u8], hdr: &LjpegHeader, rows: usize, frame: &mut [u16]) -> Result<bool> {
89 decode_frame_chunked(data, hdr, rows.min(hdr.height as usize), frame, None)
90}
91
92pub(crate) fn decode_frame_chunked(
93 data: &[u8],
94 hdr: &LjpegHeader,
95 height: usize,
96 frame: &mut [u16],
97 chunk_bytes: Option<usize>,
98) -> Result<bool> {
99 let clrs = hdr.clrs as usize;
100 let rl = hdr.row_len();
101 let total = rl.checked_mul(height).ok_or_else(|| Error::corrupt("lossless JPEG: frame too large"))?;
102 if hdr.restart_interval != 0 {
103 return decode_frame_restarts(data, hdr, height, frame);
104 }
105 if clrs == 0 || clrs > 6 || frame.len() < total {
106 return Ok(false);
107 }
108 let Some(scan) = data.get(hdr.scan_offset..) else { return Ok(false) };
109 if chunk_bytes.is_none() && par_entropy::default_chunk(scan.len()).is_none() {
110 return Ok(false);
112 }
113 let un = crate::ljpeg::unstuff_scan(scan, false);
114 if un.segments.len() != 1 {
115 return Ok(false);
116 }
117 let stream = un.segment(0);
118 let chunk = match chunk_bytes.or_else(|| par_entropy::default_chunk(stream.len())) {
119 Some(c) => c,
120 None => return Ok(false),
121 };
122 let src = Scan { stream, tables: &hdr.tables, period: phase_period(&hdr.table_ids) };
123 let Some(diffs) = par_entropy::decode(&src, total, chunk) else { return Ok(false) };
124
125 if hdr.predictor == 1 && (hdr.sraw != 0 || clrs > 4) {
126 let sraw = hdr.sraw as usize;
130 let init = 1u16 << (hdr.bits - 1);
131 let mut starts = vec![[init; 6]; height];
132 let mut v = [init; 6];
133 for (r, st) in starts.iter_mut().enumerate() {
134 *st = v;
135 for c in (0..clrs).filter(|&c| c == 0 || c > sraw) {
136 v[c] = v[c].wrapping_add(diffs.get(r * rl + c));
137 }
138 }
139 let rows_per_task = height.div_ceil(par::threads().max(1) * 4).max(1);
140 let failed = std::sync::atomic::AtomicBool::new(false);
141 par::for_each_row_chunk(&mut frame[..total], rl, rows_per_task, true, |r0, rows| {
142 let mut buf = vec![0u16; rl];
143 for (i, row) in rows.chunks_exact_mut(rl).enumerate() {
144 let r = r0 + i;
145 diffs.copy_to(r * rl, &mut buf);
146 let mut vpred = starts[r];
147 let mut k = 0usize;
148 let next = |_c: usize| {
149 let d = buf[k] as i16 as i32;
150 k += 1;
151 Ok(d)
152 };
153 if crate::ljpeg::reconstruct_row(hdr, next, row, &[], 0, clrs, &mut vpred).is_err() {
155 failed.store(true, std::sync::atomic::Ordering::Relaxed);
156 }
157 }
158 });
159 return Ok(!failed.into_inner());
160 }
161 if hdr.sraw == 0 && (2..=7).contains(&hdr.predictor) && height > 1 {
162 let rows_per_task = height.div_ceil(par::threads().max(1) * 4).max(1);
165 par::for_each_row_chunk(&mut frame[..total], rl, rows_per_task, true, |r0, rows| {
166 diffs.copy_to(r0 * rl, rows);
167 });
168 rebuild_2d(hdr, &mut frame[..total], rl);
169 return Ok(true);
170 }
171 if hdr.predictor != 1 || hdr.sraw != 0 || clrs > 4 {
172 let init = 1u16 << (hdr.bits - 1);
176 let mut vpred = [init; 6];
177 let mut buf = vec![0u16; rl];
178 for r in 0..height {
179 diffs.copy_to(r * rl, &mut buf);
180 let (done, rest) = frame.split_at_mut(r * rl);
181 let prev = if r > 0 { &done[(r - 1) * rl..] } else { &[][..] };
182 let mut k = 0usize;
183 let next = |_c: usize| {
184 let d = buf[k] as i16 as i32;
186 k += 1;
187 Ok(d)
188 };
189 crate::ljpeg::reconstruct_row(hdr, next, &mut rest[..rl], prev, r, clrs, &mut vpred)?;
190 }
191 return Ok(true);
192 }
193 let init = 1u16 << (hdr.bits - 1);
196 let mut starts = vec![0u16; height * clrs];
197 let mut v = [init; 4];
198 for (r, s) in starts.chunks_exact_mut(clrs).enumerate() {
199 for c in 0..clrs {
200 v[c] = v[c].wrapping_add(diffs.get(r * rl + c));
201 s[c] = v[c];
202 }
203 }
204 let rows_per_task = height.div_ceil(par::threads().max(1) * 4).max(1);
205 par::for_each_row_chunk(&mut frame[..total], rl, rows_per_task, true, |r0, rows| {
206 for (i, row) in rows.chunks_exact_mut(rl).enumerate() {
207 let r = r0 + i;
208 diffs.copy_to(r * rl, row);
209 row[..clrs].copy_from_slice(&starts[r * clrs..(r + 1) * clrs]);
210 match clrs {
211 1 => prefix::<1>(row),
212 2 => prefix::<2>(row),
213 3 => prefix::<3>(row),
214 _ => prefix::<4>(row),
215 }
216 }
217 });
218 Ok(true)
219}
220
221pub(crate) fn decode_frame_restarts(data: &[u8], hdr: &LjpegHeader, rows: usize, frame: &mut [u16]) -> Result<bool> {
227 let rl = hdr.row_len();
228 let rows = rows.min(hdr.height as usize);
229 let total = rl.checked_mul(rows).ok_or_else(|| Error::corrupt("lossless JPEG: frame too large"))?;
230 let fast = crate::ljpeg::fast_rows(hdr);
231 let restart = hdr.restart_interval as usize;
232 let clrs = hdr.clrs as usize;
233 if restart == 0 || rl == 0 || clrs == 0 || clrs > 6 || frame.len() < total || !(fast || hdr.predictor == 1) {
234 return Ok(false);
235 }
236 let width = hdr.width as usize;
238 let starts: Vec<usize> = (0..rows).filter(|&r| (r * width) % restart == 0).collect();
239 if starts.len() < 2 {
240 return Ok(false);
241 }
242 let Some(scan) = data.get(hdr.scan_offset..) else { return Ok(false) };
243 let un = crate::ljpeg::unstuff_scan(scan, true);
244 if un.segments.len() < starts.len() {
245 return Ok(false);
246 }
247 let bounds: Vec<(usize, usize)> = starts
248 .iter()
249 .zip(starts.iter().skip(1).chain(std::iter::once(&rows)))
250 .map(|(&a, &b)| (a * rl, b * rl))
251 .collect();
252 let Some(parts) = par::split_disjoint(&mut frame[..total], &bounds) else { return Ok(false) };
253 let init = 1u16 << (hdr.bits - 1);
254 let ok = par::map(parts.into_iter().enumerate().collect(), true, |(k, part): (usize, &mut [u16])| {
255 let mut bits = BitPumpMsb::new(un.segment(k));
256 let mut vpred = [init; 6];
257 let zeros = if fast { Vec::new() } else { vec![0u16; rl] };
259 let mut rest = part;
260 let mut jrow = starts[k];
261 while !rest.is_empty() {
262 let (row, tail) = std::mem::take(&mut rest).split_at_mut(rl);
263 if crate::ljpeg::decode_row(hdr, fast, &mut bits, row, &zeros, jrow, &mut vpred).is_err() {
264 return false;
265 }
266 rest = tail;
267 jrow += 1;
268 }
269 true
270 });
271 Ok(ok.into_iter().all(|v| v))
272}
273
274fn rebuild_2d(hdr: &LjpegHeader, frame: &mut [u16], rl: usize) {
281 match hdr.predictor {
282 2 => rebuild_2d_psv::<2>(hdr, frame, rl),
283 3 => rebuild_2d_psv::<3>(hdr, frame, rl),
284 4 => rebuild_2d_psv::<4>(hdr, frame, rl),
285 5 => rebuild_2d_psv::<5>(hdr, frame, rl),
286 6 => rebuild_2d_psv::<6>(hdr, frame, rl),
287 _ => rebuild_2d_psv::<7>(hdr, frame, rl),
288 }
289}
290
291fn rebuild_2d_psv<const PSV: u32>(hdr: &LjpegHeader, frame: &mut [u16], rl: usize) {
292 let clrs = hdr.clrs as usize;
293 let init = 1u16 << (hdr.bits - 1);
294 let (row0, rest) = frame.split_at_mut(rl);
295 for c in 0..clrs {
296 row0[c] = init.wrapping_add(row0[c]);
297 }
298 for i in clrs..rl {
299 row0[i] = row0[i - clrs].wrapping_add(row0[i]);
300 }
301 let geo = par::Wavefront { row_len: rl, halo: 1, margin: clrs, block: block_width(rl, clrs) };
303 par::wavefront(rest, row0, geo, true, |_, band, above, lo, a, b| {
304 let mut prev: &[u16] = above;
305 for row in band.chunks_exact_mut(rl) {
306 let cur = &mut row[lo..b];
307 rebuild_window::<PSV>(cur, prev, a - lo, clrs);
308 prev = cur;
309 }
310 });
311}
312
313fn block_width(rl: usize, clrs: usize) -> usize {
315 (rl / clrs).div_ceil(4 * par::threads().max(1)).max(64) * clrs
316}
317
318#[inline(always)]
321fn rebuild_window<const PSV: u32>(cur: &mut [u16], prev: &[u16], start: usize, clrs: usize) {
322 let n = cur.len().min(prev.len());
323 let (cur, prev) = (&mut cur[..n], &prev[..n]);
324 let mut i = start;
325 if start == 0 {
326 while i < clrs.min(n) {
328 cur[i] = prev[i].wrapping_add(cur[i]);
329 i += 1;
330 }
331 }
332 if i >= n {
333 return;
334 }
335 match PSV {
336 2 => {
337 for (c, &p) in cur[i..].iter_mut().zip(&prev[i..]) {
338 *c = p.wrapping_add(*c);
339 }
340 }
341 3 => {
342 for (c, &p) in cur[i..].iter_mut().zip(&prev[i - clrs..]) {
343 *c = p.wrapping_add(*c);
344 }
345 }
346 _ => {
347 for i in i..n {
348 let (ra, rb, rc) = (cur[i - clrs] as i32, prev[i] as i32, prev[i - clrs] as i32);
349 let pred = match PSV {
350 4 => ra + rb - rc,
351 5 => ra + ((rb - rc) >> 1),
352 6 => rb + ((ra - rc) >> 1),
353 _ => (ra + rb) >> 1,
354 };
355 cur[i] = (pred as u16).wrapping_add(cur[i]);
356 }
357 }
358 }
359}
360
361fn phase_period(ids: &[u8]) -> usize {
363 let n = ids.len().max(1);
364 (1..=n).find(|&p| n % p == 0 && (0..n).all(|i| ids[i] == ids[i % p])).unwrap_or(n)
365}
366
367#[inline(always)]
368fn prefix<const N: usize>(row: &mut [u16]) {
369 let mut p: [u16; N] = std::array::from_fn(|c| row[c]);
370 for px in row[N..].chunks_exact_mut(N) {
371 for c in 0..N {
372 p[c] = p[c].wrapping_add(px[c]);
373 px[c] = p[c];
374 }
375 }
376}
377
378#[cfg(test)]
379mod tests {
380 use super::*;
381 use crate::ljpeg::{self, LjpegOptions, encoder::encode};
382
383 fn pseudo(n: usize, bits: u32, seed: u32) -> Vec<u16> {
384 let mut x = seed;
385 let mut v = 1u32 << (bits - 1);
386 (0..n)
387 .map(|_| {
388 x = x.wrapping_mul(1103515245).wrapping_add(12345);
389 let step = ((x >> 16) & 0xff) as i32 - 128;
391 let step = if (x >> 8) & 31 == 0 { step * 40 } else { step / 8 };
392 v = (v as i32 + step).clamp(0, (1 << bits) - 1) as u32;
393 v as u16
394 })
395 .collect()
396 }
397
398 fn sequential(data: &[u8], hdr: &LjpegHeader) -> Vec<u16> {
399 let mut out = Vec::new();
400 ljpeg::decode_rows(data, hdr, |_, r| {
401 out.extend_from_slice(r);
402 Ok(())
403 })
404 .unwrap();
405 out
406 }
407
408 #[test]
409 fn matches_sequential_for_many_chunkings() {
410 let cases = [(1usize, 12u32, 1u32), (2, 14, 1), (3, 12, 1), (4, 14, 1), (2, 14, 6), (1, 12, 7)];
411 let cases = cases.into_iter().chain((2..=5).map(|p| (2, 14, p)));
412 for (comps, bits, psv) in cases {
413 let (w, h) = (97usize, 61usize);
414 let samples = pseudo(w * h * comps, bits, comps as u32 * 7 + psv);
415 let enc = encode(w, h, comps, bits, psv, &samples);
416 let hdr = LjpegHeader::parse(&enc, LjpegOptions::default()).unwrap();
417 let want = sequential(&enc, &hdr);
418 assert_eq!(want, samples);
419 for chunk in [7usize, 64, 333, 1000, 5000, 1 << 20] {
420 let mut frame = vec![0u16; want.len()];
421 let ok = decode_frame_chunked(&enc, &hdr, hdr.height as usize, &mut frame, Some(chunk)).unwrap();
422 assert!(ok, "comps {comps} psv {psv} chunk {chunk}: no synchronisation");
423 assert_eq!(frame, want, "comps {comps} psv {psv} chunk {chunk}");
424 }
425 }
426 }
427
428 #[test]
429 fn truncated_stream_is_left_to_the_sequential_decoder() {
430 let (w, h) = (64usize, 40usize);
431 let samples = pseudo(w * h * 2, 14, 3);
432 let enc = encode(w, h, 2, 14, 1, &samples);
433 let hdr = LjpegHeader::parse(&enc, LjpegOptions::default()).unwrap();
434 let cut = &enc[..hdr.scan_offset + (enc.len() - hdr.scan_offset) / 2];
435 let mut frame = vec![0u16; w * h * 2];
436 assert!(!decode_frame_chunked(cut, &hdr, hdr.height as usize, &mut frame, Some(100)).unwrap());
437 }
438
439 #[test]
440 fn wavefront_rebuild_matches_sequential() {
441 for (w, h) in [(700usize, 61usize), (300, 2), (129, 5)] {
443 for comps in 1..=4 {
444 for psv in 2..=7 {
445 let samples = pseudo(w * h * comps, 16, comps as u32 * 3 + psv);
446 let enc = encode(w, h, comps, 16, psv, &samples);
447 let hdr = LjpegHeader::parse(&enc, LjpegOptions::default()).unwrap();
448 let want = sequential(&enc, &hdr);
449 assert_eq!(want, samples);
450 let mut frame = vec![0u16; want.len()];
451 let ok = decode_frame_chunked(&enc, &hdr, h, &mut frame, Some(500)).unwrap();
452 assert!(ok, "{w}x{h} comps {comps} psv {psv}");
453 assert_eq!(frame, want, "{w}x{h} comps {comps} psv {psv}");
454 }
455 }
456 }
457 }
458
459 #[test]
460 fn restart_intervals_match_sequential() {
461 let (w, h) = (53usize, 61usize);
462 for comps in 1..=4 {
463 for psv in 1..=7u32 {
464 for rows_per_interval in [1usize, 3, 8] {
466 let samples = pseudo(w * h * comps, 14, comps as u32 * 13 + psv);
467 let enc =
468 ljpeg::encoder::encode_with_restarts(w, h, comps, 14, psv, &samples, w * rows_per_interval);
469 let hdr = LjpegHeader::parse(&enc, LjpegOptions::default()).unwrap();
470 assert_eq!(hdr.restart_interval as usize, w * rows_per_interval);
471 let want = sequential(&enc, &hdr);
472 assert_eq!(want, samples, "comps {comps} psv {psv} interval {rows_per_interval}");
473 let mut frame = vec![0u16; want.len()];
474 let ok = decode_frame_restarts(&enc, &hdr, h, &mut frame).unwrap();
475 assert_eq!(ok, psv == 1, "comps {comps} psv {psv}");
477 if ok {
478 assert_eq!(frame, want, "comps {comps} interval {rows_per_interval}");
479 let mut part = vec![0u16; 20 * w * comps];
481 assert!(decode_frame_restarts(&enc, &hdr, 20, &mut part).unwrap());
482 assert_eq!(part[..], want[..part.len()]);
483 }
484 let mut via_rows = Vec::new();
485 ljpeg::decode_rows_par(&enc, &hdr, true, |_, r| {
486 via_rows.extend_from_slice(r);
487 Ok(())
488 })
489 .unwrap();
490 assert_eq!(via_rows, want);
491 }
492 }
493 }
494 }
495
496 #[test]
497 fn damaged_restart_interval_is_left_to_the_sequential_decoder() {
498 let (w, h) = (64usize, 48usize);
499 let samples = pseudo(w * h * 2, 12, 5);
500 let enc = ljpeg::encoder::encode_with_restarts(w, h, 2, 12, 1, &samples, w * 4);
501 let hdr = LjpegHeader::parse(&enc, LjpegOptions::default()).unwrap();
502 let rst: Vec<usize> = (hdr.scan_offset..enc.len() - 1)
503 .filter(|&i| enc[i] == 0xFF && (0xD0..=0xD7).contains(&enc[i + 1]))
504 .collect();
505 assert_eq!(rst.len(), h / 4 - 1);
506 let mut cut = enc[..(rst[3] + rst[4]) / 2].to_vec();
508 cut.extend_from_slice(&enc[rst[4]..]);
509 let mut frame = vec![0u16; w * h * 2];
510 assert!(!decode_frame_restarts(&cut, &hdr, h, &mut frame).unwrap());
511 assert!(ljpeg::decode_rows_par(&cut, &hdr, true, |_, _| Ok(())).is_err());
512 let mut merged = enc[..rst[2]].to_vec();
514 merged.extend_from_slice(&enc[rst[2] + 2..]);
515 assert!(!decode_frame_restarts(&merged, &hdr, h, &mut frame).unwrap());
516 let seq = ljpeg::decode_rows(&merged, &hdr, |_, _| Ok(()));
517 let par = ljpeg::decode_rows_par(&merged, &hdr, true, |_, _| Ok(()));
518 assert_eq!(seq.is_err(), par.is_err());
519 }
520
521 #[test]
522 fn phase_periods() {
523 assert_eq!(phase_period(&[0]), 1);
524 assert_eq!(phase_period(&[0, 0]), 1);
525 assert_eq!(phase_period(&[0, 1]), 2);
526 assert_eq!(phase_period(&[0, 1, 0, 1]), 2);
527 assert_eq!(phase_period(&[0, 1, 1]), 3);
528 }
529}