Skip to main content
← PSoXide SDK guides and examples · SDK f2fec1c301f1 · All Cargo features enabled; check feature gates before use.

psx_fmv/
bitstream.rs

1// SPDX-License-Identifier: GPL-2.0-or-later
2//! BS ("bitstream") frame decode: variable-length codes to MDEC run-length
3//! halfwords.
4//!
5//! A BS frame starts with an 8-byte header:
6//!
7//! | Bytes | Field |
8//! |-------|-------|
9//! | 0..2  | MDEC data size in 32-bit words (low half of the MDEC command) |
10//! | 2..4  | `0x3800` (high half of a 15bpp decode command) |
11//! | 4..6  | quantization scale, 1..63 |
12//! | 6..8  | bitstream version (1, 2 or 3) |
13//!
14//! The body is read as little-endian 16-bit words, most significant bit
15//! first. Macroblocks come in column-major order (top to bottom, then left
16//! to right), six 8x8 blocks each: Cr, Cb, Y0..Y3. In versions 1 and 2 every
17//! block starts with a raw 10-bit signed DC value (`0x1FF` there ends the
18//! frame), followed by the AC run/level codes of the MPEG-1 DCT
19//! coefficient table (ISO 11172-2 table B.5c, with the sign bit after the
20//! code), a 6-bit escape `000001` followed by a raw 16-bit MDEC halfword,
21//! and `10` for end of block.
22//!
23//! The MDEC wants, per block, `(qscale << 10) | dc` then one halfword per
24//! non-zero AC coefficient (`run << 10 | level`, level 10-bit signed) and
25//! `0xFE00` to end the block. The same `0xFE00` pads the tail.
26//!
27//! The code table is the one every BS encoder uses; the listing here was
28//! cross-checked against psxavenc's encoder table (zlib license) and the
29//! PSX-SPX description.
30
31/// Fixed BS frame header size in bytes.
32pub const HEADER_BYTES: usize = 8;
33/// MDEC end-of-block / padding halfword.
34pub const END_OF_BLOCK: u16 = 0xFE00;
35/// Version-2 DC value that ends the frame.
36const V2_END_OF_FRAME: u32 = 0x1FF;
37
38/// Why a frame could not be decoded.
39#[derive(Clone, Copy, Debug, PartialEq, Eq)]
40pub enum DecodeError {
41    /// Shorter than the 8-byte header.
42    Truncated,
43    /// Bitstream version other than 1 or 2.
44    Version(u16),
45    /// A bit pattern that is not in the code table.
46    BadCode,
47    /// The output buffer is too small for the frame.
48    OutputFull,
49    /// The decoder ran past the end of the input.
50    Overrun,
51}
52
53/// Parsed frame header.
54#[derive(Clone, Copy, Debug, PartialEq, Eq)]
55pub struct Header {
56    /// MDEC data size the encoder announced, in 32-bit words.
57    pub mdec_words: u16,
58    /// Quantization scale.
59    pub qscale: u16,
60    /// Bitstream version.
61    pub version: u16,
62}
63
64impl Header {
65    /// Parse the 8-byte header.
66    pub fn parse(frame: &[u8]) -> Result<Self, DecodeError> {
67        if frame.len() < HEADER_BYTES {
68            return Err(DecodeError::Truncated);
69        }
70        let h = |i: usize| u16::from_le_bytes([frame[i], frame[i + 1]]);
71        Ok(Header {
72            mdec_words: h(0),
73            qscale: h(4),
74            version: h(6),
75        })
76    }
77}
78
79// Table entry layout: bits 0..16 MDEC halfword (positive level), 16..21 code
80// length (without the sign bit), 24..27 kind.
81const KIND_INVALID: u32 = 0;
82const KIND_CODE: u32 = 1;
83const KIND_ESCAPE: u32 = 2;
84const KIND_EOB: u32 = 3;
85const KIND_LONG: u32 = 4;
86
87const fn entry(kind: u32, len: u32, hw: u32) -> u32 {
88    (kind << 24) | (len << 16) | hw
89}
90
91/// (code length without sign, code, run, level) for every AC code.
92/// `11` (run 0, level 1) and the end-of-block `10` share the top level.
93const AC_CODES: [(u8, u16, u8, u8); 111] = [
94    (2, 0x3, 0, 1),
95    (3, 0x3, 1, 1),
96    (4, 0x4, 0, 2),
97    (4, 0x5, 2, 1),
98    (5, 0x05, 0, 3),
99    (5, 0x06, 4, 1),
100    (5, 0x07, 3, 1),
101    (6, 0x04, 7, 1),
102    (6, 0x05, 6, 1),
103    (6, 0x06, 1, 2),
104    (6, 0x07, 5, 1),
105    (7, 0x04, 2, 2),
106    (7, 0x05, 9, 1),
107    (7, 0x06, 0, 4),
108    (7, 0x07, 8, 1),
109    (8, 0x20, 13, 1),
110    (8, 0x21, 0, 6),
111    (8, 0x22, 12, 1),
112    (8, 0x23, 11, 1),
113    (8, 0x24, 3, 2),
114    (8, 0x25, 1, 3),
115    (8, 0x26, 0, 5),
116    (8, 0x27, 10, 1),
117    (10, 0x008, 16, 1),
118    (10, 0x009, 5, 2),
119    (10, 0x00A, 0, 7),
120    (10, 0x00B, 2, 3),
121    (10, 0x00C, 1, 4),
122    (10, 0x00D, 15, 1),
123    (10, 0x00E, 14, 1),
124    (10, 0x00F, 4, 2),
125    (12, 0x010, 0, 11),
126    (12, 0x011, 8, 2),
127    (12, 0x012, 4, 3),
128    (12, 0x013, 0, 10),
129    (12, 0x014, 2, 4),
130    (12, 0x015, 7, 2),
131    (12, 0x016, 21, 1),
132    (12, 0x017, 20, 1),
133    (12, 0x018, 0, 9),
134    (12, 0x019, 19, 1),
135    (12, 0x01A, 18, 1),
136    (12, 0x01B, 1, 5),
137    (12, 0x01C, 3, 3),
138    (12, 0x01D, 0, 8),
139    (12, 0x01E, 6, 2),
140    (12, 0x01F, 17, 1),
141    (13, 0x0010, 10, 2),
142    (13, 0x0011, 9, 2),
143    (13, 0x0012, 5, 3),
144    (13, 0x0013, 3, 4),
145    (13, 0x0014, 2, 5),
146    (13, 0x0015, 1, 7),
147    (13, 0x0016, 1, 6),
148    (13, 0x0017, 0, 15),
149    (13, 0x0018, 0, 14),
150    (13, 0x0019, 0, 13),
151    (13, 0x001A, 0, 12),
152    (13, 0x001B, 26, 1),
153    (13, 0x001C, 25, 1),
154    (13, 0x001D, 24, 1),
155    (13, 0x001E, 23, 1),
156    (13, 0x001F, 22, 1),
157    (14, 0x0010, 0, 31),
158    (14, 0x0011, 0, 30),
159    (14, 0x0012, 0, 29),
160    (14, 0x0013, 0, 28),
161    (14, 0x0014, 0, 27),
162    (14, 0x0015, 0, 26),
163    (14, 0x0016, 0, 25),
164    (14, 0x0017, 0, 24),
165    (14, 0x0018, 0, 23),
166    (14, 0x0019, 0, 22),
167    (14, 0x001A, 0, 21),
168    (14, 0x001B, 0, 20),
169    (14, 0x001C, 0, 19),
170    (14, 0x001D, 0, 18),
171    (14, 0x001E, 0, 17),
172    (14, 0x001F, 0, 16),
173    (15, 0x0010, 0, 40),
174    (15, 0x0011, 0, 39),
175    (15, 0x0012, 0, 38),
176    (15, 0x0013, 0, 37),
177    (15, 0x0014, 0, 36),
178    (15, 0x0015, 0, 35),
179    (15, 0x0016, 0, 34),
180    (15, 0x0017, 0, 33),
181    (15, 0x0018, 0, 32),
182    (15, 0x0019, 1, 14),
183    (15, 0x001A, 1, 13),
184    (15, 0x001B, 1, 12),
185    (15, 0x001C, 1, 11),
186    (15, 0x001D, 1, 10),
187    (15, 0x001E, 1, 9),
188    (15, 0x001F, 1, 8),
189    (16, 0x0010, 1, 18),
190    (16, 0x0011, 1, 17),
191    (16, 0x0012, 1, 16),
192    (16, 0x0013, 1, 15),
193    (16, 0x0014, 6, 3),
194    (16, 0x0015, 16, 2),
195    (16, 0x0016, 15, 2),
196    (16, 0x0017, 14, 2),
197    (16, 0x0018, 13, 2),
198    (16, 0x0019, 12, 2),
199    (16, 0x001A, 11, 2),
200    (16, 0x001B, 31, 1),
201    (16, 0x001C, 30, 1),
202    (16, 0x001D, 29, 1),
203    (16, 0x001E, 28, 1),
204    (16, 0x001F, 27, 1),
205];
206
207/// First-level table, indexed by the next 8 bits. Covers every code of up
208/// to 8 bits, the escape prefix, end of block, and routes codes with 6 or
209/// more leading zeros to [`LONG`].
210static SHORT: [u32; 256] = build_short();
211/// Second level for codes with `lz` = 6..=11 leading zeros, indexed by
212/// `(lz - 6) * 16` plus the 4 bits after the first one bit (lz 6 codes
213/// have 3 such bits and fill two slots each).
214static LONG: [u32; 96] = build_long();
215
216const fn build_short() -> [u32; 256] {
217    let mut t = [entry(KIND_INVALID, 0, 0); 256];
218    // End of block `10`.
219    let mut i = 0b1000_0000;
220    while i < 0b1100_0000 {
221        t[i] = entry(KIND_EOB, 2, 0);
222        i += 1;
223    }
224    // Escape `000001`.
225    let mut i = 0b0000_0100;
226    while i < 0b0000_1000 {
227        t[i] = entry(KIND_ESCAPE, 6, 0);
228        i += 1;
229    }
230    // Six or more leading zeros: second level.
231    let mut i = 0;
232    while i < 0b0000_0100 {
233        t[i] = entry(KIND_LONG, 0, 0);
234        i += 1;
235    }
236    let mut c = 0;
237    while c < AC_CODES.len() {
238        let (len, code, run, level) = AC_CODES[c];
239        if len <= 8 {
240            let shift = 8 - len as usize;
241            let base = (code as usize) << shift;
242            let mut k = 0;
243            while k < (1 << shift) {
244                t[base + k] = entry(KIND_CODE, len as u32, ((run as u32) << 10) | level as u32);
245                k += 1;
246            }
247        }
248        c += 1;
249    }
250    t
251}
252
253const fn build_long() -> [u32; 96] {
254    let mut t = [entry(KIND_INVALID, 0, 0); 96];
255    let mut c = 0;
256    while c < AC_CODES.len() {
257        let (len, code, run, level) = AC_CODES[c];
258        if len >= 10 {
259            let significant = 16 - code.leading_zeros(); // bits from the top one
260            let lz = len as u32 - significant;
261            let suffix_bits = significant - 1;
262            let suffix = (code as u32) & ((1 << suffix_bits) - 1);
263            let base = ((lz - 6) * 16) as usize;
264            let hw = ((run as u32) << 10) | level as u32;
265            // Index by the 4 bits after the one bit; shorter suffixes fill
266            // every slot that shares their prefix.
267            let pad = 4 - suffix_bits;
268            let first = (suffix << pad) as usize;
269            let mut k = 0;
270            while k < (1 << pad) {
271                t[base + first + k] = entry(KIND_CODE, len as u32, hw);
272                k += 1;
273            }
274        }
275        c += 1;
276    }
277    t
278}
279
280/// Entry of [`FAST`], the table the decode loop uses: bit 31 set routes to
281/// [`SHORT`]'s slower kinds (end of block, escape, long codes, invalid);
282/// clear, bits 0..16 are the MDEC halfword for a positive level and bits
283/// 16..21 the code length plus its sign bit.
284static FAST: [u32; 256] = build_fast();
285
286const fn build_fast() -> [u32; 256] {
287    let mut t = [0u32; 256];
288    let mut i = 0;
289    while i < 256 {
290        let e = SHORT[i];
291        t[i] = if e >> 24 == KIND_CODE {
292            ((((e >> 16) & 0x1F) + 1) << 16) | (e & 0xFFFF)
293        } else {
294            0x8000_0000
295        };
296        i += 1;
297    }
298    t
299}
300
301/// MSB-first reader over the frame body's little-endian 16-bit words, as
302/// plain values so the decode loop keeps all of it in registers.
303///
304/// `ALIGNED` reads whole halfwords (one `lhu` on the R3000); a streaming
305/// player's frame buffers are always word aligned, and the byte path only
306/// exists so a caller's odd-addressed slice still decodes.
307#[derive(Clone, Copy)]
308struct Bits<const ALIGNED: bool> {
309    /// Next halfword to load, and one past the last whole halfword (a
310    /// trailing odd byte reads as zero).
311    p: *const u8,
312    end: *const u8,
313    /// Pending bits, left-aligned.
314    buf: u32,
315    /// Valid bits in `buf`.
316    avail: u32,
317}
318
319impl<const ALIGNED: bool> Bits<ALIGNED> {
320    fn new(data: &[u8]) -> Self {
321        let p = data.as_ptr();
322        let mut b = Bits {
323            p,
324            end: p.wrapping_add(data.len() & !1),
325            buf: 0,
326            avail: 0,
327        };
328        b.refill();
329        b
330    }
331
332    /// Top up to at least 17 valid bits. Reads past the end yield zeros;
333    /// the caller's overrun check reports it.
334    #[inline(always)]
335    fn refill(&mut self) {
336        while self.avail <= 16 {
337            let hw = if self.p < self.end {
338                // SAFETY: `p` is below `end`, so both bytes are in the slice;
339                // the aligned path is taken only for a 2-aligned start.
340                unsafe {
341                    if ALIGNED {
342                        u32::from(u16::from_le((self.p as *const u16).read()))
343                    } else {
344                        u32::from(*self.p) | u32::from(*self.p.add(1)) << 8
345                    }
346                }
347            } else {
348                0
349            };
350            self.p = self.p.wrapping_add(2);
351            self.buf |= hw << (16 - self.avail);
352            self.avail += 16;
353        }
354    }
355
356    #[inline(always)]
357    fn skip(&mut self, n: u32) {
358        self.buf <<= n;
359        self.avail -= n;
360        self.refill();
361    }
362
363    /// Read `n` (1..=16) bits.
364    #[inline(always)]
365    fn read(&mut self, n: u32) -> u32 {
366        let v = self.buf >> (32 - n);
367        self.skip(n);
368        v
369    }
370}
371
372/// Decode one version-1 or version-2 BS frame (header included) into MDEC
373/// halfwords. The two versions code the bitstream the same way: version 1
374/// is what the earliest (1995) Sony encoder wrote, WipEout's intro among
375/// them.
376///
377/// Stops at the end-of-frame code or after `max_macroblocks`, whichever
378/// comes first, then pads the output with [`END_OF_BLOCK`] to a multiple of
379/// 64 halfwords (32-word DMA blocks) and at least up to the size the header
380/// announced. Returns the number of 32-bit words to send.
381///
382/// `pump` runs after every `pump_every` macroblocks (one column when set to
383/// `height / 16`). A streaming player drains CD sectors there so the drive
384/// never runs ahead of the decoder.
385pub fn decode_frame(
386    frame: &[u8],
387    out: &mut [u16],
388    max_macroblocks: u32,
389    pump_every: u32,
390    pump: &mut impl FnMut(),
391) -> Result<usize, DecodeError> {
392    let header = Header::parse(frame)?;
393    if !(1..=2).contains(&header.version) {
394        return Err(DecodeError::Version(header.version));
395    }
396    let body = &frame[HEADER_BYTES..];
397    let mut pump = || cold_pump(pump);
398    let n = if (body.as_ptr() as usize).is_multiple_of(2) {
399        decode_body::<true>(
400            body,
401            header.qscale,
402            out,
403            max_macroblocks,
404            pump_every,
405            &mut pump,
406        )?
407    } else {
408        decode_body::<false>(
409            body,
410            header.qscale,
411            out,
412            max_macroblocks,
413            pump_every,
414            &mut pump,
415        )?
416    };
417
418    let announced = header.mdec_words as usize * 2;
419    let mut padded = (n + 63) & !63;
420    if padded < announced {
421        padded = (announced + 63) & !63;
422    }
423    if padded > out.len() {
424        return Err(DecodeError::OutputFull);
425    }
426    for slot in &mut out[n..padded] {
427        *slot = END_OF_BLOCK;
428    }
429    Ok(padded / 2)
430}
431
432/// The caller's pump, kept out of line so its code and registers stay out
433/// of the decode loop.
434#[cold]
435#[inline(never)]
436fn cold_pump(pump: &mut impl FnMut()) {
437    pump();
438}
439
440/// The macroblock loop of [`decode_frame`]; returns the halfwords written.
441///
442/// This is the per-frame hot path of a player on a 33 MHz R3000 without a
443/// data cache, where every spilled register costs a RAM access. So the state
444/// is a handful of plain locals (bit buffer, input and output cursors), the
445/// common code costs one table load with its sign folded into the same
446/// shift, and the output has one bound check per halfword.
447#[inline(never)]
448fn decode_body<const ALIGNED: bool>(
449    body: &[u8],
450    qscale: u16,
451    out: &mut [u16],
452    max_macroblocks: u32,
453    pump_every: u32,
454    pump: &mut impl FnMut(),
455) -> Result<usize, DecodeError> {
456    let qscale = ((qscale as u32) & 0x3F) << 10;
457    let mut bits = Bits::<ALIGNED>::new(body);
458    // Past this, the reader has run more than the two look-ahead words off
459    // the end of the input.
460    let overrun = body.as_ptr().wrapping_add((body.len() + 4) & !1);
461    let o0 = out.as_mut_ptr();
462    let oend = o0.wrapping_add(out.len());
463    let mut o = o0;
464    let mut mb = 0u32;
465    let mut since_pump = 0u32;
466
467    // SAFETY (every write below): `o` only advances after a check that it is
468    // still below `oend`, one past the end of `out`.
469    'frame: while mb < max_macroblocks {
470        for block in 0..6 {
471            let dc = bits.read(10);
472            if dc == V2_END_OF_FRAME && block == 0 {
473                break 'frame;
474            }
475            if o == oend {
476                return Err(DecodeError::OutputFull);
477            }
478            // SAFETY: `o` is below `oend` (checked just above).
479            unsafe { o.write((qscale | dc) as u16) };
480            o = o.wrapping_add(1);
481            loop {
482                let e = FAST[(bits.buf >> 24) as usize];
483                let hw = if (e as i32) >= 0 {
484                    // A code of up to 8 bits, then its sign bit.
485                    let used = e >> 16;
486                    let sign = ((bits.buf << (used - 1)) as i32 >> 31) as u32;
487                    bits.skip(used);
488                    let level = ((e & 0x3FF) ^ sign).wrapping_sub(sign) & 0x3FF;
489                    (e & 0xFC00) | level
490                } else {
491                    match slow_code(&mut bits) {
492                        Ok(Some(hw)) => hw,
493                        Ok(None) => {
494                            if o == oend {
495                                return Err(DecodeError::OutputFull);
496                            }
497                            // SAFETY: `o` is below `oend` (checked just above).
498                            unsafe { o.write(END_OF_BLOCK) };
499                            o = o.wrapping_add(1);
500                            break;
501                        }
502                        Err(e) => return Err(e),
503                    }
504                };
505                if o == oend {
506                    return Err(DecodeError::OutputFull);
507                }
508                // SAFETY: `o` is below `oend` (checked just above).
509                unsafe { o.write(hw as u16) };
510                o = o.wrapping_add(1);
511            }
512            if bits.p > overrun {
513                return Err(DecodeError::Overrun);
514            }
515        }
516        mb += 1;
517        since_pump += 1;
518        if since_pump == pump_every {
519            since_pump = 0;
520            pump();
521        }
522    }
523    // SAFETY: `o` walked forward from `o0` inside `out`.
524    Ok(unsafe { o.offset_from(o0) } as usize)
525}
526
527/// The codes [`FAST`] does not cover: end of block (`None`), the escape,
528/// codes of 10 bits and more, and invalid ones. Inlined: an out-of-line call
529/// would take the bit reader's address and pin it to the stack.
530#[inline(always)]
531fn slow_code<const ALIGNED: bool>(bits: &mut Bits<ALIGNED>) -> Result<Option<u32>, DecodeError> {
532    match SHORT[(bits.buf >> 24) as usize] >> 24 {
533        KIND_EOB => {
534            bits.skip(2);
535            Ok(None)
536        }
537        KIND_ESCAPE => {
538            bits.skip(6);
539            Ok(Some(bits.read(16)))
540        }
541        KIND_LONG => {
542            let lz = bits.buf.leading_zeros();
543            if !(6..=11).contains(&lz) {
544                return Err(DecodeError::BadCode);
545            }
546            let next4 = (bits.buf << (lz + 1)) >> 28;
547            let e2 = LONG[((lz - 6) * 16 + next4) as usize];
548            if e2 >> 24 != KIND_CODE {
549                return Err(DecodeError::BadCode);
550            }
551            bits.skip((e2 >> 16) & 0x1F);
552            let negative = bits.read(1) != 0;
553            let hw = e2 & 0xFFFF;
554            Ok(Some(if negative {
555                (hw & 0xFC00) | ((0u32.wrapping_sub(hw & 0x3FF)) & 0x3FF)
556            } else {
557                hw
558            }))
559        }
560        _ => Err(DecodeError::BadCode),
561    }
562}
563
564#[cfg(test)]
565mod tests {
566    extern crate std;
567    use super::*;
568
569    /// The decoder as it was before the R3000 rewrite, kept as the oracle
570    /// the rewrite must match halfword for halfword.
571    mod reference {
572        use super::super::*;
573
574        struct Bits<'a> {
575            data: &'a [u8],
576            pos: usize,
577            buf: u32,
578            avail: u32,
579        }
580
581        impl<'a> Bits<'a> {
582            fn new(data: &'a [u8]) -> Self {
583                let mut b = Bits {
584                    data,
585                    pos: 0,
586                    buf: 0,
587                    avail: 0,
588                };
589                b.refill();
590                b
591            }
592            fn refill(&mut self) {
593                while self.avail <= 16 {
594                    let hw = if self.pos + 1 < self.data.len() {
595                        self.data[self.pos] as u32 | (self.data[self.pos + 1] as u32) << 8
596                    } else {
597                        0
598                    };
599                    self.pos += 2;
600                    self.buf |= hw << (16 - self.avail);
601                    self.avail += 16;
602                }
603            }
604            fn skip(&mut self, n: u32) {
605                self.buf <<= n;
606                self.avail -= n;
607                self.refill();
608            }
609            fn read(&mut self, n: u32) -> u32 {
610                let v = self.buf >> (32 - n);
611                self.skip(n);
612                v
613            }
614            fn overrun(&self) -> bool {
615                self.pos > self.data.len() + 4
616            }
617        }
618
619        pub fn decode_frame(
620            frame: &[u8],
621            out: &mut [u16],
622            max_macroblocks: u32,
623        ) -> Result<usize, DecodeError> {
624            let header = Header::parse(frame)?;
625            if !(1..=2).contains(&header.version) {
626                return Err(DecodeError::Version(header.version));
627            }
628            let qscale = ((header.qscale as u32) & 0x3F) << 10;
629            let mut bits = Bits::new(&frame[HEADER_BYTES..]);
630            let mut n = 0usize;
631            let mut mb = 0u32;
632            'frame: while mb < max_macroblocks {
633                for block in 0..6 {
634                    let dc = bits.read(10);
635                    if dc == V2_END_OF_FRAME && block == 0 {
636                        break 'frame;
637                    }
638                    if n >= out.len() {
639                        return Err(DecodeError::OutputFull);
640                    }
641                    out[n] = (qscale | dc) as u16;
642                    n += 1;
643                    loop {
644                        let e = SHORT[(bits.buf >> 24) as usize];
645                        let (len, hw) = match e >> 24 {
646                            KIND_EOB => {
647                                bits.skip(2);
648                                if n >= out.len() {
649                                    return Err(DecodeError::OutputFull);
650                                }
651                                out[n] = END_OF_BLOCK;
652                                n += 1;
653                                break;
654                            }
655                            KIND_CODE => ((e >> 16) & 0x1F, e & 0xFFFF),
656                            KIND_ESCAPE => {
657                                bits.skip(6);
658                                let raw = bits.read(16);
659                                if n >= out.len() {
660                                    return Err(DecodeError::OutputFull);
661                                }
662                                out[n] = raw as u16;
663                                n += 1;
664                                continue;
665                            }
666                            KIND_LONG => {
667                                let lz = bits.buf.leading_zeros();
668                                if !(6..=11).contains(&lz) {
669                                    return Err(DecodeError::BadCode);
670                                }
671                                let next4 = (bits.buf << (lz + 1)) >> 28;
672                                let e2 = LONG[((lz - 6) * 16 + next4) as usize];
673                                if e2 >> 24 != KIND_CODE {
674                                    return Err(DecodeError::BadCode);
675                                }
676                                ((e2 >> 16) & 0x1F, e2 & 0xFFFF)
677                            }
678                            _ => return Err(DecodeError::BadCode),
679                        };
680                        bits.skip(len);
681                        let negative = bits.read(1) != 0;
682                        let hw = if negative {
683                            (hw & 0xFC00) | ((0u32.wrapping_sub(hw & 0x3FF)) & 0x3FF)
684                        } else {
685                            hw
686                        };
687                        if n >= out.len() {
688                            return Err(DecodeError::OutputFull);
689                        }
690                        out[n] = hw as u16;
691                        n += 1;
692                    }
693                    if bits.overrun() {
694                        return Err(DecodeError::Overrun);
695                    }
696                }
697                mb += 1;
698            }
699            let announced = header.mdec_words as usize * 2;
700            let mut padded = (n + 63) & !63;
701            if padded < announced {
702                padded = (announced + 63) & !63;
703            }
704            if padded > out.len() {
705                return Err(DecodeError::OutputFull);
706            }
707            for slot in &mut out[n..padded] {
708                *slot = END_OF_BLOCK;
709            }
710            Ok(padded / 2)
711        }
712    }
713
714    /// Both decoders on one input: same result, same halfwords.
715    fn same_as_reference(frame: &[u8], out_len: usize, mbs: u32) {
716        let mut a = std::vec![0u16; out_len];
717        let mut b = std::vec![0u16; out_len];
718        let ra = reference::decode_frame(frame, &mut a, mbs);
719        let rb = decode_frame(frame, &mut b, mbs, 1, &mut || {});
720        assert_eq!(ra, rb);
721        if let Ok(words) = ra {
722            assert_eq!(a[..words * 2], b[..words * 2]);
723        }
724    }
725
726    #[test]
727    fn rewrite_matches_reference_on_random_streams() {
728        // Random bodies hit every code, escape, long code, bad code, output
729        // bound and overrun; small xorshift so the test needs no crate.
730        let mut x = 0x2545_F491u32;
731        let mut next = || {
732            x ^= x << 13;
733            x ^= x >> 17;
734            x ^= x << 5;
735            x
736        };
737        // Miri is some orders slower; a few hundred streams still reach every path.
738        let cases = if cfg!(miri) { 150 } else { 4000 };
739        for case in 0..cases {
740            let body = 8 + (next() % 400) as usize;
741            let mut frame = std::vec![0u8; HEADER_BYTES + body];
742            frame[0..2].copy_from_slice(&((next() % 64) as u16).to_le_bytes());
743            frame[2..4].copy_from_slice(&0x3800u16.to_le_bytes());
744            frame[4..6].copy_from_slice(&((next() % 64) as u16).to_le_bytes());
745            frame[6..8].copy_from_slice(&2u16.to_le_bytes());
746            for byte in &mut frame[HEADER_BYTES..] {
747                // Bias towards zero bits so long codes and escapes show up.
748                *byte = (next() & next()) as u8;
749            }
750            let out_len = [64, 256, 4096][case % 3];
751            same_as_reference(&frame, out_len, 1 + next() % 8);
752            // The byte path, from an odd address.
753            let mut shifted = std::vec![0u8; frame.len() + 1];
754            shifted[1..].copy_from_slice(&frame);
755            same_as_reference(&shifted[1..], out_len, 4);
756        }
757    }
758
759    /// Every frame of a real movie, when `PSX_FMV_TEST_STR` names one: a
760    /// 2048-byte-sector `.str` (psxavenc `-t strv`) or one with 2336-byte
761    /// XA sectors (`-t str`, what `tools/fmv_test_movie.py` writes).
762    #[test]
763    fn rewrite_matches_reference_on_a_movie() {
764        let Some(path) = std::env::var_os("PSX_FMV_TEST_STR") else {
765            return;
766        };
767        let data = std::fs::read(path).unwrap();
768        let (size, skip) = if data.len() % 2336 == 0 && data.len() % 2048 != 0 {
769            (2336, 8)
770        } else {
771            (2048, 0)
772        };
773        let mut asm = crate::stream::FrameAssembler::new();
774        let mut buf = std::vec![0u32; 16 * 1024];
775        let mut frames = 0;
776        for sector in data.chunks_exact(size) {
777            let payload = &sector[skip..skip + 2048];
778            // SAFETY: a u32 buffer viewed as bytes, for the word alignment
779            // the device's slots have.
780            let bytes = unsafe {
781                core::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len() * 4)
782            };
783            if let Some(frame) = asm.add(payload, bytes) {
784                same_as_reference(&bytes[..frame.size as usize], 32 * 1024, 300);
785                frames += 1;
786            }
787        }
788        assert!(frames > 0, "no frames in the movie");
789        std::eprintln!("{frames} frames match");
790    }
791
792    /// MSB-first bit writer producing little-endian 16-bit words, the
793    /// layout the encoder emits.
794    struct Writer {
795        words: [u16; 64],
796        n: usize,
797        acc: u32,
798        used: u32,
799    }
800
801    impl Writer {
802        fn new() -> Self {
803            Writer {
804                words: [0; 64],
805                n: 0,
806                acc: 0,
807                used: 0,
808            }
809        }
810        fn put(&mut self, len: u32, value: u32) {
811            for i in (0..len).rev() {
812                self.acc = (self.acc << 1) | ((value >> i) & 1);
813                self.used += 1;
814                if self.used == 16 {
815                    self.words[self.n] = self.acc as u16;
816                    self.n += 1;
817                    self.acc = 0;
818                    self.used = 0;
819                }
820            }
821        }
822        fn frame(mut self, qscale: u16) -> ([u8; 136], usize) {
823            if self.used > 0 {
824                let pad = 16 - self.used;
825                self.put(pad, 0);
826            }
827            let mut out = [0u8; 136];
828            out[0..2].copy_from_slice(&0x0020u16.to_le_bytes());
829            out[2..4].copy_from_slice(&0x3800u16.to_le_bytes());
830            out[4..6].copy_from_slice(&qscale.to_le_bytes());
831            out[6..8].copy_from_slice(&2u16.to_le_bytes());
832            for i in 0..self.n {
833                out[8 + 2 * i..10 + 2 * i].copy_from_slice(&self.words[i].to_le_bytes());
834            }
835            (out, 8 + 2 * self.n)
836        }
837    }
838
839    fn decode(frame: &[u8], mbs: u32) -> ([u16; 256], usize) {
840        let mut out = [0u16; 256];
841        let words = decode_frame(frame, &mut out, mbs, 1, &mut || {}).unwrap();
842        (out, words)
843    }
844
845    #[test]
846    fn every_table_code_round_trips() {
847        // One macroblock: block 0 carries every code once (positive, then
848        // negative for odd entries), blocks 1..5 are DC + EOB.
849        let mut w = Writer::new();
850        w.put(10, 0x123);
851        for (i, &(len, code, _, _)) in AC_CODES.iter().enumerate().take(20) {
852            w.put(len as u32, code as u32);
853            w.put(1, (i & 1) as u32);
854        }
855        w.put(2, 0b10);
856        for _ in 1..6 {
857            w.put(10, 0x3FE); // DC -2
858            w.put(2, 0b10);
859        }
860        w.put(10, 0x1FF);
861        let (frame, len) = w.frame(5);
862        let (out, words) = decode(&frame[..len], 16);
863        assert_eq!(out[0], (5 << 10) | 0x123);
864        for (i, &(_, _, run, level)) in AC_CODES.iter().enumerate().take(20) {
865            let lv = if i & 1 == 1 {
866                (-(level as i32)) as u32 & 0x3FF
867            } else {
868                level as u32
869            };
870            assert_eq!(out[1 + i] as u32, ((run as u32) << 10) | lv, "code {i}");
871        }
872        assert_eq!(out[21], END_OF_BLOCK);
873        assert_eq!(out[22], (5 << 10) | 0x3FE);
874        assert_eq!(words, 32);
875        assert!(out[33..64].iter().all(|&h| h == END_OF_BLOCK));
876    }
877
878    #[test]
879    fn long_codes_and_escape_decode() {
880        let mut w = Writer::new();
881        w.put(10, 0);
882        // Every code of 10+ bits, alternating sign.
883        let long: [usize; 4] = [23, 31, 63, 110];
884        for (k, &i) in long.iter().enumerate() {
885            let (len, code, _, _) = AC_CODES[i];
886            w.put(len as u32, code as u32);
887            w.put(1, (k & 1) as u32);
888        }
889        w.put(6, 0b000001);
890        w.put(16, (40 << 10) | 0x155);
891        w.put(2, 0b10);
892        for _ in 1..6 {
893            w.put(10, 0);
894            w.put(2, 0b10);
895        }
896        let (frame, len) = w.frame(1);
897        let (out, _) = decode(&frame[..len], 1);
898        for (k, &i) in long.iter().enumerate() {
899            let (_, _, run, level) = AC_CODES[i];
900            let lv = if k & 1 == 1 {
901                (-(level as i32)) as u32 & 0x3FF
902            } else {
903                level as u32
904            };
905            assert_eq!(out[1 + k] as u32, ((run as u32) << 10) | lv, "entry {i}");
906        }
907        assert_eq!(out[5], (40 << 10) | 0x155);
908        assert_eq!(out[6], END_OF_BLOCK);
909    }
910
911    #[test]
912    fn version_1_decodes_like_version_2() {
913        let mut w = Writer::new();
914        for block in 0..6u32 {
915            w.put(10, 0x1F0 + block);
916            let (len, code, _, _) = AC_CODES[block as usize * 7];
917            w.put(len as u32, code as u32);
918            w.put(1, block & 1);
919            w.put(2, 0b10);
920        }
921        let (mut frame, len) = w.frame(3);
922        let v2 = decode(&frame[..len], 1);
923        frame[6..8].copy_from_slice(&1u16.to_le_bytes());
924        assert_eq!(decode(&frame[..len], 1), v2);
925    }
926
927    #[test]
928    fn table_is_prefix_free_and_complete() {
929        // Every AC code must land in exactly the slots it owns.
930        let mut seen = 0;
931        for &(len, code, run, level) in AC_CODES.iter() {
932            let hw = ((run as u32) << 10) | level as u32;
933            let e = if len <= 8 {
934                SHORT[(code as usize) << (8 - len)]
935            } else {
936                let significant = 16 - code.leading_zeros();
937                let lz = len as u32 - significant;
938                let suffix_bits = significant - 1;
939                let suffix = code as u32 & ((1 << suffix_bits) - 1);
940                LONG[((lz - 6) * 16 + (suffix << (4 - suffix_bits))) as usize]
941            };
942            assert_eq!(e & 0xFFFF, hw, "code len {len} value {code:#x}");
943            assert_eq!((e >> 16) & 0x1F, len as u32);
944            seen += 1;
945        }
946        assert_eq!(seen, 111);
947    }
948
949    #[test]
950    fn rejects_v3_and_short_input() {
951        assert_eq!(Header::parse(&[0; 4]), Err(DecodeError::Truncated));
952        let mut f = [0u8; 16];
953        f[6] = 3;
954        let mut out = [0u16; 64];
955        assert_eq!(
956            decode_frame(&f, &mut out, 1, 1, &mut || {}),
957            Err(DecodeError::Version(3))
958        );
959    }
960}