1#![allow(dead_code, clippy::needless_range_loop)]
8
9use super::h264::{
10 dequant_4x4, extract_rbsp, intra_16x16_predict, intra_4x4_predict, intra_chroma_predict,
11 inverse_transform_4x4, parse_avcc, parse_pps, parse_sps, split_annexb, split_avcc, BitReader,
12 Pps, Sps, NORM_ADJUST_4X4,
13};
14use super::h264_cabac::CabacEngine;
15use super::h264_slice::{parse_slice_header, PocState, PredWeightTable, SliceKind};
16use alloc::vec::Vec;
17
18const ZIGZAG_4X4: [usize; 16] = [0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15];
20
21const LUMA_4X4_BLOCK_XY: [(usize, usize); 16] = [
24 (0, 0),
25 (4, 0),
26 (0, 4),
27 (4, 4),
28 (8, 0),
29 (12, 0),
30 (8, 4),
31 (12, 4),
32 (0, 8),
33 (4, 8),
34 (0, 12),
35 (4, 12),
36 (8, 8),
37 (12, 8),
38 (8, 12),
39 (12, 12),
40];
41
42fn clip1(v: i32) -> i32 {
43 v.clamp(0, 255)
44}
45
46type TokEntry = (u8, u16, u8, u8);
51
52const COEFF_TOKEN_0: &[TokEntry] = &[
54 (1, 0b1, 0, 0),
55 (6, 0b000101, 1, 0),
56 (2, 0b01, 1, 1),
57 (8, 0b00000111, 2, 0),
58 (6, 0b000100, 2, 1),
59 (3, 0b001, 2, 2),
60 (9, 0b000000111, 3, 0),
61 (8, 0b00000110, 3, 1),
62 (7, 0b0000101, 3, 2),
63 (5, 0b00011, 3, 3),
64 (10, 0b0000000111, 4, 0),
65 (9, 0b000000110, 4, 1),
66 (8, 0b00000101, 4, 2),
67 (6, 0b000011, 4, 3),
68 (11, 0b00000000111, 5, 0),
69 (10, 0b0000000110, 5, 1),
70 (9, 0b000000101, 5, 2),
71 (7, 0b0000100, 5, 3),
72 (13, 0b0000000001111, 6, 0),
73 (11, 0b00000000110, 6, 1),
74 (10, 0b0000000101, 6, 2),
75 (8, 0b00000100, 6, 3),
76 (13, 0b0000000001011, 7, 0),
77 (13, 0b0000000001110, 7, 1),
78 (11, 0b00000000101, 7, 2),
79 (9, 0b000000100, 7, 3),
80 (13, 0b0000000001000, 8, 0),
81 (13, 0b0000000001010, 8, 1),
82 (13, 0b0000000001101, 8, 2),
83 (10, 0b0000000100, 8, 3),
84 (14, 0b00000000001111, 9, 0),
85 (14, 0b00000000001110, 9, 1),
86 (13, 0b0000000001001, 9, 2),
87 (11, 0b00000000100, 9, 3),
88 (14, 0b00000000001011, 10, 0),
89 (14, 0b00000000001010, 10, 1),
90 (14, 0b00000000001101, 10, 2),
91 (13, 0b0000000001100, 10, 3),
92 (15, 0b000000000001111, 11, 0),
93 (15, 0b000000000001110, 11, 1),
94 (14, 0b00000000001001, 11, 2),
95 (14, 0b00000000001100, 11, 3),
96 (15, 0b000000000001011, 12, 0),
97 (15, 0b000000000001010, 12, 1),
98 (15, 0b000000000001101, 12, 2),
99 (14, 0b00000000001000, 12, 3),
100 (16, 0b0000000000001111, 13, 0),
101 (15, 0b000000000000001, 13, 1),
102 (15, 0b000000000001001, 13, 2),
103 (15, 0b000000000001100, 13, 3),
104 (16, 0b0000000000001011, 14, 0),
105 (16, 0b0000000000001110, 14, 1),
106 (16, 0b0000000000001101, 14, 2),
107 (15, 0b000000000001000, 14, 3),
108 (16, 0b0000000000000111, 15, 0),
109 (16, 0b0000000000001010, 15, 1),
110 (16, 0b0000000000001001, 15, 2),
111 (16, 0b0000000000001100, 15, 3),
112 (16, 0b0000000000000100, 16, 0),
113 (16, 0b0000000000000110, 16, 1),
114 (16, 0b0000000000000101, 16, 2),
115 (16, 0b0000000000001000, 16, 3),
116];
117
118const COEFF_TOKEN_CHROMA_DC: &[TokEntry] = &[
120 (2, 0b01, 0, 0),
121 (6, 0b000111, 1, 0),
122 (1, 0b1, 1, 1),
123 (6, 0b000100, 2, 0),
124 (6, 0b000110, 2, 1),
125 (3, 0b001, 2, 2),
126 (6, 0b000011, 3, 0),
127 (7, 0b0000011, 3, 1),
128 (7, 0b0000010, 3, 2),
129 (6, 0b000101, 3, 3),
130 (6, 0b000010, 4, 0),
131 (8, 0b00000011, 4, 1),
132 (8, 0b00000010, 4, 2),
133 (7, 0b0000000, 4, 3),
134];
135
136fn read_coeff_token(r: &mut BitReader, table: &[TokEntry]) -> Option<(u8, u8)> {
138 let mut code: u16 = 0;
139 for len in 1..=16u8 {
140 code = (code << 1) | (r.read_bit() as u16);
141 for &(l, c, tc, t1) in table {
142 if l == len && c == code {
143 return Some((tc, t1));
144 }
145 }
146 }
147 None
148}
149
150const COEFF_TOKEN_2: &[TokEntry] = &[
152 (2, 0b11, 0, 0),
153 (6, 0b001011, 1, 0),
154 (2, 0b10, 1, 1),
155 (6, 0b000111, 2, 0),
156 (5, 0b00111, 2, 1),
157 (3, 0b011, 2, 2),
158 (7, 0b0000111, 3, 0),
159 (6, 0b001010, 3, 1),
160 (6, 0b001001, 3, 2),
161 (4, 0b0101, 3, 3),
162 (8, 0b00000111, 4, 0),
163 (6, 0b000110, 4, 1),
164 (6, 0b000101, 4, 2),
165 (4, 0b0100, 4, 3),
166 (8, 0b00000100, 5, 0),
167 (7, 0b0000110, 5, 1),
168 (7, 0b0000101, 5, 2),
169 (5, 0b00110, 5, 3),
170 (9, 0b000000111, 6, 0),
171 (8, 0b00000110, 6, 1),
172 (8, 0b00000101, 6, 2),
173 (6, 0b001000, 6, 3),
174 (11, 0b00000001111, 7, 0),
175 (9, 0b000000110, 7, 1),
176 (9, 0b000000101, 7, 2),
177 (6, 0b000100, 7, 3),
178 (11, 0b00000001011, 8, 0),
179 (11, 0b00000001110, 8, 1),
180 (11, 0b00000001101, 8, 2),
181 (7, 0b0000100, 8, 3),
182 (12, 0b000000001111, 9, 0),
183 (11, 0b00000001010, 9, 1),
184 (11, 0b00000001001, 9, 2),
185 (9, 0b000000100, 9, 3),
186 (12, 0b000000001011, 10, 0),
187 (12, 0b000000001110, 10, 1),
188 (12, 0b000000001101, 10, 2),
189 (11, 0b00000001100, 10, 3),
190 (12, 0b000000001000, 11, 0),
191 (12, 0b000000001010, 11, 1),
192 (12, 0b000000001001, 11, 2),
193 (11, 0b00000001000, 11, 3),
194 (13, 0b0000000001111, 12, 0),
195 (13, 0b0000000001110, 12, 1),
196 (13, 0b0000000001101, 12, 2),
197 (12, 0b000000001100, 12, 3),
198 (13, 0b0000000001011, 13, 0),
199 (13, 0b0000000001010, 13, 1),
200 (13, 0b0000000001001, 13, 2),
201 (13, 0b0000000001100, 13, 3),
202 (13, 0b0000000000111, 14, 0),
203 (14, 0b00000000001011, 14, 1),
204 (13, 0b0000000000110, 14, 2),
205 (13, 0b0000000001000, 14, 3),
206 (14, 0b00000000001001, 15, 0),
207 (14, 0b00000000001000, 15, 1),
208 (14, 0b00000000001010, 15, 2),
209 (13, 0b0000000000001, 15, 3),
210 (14, 0b00000000000111, 16, 0),
211 (14, 0b00000000000110, 16, 1),
212 (14, 0b00000000000101, 16, 2),
213 (14, 0b00000000000100, 16, 3),
214];
215
216const COEFF_TOKEN_4: &[TokEntry] = &[
218 (4, 0b1111, 0, 0),
219 (6, 0b001111, 1, 0),
220 (4, 0b1110, 1, 1),
221 (6, 0b001011, 2, 0),
222 (5, 0b01111, 2, 1),
223 (4, 0b1101, 2, 2),
224 (6, 0b001000, 3, 0),
225 (5, 0b01100, 3, 1),
226 (5, 0b01110, 3, 2),
227 (4, 0b1100, 3, 3),
228 (7, 0b0001111, 4, 0),
229 (5, 0b01010, 4, 1),
230 (5, 0b01011, 4, 2),
231 (4, 0b1011, 4, 3),
232 (7, 0b0001011, 5, 0),
233 (5, 0b01000, 5, 1),
234 (5, 0b01001, 5, 2),
235 (4, 0b1010, 5, 3),
236 (7, 0b0001001, 6, 0),
237 (6, 0b001110, 6, 1),
238 (6, 0b001101, 6, 2),
239 (4, 0b1001, 6, 3),
240 (7, 0b0001000, 7, 0),
241 (6, 0b001010, 7, 1),
242 (6, 0b001001, 7, 2),
243 (4, 0b1000, 7, 3),
244 (8, 0b00001111, 8, 0),
245 (7, 0b0001110, 8, 1),
246 (7, 0b0001101, 8, 2),
247 (5, 0b01101, 8, 3),
248 (8, 0b00001011, 9, 0),
249 (8, 0b00001110, 9, 1),
250 (7, 0b0001010, 9, 2),
251 (6, 0b001100, 9, 3),
252 (9, 0b000001111, 10, 0),
253 (8, 0b00001010, 10, 1),
254 (8, 0b00001101, 10, 2),
255 (7, 0b0001100, 10, 3),
256 (9, 0b000001011, 11, 0),
257 (9, 0b000001110, 11, 1),
258 (8, 0b00001001, 11, 2),
259 (8, 0b00001100, 11, 3),
260 (9, 0b000001000, 12, 0),
261 (9, 0b000001010, 12, 1),
262 (9, 0b000001101, 12, 2),
263 (8, 0b00001000, 12, 3),
264 (10, 0b0000001101, 13, 0),
265 (9, 0b000000111, 13, 1),
266 (9, 0b000001001, 13, 2),
267 (9, 0b000001100, 13, 3),
268 (10, 0b0000001001, 14, 0),
269 (10, 0b0000001100, 14, 1),
270 (10, 0b0000001011, 14, 2),
271 (10, 0b0000001010, 14, 3),
272 (10, 0b0000000101, 15, 0),
273 (10, 0b0000001000, 15, 1),
274 (10, 0b0000000111, 15, 2),
275 (10, 0b0000000110, 15, 3),
276 (10, 0b0000000001, 16, 0),
277 (10, 0b0000000100, 16, 1),
278 (10, 0b0000000011, 16, 2),
279 (10, 0b0000000010, 16, 3),
280];
281
282fn read_coeff_token_nc(r: &mut BitReader, n_c: i32) -> Option<(u8, u8)> {
284 if n_c == -1 {
285 return read_coeff_token(r, COEFF_TOKEN_CHROMA_DC);
286 }
287 if n_c >= 8 {
288 let code = r.read_bits(6);
289 if code == 3 {
290 return Some((0, 0));
291 }
292 return Some(((code >> 2) as u8 + 1, (code & 3) as u8));
293 }
294 let table = if n_c < 2 {
295 COEFF_TOKEN_0
296 } else if n_c < 4 {
297 COEFF_TOKEN_2
298 } else {
299 COEFF_TOKEN_4
300 };
301 read_coeff_token(r, table)
302}
303
304const CBP_INTRA_MAP: [u8; 48] = [
306 47, 31, 15, 0, 23, 27, 29, 30, 7, 11, 13, 14, 39, 43, 45, 46, 16, 3, 5, 10, 12, 19, 21, 26, 28,
307 35, 37, 42, 44, 1, 2, 4, 8, 17, 18, 20, 24, 6, 9, 22, 25, 32, 33, 34, 36, 40, 38, 41,
308];
309
310const CBP_INTER_MAP: [u8; 48] = [
312 0, 16, 1, 2, 4, 8, 32, 3, 5, 10, 12, 15, 47, 7, 11, 13, 14, 6, 9, 31, 35, 37, 42, 44, 33, 34,
313 36, 40, 39, 43, 45, 46, 17, 18, 20, 24, 19, 21, 26, 28, 23, 27, 29, 30, 22, 25, 38, 41,
314];
315
316const ALPHA_TABLE: [u8; 52] = [
318 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 5, 6, 7, 8, 9, 10, 12, 13, 15, 17, 20,
319 22, 25, 28, 32, 36, 40, 45, 50, 56, 63, 71, 80, 90, 101, 113, 127, 144, 162, 182, 203, 226,
320 255, 255,
321];
322const BETA_TABLE: [u8; 52] = [
323 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 6, 6, 7, 7, 8, 8,
324 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18,
325];
326const TC0_TABLE: [[u8; 3]; 52] = [
328 [0, 0, 0],
329 [0, 0, 0],
330 [0, 0, 0],
331 [0, 0, 0],
332 [0, 0, 0],
333 [0, 0, 0],
334 [0, 0, 0],
335 [0, 0, 0],
336 [0, 0, 0],
337 [0, 0, 0],
338 [0, 0, 0],
339 [0, 0, 0],
340 [0, 0, 0],
341 [0, 0, 0],
342 [0, 0, 0],
343 [0, 0, 0],
344 [0, 0, 0],
345 [0, 0, 1],
346 [0, 0, 1],
347 [0, 0, 1],
348 [0, 0, 1],
349 [0, 1, 1],
350 [0, 1, 1],
351 [1, 1, 1],
352 [1, 1, 1],
353 [1, 1, 1],
354 [1, 1, 1],
355 [1, 1, 2],
356 [1, 1, 2],
357 [1, 1, 2],
358 [1, 1, 2],
359 [1, 2, 3],
360 [1, 2, 3],
361 [2, 2, 3],
362 [2, 2, 4],
363 [2, 3, 4],
364 [2, 3, 4],
365 [3, 3, 5],
366 [3, 4, 6],
367 [3, 4, 6],
368 [4, 5, 7],
369 [4, 5, 8],
370 [4, 6, 9],
371 [5, 7, 10],
372 [6, 8, 11],
373 [6, 8, 13],
374 [7, 10, 14],
375 [8, 11, 16],
376 [9, 12, 18],
377 [10, 13, 20],
378 [11, 15, 23],
379 [13, 17, 25],
380];
381
382const TOTAL_ZEROS_16: &[&[(u8, u16)]] = &[
385 &[
386 (1, 0b1),
387 (3, 0b011),
388 (3, 0b010),
389 (4, 0b0011),
390 (4, 0b0010),
391 (5, 0b00011),
392 (5, 0b00010),
393 (6, 0b000011),
394 (6, 0b000010),
395 (7, 0b0000011),
396 (7, 0b0000010),
397 (8, 0b00000011),
398 (8, 0b00000010),
399 (9, 0b000000011),
400 (9, 0b000000010),
401 (9, 0b000000001),
402 ],
403 &[
404 (3, 0b111),
405 (3, 0b110),
406 (3, 0b101),
407 (3, 0b100),
408 (3, 0b011),
409 (4, 0b0101),
410 (4, 0b0100),
411 (4, 0b0011),
412 (4, 0b0010),
413 (5, 0b00011),
414 (5, 0b00010),
415 (6, 0b000011),
416 (6, 0b000010),
417 (6, 0b000001),
418 (6, 0b000000),
419 ],
420 &[
421 (4, 0b0101),
422 (3, 0b111),
423 (3, 0b110),
424 (3, 0b101),
425 (4, 0b0100),
426 (4, 0b0011),
427 (3, 0b100),
428 (3, 0b011),
429 (4, 0b0010),
430 (5, 0b00011),
431 (5, 0b00010),
432 (6, 0b000001),
433 (5, 0b00001),
434 (6, 0b000000),
435 ],
436 &[
437 (5, 0b00011),
438 (3, 0b111),
439 (4, 0b0101),
440 (4, 0b0100),
441 (3, 0b110),
442 (3, 0b101),
443 (3, 0b100),
444 (4, 0b0011),
445 (3, 0b011),
446 (4, 0b0010),
447 (5, 0b00010),
448 (5, 0b00001),
449 (5, 0b00000),
450 ],
451 &[
452 (4, 0b0101),
453 (4, 0b0100),
454 (4, 0b0011),
455 (3, 0b111),
456 (3, 0b110),
457 (3, 0b101),
458 (3, 0b100),
459 (3, 0b011),
460 (4, 0b0010),
461 (5, 0b00001),
462 (4, 0b0001),
463 (5, 0b00000),
464 ],
465 &[
466 (6, 0b000001),
467 (5, 0b00001),
468 (3, 0b111),
469 (3, 0b110),
470 (3, 0b101),
471 (3, 0b100),
472 (3, 0b011),
473 (3, 0b010),
474 (4, 0b0001),
475 (3, 0b001),
476 (6, 0b000000),
477 ],
478 &[
479 (6, 0b000001),
480 (5, 0b00001),
481 (3, 0b101),
482 (3, 0b100),
483 (3, 0b011),
484 (2, 0b11),
485 (3, 0b010),
486 (4, 0b0001),
487 (3, 0b001),
488 (6, 0b000000),
489 ],
490 &[
491 (6, 0b000001),
492 (4, 0b0001),
493 (5, 0b00001),
494 (3, 0b011),
495 (2, 0b11),
496 (2, 0b10),
497 (3, 0b010),
498 (3, 0b001),
499 (6, 0b000000),
500 ],
501 &[
502 (6, 0b000001),
503 (6, 0b000000),
504 (4, 0b0001),
505 (2, 0b11),
506 (2, 0b10),
507 (3, 0b001),
508 (2, 0b01),
509 (5, 0b00001),
510 ],
511 &[
512 (5, 0b00001),
513 (5, 0b00000),
514 (3, 0b001),
515 (2, 0b11),
516 (2, 0b10),
517 (2, 0b01),
518 (4, 0b0001),
519 ],
520 &[
521 (4, 0b0000),
522 (4, 0b0001),
523 (3, 0b001),
524 (3, 0b010),
525 (1, 0b1),
526 (3, 0b011),
527 ],
528 &[(4, 0b0000), (4, 0b0001), (2, 0b01), (1, 0b1), (3, 0b001)],
529 &[(3, 0b000), (3, 0b001), (1, 0b1), (2, 0b01)],
530 &[(2, 0b00), (2, 0b01), (1, 0b1)],
531 &[(1, 0b0), (1, 0b1)],
532];
533
534const TOTAL_ZEROS_CHROMA: &[&[(u8, u16)]] = &[
536 &[(1, 0b1), (2, 0b01), (3, 0b001), (3, 0b000)],
537 &[(1, 0b1), (2, 0b01), (2, 0b00)],
538 &[(1, 0b1), (1, 0b0)],
539];
540
541fn read_total_zeros(r: &mut BitReader, total_coeff: u8, tables: &[&[(u8, u16)]]) -> u8 {
542 let row = tables[(total_coeff - 1) as usize];
543 let mut code: u16 = 0;
544 for len in 1..=9u8 {
545 code = (code << 1) | (r.read_bit() as u16);
546 for (tz, &(l, c)) in row.iter().enumerate() {
547 if l == len && c == code {
548 return tz as u8;
549 }
550 }
551 }
552 0
553}
554
555const RUN_BEFORE: &[&[(u8, u16)]] = &[
557 &[(1, 0b1), (1, 0b0)],
558 &[(1, 0b1), (2, 0b01), (2, 0b00)],
559 &[(2, 0b11), (2, 0b10), (2, 0b01), (2, 0b00)],
560 &[(2, 0b11), (2, 0b10), (2, 0b01), (3, 0b001), (3, 0b000)],
561 &[
562 (2, 0b11),
563 (2, 0b10),
564 (3, 0b011),
565 (3, 0b010),
566 (3, 0b001),
567 (3, 0b000),
568 ],
569 &[
570 (2, 0b11),
571 (3, 0b000),
572 (3, 0b001),
573 (3, 0b011),
574 (3, 0b010),
575 (3, 0b101),
576 (3, 0b100),
577 ],
578 &[
579 (3, 0b111),
580 (3, 0b110),
581 (3, 0b101),
582 (3, 0b100),
583 (3, 0b011),
584 (3, 0b010),
585 (3, 0b001),
586 (4, 0b0001),
587 (5, 0b00001),
588 (6, 0b000001),
589 (7, 0b0000001),
590 (8, 0b00000001),
591 (9, 0b000000001),
592 (10, 0b0000000001),
593 (11, 0b00000000001),
594 ],
595];
596
597fn read_run_before(r: &mut BitReader, zeros_left: i32) -> i32 {
598 let idx = (zeros_left.min(7) - 1).max(0) as usize;
599 let row = RUN_BEFORE[idx];
600 let mut code: u16 = 0;
601 for len in 1..=11u8 {
602 code = (code << 1) | (r.read_bit() as u16);
603 for (run, &(l, c)) in row.iter().enumerate() {
604 if l == len && c == code {
605 return run as i32;
606 }
607 }
608 }
609 0
610}
611
612fn residual_block_cavlc(
615 r: &mut BitReader,
616 max_num_coeff: usize,
617 n_c: i32,
618 tz_tables: &[&[(u8, u16)]],
619) -> ([i32; 16], u8) {
620 let mut coeff = [0i32; 16];
621 let (total_coeff, trailing_ones) = match read_coeff_token_nc(r, n_c) {
622 Some(v) => v,
623 None => return (coeff, 0),
624 };
625 let ret_total = total_coeff;
626 if total_coeff == 0 {
627 return (coeff, 0);
628 }
629 let total_coeff = total_coeff as usize;
630 let trailing_ones = trailing_ones as usize;
631
632 let mut level = [0i32; 16];
634 for i in 0..trailing_ones {
635 level[i] = if r.read_bit() == 1 { -1 } else { 1 };
636 }
637 let mut suffix_length: u32 = if total_coeff > 10 && trailing_ones < 3 {
638 1
639 } else {
640 0
641 };
642 for i in trailing_ones..total_coeff {
643 let mut level_prefix = 0u32;
644 while r.read_bit() == 0 {
645 level_prefix += 1;
646 if level_prefix > 31 {
647 break;
648 }
649 }
650 let mut suffix_size = suffix_length;
651 if level_prefix == 14 && suffix_length == 0 {
652 suffix_size = 4;
653 } else if level_prefix >= 15 {
654 suffix_size = level_prefix - 3;
655 }
656 let level_suffix = if suffix_size > 0 {
657 r.read_bits(suffix_size) as i32
658 } else {
659 0
660 };
661 let mut level_code = ((level_prefix.min(15) << suffix_length) as i32) + level_suffix;
662 if level_prefix >= 15 && suffix_length == 0 {
663 level_code += 15;
664 }
665 if level_prefix >= 16 {
666 level_code += (1 << (level_prefix - 3)) - 4096;
667 }
668 if i == trailing_ones && trailing_ones < 3 {
669 level_code += 2;
670 }
671 level[i] = if level_code % 2 == 0 {
672 (level_code + 2) >> 1
673 } else {
674 (-level_code - 1) >> 1
675 };
676 if suffix_length == 0 {
677 suffix_length = 1;
678 }
679 if level[i].unsigned_abs() > (3u32 << (suffix_length - 1)) && suffix_length < 6 {
680 suffix_length += 1;
681 }
682 }
683
684 let total_zeros = if total_coeff < max_num_coeff {
686 read_total_zeros(r, total_coeff as u8, tz_tables) as i32
687 } else {
688 0
689 };
690
691 let mut run = [0i32; 16];
693 let mut zeros_left = total_zeros;
694 for i in 0..total_coeff {
695 if i < total_coeff - 1 && zeros_left > 0 {
696 let rb = read_run_before(r, zeros_left);
697 run[i] = rb;
698 zeros_left -= rb;
699 } else if i == total_coeff - 1 {
700 run[i] = zeros_left;
701 } else {
702 run[i] = 0;
703 }
704 }
705
706 let mut coeff_ctr: i32 = -1;
708 for i in (0..total_coeff).rev() {
709 coeff_ctr += run[i] + 1;
710 if (coeff_ctr as usize) < 16 {
711 coeff[coeff_ctr as usize] = level[i];
712 }
713 }
714 (coeff, ret_total)
715}
716
717fn inverse_hadamard_4x4(b: &mut [i32; 16]) {
721 for i in 0..4 {
722 let o = i * 4;
723 let (a0, a1, a2, a3) = (
724 b[o] + b[o + 2],
725 b[o] - b[o + 2],
726 b[o + 1] - b[o + 3],
727 b[o + 1] + b[o + 3],
728 );
729 b[o] = a0 + a3;
730 b[o + 1] = a1 + a2;
731 b[o + 2] = a1 - a2;
732 b[o + 3] = a0 - a3;
733 }
734 for j in 0..4 {
735 let (a0, a1, a2, a3) = (
736 b[j] + b[8 + j],
737 b[j] - b[8 + j],
738 b[4 + j] - b[12 + j],
739 b[4 + j] + b[12 + j],
740 );
741 b[j] = a0 + a3;
742 b[4 + j] = a1 + a2;
743 b[8 + j] = a1 - a2;
744 b[12 + j] = a0 - a3;
745 }
746}
747
748fn scale_luma_dc(f: &mut [i32; 16], qp: i32) {
750 let m = (qp % 6) as usize;
751 let ls = 16 * NORM_ADJUST_4X4[m][0];
752 let shift = qp / 6;
753 for v in f.iter_mut() {
754 *v = if qp >= 36 {
755 (*v * ls) << (shift - 6)
756 } else {
757 (*v * ls + (1 << (5 - shift))) >> (6 - shift)
758 };
759 }
760}
761
762pub struct DecodedYuv {
765 pub width: u32,
766 pub height: u32,
767 pub y: Vec<u8>,
768 pub u: Vec<u8>,
769 pub v: Vec<u8>,
770}
771
772pub fn yuv_to_rgb(yuv: &DecodedYuv) -> Vec<u8> {
774 let w = yuv.width as usize;
775 let h = yuv.height as usize;
776 let cw = (yuv.width / 2) as usize;
777 let mut rgb = alloc::vec![0u8; w * h * 3];
778 let mut oi = 0usize;
779 for y in 0..h {
780 let yrow = y * w;
781 let crow = (y >> 1) * cw;
782 for x in 0..w {
783 let yy = yuv.y[yrow + x] as i32;
784 let ci = crow + (x >> 1);
785 let cu = yuv.u[ci] as i32 - 128;
786 let cv = yuv.v[ci] as i32 - 128;
787 let r = yy + ((91881 * cv) >> 16);
788 let g = yy - ((22554 * cu + 46802 * cv) >> 16);
789 let b = yy + ((116130 * cu) >> 16);
790 rgb[oi] = r.clamp(0, 255) as u8;
791 rgb[oi + 1] = g.clamp(0, 255) as u8;
792 rgb[oi + 2] = b.clamp(0, 255) as u8;
793 oi += 3;
794 }
795 }
796 rgb
797}
798
799#[derive(Clone)]
802pub struct Motion {
803 blk_w: usize,
804 mv: [Vec<[i16; 2]>; 2],
805 refi: [Vec<i8>; 2],
806}
807
808pub struct RefPic {
810 pub yuv: DecodedYuv,
811 pub poc: i32,
812 frame_num: u32,
813 motion: Motion,
814}
815
816#[derive(Clone, Copy)]
819pub struct RefEntry<'a> {
820 yuv: &'a DecodedYuv,
821 id: i32,
822 pic_num: i32,
824 motion: Option<&'a Motion>,
825}
826
827fn pic_num(frame_num: u32, cur_frame_num: u32, max_frame_num: i32) -> i32 {
829 if frame_num > cur_frame_num {
830 frame_num as i32 - max_frame_num
831 } else {
832 frame_num as i32
833 }
834}
835
836fn modify_ref_list<'a>(
839 list: &mut Vec<RefEntry<'a>>,
840 mods: &[(u32, u32)],
841 all: &[RefEntry<'a>],
842 cur_frame_num: u32,
843 max_frame_num: i32,
844 num_active: usize,
845) -> Result<(), &'static str> {
846 let cur = cur_frame_num as i32;
847 let mut pred = cur;
848 for (ref_idx, &(idc, abs_diff_minus1)) in mods.iter().enumerate() {
849 let d = abs_diff_minus1 as i32 + 1;
850 let mut no_wrap = if idc == 0 { pred - d } else { pred + d };
851 if no_wrap < 0 {
852 no_wrap += max_frame_num;
853 } else if no_wrap >= max_frame_num {
854 no_wrap -= max_frame_num;
855 }
856 pred = no_wrap;
857 let target = if no_wrap > cur { no_wrap - max_frame_num } else { no_wrap };
858 let pic = *all.iter().find(|e| e.pic_num == target).ok_or("ref_pic_list_modification: no such picture")?;
859 if let Some(pos) = list.iter().skip(ref_idx).position(|e| e.pic_num == target) {
860 list.remove(ref_idx + pos);
861 }
862 list.insert(ref_idx.min(list.len()), pic);
863 list.truncate(num_active);
864 }
865 Ok(())
866}
867
868struct RefLists<'a> {
871 p: Vec<RefEntry<'a>>,
872 b: [Vec<RefEntry<'a>>; 2],
873 cur_poc: i32,
875}
876
877#[derive(Default)]
882pub struct RefFrames {
883 frames: Vec<RefPic>,
884 poc: PocState,
885}
886
887impl RefFrames {
888 pub fn new() -> Self {
889 Self::default()
890 }
891
892 fn lists(&self, cur_poc: i32, cur_frame_num: u32, max_frame_num: i32) -> RefLists<'_> {
894 fn entry_of(f: &RefPic, cur_frame_num: u32, max_frame_num: i32) -> RefEntry<'_> {
895 let pn = pic_num(f.frame_num, cur_frame_num, max_frame_num);
896 RefEntry { yuv: &f.yuv, id: f.poc, pic_num: pn, motion: Some(&f.motion) }
897 }
898 let entry = |f| entry_of(f, cur_frame_num, max_frame_num);
899 let p: Vec<RefEntry> = self.frames.iter().map(entry).collect();
900 let mut before: Vec<&RefPic> = self.frames.iter().filter(|f| f.poc < cur_poc).collect();
902 let mut after: Vec<&RefPic> = self.frames.iter().filter(|f| f.poc > cur_poc).collect();
903 before.sort_by_key(|f| core::cmp::Reverse(f.poc));
904 after.sort_by_key(|f| f.poc);
905 let l0: Vec<RefEntry> = before.iter().chain(after.iter()).map(|f| entry(f)).collect();
906 let mut l1: Vec<RefEntry> = after.iter().chain(before.iter()).map(|f| entry(f)).collect();
907 if l1.len() > 1 && l1.iter().zip(&l0).all(|(a, b)| a.id == b.id) {
909 l1.swap(0, 1);
910 }
911 RefLists { p, b: [l0, l1], cur_poc }
912 }
913
914 pub fn decode(
917 &mut self,
918 sps: &Sps,
919 pps: &Pps,
920 slices: &[&[u8]],
921 is_idr: bool,
922 nal_ref_idc: u8,
923 ) -> Result<(DecodedYuv, i32), &'static str> {
924 let first = slices.first().ok_or("no slices")?;
925 let h = parse_slice_header(&mut BitReader::new(first), sps, pps, is_idr, nal_ref_idc)?;
926 if is_idr {
927 self.frames.clear();
928 }
929 let poc = self.poc.compute(sps, &h, is_idr, nal_ref_idc);
930 let max_frame_num = 1i32 << sps.log2_max_frame_num;
931 let (yuv, motion) = {
932 let lists = self.lists(poc, h.frame_num, max_frame_num);
933 decode_picture_lists(sps, pps, slices, is_idr, nal_ref_idc, &lists)?
934 };
935 if nal_ref_idc != 0 {
936 for &diff in &h.mmco_unmark {
938 let target = h.frame_num as i32 - (diff as i32 + 1);
939 self.frames.retain(|f| pic_num(f.frame_num, h.frame_num, max_frame_num) != target);
940 }
941 let copy = DecodedYuv {
942 width: yuv.width,
943 height: yuv.height,
944 y: yuv.y.clone(),
945 u: yuv.u.clone(),
946 v: yuv.v.clone(),
947 };
948 let max = sps.max_num_ref_frames.max(1) as usize;
950 if !h.adaptive_marking && self.frames.len() >= max {
951 self.frames.truncate(max - 1);
952 }
953 self.frames.insert(0, RefPic { yuv: copy, poc, frame_num: h.frame_num, motion });
954 self.frames.truncate(max);
955 }
956 Ok((yuv, poc))
957 }
958}
959
960fn crop_rgb(rgb: Vec<u8>, fw: u32, fh: u32, x: u32, y: u32, w: u32, h: u32) -> (u32, u32, Vec<u8>) {
963 if w == 0 || h == 0 || x + w > fw || y + h > fh || (w == fw && h == fh) {
964 return (fw, fh, rgb);
965 }
966 let mut out = Vec::with_capacity((w * h * 3) as usize);
967 for row in y..y + h {
968 let o = ((row * fw + x) * 3) as usize;
969 out.extend_from_slice(&rgb[o..o + (w * 3) as usize]);
970 }
971 (w, h, out)
972}
973
974pub struct VideoDecoder {
977 sps: Option<Sps>,
978 pps: Option<Pps>,
979 length_size: usize,
980 refs: RefFrames,
981 reorder: Vec<((u32, i32), DecodedYuv)>,
983 idr_count: u32,
984}
985
986impl Default for VideoDecoder {
987 fn default() -> Self {
988 Self::new()
989 }
990}
991
992impl VideoDecoder {
993 pub fn new() -> Self {
994 Self {
995 sps: None,
996 pps: None,
997 length_size: 4,
998 refs: RefFrames::new(),
999 reorder: Vec::new(),
1000 idr_count: 0,
1001 }
1002 }
1003
1004 pub fn init_avcc(&mut self, avcc: &[u8]) {
1006 if let Some((ls, sps_list, pps_list)) = parse_avcc(avcc) {
1007 self.length_size = ls;
1008 if let Some(p) = sps_list.first() {
1009 if p.len() > 1 {
1010 self.sps = parse_sps(&extract_rbsp(&p[1..])).ok();
1011 }
1012 }
1013 if let Some(p) = pps_list.first() {
1014 if p.len() > 1 {
1015 self.pps = parse_pps(&extract_rbsp(&p[1..])).ok();
1016 }
1017 }
1018 }
1019 }
1020
1021 pub fn decode_sample_rgb(&mut self, sample: &[u8]) -> Option<(u32, u32, Vec<u8>)> {
1023 let nals = split_avcc(sample, self.length_size);
1024 let mut slices: Vec<&[u8]> = Vec::new();
1026 let mut is_idr = false;
1027 let mut ref_idc = 0u8;
1028 for nu in &nals {
1029 match nu.unit_type {
1030 7 => self.sps = parse_sps(&nu.rbsp).ok(),
1031 8 => self.pps = parse_pps(&nu.rbsp).ok(),
1032 1 | 5 => {
1033 slices.push(&nu.rbsp);
1034 is_idr = nu.unit_type == 5;
1035 ref_idc = nu.ref_idc;
1036 }
1037 _ => {}
1038 }
1039 }
1040 let (s, p) = match (self.sps.clone(), self.pps.clone()) {
1041 (Some(s), Some(p)) => (s, p),
1042 _ => return None,
1043 };
1044 if slices.is_empty() {
1045 return None;
1046 }
1047 let (frame, poc) = self.refs.decode(&s, &p, &slices, is_idr, ref_idc).ok()?;
1048 if is_idr {
1049 self.idr_count = self.idr_count.wrapping_add(1);
1050 }
1051 self.reorder.push(((self.idr_count, poc), frame));
1052 let depth = if s.profile_idc == 66 { 0 } else { s.max_num_ref_frames.clamp(1, 4) as usize };
1055 if self.reorder.len() <= depth {
1056 return None;
1057 }
1058 let (idx, _) = self.reorder.iter().enumerate().min_by_key(|(_, (k, _))| *k)?;
1059 let (_, frame) = self.reorder.remove(idx);
1060 let rgb = yuv_to_rgb(&frame);
1061 Some(crop_rgb(rgb, frame.width, frame.height, s.crop_x, s.crop_y, s.width, s.height))
1062 }
1063}
1064
1065struct DecState {
1067 yuv: DecodedYuv,
1068 blk_w: usize, nnz_luma: Vec<u8>, mode_luma: Vec<i8>, decoded: Vec<bool>, cblk_w: usize, nnz_chroma: [Vec<u8>; 2], mb_w: usize, mb_qp: Vec<i32>, mv: [Vec<[i16; 2]>; 2], is_inter: Vec<bool>, blk_h: usize, refi: [Vec<i8>; 2], refp: [Vec<i32>; 2], num_ref: [u32; 2], mb_slice: Vec<u32>, cur_slice: u32, mb_db: Vec<MbDeblock>, mb_t8: Vec<bool>, wp: WpMode, cur_poc: i32, }
1089
1090enum WpMode {
1092 Off,
1094 Explicit(PredWeightTable),
1096 Implicit,
1098}
1099
1100fn combine_nc(na: i32, nb: i32) -> i32 {
1102 if na >= 0 && nb >= 0 {
1103 (na + nb + 1) >> 1
1104 } else if na >= 0 {
1105 na
1106 } else if nb >= 0 {
1107 nb
1108 } else {
1109 0
1110 }
1111}
1112
1113impl DecState {
1114 fn li(&self, bx4: usize, by4: usize) -> usize {
1115 by4 * self.blk_w + bx4
1116 }
1117
1118 fn has_coeffs(&self, li: usize) -> bool {
1121 let (bx, by) = (li % self.blk_w, li / self.blk_w);
1122 if self.mb_t8[(by / 4) * self.mb_w + bx / 4] {
1123 let (x0, y0) = (bx & !1, by & !1);
1124 [(0, 0), (1, 0), (0, 1), (1, 1)].iter().any(|&(dx, dy)| self.nnz_luma[self.li(x0 + dx, y0 + dy)] > 0)
1125 } else {
1126 self.nnz_luma[li] > 0
1127 }
1128 }
1129
1130 fn avail_px(&self, x: isize, y: isize) -> bool {
1134 if x < 0 || y < 0 || x >= self.yuv.width as isize || y >= self.yuv.height as isize {
1135 return false;
1136 }
1137 let mb = (y as usize / 16) * self.mb_w + x as usize / 16;
1138 self.mb_slice.get(mb).is_some_and(|&s| s == self.cur_slice)
1139 }
1140
1141 fn avail_blk(&self, bx4: isize, by4: isize) -> bool {
1143 self.avail_px(bx4 * 4, by4 * 4)
1144 }
1145
1146 fn luma_nc(&self, bx4: usize, by4: usize) -> i32 {
1148 let na = if self.avail_blk(bx4 as isize - 1, by4 as isize) {
1149 self.nnz_luma[self.li(bx4 - 1, by4)] as i32
1150 } else {
1151 -1
1152 };
1153 let nb = if self.avail_blk(bx4 as isize, by4 as isize - 1) {
1154 self.nnz_luma[self.li(bx4, by4 - 1)] as i32
1155 } else {
1156 -1
1157 };
1158 combine_nc(na, nb)
1159 }
1160
1161 fn pred_i4x4_mode(&self, bx4: usize, by4: usize) -> i32 {
1163 if !self.avail_blk(bx4 as isize - 1, by4 as isize) || !self.avail_blk(bx4 as isize, by4 as isize - 1) {
1164 return 2;
1165 } let ma = self.mode_luma[self.li(bx4 - 1, by4)];
1167 let mb = self.mode_luma[self.li(bx4, by4 - 1)];
1168 let ma = if ma >= 0 { ma as i32 } else { 2 };
1169 let mb = if mb >= 0 { mb as i32 } else { 2 };
1170 ma.min(mb)
1171 }
1172
1173 fn predict_luma_4x4(&self, px: usize, py: usize, mode: u8) -> [i32; 16] {
1176 let w = self.yuv.width as usize;
1177 let top_avail = self.avail_px(px as isize, py as isize - 1);
1178 let left_avail = self.avail_px(px as isize - 1, py as isize);
1179 let bx4 = px / 4;
1180 let by4 = py / 4;
1181 let mut top = [0i32; 8];
1182 let mut left = [0i32; 4];
1183 let mut corner = 0i32;
1184 if top_avail {
1185 for x in 0..4 {
1186 top[x] = self.yuv.y[(py - 1) * w + px + x] as i32;
1187 }
1188 let tr_ok = by4 > 0
1190 && bx4 + 1 < self.blk_w
1191 && self.decoded[self.li(bx4 + 1, by4 - 1)]
1192 && self.avail_blk(bx4 as isize + 1, by4 as isize - 1);
1193 if tr_ok {
1194 for x in 0..4 {
1195 top[4 + x] = self.yuv.y[(py - 1) * w + px + 4 + x] as i32;
1196 }
1197 } else {
1198 for x in 0..4 {
1199 top[4 + x] = top[3];
1200 }
1201 }
1202 }
1203 if left_avail {
1204 for y in 0..4 {
1205 left[y] = self.yuv.y[(py + y) * w + px - 1] as i32;
1206 }
1207 }
1208 if top_avail && left_avail {
1209 corner = self.yuv.y[(py - 1) * w + px - 1] as i32;
1210 }
1211 intra_4x4_predict(mode, &top, corner, &left, top_avail, left_avail)
1212 }
1213}
1214
1215pub fn decode_slice(
1218 sps: &Sps,
1219 pps: &Pps,
1220 rbsp: &[u8],
1221 is_idr: bool,
1222 reference: Option<&DecodedYuv>,
1223) -> Result<DecodedYuv, &'static str> {
1224 let refs: Vec<&DecodedYuv> = reference.into_iter().collect();
1225 decode_slice_refs(sps, pps, rbsp, is_idr, 1, &refs)
1226}
1227
1228pub fn decode_slice_refs(
1230 sps: &Sps,
1231 pps: &Pps,
1232 rbsp: &[u8],
1233 is_idr: bool,
1234 nal_ref_idc: u8,
1235 refs: &[&DecodedYuv],
1236) -> Result<DecodedYuv, &'static str> {
1237 decode_picture(sps, pps, &[rbsp], is_idr, nal_ref_idc, refs)
1238}
1239
1240pub fn slice_first_mb(rbsp: &[u8]) -> u32 {
1242 BitReader::new(rbsp).read_ue()
1243}
1244
1245#[derive(Clone, Copy, Default)]
1247struct MbDeblock {
1248 disable_idc: u32,
1249 alpha_off: i32,
1250 beta_off: i32,
1251}
1252
1253pub fn decode_picture(
1260 sps: &Sps,
1261 pps: &Pps,
1262 slices: &[&[u8]],
1263 is_idr: bool,
1264 nal_ref_idc: u8,
1265 refs: &[&DecodedYuv],
1266) -> Result<DecodedYuv, &'static str> {
1267 let p: Vec<RefEntry> = refs
1269 .iter()
1270 .enumerate()
1271 .map(|(i, f)| RefEntry { yuv: f, id: -(i as i32) - 1, pic_num: -(i as i32) - 1, motion: None })
1272 .collect();
1273 let lists = RefLists { b: [p.clone(), Vec::new()], p, cur_poc: 0 };
1274 Ok(decode_picture_lists(sps, pps, slices, is_idr, nal_ref_idc, &lists)?.0)
1275}
1276
1277fn decode_picture_lists(
1279 sps: &Sps,
1280 pps: &Pps,
1281 slices: &[&[u8]],
1282 is_idr: bool,
1283 nal_ref_idc: u8,
1284 lists: &RefLists,
1285) -> Result<(DecodedYuv, Motion), &'static str> {
1286 if sps.width_mbs == 0 || sps.height_mbs == 0 || sps.width_mbs > 300 || sps.height_mbs > 300 {
1288 return Err("invalid frame dimensions");
1289 }
1290 let width = sps.width_mbs * 16;
1291 let height = sps.height_mbs * 16;
1292 let cw = width / 2;
1293 let ch = height / 2;
1294 let yuv = DecodedYuv {
1295 width,
1296 height,
1297 y: alloc::vec![0u8; (width * height) as usize],
1298 u: alloc::vec![128u8; (cw * ch) as usize],
1299 v: alloc::vec![128u8; (cw * ch) as usize],
1300 };
1301 let blk_w = (width / 4) as usize;
1302 let blk_h = (height / 4) as usize;
1303 let cblk_w = (cw / 4) as usize;
1304 let cblk_h = (ch / 4) as usize;
1305 let mut st = DecState {
1306 yuv,
1307 blk_w,
1308 nnz_luma: alloc::vec![0u8; blk_w * blk_h],
1309 mode_luma: alloc::vec![-1i8; blk_w * blk_h],
1310 decoded: alloc::vec![false; blk_w * blk_h],
1311 cblk_w,
1312 nnz_chroma: [
1313 alloc::vec![0u8; cblk_w * cblk_h],
1314 alloc::vec![0u8; cblk_w * cblk_h],
1315 ],
1316 mb_w: sps.width_mbs as usize,
1317 mb_qp: alloc::vec![0i32; (sps.width_mbs * sps.height_mbs) as usize],
1318 mv: [alloc::vec![[0i16; 2]; blk_w * blk_h], alloc::vec![[0i16; 2]; blk_w * blk_h]],
1319 is_inter: alloc::vec![false; blk_w * blk_h],
1320 blk_h,
1321 refi: [alloc::vec![-1i8; blk_w * blk_h], alloc::vec![-1i8; blk_w * blk_h]],
1322 refp: [alloc::vec![0i32; blk_w * blk_h], alloc::vec![0i32; blk_w * blk_h]],
1323 num_ref: [1, 1],
1324 mb_slice: alloc::vec![0u32; (sps.width_mbs * sps.height_mbs) as usize],
1325 cur_slice: 0,
1326 mb_db: alloc::vec![MbDeblock::default(); (sps.width_mbs * sps.height_mbs) as usize],
1327 mb_t8: alloc::vec![false; (sps.width_mbs * sps.height_mbs) as usize],
1328 wp: WpMode::Off,
1329 cur_poc: lists.cur_poc,
1330 };
1331 if slices.is_empty() {
1332 return Err("no slices");
1333 }
1334 for (i, rbsp) in slices.iter().enumerate() {
1335 st.cur_slice = i as u32 + 1;
1337 st.decoded.fill(false);
1338 decode_slice_into(&mut st, sps, pps, rbsp, is_idr, nal_ref_idc, lists)?;
1339 }
1340 deblock_frame(
1342 &mut st,
1343 sps.width_mbs as usize,
1344 sps.height_mbs as usize,
1345 pps.chroma_qp_offsets(),
1346 );
1347 let motion = Motion { blk_w: st.blk_w, mv: st.mv, refi: st.refi };
1348 Ok((st.yuv, motion))
1349}
1350
1351#[allow(clippy::too_many_arguments)]
1353fn decode_slice_into(
1354 st: &mut DecState,
1355 sps: &Sps,
1356 pps: &Pps,
1357 rbsp: &[u8],
1358 is_idr: bool,
1359 nal_ref_idc: u8,
1360 lists: &RefLists,
1361) -> Result<(), &'static str> {
1362 let width = st.yuv.width;
1363 let height = st.yuv.height;
1364
1365 let mut r = BitReader::new(rbsp);
1366
1367 let h = parse_slice_header(&mut r, sps, pps, is_idr, nal_ref_idc)?;
1369 let first_mb = h.first_mb as usize;
1370 let is_i = h.kind == SliceKind::I;
1371 let max_frame_num = 1i32 << sps.log2_max_frame_num;
1373 let mut l0: Vec<RefEntry> = if h.kind == SliceKind::B { lists.b[0].clone() } else { lists.p.clone() };
1374 let mut l1: Vec<RefEntry> = lists.b[1].clone();
1375 for (list, l) in [&mut l0, &mut l1].into_iter().enumerate() {
1376 let n = h.num_ref_idx_active[list] as usize;
1377 l.truncate(n);
1378 if !h.list_mod[list].is_empty() {
1379 modify_ref_list(l, &h.list_mod[list], &lists.p, h.frame_num, max_frame_num, n)?;
1380 }
1381 }
1382 let refs: &[RefEntry] = &l0;
1383 let refs_l1: &[RefEntry] = &l1;
1384 if h.kind == SliceKind::B {
1385 if !h.direct_spatial_mv_pred {
1386 return Err("temporal direct not supported");
1387 }
1388 if refs.is_empty() || refs_l1.is_empty() {
1389 return Err("B slice without reference frames");
1390 }
1391 if refs_l1[0].motion.is_none() {
1393 return Err("B slice needs co-located motion");
1394 }
1395 }
1396 if h.kind != SliceKind::I {
1397 if refs.is_empty() {
1399 return Err("P slice without reference frame");
1400 }
1401 if refs.iter().chain(refs_l1.iter()).any(|f| f.yuv.width != width || f.yuv.height != height) {
1402 return Err("reference dimension mismatch");
1403 }
1404 st.num_ref = h.num_ref_idx_active;
1405 if h.kind == SliceKind::P && st.num_ref[0] as usize > refs.len() {
1406 return Err("not enough reference frames");
1407 }
1408 }
1409 st.wp = match (&h.pwt, h.kind) {
1410 (Some(t), _) => WpMode::Explicit(t.clone()),
1411 (None, SliceKind::B) if pps.weighted_bipred_idc == 2 => WpMode::Implicit,
1412 _ => WpMode::Off,
1413 };
1414 let slice_qp = h.slice_qp;
1415 let disable_deblock_idc = h.disable_deblocking_filter_idc;
1416 let alpha_off = h.slice_alpha_c0_offset;
1417 let beta_off = h.slice_beta_offset;
1418
1419 let mb_w = sps.width_mbs;
1421 let mb_h = sps.height_mbs;
1422 let total_mb = (mb_w * mb_h) as usize;
1423 if first_mb >= total_mb {
1424 return Err("first_mb_in_slice out of range");
1425 }
1426 let mut qp = slice_qp;
1427 let db = MbDeblock { disable_idc: disable_deblock_idc, alpha_off, beta_off };
1428 let slice_id = st.cur_slice;
1429 let begin_mb = |st: &mut DecState, mb_idx: usize| {
1431 if let Some(m) = st.mb_slice.get_mut(mb_idx) {
1432 *m = slice_id;
1433 }
1434 if let Some(m) = st.mb_db.get_mut(mb_idx) {
1435 *m = db;
1436 }
1437 };
1438
1439 if pps.entropy_coding_mode_flag != 0 {
1440 let init = if is_i { None } else { Some(h.cabac_init_idc) };
1442 let engine = CabacEngine::new(rbsp, r.bit_position(), slice_qp, init);
1443 let mut cr = CabacReader::new(engine, st);
1444 let ctx = BCtx { l: [refs, refs_l1], direct_8x8: sps.direct_8x8_inference_flag };
1445 let mut mb_idx = first_mb;
1446 while mb_idx < total_mb {
1447 let mb_x = (mb_idx as u32 % mb_w) * 16;
1448 let mb_y = (mb_idx as u32 / mb_w) * 16;
1449 begin_mb(st, mb_idx);
1450 cr.start_mb(mb_idx);
1451 let res = if !is_i && cr.mb_skip(st, mb_x, mb_y, h.kind) {
1452 if h.kind == SliceKind::B {
1453 cr.mark_direct(mb_x as usize, mb_y as usize, 16, 16);
1454 let r = decode_b_direct_mb(st, mb_x, mb_y, &ctx);
1455 st.mb_qp[mb_idx] = qp;
1456 r
1457 } else {
1458 decode_pskip(st, mb_x, mb_y, qp, refs);
1459 Ok(())
1460 }
1461 } else {
1462 match h.kind {
1463 SliceKind::I => decode_mb(&mut cr, st, mb_x, mb_y, &mut qp, pps),
1464 SliceKind::P => decode_mb_p(&mut cr, st, mb_x, mb_y, &mut qp, pps, refs),
1465 SliceKind::B => decode_mb_b(&mut cr, st, mb_x, mb_y, &mut qp, pps, &ctx),
1466 }
1467 };
1468 if let Err(e) = res {
1469 crate::println!(" H264 CABAC decode stopped at mb {} (of {}): {}", mb_idx, total_mb, e);
1470 return Err(e);
1471 }
1472 mb_idx += 1;
1473 if cr.e.terminate() == 1 {
1474 break;
1475 }
1476 }
1477 } else if is_i {
1478 let mut mb_idx = first_mb;
1479 while mb_idx < total_mb {
1480 let mb_x = (mb_idx as u32 % mb_w) * 16;
1481 let mb_y = (mb_idx as u32 / mb_w) * 16;
1482 begin_mb(st, mb_idx);
1483 if let Err(e) = decode_mb(&mut r, st, mb_x, mb_y, &mut qp, pps) {
1484 crate::println!(
1485 " H264 decode stopped at mb {} (of {}): {}",
1486 mb_idx,
1487 total_mb,
1488 e
1489 );
1490 return Err(e);
1491 }
1492 mb_idx += 1;
1493 if !r.more_rbsp_data() {
1494 break;
1495 }
1496 }
1497 } else if h.kind == SliceKind::B {
1498 let ctx = BCtx { l: [refs, refs_l1], direct_8x8: sps.direct_8x8_inference_flag };
1500 let mut mb_idx = first_mb;
1501 while mb_idx < total_mb {
1502 let skip_run = r.read_ue() as usize;
1503 for _ in 0..skip_run {
1504 if mb_idx >= total_mb {
1505 break;
1506 }
1507 let mb_x = (mb_idx as u32 % mb_w) * 16;
1508 let mb_y = (mb_idx as u32 / mb_w) * 16;
1509 begin_mb(st, mb_idx);
1510 decode_b_direct_mb(st, mb_x, mb_y, &ctx)?;
1511 st.mb_qp[mb_idx] = qp;
1512 mb_idx += 1;
1513 }
1514 if mb_idx >= total_mb || !r.more_rbsp_data() {
1515 break;
1516 }
1517 let mb_x = (mb_idx as u32 % mb_w) * 16;
1518 let mb_y = (mb_idx as u32 / mb_w) * 16;
1519 begin_mb(st, mb_idx);
1520 if let Err(e) = decode_mb_b(&mut r, st, mb_x, mb_y, &mut qp, pps, &ctx) {
1521 crate::println!(" H264 B decode stopped at mb {} (of {}): {}", mb_idx, total_mb, e);
1522 return Err(e);
1523 }
1524 mb_idx += 1;
1525 if !r.more_rbsp_data() {
1526 break;
1527 }
1528 }
1529 } else {
1530 let mut mb_idx = first_mb;
1533 while mb_idx < total_mb {
1534 let skip_run = r.read_ue() as usize;
1535 for _ in 0..skip_run {
1536 if mb_idx >= total_mb {
1537 break;
1538 }
1539 let mb_x = (mb_idx as u32 % mb_w) * 16;
1540 let mb_y = (mb_idx as u32 / mb_w) * 16;
1541 begin_mb(st, mb_idx);
1542 decode_pskip(st, mb_x, mb_y, qp, refs);
1543 mb_idx += 1;
1544 }
1545 if mb_idx >= total_mb || !r.more_rbsp_data() {
1547 break;
1548 }
1549 let mb_x = (mb_idx as u32 % mb_w) * 16;
1550 let mb_y = (mb_idx as u32 / mb_w) * 16;
1551 begin_mb(st, mb_idx);
1552 if let Err(e) = decode_mb_p(&mut r, st, mb_x, mb_y, &mut qp, pps, refs) {
1553 crate::println!(
1554 " H264 P decode stopped at mb {} (of {}): {}",
1555 mb_idx,
1556 total_mb,
1557 e
1558 );
1559 return Err(e);
1560 }
1561 mb_idx += 1;
1562 if !r.more_rbsp_data() {
1563 break;
1564 }
1565 }
1566 }
1567 Ok(())
1568
1569}
1570
1571#[derive(Clone, Copy)]
1579enum ResBlock {
1580 LumaDc { bx4: usize, by4: usize },
1582 LumaAc { bx4: usize, by4: usize },
1584 Luma4x4 { bx4: usize, by4: usize },
1586 ChromaDc { comp: usize, mb_x: u32, mb_y: u32 },
1588 ChromaAc { comp: usize, cbx4: usize, cby4: usize },
1590}
1591
1592#[allow(clippy::too_many_arguments)]
1594trait MbSyntax {
1595 fn mb_type(&mut self, st: &DecState, mb_x: u32, mb_y: u32, kind: SliceKind) -> Result<u32, &'static str>;
1596 fn sub_mb_type(&mut self, kind: SliceKind) -> Result<u32, &'static str>;
1597 fn intra4x4_rem(&mut self) -> Option<i32>;
1599 fn intra_chroma_mode(&mut self, st: &DecState, mb_x: u32, mb_y: u32) -> Result<u8, &'static str>;
1600 fn cbp(&mut self, st: &DecState, mb_x: u32, mb_y: u32, intra: bool) -> Result<u32, &'static str>;
1601 fn qp_delta(&mut self) -> Result<i32, &'static str>;
1602 fn ref_idx(&mut self, st: &DecState, list: usize, px: usize, py: usize, pw: usize, ph: usize, num_ref: u32) -> Result<i8, &'static str>;
1604 fn mvd(&mut self, st: &DecState, list: usize, px: usize, py: usize, pw: usize, ph: usize) -> Result<[i16; 2], &'static str>;
1606 fn residual(&mut self, st: &DecState, blk: ResBlock) -> Result<([i32; 16], u8), &'static str>;
1608 fn pcm(&mut self, out: &mut [u8; 384]);
1610 fn transform_8x8(&mut self, st: &DecState, mb_x: u32, mb_y: u32) -> bool;
1612 fn residual8x8(&mut self, st: &DecState, bx4: usize, by4: usize) -> Result<([i32; 64], [u8; 4]), &'static str>;
1614 fn mark_direct(&mut self, _px: usize, _py: usize, _pw: usize, _ph: usize) {}
1616}
1617
1618impl MbSyntax for BitReader<'_> {
1619 fn mb_type(&mut self, _st: &DecState, _mb_x: u32, _mb_y: u32, _kind: SliceKind) -> Result<u32, &'static str> {
1620 Ok(self.read_ue())
1621 }
1622 fn sub_mb_type(&mut self, _kind: SliceKind) -> Result<u32, &'static str> {
1623 Ok(self.read_ue())
1624 }
1625 fn intra4x4_rem(&mut self) -> Option<i32> {
1626 if self.read_bit() == 1 {
1627 None
1628 } else {
1629 Some(self.read_bits(3) as i32)
1630 }
1631 }
1632 fn intra_chroma_mode(&mut self, _st: &DecState, _mb_x: u32, _mb_y: u32) -> Result<u8, &'static str> {
1633 let m = self.read_ue();
1634 if m > 3 {
1635 return Err("bad intra_chroma_pred_mode");
1636 }
1637 Ok(m as u8)
1638 }
1639 fn cbp(&mut self, _st: &DecState, _mb_x: u32, _mb_y: u32, intra: bool) -> Result<u32, &'static str> {
1640 let codenum = self.read_ue() as usize;
1641 let map = if intra { &CBP_INTRA_MAP } else { &CBP_INTER_MAP };
1642 Ok(*map.get(codenum).ok_or("cbp codeNum out of range")? as u32)
1643 }
1644 fn qp_delta(&mut self) -> Result<i32, &'static str> {
1645 Ok(self.read_se())
1646 }
1647 fn ref_idx(&mut self, _st: &DecState, _list: usize, _px: usize, _py: usize, _pw: usize, _ph: usize, num_ref: u32) -> Result<i8, &'static str> {
1648 read_ref_idx(self, num_ref)
1649 }
1650 fn mvd(&mut self, _st: &DecState, _list: usize, _px: usize, _py: usize, _pw: usize, _ph: usize) -> Result<[i16; 2], &'static str> {
1651 Ok([self.read_se() as i16, self.read_se() as i16])
1652 }
1653 fn residual(&mut self, st: &DecState, blk: ResBlock) -> Result<([i32; 16], u8), &'static str> {
1654 Ok(match blk {
1655 ResBlock::LumaDc { bx4, by4 } => residual_block_cavlc(self, 16, st.luma_nc(bx4, by4), TOTAL_ZEROS_16),
1656 ResBlock::LumaAc { bx4, by4 } => residual_block_cavlc(self, 15, st.luma_nc(bx4, by4), TOTAL_ZEROS_16),
1657 ResBlock::Luma4x4 { bx4, by4 } => residual_block_cavlc(self, 16, st.luma_nc(bx4, by4), TOTAL_ZEROS_16),
1658 ResBlock::ChromaDc { .. } => residual_block_cavlc(self, 4, -1, TOTAL_ZEROS_CHROMA),
1659 ResBlock::ChromaAc { comp, cbx4, cby4 } => {
1660 residual_block_cavlc(self, 15, chroma_nc(st, comp, cbx4, cby4), TOTAL_ZEROS_16)
1661 }
1662 })
1663 }
1664 fn pcm(&mut self, out: &mut [u8; 384]) {
1665 self.byte_align();
1666 for o in out.iter_mut() {
1667 *o = self.read_bits(8) as u8;
1668 }
1669 }
1670 fn transform_8x8(&mut self, _st: &DecState, _mb_x: u32, _mb_y: u32) -> bool {
1671 self.read_bit() == 1
1672 }
1673 fn residual8x8(&mut self, st: &DecState, bx4: usize, by4: usize) -> Result<([i32; 64], [u8; 4]), &'static str> {
1677 let mut coeff = [0i32; 64];
1678 let mut cnt = [0u8; 4];
1679 for i in 0..4 {
1680 let (x, y) = ((bx4 + i % 2) as isize, (by4 + i / 2) as isize);
1681 let nnz_at = |xx: isize, yy: isize, cnt: &[u8; 4]| -> i32 {
1682 if xx >= bx4 as isize && yy >= by4 as isize {
1683 cnt[(yy as usize - by4) * 2 + (xx as usize - bx4)] as i32
1684 } else if st.avail_blk(xx, yy) {
1685 st.nnz_luma[st.li(xx as usize, yy as usize)] as i32
1686 } else {
1687 -1
1688 }
1689 };
1690 let nc = combine_nc(nnz_at(x - 1, y, &cnt), nnz_at(x, y - 1, &cnt));
1691 let (scan, tc) = residual_block_cavlc(self, 16, nc, TOTAL_ZEROS_16);
1692 cnt[i] = tc;
1693 for k in 0..16 {
1694 coeff[4 * k + i] = scan[k];
1695 }
1696 }
1697 Ok((coeff, cnt))
1698 }
1699}
1700
1701const MBF_INTRA: u8 = 1;
1703const MBF_I16: u8 = 2;
1704const MBF_PCM: u8 = 4;
1705const MBF_DIRECT16: u8 = 8;
1706const MBF_SKIP: u8 = 16;
1707
1708struct CabacReader<'a> {
1711 e: CabacEngine<'a>,
1712 blk_w: usize,
1713 mb_w: usize,
1714 cur_mb: usize,
1715 cur_intra: bool,
1716 mb_flags: Vec<u8>,
1719 mb_cbp: Vec<u8>,
1720 mb_dc: Vec<u8>,
1721 mb_cpm: Vec<u8>,
1722 prev_dqp: i32,
1723 cur_dqp: i32,
1724 mvd: [Vec<[u8; 2]>; 2],
1726 ref_gt0: [Vec<bool>; 2],
1727 direct: Vec<bool>,
1728}
1729
1730impl<'a> CabacReader<'a> {
1731 fn new(e: CabacEngine<'a>, st: &DecState) -> Self {
1732 let n_mb = st.mb_slice.len();
1733 let n_blk = st.blk_w * st.blk_h;
1734 Self {
1735 e,
1736 blk_w: st.blk_w,
1737 mb_w: st.mb_w,
1738 cur_mb: 0,
1739 cur_intra: false,
1740 mb_flags: alloc::vec![0; n_mb],
1741 mb_cbp: alloc::vec![0; n_mb],
1742 mb_dc: alloc::vec![0; n_mb],
1743 mb_cpm: alloc::vec![0; n_mb],
1744 prev_dqp: 0,
1745 cur_dqp: 0,
1746 mvd: [alloc::vec![[0; 2]; n_blk], alloc::vec![[0; 2]; n_blk]],
1747 ref_gt0: [alloc::vec![false; n_blk], alloc::vec![false; n_blk]],
1748 direct: alloc::vec![false; n_blk],
1749 }
1750 }
1751
1752 fn start_mb(&mut self, mb_idx: usize) {
1754 self.cur_mb = mb_idx;
1755 self.prev_dqp = self.cur_dqp;
1756 self.cur_dqp = 0;
1757 self.cur_intra = false;
1758 }
1759
1760 fn nb_mbs(&self, st: &DecState, mb_x: u32, mb_y: u32) -> (Option<usize>, Option<usize>) {
1762 let a = st.avail_px(mb_x as isize - 1, mb_y as isize).then(|| self.cur_mb - 1);
1763 let b = st.avail_px(mb_x as isize, mb_y as isize - 1).then(|| self.cur_mb - self.mb_w);
1764 (a, b)
1765 }
1766
1767 fn mb_skip(&mut self, st: &DecState, mb_x: u32, mb_y: u32, kind: SliceKind) -> bool {
1769 let (a, b) = self.nb_mbs(st, mb_x, mb_y);
1770 let cond = |m: Option<usize>| m.is_some_and(|m| self.mb_flags[m] & MBF_SKIP == 0) as usize;
1771 let base = if kind == SliceKind::B { 24 } else { 11 };
1772 let skip = self.e.decision(base + cond(a) + cond(b)) == 1;
1773 if skip {
1774 self.mb_flags[self.cur_mb] = MBF_SKIP | if kind == SliceKind::B { MBF_DIRECT16 } else { 0 };
1775 self.mb_cbp[self.cur_mb] = 0;
1776 }
1777 skip
1778 }
1779
1780 fn intra_mb_type(&mut self, base: usize, intra_slice: bool, inc: usize) -> u32 {
1782 let mut b = base;
1783 if intra_slice {
1784 if self.e.decision(base + inc) == 0 {
1785 return 0;
1786 }
1787 b += 2;
1788 } else if self.e.decision(base) == 0 {
1789 return 0;
1790 }
1791 if self.e.terminate() == 1 {
1792 return 25;
1793 }
1794 let is = intra_slice as usize;
1795 let mut t = 1 + 12 * self.e.decision(b + 1);
1796 if self.e.decision(b + 2) == 1 {
1797 t += 4 + 4 * self.e.decision(b + 2 + is);
1798 }
1799 t += 2 * self.e.decision(b + 3 + is);
1800 t += self.e.decision(b + 3 + 2 * is);
1801 t
1802 }
1803
1804 fn mvd_comp(&mut self, base: usize, amvd: u32) -> Result<(i16, u8), &'static str> {
1806 let inc = if amvd < 3 { 0 } else if amvd > 32 { 2 } else { 1 };
1807 if self.e.decision(base + inc) == 0 {
1808 return Ok((0, 0));
1809 }
1810 let mut mvd: u32 = 1;
1811 let mut ctx = base + 3;
1812 while mvd < 9 && self.e.decision(ctx) == 1 {
1813 if mvd < 4 {
1814 ctx += 1;
1815 }
1816 mvd += 1;
1817 }
1818 if mvd >= 9 {
1819 let mut k = 3;
1820 while self.e.bypass() == 1 {
1821 mvd += 1 << k;
1822 k += 1;
1823 if k > 24 {
1824 return Err("mvd overflow");
1825 }
1826 }
1827 while k > 0 {
1828 k -= 1;
1829 mvd += self.e.bypass() << k;
1830 }
1831 }
1832 let abs = mvd.min(70) as u8;
1833 let v = mvd.min(i16::MAX as u32) as i16;
1834 Ok((if self.e.bypass() == 1 { -v } else { v }, abs))
1835 }
1836
1837 fn blk_ok(st: &DecState, bx4: isize, by4: isize) -> bool {
1839 bx4 >= 0 && by4 >= 0 && st.avail_blk(bx4, by4)
1840 }
1841}
1842
1843impl MbSyntax for CabacReader<'_> {
1844 fn mb_type(&mut self, st: &DecState, mb_x: u32, mb_y: u32, kind: SliceKind) -> Result<u32, &'static str> {
1845 let (a, b) = self.nb_mbs(st, mb_x, mb_y);
1846 let t = match kind {
1847 SliceKind::I => {
1848 let c = |m: Option<usize>| m.is_some_and(|m| self.mb_flags[m] & (MBF_I16 | MBF_PCM) != 0) as usize;
1849 let inc = c(a) + c(b);
1850 self.intra_mb_type(3, true, inc)
1851 }
1852 SliceKind::P => {
1853 if self.e.decision(14) == 0 {
1854 if self.e.decision(15) == 0 {
1855 3 * self.e.decision(16)
1856 } else {
1857 2 - self.e.decision(17)
1858 }
1859 } else {
1860 5 + self.intra_mb_type(17, false, 0)
1861 }
1862 }
1863 SliceKind::B => {
1864 let c = |m: Option<usize>| m.is_some_and(|m| self.mb_flags[m] & MBF_DIRECT16 == 0) as usize;
1865 let inc = c(a) + c(b);
1866 if self.e.decision(27 + inc) == 0 {
1867 0
1868 } else if self.e.decision(27 + 3) == 0 {
1869 1 + self.e.decision(27 + 5)
1870 } else {
1871 let mut bits = self.e.decision(27 + 4) << 3;
1872 bits |= self.e.decision(27 + 5) << 2;
1873 bits |= self.e.decision(27 + 5) << 1;
1874 bits |= self.e.decision(27 + 5);
1875 match bits {
1876 0..=7 => bits + 3,
1877 13 => 23 + self.intra_mb_type(32, false, 0),
1878 14 => 11,
1879 15 => 22,
1880 _ => ((bits << 1) | self.e.decision(27 + 5)) - 4,
1881 }
1882 }
1883 }
1884 };
1885 let it = match kind {
1887 SliceKind::I => Some(t),
1888 SliceKind::P => t.checked_sub(5),
1889 SliceKind::B => t.checked_sub(23),
1890 };
1891 let m = self.cur_mb;
1892 self.mb_flags[m] = 0;
1893 if let Some(it) = it {
1894 self.cur_intra = true;
1895 self.mb_flags[m] = MBF_INTRA;
1896 if it == 25 {
1897 self.mb_flags[m] |= MBF_PCM;
1898 self.mb_cbp[m] = 0x2f;
1899 self.mb_dc[m] = 7;
1900 } else if it >= 1 {
1901 self.mb_flags[m] |= MBF_I16;
1902 let m1 = it - 1;
1903 self.mb_cbp[m] = ((if m1 >= 12 { 15 } else { 0 }) | (((m1 / 4) % 3) << 4)) as u8;
1904 }
1905 } else if kind == SliceKind::B && t == 0 {
1906 self.mb_flags[m] = MBF_DIRECT16;
1907 }
1908 Ok(t)
1909 }
1910
1911 fn sub_mb_type(&mut self, kind: SliceKind) -> Result<u32, &'static str> {
1912 let e = &mut self.e;
1913 Ok(if kind == SliceKind::B {
1914 if e.decision(36) == 0 {
1915 0
1916 } else if e.decision(37) == 0 {
1917 1 + e.decision(39)
1918 } else {
1919 let mut t = 3;
1920 if e.decision(38) == 1 {
1921 if e.decision(39) == 1 {
1922 return Ok(11 + e.decision(39));
1923 }
1924 t += 4;
1925 }
1926 t += 2 * e.decision(39);
1927 t + e.decision(39)
1928 }
1929 } else if e.decision(21) == 1 {
1930 0
1931 } else if e.decision(22) == 0 {
1932 1
1933 } else if e.decision(23) == 1 {
1934 2
1935 } else {
1936 3
1937 })
1938 }
1939
1940 fn intra4x4_rem(&mut self) -> Option<i32> {
1941 if self.e.decision(68) == 1 {
1942 return None;
1943 }
1944 let b0 = self.e.decision(69);
1945 let b1 = self.e.decision(69);
1946 let b2 = self.e.decision(69);
1947 Some((b0 | (b1 << 1) | (b2 << 2)) as i32)
1948 }
1949
1950 fn intra_chroma_mode(&mut self, st: &DecState, mb_x: u32, mb_y: u32) -> Result<u8, &'static str> {
1951 let (a, b) = self.nb_mbs(st, mb_x, mb_y);
1952 let c = |m: Option<usize>| m.is_some_and(|m| self.mb_cpm[m] != 0) as usize;
1953 let inc = c(a) + c(b);
1954 let mode = if self.e.decision(64 + inc) == 0 {
1955 0
1956 } else if self.e.decision(67) == 0 {
1957 1
1958 } else if self.e.decision(67) == 0 {
1959 2
1960 } else {
1961 3
1962 };
1963 self.mb_cpm[self.cur_mb] = mode;
1964 Ok(mode)
1965 }
1966
1967 fn cbp(&mut self, st: &DecState, mb_x: u32, mb_y: u32, _intra: bool) -> Result<u32, &'static str> {
1968 let (a, b) = self.nb_mbs(st, mb_x, mb_y);
1969 let ca = a.map_or(0x0f, |m| self.mb_cbp[m] as u32);
1971 let cb = b.map_or(0x0f, |m| self.mb_cbp[m] as u32);
1972 let nz = |v: u32, bit: u32| (v & bit == 0) as usize;
1973 let mut cbp = 0u32;
1974 cbp |= self.e.decision(73 + nz(ca, 2) + 2 * nz(cb, 4));
1975 cbp |= self.e.decision(73 + nz(cbp, 1) + 2 * nz(cb, 8)) << 1;
1976 cbp |= self.e.decision(73 + nz(ca, 8) + 2 * nz(cbp, 1)) << 2;
1977 cbp |= self.e.decision(73 + nz(cbp, 4) + 2 * nz(cbp, 2)) << 3;
1978 let (cha, chb) = ((ca >> 4) & 3, (cb >> 4) & 3);
1979 let inc = (cha > 0) as usize + 2 * (chb > 0) as usize;
1980 if self.e.decision(77 + inc) == 1 {
1981 let inc2 = 4 + (cha == 2) as usize + 2 * (chb == 2) as usize;
1982 cbp |= (1 + self.e.decision(77 + inc2)) << 4;
1983 }
1984 self.mb_cbp[self.cur_mb] = cbp as u8;
1985 Ok(cbp)
1986 }
1987
1988 fn qp_delta(&mut self) -> Result<i32, &'static str> {
1989 let mut v = 0i32;
1990 if self.e.decision(60 + (self.prev_dqp != 0) as usize) == 1 {
1991 v = 1;
1992 let mut ctx = 2;
1993 while self.e.decision(60 + ctx) == 1 {
1994 ctx = 3;
1995 v += 1;
1996 if v > 104 {
1997 return Err("bad mb_qp_delta");
1998 }
1999 }
2000 v = if v & 1 == 1 { (v + 1) >> 1 } else { -((v + 1) >> 1) };
2001 }
2002 self.cur_dqp = v;
2003 Ok(v)
2004 }
2005
2006 fn ref_idx(&mut self, st: &DecState, list: usize, px: usize, py: usize, pw: usize, ph: usize, num_ref: u32) -> Result<i8, &'static str> {
2007 if num_ref <= 1 {
2008 return Ok(0);
2009 }
2010 let (bx, by) = ((px / 4) as isize, (py / 4) as isize);
2011 let cond = |x: isize, y: isize| -> usize {
2012 if !Self::blk_ok(st, x, y) {
2013 return 0;
2014 }
2015 let li = y as usize * self.blk_w + x as usize;
2016 (self.ref_gt0[list][li] && !self.direct[li]) as usize
2017 };
2018 let mut ctx = cond(bx - 1, by) + 2 * cond(bx, by - 1);
2019 let mut v = 0u32;
2020 while self.e.decision(54 + ctx) == 1 {
2021 v += 1;
2022 ctx = if ctx < 4 { 4 } else { 5 };
2023 if v >= 32 {
2024 return Err("ref_idx overflow");
2025 }
2026 }
2027 if v >= num_ref {
2028 return Err("ref_idx out of range");
2029 }
2030 for y in py / 4..(py + ph) / 4 {
2031 for x in px / 4..(px + pw) / 4 {
2032 self.ref_gt0[list][y * self.blk_w + x] = v > 0;
2033 }
2034 }
2035 Ok(v as i8)
2036 }
2037
2038 fn mvd(&mut self, st: &DecState, list: usize, px: usize, py: usize, pw: usize, ph: usize) -> Result<[i16; 2], &'static str> {
2039 let (bx, by) = ((px / 4) as isize, (py / 4) as isize);
2040 let get = |x: isize, y: isize| -> [u32; 2] {
2041 if !Self::blk_ok(st, x, y) {
2042 return [0, 0];
2043 }
2044 let m = self.mvd[list][y as usize * self.blk_w + x as usize];
2045 [m[0] as u32, m[1] as u32]
2046 };
2047 let (a, b) = (get(bx - 1, by), get(bx, by - 1));
2048 let (mx, ax) = self.mvd_comp(40, a[0] + b[0])?;
2049 let (my, ay) = self.mvd_comp(47, a[1] + b[1])?;
2050 for y in py / 4..(py + ph) / 4 {
2051 for x in px / 4..(px + pw) / 4 {
2052 self.mvd[list][y * self.blk_w + x] = [ax, ay];
2053 }
2054 }
2055 Ok([mx, my])
2056 }
2057
2058 fn residual(&mut self, st: &DecState, blk: ResBlock) -> Result<([i32; 16], u8), &'static str> {
2059 let intra = self.cur_intra as usize;
2061 let mb_cond = |rd: &Self, avail: bool, m: usize, bit: u8| -> usize {
2062 if !avail {
2063 intra
2064 } else if rd.mb_flags[m] & MBF_PCM != 0 {
2065 1
2066 } else {
2067 (rd.mb_dc[m] & bit != 0) as usize
2068 }
2069 };
2070 let blk_cond = |avail: bool, nnz: u8| -> usize { if !avail { intra } else { (nnz > 0) as usize } };
2071 let (cat, max, inc) = match blk {
2072 ResBlock::LumaDc { bx4, by4 } => {
2073 let (mx, my) = ((bx4 * 4) as u32, (by4 * 4) as u32);
2074 let (a, b) = self.nb_mbs(st, mx, my);
2075 let ia = mb_cond(self, a.is_some(), a.unwrap_or(0), 1);
2076 let ib = mb_cond(self, b.is_some(), b.unwrap_or(0), 1);
2077 (0usize, 16usize, ia + 2 * ib)
2078 }
2079 ResBlock::LumaAc { bx4, by4 } | ResBlock::Luma4x4 { bx4, by4 } => {
2080 let (x, y) = (bx4 as isize, by4 as isize);
2081 let ao = Self::blk_ok(st, x - 1, y);
2082 let bo = Self::blk_ok(st, x, y - 1);
2083 let ia = blk_cond(ao, if ao { st.nnz_luma[st.li(bx4 - 1, by4)] } else { 0 });
2084 let ib = blk_cond(bo, if bo { st.nnz_luma[st.li(bx4, by4 - 1)] } else { 0 });
2085 if matches!(blk, ResBlock::LumaAc { .. }) {
2086 (1, 15, ia + 2 * ib)
2087 } else {
2088 (2, 16, ia + 2 * ib)
2089 }
2090 }
2091 ResBlock::ChromaDc { comp, mb_x, mb_y } => {
2092 let (a, b) = self.nb_mbs(st, mb_x, mb_y);
2093 let bit = 2 << comp;
2094 let ia = mb_cond(self, a.is_some(), a.unwrap_or(0), bit);
2095 let ib = mb_cond(self, b.is_some(), b.unwrap_or(0), bit);
2096 (3, 4, ia + 2 * ib)
2097 }
2098 ResBlock::ChromaAc { comp, cbx4, cby4 } => {
2099 let ao = st.avail_px(cbx4 as isize * 8 - 1, cby4 as isize * 8);
2100 let bo = st.avail_px(cbx4 as isize * 8, cby4 as isize * 8 - 1);
2101 let ia = blk_cond(ao, if ao { st.nnz_chroma[comp][cby4 * st.cblk_w + cbx4 - 1] } else { 0 });
2102 let ib = blk_cond(bo, if bo { st.nnz_chroma[comp][(cby4 - 1) * st.cblk_w + cbx4] } else { 0 });
2103 (4, 15, ia + 2 * ib)
2104 }
2105 };
2106 let mut coeff = [0i32; 16];
2107 if self.e.decision(85 + cat * 4 + inc) == 0 {
2108 return Ok((coeff, 0));
2109 }
2110 match blk {
2111 ResBlock::LumaDc { .. } => self.mb_dc[self.cur_mb] |= 1,
2112 ResBlock::ChromaDc { comp, .. } => self.mb_dc[self.cur_mb] |= 2 << comp,
2113 _ => {}
2114 }
2115 const SIG_OFF: [usize; 5] = [0, 15, 29, 44, 47];
2117 const ABS_OFF: [usize; 5] = [0, 10, 20, 30, 39];
2118 let sig = 105 + SIG_OFF[cat];
2119 let last = 166 + SIG_OFF[cat];
2120 let mut pos = [0usize; 16];
2121 let mut n = 0usize;
2122 let mut ended = false;
2123 for i in 0..max - 1 {
2124 let inc = if cat == 3 { i.min(2) } else { i };
2125 if self.e.decision(sig + inc) == 1 {
2126 pos[n] = i;
2127 n += 1;
2128 if self.e.decision(last + inc) == 1 {
2129 ended = true;
2130 break;
2131 }
2132 }
2133 }
2134 if !ended {
2135 pos[n] = max - 1;
2136 n += 1;
2137 }
2138 let abs_base = 227 + ABS_OFF[cat];
2140 let (mut eq1, mut gt1) = (0usize, 0usize);
2141 for k in (0..n).rev() {
2142 let inc0 = if gt1 != 0 { 0 } else { (1 + eq1).min(4) };
2143 let mut abs: u32 = 1;
2144 if self.e.decision(abs_base + inc0) == 1 {
2145 let inc = 5 + gt1.min(4 - (cat == 3) as usize);
2146 abs = 2;
2147 while abs < 15 && self.e.decision(abs_base + inc) == 1 {
2148 abs += 1;
2149 }
2150 if abs >= 15 {
2151 let mut j = 0;
2152 while self.e.bypass() == 1 && j < 23 {
2153 j += 1;
2154 }
2155 let mut v: u32 = 1;
2156 for _ in 0..j {
2157 v = 2 * v + self.e.bypass();
2158 }
2159 abs = v + 14;
2160 }
2161 }
2162 if abs == 1 {
2163 eq1 += 1;
2164 } else {
2165 gt1 += 1;
2166 }
2167 let v = abs.min(i32::MAX as u32) as i32;
2168 coeff[pos[k]] = if self.e.bypass() == 1 { -v } else { v };
2169 }
2170 Ok((coeff, n as u8))
2171 }
2172
2173 fn pcm(&mut self, out: &mut [u8; 384]) {
2174 self.e.read_pcm(out);
2175 }
2176
2177 fn transform_8x8(&mut self, st: &DecState, mb_x: u32, mb_y: u32) -> bool {
2178 let (a, b) = self.nb_mbs(st, mb_x, mb_y);
2179 let c = |m: Option<usize>| m.is_some_and(|m| st.mb_t8[m]) as usize;
2180 self.e.decision(399 + c(a) + c(b)) == 1
2181 }
2182
2183 fn residual8x8(&mut self, _st: &DecState, _bx4: usize, _by4: usize) -> Result<([i32; 64], [u8; 4]), &'static str> {
2185 let mut coeff = [0i32; 64];
2186 let mut pos = [0usize; 64];
2187 let mut n = 0usize;
2188 let mut ended = false;
2189 for i in 0..63 {
2190 if self.e.decision(402 + SIG_CTX_8X8_FRAME[i] as usize) == 1 {
2191 pos[n] = i;
2192 n += 1;
2193 if self.e.decision(417 + LAST_CTX_8X8[i] as usize) == 1 {
2194 ended = true;
2195 break;
2196 }
2197 }
2198 }
2199 if !ended {
2200 pos[n] = 63;
2201 n += 1;
2202 }
2203 let (mut eq1, mut gt1) = (0usize, 0usize);
2204 for k in (0..n).rev() {
2205 let inc0 = if gt1 != 0 { 0 } else { (1 + eq1).min(4) };
2206 let mut abs: u32 = 1;
2207 if self.e.decision(426 + inc0) == 1 {
2208 let inc = 5 + gt1.min(4);
2209 abs = 2;
2210 while abs < 15 && self.e.decision(426 + inc) == 1 {
2211 abs += 1;
2212 }
2213 if abs >= 15 {
2214 let mut j = 0;
2215 while self.e.bypass() == 1 && j < 23 {
2216 j += 1;
2217 }
2218 let mut v: u32 = 1;
2219 for _ in 0..j {
2220 v = 2 * v + self.e.bypass();
2221 }
2222 abs = v + 14;
2223 }
2224 }
2225 if abs == 1 {
2226 eq1 += 1;
2227 } else {
2228 gt1 += 1;
2229 }
2230 let v = abs.min(i32::MAX as u32) as i32;
2231 coeff[pos[k]] = if self.e.bypass() == 1 { -v } else { v };
2232 }
2233 Ok((coeff, [n as u8; 4]))
2234 }
2235
2236 fn mark_direct(&mut self, px: usize, py: usize, pw: usize, ph: usize) {
2237 for y in py / 4..(py + ph) / 4 {
2238 for x in px / 4..(px + pw) / 4 {
2239 self.direct[y * self.blk_w + x] = true;
2240 }
2241 }
2242 }
2243}
2244
2245#[allow(clippy::too_many_arguments)]
2246fn decode_mb<R: MbSyntax>(
2247 r: &mut R,
2248 st: &mut DecState,
2249 mb_x: u32,
2250 mb_y: u32,
2251 qp: &mut i32,
2252 pps: &Pps,
2253) -> Result<(), &'static str> {
2254 let mb_type = r.mb_type(st, mb_x, mb_y, SliceKind::I)?;
2255 if mb_type == 25 {
2256 return decode_mb_ipcm(r, st, mb_x, mb_y);
2257 }
2258 if mb_type == 0 {
2259 decode_mb_i4x4(r, st, mb_x, mb_y, qp, pps)
2260 } else if (1..=24).contains(&mb_type) {
2261 decode_mb_i16x16(r, st, mb_x, mb_y, qp, mb_type, pps)
2262 } else {
2263 Err("unsupported mb_type (non-I)")
2264 }
2265}
2266
2267fn decode_mb_ipcm<R: MbSyntax>(
2269 r: &mut R,
2270 st: &mut DecState,
2271 mb_x: u32,
2272 mb_y: u32,
2273) -> Result<(), &'static str> {
2274 let mut buf = [0u8; 384];
2275 r.pcm(&mut buf);
2276 let w = st.yuv.width as usize;
2277 let cw = (st.yuv.width / 2) as usize;
2278 let (mx, my) = (mb_x as usize, mb_y as usize);
2279 for by in 0..16 {
2280 for bx in 0..16 {
2281 st.yuv.y[(my + by) * w + mx + bx] = buf[by * 16 + bx];
2282 }
2283 }
2284 let (cmx, cmy) = (mx / 2, my / 2);
2285 for by in 0..8 {
2286 for bx in 0..8 {
2287 st.yuv.u[(cmy + by) * cw + cmx + bx] = buf[256 + by * 8 + bx];
2288 st.yuv.v[(cmy + by) * cw + cmx + bx] = buf[320 + by * 8 + bx];
2289 }
2290 }
2291 let bx0 = mx / 4;
2293 let by0 = my / 4;
2294 for dy in 0..4 {
2295 for dx in 0..4 {
2296 let li = st.li(bx0 + dx, by0 + dy);
2297 st.nnz_luma[li] = 16;
2298 st.mode_luma[li] = -1;
2299 st.decoded[li] = true;
2300 }
2301 }
2302 let cbx0 = cmx / 4;
2303 let cby0 = cmy / 4;
2304 for comp in 0..2 {
2305 for dy in 0..2 {
2306 for dx in 0..2 {
2307 st.nnz_chroma[comp][(cby0 + dy) * st.cblk_w + cbx0 + dx] = 16;
2308 }
2309 }
2310 }
2311 st.mb_qp[(my / 16) * st.mb_w + (mx / 16)] = 0;
2313 Ok(())
2314}
2315
2316fn median3(a: i16, b: i16, c: i16) -> i16 {
2317 a + b + c - a.min(b).min(c) - a.max(b).max(c)
2318}
2319
2320fn mv_predict_16x16(st: &DecState, mb_x: u32, mb_y: u32) -> [i16; 2] {
2324 let bx0 = (mb_x / 4) as i32;
2325 let by0 = (mb_y / 4) as i32;
2326 let getn = |bx: i32, by: i32| -> (bool, bool, [i16; 2]) {
2328 if bx >= 0 && by >= 0 && (bx as usize) < st.blk_w && (by as usize) < st.blk_h {
2329 let li = (by as usize) * st.blk_w + bx as usize;
2330 if st.decoded[li] {
2331 if st.is_inter[li] {
2332 return (true, true, st.mv[0][li]);
2333 }
2334 return (true, false, [0, 0]); }
2336 }
2337 (false, false, [0, 0])
2338 };
2339 let (_a_av, a_m, mva) = getn(bx0 - 1, by0); let (_b_av, b_m, mvb) = getn(bx0, by0 - 1); let (c_av, c_m0, mvc0) = getn(bx0 + 4, by0 - 1); let (mut c_m, mut mvc) = (c_m0, mvc0);
2343 if !c_av {
2344 let (_d_av, d_m, mvd) = getn(bx0 - 1, by0 - 1);
2346 c_m = d_m;
2347 mvc = mvd;
2348 }
2349 let b_mb_avail = mb_y > 0;
2351 let c_mb_avail = mb_y > 0 && (bx0 + 4 < st.blk_w as i32 || mb_x > 0);
2352 if !b_mb_avail && !c_mb_avail && mb_x > 0 {
2353 return mva;
2354 }
2355 let matches = a_m as i32 + b_m as i32 + c_m as i32;
2356 if matches == 1 {
2357 if a_m {
2358 return mva;
2359 }
2360 if b_m {
2361 return mvb;
2362 }
2363 return mvc;
2364 }
2365 [
2366 median3(mva[0], mvb[0], mvc[0]),
2367 median3(mva[1], mvb[1], mvc[1]),
2368 ]
2369}
2370
2371fn predict_pskip_mv(st: &DecState, mb_x: u32, mb_y: u32) -> [i16; 2] {
2373 let bx0 = (mb_x / 4) as usize;
2374 let by0 = (mb_y / 4) as usize;
2375 let a_avail = st.avail_px(mb_x as isize - 1, mb_y as isize);
2376 let b_avail = st.avail_px(mb_x as isize, mb_y as isize - 1);
2377 if !a_avail || !b_avail {
2378 return [0, 0];
2379 }
2380 let a_li = by0 * st.blk_w + bx0 - 1;
2381 let b_li = (by0 - 1) * st.blk_w + bx0;
2382 let zero_inter = |li: usize| st.is_inter[li] && st.refi[0][li] == 0 && st.mv[0][li] == [0, 0];
2387 if zero_inter(a_li) || zero_inter(b_li) {
2388 return [0, 0];
2389 }
2390 let _ = (bx0, by0);
2391 mv_predict(st, mb_x as usize, mb_y as usize, 16, MvDir::None, 0)
2392}
2393
2394fn interp_luma_core<F: Fn(isize, isize) -> i32>(get: F, fx: i32, fy: i32) -> i32 {
2396 let tap =
2397 |a: i32, b: i32, c: i32, d: i32, e: i32, f: i32| a - 5 * b + 20 * c + 20 * d - 5 * e + f;
2398 if fx == 0 && fy == 0 {
2399 return get(0, 0);
2400 }
2401 let hh = |dy: isize| -> i32 {
2403 clip1(
2404 (tap(
2405 get(-2, dy),
2406 get(-1, dy),
2407 get(0, dy),
2408 get(1, dy),
2409 get(2, dy),
2410 get(3, dy),
2411 ) + 16)
2412 >> 5,
2413 )
2414 };
2415 let vh = |dx: isize| -> i32 {
2416 clip1(
2417 (tap(
2418 get(dx, -2),
2419 get(dx, -1),
2420 get(dx, 0),
2421 get(dx, 1),
2422 get(dx, 2),
2423 get(dx, 3),
2424 ) + 16)
2425 >> 5,
2426 )
2427 };
2428 let jj = || -> i32 {
2429 let vi = |dx: isize| {
2430 tap(
2431 get(dx, -2),
2432 get(dx, -1),
2433 get(dx, 0),
2434 get(dx, 1),
2435 get(dx, 2),
2436 get(dx, 3),
2437 )
2438 };
2439 clip1((tap(vi(-2), vi(-1), vi(0), vi(1), vi(2), vi(3)) + 512) >> 10)
2440 };
2441 match (fx, fy) {
2442 (1, 0) => (get(0, 0) + hh(0) + 1) >> 1,
2443 (2, 0) => hh(0),
2444 (3, 0) => (get(1, 0) + hh(0) + 1) >> 1,
2445 (0, 1) => (get(0, 0) + vh(0) + 1) >> 1,
2446 (0, 2) => vh(0),
2447 (0, 3) => (get(0, 1) + vh(0) + 1) >> 1,
2448 (2, 2) => jj(),
2449 (1, 1) => (hh(0) + vh(0) + 1) >> 1,
2450 (3, 1) => (hh(0) + vh(1) + 1) >> 1,
2451 (1, 3) => (vh(0) + hh(1) + 1) >> 1,
2452 (3, 3) => (vh(1) + hh(1) + 1) >> 1,
2453 (2, 1) => (hh(0) + jj() + 1) >> 1,
2454 (1, 2) => (vh(0) + jj() + 1) >> 1,
2455 (3, 2) => (jj() + vh(1) + 1) >> 1,
2456 (2, 3) => (jj() + hh(1) + 1) >> 1,
2457 _ => get(0, 0),
2458 }
2459}
2460
2461fn interp_luma_sample(refr: &DecodedYuv, x: isize, y: isize, fx: i32, fy: i32) -> i32 {
2463 let w = refr.width as isize;
2464 let h = refr.height as isize;
2465 interp_luma_core(
2466 |dx, dy| {
2467 let sx = (x + dx).clamp(0, w - 1);
2468 let sy = (y + dy).clamp(0, h - 1);
2469 refr.y[(sy * w + sx) as usize] as i32
2470 },
2471 fx,
2472 fy,
2473 )
2474}
2475
2476fn mc_part_luma(
2478 st: &mut DecState,
2479 px: usize,
2480 py: usize,
2481 pw: usize,
2482 ph: usize,
2483 mv: [i16; 2],
2484 refr: &DecodedYuv,
2485) {
2486 let w = st.yuv.width as usize;
2487 let h = st.yuv.height as usize;
2488 let fx = (mv[0] & 3) as i32;
2489 let fy = (mv[1] & 3) as i32;
2490 let ix = (mv[0] >> 2) as isize;
2491 let iy = (mv[1] >> 2) as isize;
2492 if fx == 0 && fy == 0 {
2494 let sx0 = px as isize + ix;
2495 let sy0 = py as isize + iy;
2496 if sx0 >= 0
2497 && sy0 >= 0
2498 && sx0 + pw as isize <= w as isize
2499 && sy0 + ph as isize <= h as isize
2500 {
2501 let (sx0, sy0) = (sx0 as usize, sy0 as usize);
2502 for y in 0..ph {
2503 let s = (sy0 + y) * w + sx0;
2504 let d = (py + y) * w + px;
2505 st.yuv.y[d..d + pw].copy_from_slice(&refr.y[s..s + pw]);
2506 }
2507 return;
2508 }
2509 }
2510 let wi = w as isize;
2512 let hi = h as isize;
2513 let halo_ok = px as isize + ix - 2 >= 0
2514 && py as isize + iy - 2 >= 0
2515 && px as isize + ix + pw as isize + 2 < wi
2516 && py as isize + iy + ph as isize + 2 < hi;
2517 if halo_ok {
2518 let needs_j = matches!((fx, fy), (2, 2) | (2, 1) | (2, 3) | (1, 2) | (3, 2));
2521 if needs_j {
2522 let base_x = px as isize + ix;
2523 let base_y = py as isize + iy;
2524 let tap = |a: i32, b: i32, c: i32, d: i32, e: i32, f: i32| {
2525 a - 5 * b + 20 * c + 20 * d - 5 * e + f
2526 };
2527 let g = |rx: isize, ry: isize| refr.y[(ry * wi + rx) as usize] as i32;
2528 let mut vrow = [0i32; 21]; for y in 0..ph {
2530 let ry = base_y + y as isize;
2531 for c in 0..pw + 5 {
2532 let rx = base_x + c as isize - 2;
2533 vrow[c] = tap(
2534 g(rx, ry - 2),
2535 g(rx, ry - 1),
2536 g(rx, ry),
2537 g(rx, ry + 1),
2538 g(rx, ry + 2),
2539 g(rx, ry + 3),
2540 );
2541 }
2542 for x in 0..pw {
2543 let j = clip1(
2544 (tap(
2545 vrow[x],
2546 vrow[x + 1],
2547 vrow[x + 2],
2548 vrow[x + 3],
2549 vrow[x + 4],
2550 vrow[x + 5],
2551 ) + 512)
2552 >> 10,
2553 );
2554 let rx = base_x + x as isize;
2555 let val = match (fx, fy) {
2556 (2, 2) => j,
2557 (2, 1) => {
2558 let b = clip1(
2559 (tap(
2560 g(rx - 2, ry),
2561 g(rx - 1, ry),
2562 g(rx, ry),
2563 g(rx + 1, ry),
2564 g(rx + 2, ry),
2565 g(rx + 3, ry),
2566 ) + 16)
2567 >> 5,
2568 );
2569 (b + j + 1) >> 1
2570 }
2571 (2, 3) => {
2572 let s = clip1(
2573 (tap(
2574 g(rx - 2, ry + 1),
2575 g(rx - 1, ry + 1),
2576 g(rx, ry + 1),
2577 g(rx + 1, ry + 1),
2578 g(rx + 2, ry + 1),
2579 g(rx + 3, ry + 1),
2580 ) + 16)
2581 >> 5,
2582 );
2583 (j + s + 1) >> 1
2584 }
2585 (1, 2) => {
2586 let hp = clip1(
2587 (tap(
2588 g(rx, ry - 2),
2589 g(rx, ry - 1),
2590 g(rx, ry),
2591 g(rx, ry + 1),
2592 g(rx, ry + 2),
2593 g(rx, ry + 3),
2594 ) + 16)
2595 >> 5,
2596 );
2597 (hp + j + 1) >> 1
2598 }
2599 (3, 2) => {
2600 let m = clip1(
2601 (tap(
2602 g(rx + 1, ry - 2),
2603 g(rx + 1, ry - 1),
2604 g(rx + 1, ry),
2605 g(rx + 1, ry + 1),
2606 g(rx + 1, ry + 2),
2607 g(rx + 1, ry + 3),
2608 ) + 16)
2609 >> 5,
2610 );
2611 (j + m + 1) >> 1
2612 }
2613 _ => j,
2614 };
2615 st.yuv.y[(py + y) * w + px + x] = val as u8;
2616 }
2617 }
2618 return;
2619 }
2620 for y in 0..ph {
2621 for x in 0..pw {
2622 let bx = px as isize + x as isize + ix;
2623 let by = py as isize + y as isize + iy;
2624 let v = interp_luma_core(
2625 |dx, dy| refr.y[((by + dy) * wi + bx + dx) as usize] as i32,
2626 fx,
2627 fy,
2628 );
2629 st.yuv.y[(py + y) * w + px + x] = v as u8;
2630 }
2631 }
2632 return;
2633 }
2634 let needs_j = matches!((fx, fy), (2, 2) | (2, 1) | (2, 3) | (1, 2) | (3, 2));
2638 if needs_j {
2639 let base_x = px as isize + ix;
2640 let base_y = py as isize + iy;
2641 let tap =
2642 |a: i32, b: i32, c: i32, d: i32, e: i32, f: i32| a - 5 * b + 20 * c + 20 * d - 5 * e + f;
2643 let g = |rx: isize, ry: isize| {
2644 let cx = rx.clamp(0, wi - 1);
2645 let cy = ry.clamp(0, hi - 1);
2646 refr.y[(cy * wi + cx) as usize] as i32
2647 };
2648 let mut vrow = [0i32; 21]; for y in 0..ph {
2650 let ry = base_y + y as isize;
2651 for c in 0..pw + 5 {
2652 let rx = base_x + c as isize - 2;
2653 vrow[c] = tap(
2654 g(rx, ry - 2),
2655 g(rx, ry - 1),
2656 g(rx, ry),
2657 g(rx, ry + 1),
2658 g(rx, ry + 2),
2659 g(rx, ry + 3),
2660 );
2661 }
2662 for x in 0..pw {
2663 let j = clip1(
2664 (tap(
2665 vrow[x],
2666 vrow[x + 1],
2667 vrow[x + 2],
2668 vrow[x + 3],
2669 vrow[x + 4],
2670 vrow[x + 5],
2671 ) + 512)
2672 >> 10,
2673 );
2674 let rx = base_x + x as isize;
2675 let val = match (fx, fy) {
2676 (2, 2) => j,
2677 (2, 1) => {
2678 let b = clip1(
2679 (tap(
2680 g(rx - 2, ry),
2681 g(rx - 1, ry),
2682 g(rx, ry),
2683 g(rx + 1, ry),
2684 g(rx + 2, ry),
2685 g(rx + 3, ry),
2686 ) + 16)
2687 >> 5,
2688 );
2689 (b + j + 1) >> 1
2690 }
2691 (2, 3) => {
2692 let s = clip1(
2693 (tap(
2694 g(rx - 2, ry + 1),
2695 g(rx - 1, ry + 1),
2696 g(rx, ry + 1),
2697 g(rx + 1, ry + 1),
2698 g(rx + 2, ry + 1),
2699 g(rx + 3, ry + 1),
2700 ) + 16)
2701 >> 5,
2702 );
2703 (j + s + 1) >> 1
2704 }
2705 (1, 2) => {
2706 let hp = clip1(
2707 (tap(
2708 g(rx, ry - 2),
2709 g(rx, ry - 1),
2710 g(rx, ry),
2711 g(rx, ry + 1),
2712 g(rx, ry + 2),
2713 g(rx, ry + 3),
2714 ) + 16)
2715 >> 5,
2716 );
2717 (hp + j + 1) >> 1
2718 }
2719 (3, 2) => {
2720 let m = clip1(
2721 (tap(
2722 g(rx + 1, ry - 2),
2723 g(rx + 1, ry - 1),
2724 g(rx + 1, ry),
2725 g(rx + 1, ry + 1),
2726 g(rx + 1, ry + 2),
2727 g(rx + 1, ry + 3),
2728 ) + 16)
2729 >> 5,
2730 );
2731 (j + m + 1) >> 1
2732 }
2733 _ => j,
2734 };
2735 st.yuv.y[(py + y) * w + px + x] = val as u8;
2736 }
2737 }
2738 return;
2739 }
2740 for y in 0..ph {
2741 for x in 0..pw {
2742 let bx = px as isize + x as isize + ix;
2743 let by = py as isize + y as isize + iy;
2744 st.yuv.y[(py + y) * w + px + x] = interp_luma_sample(refr, bx, by, fx, fy) as u8;
2745 }
2746 }
2747}
2748
2749fn interp_chroma_sample(
2751 plane: &[u8],
2752 cw: isize,
2753 ch: isize,
2754 x: isize,
2755 y: isize,
2756 fx: i32,
2757 fy: i32,
2758) -> i32 {
2759 let get = |dx: isize, dy: isize| -> i32 {
2760 let sx = (x + dx).clamp(0, cw - 1);
2761 let sy = (y + dy).clamp(0, ch - 1);
2762 plane[(sy * cw + sx) as usize] as i32
2763 };
2764 let a = get(0, 0);
2765 let b = get(1, 0);
2766 let c = get(0, 1);
2767 let d = get(1, 1);
2768 ((8 - fx) * (8 - fy) * a + fx * (8 - fy) * b + (8 - fx) * fy * c + fx * fy * d + 32) >> 6
2769}
2770
2771fn mc_part_chroma(
2773 st: &mut DecState,
2774 px: usize,
2775 py: usize,
2776 pw: usize,
2777 ph: usize,
2778 mv: [i16; 2],
2779 refr: &DecodedYuv,
2780) {
2781 let cw = (st.yuv.width / 2) as isize;
2782 let chh = (st.yuv.height / 2) as isize;
2783 let cx = px / 2;
2784 let cy = py / 2;
2785 let cpw = pw / 2;
2786 let cph = ph / 2;
2787 let fx = (mv[0] & 7) as i32;
2788 let fy = (mv[1] & 7) as i32;
2789 let ix = (mv[0] >> 3) as isize;
2790 let iy = (mv[1] >> 3) as isize;
2791 let cwz = cw as usize;
2792 let integer = fx == 0 && fy == 0;
2793 let sx0 = cx as isize + ix;
2794 let sy0 = cy as isize + iy;
2795 let in_bounds = sx0 >= 0 && sy0 >= 0 && sx0 + cpw as isize <= cw && sy0 + cph as isize <= chh;
2796 for comp in 0..2 {
2797 let (dst, src) = if comp == 0 {
2798 (&mut st.yuv.u, &refr.u)
2799 } else {
2800 (&mut st.yuv.v, &refr.v)
2801 };
2802 if integer && in_bounds {
2803 let (sx0, sy0) = (sx0 as usize, sy0 as usize);
2804 for y in 0..cph {
2805 let s = (sy0 + y) * cwz + sx0;
2806 let d = (cy + y) * cwz + cx;
2807 dst[d..d + cpw].copy_from_slice(&src[s..s + cpw]);
2808 }
2809 continue;
2810 }
2811 for y in 0..cph {
2812 for x in 0..cpw {
2813 let bx = cx as isize + x as isize + ix;
2814 let by = cy as isize + y as isize + iy;
2815 dst[(cy + y) * cwz + cx + x] =
2816 interp_chroma_sample(src, cw, chh, bx, by, fx, fy) as u8;
2817 }
2818 }
2819 }
2820}
2821
2822fn mc_part(
2824 st: &mut DecState,
2825 px: usize,
2826 py: usize,
2827 pw: usize,
2828 ph: usize,
2829 mv: [i16; 2],
2830 refr: &DecodedYuv,
2831) {
2832 mc_part_luma(st, px, py, pw, ph, mv, refr);
2833 mc_part_chroma(st, px, py, pw, ph, mv, refr);
2834}
2835
2836#[allow(clippy::too_many_arguments)]
2838fn store_part_mv(st: &mut DecState, px: usize, py: usize, pw: usize, ph: usize, mv: [i16; 2], ref_idx: i8, id: i32) {
2839 store_part(st, px, py, pw, ph, [mv, [0, 0]], [ref_idx, -1], [id, 0]);
2840}
2841
2842#[allow(clippy::too_many_arguments)]
2845fn store_part(
2846 st: &mut DecState,
2847 px: usize,
2848 py: usize,
2849 pw: usize,
2850 ph: usize,
2851 mv: [[i16; 2]; 2],
2852 ref_idx: [i8; 2],
2853 id: [i32; 2],
2854) {
2855 let bx0 = px / 4;
2856 let by0 = py / 4;
2857 for dy in 0..ph / 4 {
2858 for dx in 0..pw / 4 {
2859 let li = (by0 + dy) * st.blk_w + bx0 + dx;
2860 for l in 0..2 {
2861 st.mv[l][li] = mv[l];
2862 st.refi[l][li] = ref_idx[l];
2863 st.refp[l][li] = id[l];
2864 }
2865 st.is_inter[li] = true;
2866 st.mode_luma[li] = -1;
2867 st.nnz_luma[li] = 0;
2868 st.decoded[li] = true;
2869 }
2870 }
2871}
2872
2873#[derive(Clone, Copy, PartialEq)]
2875enum MvDir {
2876 None,
2877 A,
2878 B,
2879 C,
2880}
2881
2882#[derive(Clone, Copy)]
2886struct MvNeighbor {
2887 avail: bool,
2888 ref_idx: i8,
2889 mv: [i16; 2],
2890}
2891
2892fn part_neighbors(st: &DecState, px: usize, py: usize, pw: usize, list: usize) -> (MvNeighbor, MvNeighbor, MvNeighbor) {
2893 let bx0 = (px / 4) as i32;
2894 let by0 = (py / 4) as i32;
2895 let getn = |bx: i32, by: i32| -> MvNeighbor {
2896 if bx >= 0 && by >= 0 && (bx as usize) < st.blk_w && (by as usize) < st.blk_h && st.avail_blk(bx as isize, by as isize) {
2897 let li = (by as usize) * st.blk_w + bx as usize;
2898 if st.decoded[li] {
2899 if st.is_inter[li] {
2900 let ri = st.refi[list][li];
2902 let mv = if ri >= 0 { st.mv[list][li] } else { [0, 0] };
2903 return MvNeighbor { avail: true, ref_idx: ri, mv };
2904 }
2905 return MvNeighbor { avail: true, ref_idx: -1, mv: [0, 0] };
2906 }
2907 }
2908 MvNeighbor { avail: false, ref_idx: -1, mv: [0, 0] }
2909 };
2910 let a = getn(bx0 - 1, by0);
2911 let b = getn(bx0, by0 - 1);
2912 let mut c = getn(bx0 + (pw / 4) as i32, by0 - 1);
2913 if !c.avail {
2914 c = getn(bx0 - 1, by0 - 1);
2916 }
2917 (a, b, c)
2918}
2919
2920fn mv_predict(st: &DecState, px: usize, py: usize, pw: usize, dir: MvDir, ref_idx: i8) -> [i16; 2] {
2926 mv_predict_l(st, px, py, pw, dir, ref_idx, 0)
2927}
2928
2929#[allow(clippy::too_many_arguments)]
2931fn mv_predict_l(st: &DecState, px: usize, py: usize, pw: usize, dir: MvDir, ref_idx: i8, list: usize) -> [i16; 2] {
2932 let (a, mut b, mut c) = part_neighbors(st, px, py, pw, list);
2933 match dir {
2934 MvDir::A if a.ref_idx == ref_idx => return a.mv,
2935 MvDir::B if b.ref_idx == ref_idx => return b.mv,
2936 MvDir::C if c.ref_idx == ref_idx => return c.mv,
2937 _ => {}
2938 }
2939 if !b.avail && !c.avail && a.avail {
2941 b = a;
2942 c = a;
2943 }
2944 let hits = [a, b, c].iter().filter(|n| n.ref_idx == ref_idx).count();
2945 if hits == 1 {
2946 for n in [a, b, c] {
2947 if n.ref_idx == ref_idx {
2948 return n.mv;
2949 }
2950 }
2951 }
2952 [median3(a.mv[0], b.mv[0], c.mv[0]), median3(a.mv[1], b.mv[1], c.mv[1])]
2953}
2954
2955fn set_mb_inter_grids(st: &mut DecState, mb_x: u32, mb_y: u32, mv: [i16; 2], qp: i32) {
2957 let bx0 = (mb_x / 4) as usize;
2958 let by0 = (mb_y / 4) as usize;
2959 for dy in 0..4 {
2960 for dx in 0..4 {
2961 let li = (by0 + dy) * st.blk_w + bx0 + dx;
2962 st.mv[0][li] = mv;
2963 st.nnz_luma[li] = 0;
2964 st.mode_luma[li] = -1;
2965 st.is_inter[li] = true;
2966 st.decoded[li] = true;
2967 }
2968 }
2969 let cbx0 = (mb_x / 8) as usize;
2970 let cby0 = (mb_y / 8) as usize;
2971 for comp in 0..2 {
2972 for dy in 0..2 {
2973 for dx in 0..2 {
2974 st.nnz_chroma[comp][(cby0 + dy) * st.cblk_w + cbx0 + dx] = 0;
2975 }
2976 }
2977 }
2978 st.mb_qp[(mb_y / 16) as usize * st.mb_w + (mb_x / 16) as usize] = qp;
2979}
2980
2981fn decode_pskip(st: &mut DecState, mb_x: u32, mb_y: u32, qp: i32, refs: &[RefEntry]) {
2983 let mv = predict_pskip_mv(st, mb_x, mb_y);
2984 let (px, py) = (mb_x as usize, mb_y as usize);
2985 let id = mc_pred(st, px, py, 16, 16, [mv, [0, 0]], [0, -1], [refs, &[]]).map_or(0, |ids| ids[0]);
2987 store_part_mv(st, px, py, 16, 16, mv, 0, id);
2988 st.mb_qp[(mb_y / 16) as usize * st.mb_w + (mb_x / 16) as usize] = qp;
2989}
2990
2991fn add_inter_luma_residual<R: MbSyntax>(
2993 r: &mut R,
2994 st: &mut DecState,
2995 mb_x: u32,
2996 mb_y: u32,
2997 cbp_luma: u32,
2998 qp: i32,
2999 t8: bool,
3000) -> Result<(), &'static str> {
3001 let w = st.yuv.width as usize;
3002 let bx0 = (mb_x / 4) as usize;
3003 if t8 {
3004 let by0 = (mb_y / 4) as usize;
3005 for i in 0..4 {
3006 let (bx4, by4) = (bx0 + (i % 2) * 2, by0 + (i / 2) * 2);
3007 let mut cnt = [0u8; 4];
3008 if cbp_luma & (1 << i) != 0 {
3009 let (scan, c) = r.residual8x8(st, bx4, by4)?;
3010 cnt = c;
3011 let res = residual_8x8_to_pixels(&scan, qp);
3012 let (px, py) = (bx4 * 4, by4 * 4);
3013 for y in 0..8 {
3014 for x in 0..8 {
3015 let o = (py + y) * w + px + x;
3016 st.yuv.y[o] = clip1(st.yuv.y[o] as i32 + res[y * 8 + x]) as u8;
3017 }
3018 }
3019 }
3020 for (k, (dx, dy)) in [(0, 0), (1, 0), (0, 1), (1, 1)].into_iter().enumerate() {
3021 let li = st.li(bx4 + dx, by4 + dy);
3022 st.nnz_luma[li] = cnt[k];
3023 }
3024 }
3025 return Ok(());
3026 }
3027 let by0 = (mb_y / 4) as usize;
3028 for blk in 0..16 {
3029 let (bx, by) = LUMA_4X4_BLOCK_XY[blk];
3030 let bx4 = bx0 + bx / 4;
3031 let by4 = by0 + by / 4;
3032 let li = by4 * st.blk_w + bx4;
3033 if cbp_luma & (1 << (blk / 4)) != 0 {
3034 let (scan, tc) = r.residual(st, ResBlock::Luma4x4 { bx4, by4 })?;
3035 st.nnz_luma[li] = tc;
3036 let mut block = [0i32; 16];
3037 for k in 0..16 {
3038 block[ZIGZAG_4X4[k]] = scan[k];
3039 }
3040 dequant_4x4(&mut block, qp);
3041 inverse_transform_4x4(&mut block);
3042 for yy in 0..4 {
3043 for xx in 0..4 {
3044 let px = mb_x as usize + bx + xx;
3045 let py = mb_y as usize + by + yy;
3046 let cur = st.yuv.y[py * w + px] as i32;
3047 st.yuv.y[py * w + px] = clip1(cur + block[yy * 4 + xx]) as u8;
3048 }
3049 }
3050 } else {
3051 st.nnz_luma[li] = 0;
3052 }
3053 }
3054 Ok(())
3055}
3056
3057fn add_inter_chroma_residual<R: MbSyntax>(
3059 r: &mut R,
3060 st: &mut DecState,
3061 mb_x: u32,
3062 mb_y: u32,
3063 cbp_chroma: u32,
3064 qp_y: i32,
3065 chroma_qp_off: [i32; 2],
3066) -> Result<(), &'static str> {
3067 let cw = (st.yuv.width / 2) as usize;
3068 let cmb_x = (mb_x / 2) as usize;
3069 let cmb_y = (mb_y / 2) as usize;
3070 let cbx0 = cmb_x / 4;
3071 let cby0 = cmb_y / 4;
3072 let qpcs = [chroma_qp(qp_y, chroma_qp_off[0]), chroma_qp(qp_y, chroma_qp_off[1])];
3073 let mut dc = [[0i32; 4]; 2];
3074 if cbp_chroma != 0 {
3075 for comp in 0..2 {
3076 let (scan, _) = r.residual(st, ResBlock::ChromaDc { comp, mb_x, mb_y })?;
3077 let f = inverse_hadamard_2x2([scan[0], scan[1], scan[2], scan[3]]);
3078 for i in 0..4 {
3079 dc[comp][i] = scale_chroma_dc(f[i], qpcs[comp]);
3080 }
3081 }
3082 }
3083 let mut ac = [[[0i32; 16]; 4]; 2];
3084 if cbp_chroma == 2 {
3085 for comp in 0..2 {
3086 for blk in 0..4 {
3087 let bx = (blk % 2) * 4;
3088 let by = (blk / 2) * 4;
3089 let cbx4 = cbx0 + bx / 4;
3090 let cby4 = cby0 + by / 4;
3091 let (scan, tc) = r.residual(st, ResBlock::ChromaAc { comp, cbx4, cby4 })?;
3092 for k in 0..15 {
3093 ac[comp][blk][ZIGZAG_4X4[k + 1]] = scan[k];
3094 }
3095 st.nnz_chroma[comp][cby4 * st.cblk_w + cbx4] = tc;
3096 }
3097 }
3098 }
3099 if cbp_chroma == 0 {
3100 return Ok(());
3101 }
3102 for comp in 0..2 {
3103 let plane: &mut Vec<u8> = if comp == 0 {
3104 &mut st.yuv.u
3105 } else {
3106 &mut st.yuv.v
3107 };
3108 for blk in 0..4 {
3109 let bx = (blk % 2) * 4;
3110 let by = (blk / 2) * 4;
3111 let mut block = ac[comp][blk];
3112 dequant_4x4(&mut block, qpcs[comp]);
3113 block[0] = dc[comp][blk];
3114 inverse_transform_4x4(&mut block);
3115 for yy in 0..4 {
3116 for xx in 0..4 {
3117 let px = cmb_x + bx + xx;
3118 let py = cmb_y + by + yy;
3119 let cur = plane[py * cw + px] as i32;
3120 plane[py * cw + px] = clip1(cur + block[yy * 4 + xx]) as u8;
3121 }
3122 }
3123 }
3124 }
3125 Ok(())
3126}
3127
3128fn read_ref_idx(r: &mut BitReader, num_ref: u32) -> Result<i8, &'static str> {
3133 if num_ref <= 1 {
3134 return Ok(0);
3135 }
3136 let v = if num_ref == 2 { 1 - r.read_bit() } else { r.read_ue() };
3137 if v >= num_ref {
3138 return Err("ref_idx out of range");
3139 }
3140 Ok(v as i8)
3141}
3142
3143fn decode_p8x8<R: MbSyntax>(
3144 r: &mut R,
3145 st: &mut DecState,
3146 px: usize,
3147 py: usize,
3148 refs: &[RefEntry],
3149 ref0_only: bool,
3150) -> Result<bool, &'static str> {
3151 let mut sub_types = [0u32; 4];
3152 for s in sub_types.iter_mut() {
3153 *s = r.sub_mb_type(SliceKind::P)?;
3154 if *s > 3 {
3155 return Err("bad sub_mb_type");
3156 }
3157 }
3158 let mut ref_idx = [0i8; 4];
3160 if !ref0_only {
3161 for (i, ri) in ref_idx.iter_mut().enumerate() {
3162 *ri = r.ref_idx(st, 0, px + (i % 2) * 8, py + (i / 2) * 8, 8, 8, st.num_ref[0])?;
3163 }
3164 }
3165 for (i, &stype) in sub_types.iter().enumerate() {
3166 let ri = ref_idx[i];
3167 let refr: RefEntry = *refs.get(ri as usize).ok_or("missing reference frame")?;
3168 let sx = px + (i % 2) * 8;
3169 let sy = py + (i / 2) * 8;
3170 let parts: &[(usize, usize, usize, usize)] = match stype {
3171 0 => &[(0, 0, 8, 8)],
3172 1 => &[(0, 0, 8, 4), (0, 4, 8, 4)],
3173 2 => &[(0, 0, 4, 8), (4, 0, 4, 8)],
3174 _ => &[(0, 0, 4, 4), (4, 0, 4, 4), (0, 4, 4, 4), (4, 4, 4, 4)],
3175 };
3176 for &(ox, oy, pw, ph) in parts {
3177 let ppx = sx + ox;
3178 let ppy = sy + oy;
3179 let [mvd_x, mvd_y] = r.mvd(st, 0, ppx, ppy, pw, ph)?;
3180 let mvp = mv_predict(st, ppx, ppy, pw, MvDir::None, ri);
3181 let mv = [mvp[0].wrapping_add(mvd_x), mvp[1].wrapping_add(mvd_y)];
3182 mc_pred(st, ppx, ppy, pw, ph, [mv, [0, 0]], [ri, -1], [refs, &[]])?;
3183 store_part_mv(st, ppx, ppy, pw, ph, mv, ri, refr.id);
3184 }
3185 }
3186 Ok(sub_types.iter().all(|&t| t == 0))
3188}
3189
3190#[allow(clippy::too_many_arguments)]
3192fn decode_mb_p<R: MbSyntax>(
3193 r: &mut R,
3194 st: &mut DecState,
3195 mb_x: u32,
3196 mb_y: u32,
3197 qp: &mut i32,
3198 pps: &Pps,
3199 refs: &[RefEntry],
3200) -> Result<(), &'static str> {
3201 let mb_type = r.mb_type(st, mb_x, mb_y, SliceKind::P)?;
3202 if mb_type >= 5 {
3203 let it = mb_type - 5;
3204 if it == 25 {
3205 return decode_mb_ipcm(r, st, mb_x, mb_y);
3206 }
3207 if it == 0 {
3208 return decode_mb_i4x4(r, st, mb_x, mb_y, qp, pps);
3209 }
3210 if (1..=24).contains(&it) {
3211 return decode_mb_i16x16(r, st, mb_x, mb_y, qp, it, pps);
3212 }
3213 return Err("bad intra mb_type in P slice");
3214 }
3215 let px = mb_x as usize;
3216 let py = mb_y as usize;
3217 let do_part = |r: &mut R,
3220 st: &mut DecState,
3221 ppx: usize,
3222 ppy: usize,
3223 pw: usize,
3224 ph: usize,
3225 dir: MvDir,
3226 ri: i8|
3227 -> Result<(), &'static str> {
3228 let refr: RefEntry = *refs.get(ri as usize).ok_or("missing reference frame")?;
3229 let [mvd_x, mvd_y] = r.mvd(st, 0, ppx, ppy, pw, ph)?;
3230 let mvp = mv_predict(st, ppx, ppy, pw, dir, ri);
3231 let mv = [mvp[0].wrapping_add(mvd_x), mvp[1].wrapping_add(mvd_y)];
3232 mc_pred(st, ppx, ppy, pw, ph, [mv, [0, 0]], [ri, -1], [refs, &[]])?;
3233 store_part_mv(st, ppx, ppy, pw, ph, mv, ri, refr.id);
3234 Ok(())
3235 };
3236 let mut t8_ok = true;
3237 match mb_type {
3238 0 => {
3239 let r0 = r.ref_idx(st, 0, px, py, 16, 16, st.num_ref[0])?;
3241 do_part(r, st, px, py, 16, 16, MvDir::None, r0)?;
3242 }
3243 1 => {
3244 let r0 = r.ref_idx(st, 0, px, py, 16, 8, st.num_ref[0])?;
3246 let r1 = r.ref_idx(st, 0, px, py + 8, 16, 8, st.num_ref[0])?;
3247 do_part(r, st, px, py, 16, 8, MvDir::B, r0)?;
3248 do_part(r, st, px, py + 8, 16, 8, MvDir::A, r1)?;
3249 }
3250 2 => {
3251 let r0 = r.ref_idx(st, 0, px, py, 8, 16, st.num_ref[0])?;
3253 let r1 = r.ref_idx(st, 0, px + 8, py, 8, 16, st.num_ref[0])?;
3254 do_part(r, st, px, py, 8, 16, MvDir::A, r0)?;
3255 do_part(r, st, px + 8, py, 8, 16, MvDir::C, r1)?;
3256 }
3257 3 | 4 => {
3258 t8_ok = decode_p8x8(r, st, px, py, refs, mb_type == 4)?;
3260 }
3261 _ => return Err("unknown P mb_type"),
3262 }
3263 decode_inter_residual(r, st, mb_x, mb_y, qp, pps, t8_ok)
3264}
3265
3266fn decode_inter_residual<R: MbSyntax>(
3268 r: &mut R,
3269 st: &mut DecState,
3270 mb_x: u32,
3271 mb_y: u32,
3272 qp: &mut i32,
3273 pps: &Pps,
3274 t8_allowed: bool,
3275) -> Result<(), &'static str> {
3276 let cbp = r.cbp(st, mb_x, mb_y, false)?;
3277 let cbp_luma = cbp & 0xf;
3278 let cbp_chroma = cbp >> 4;
3279 let t8 = t8_allowed && cbp_luma != 0 && pps.transform_8x8_mode_flag && r.transform_8x8(st, mb_x, mb_y);
3281 st.mb_t8[(mb_y / 16) as usize * st.mb_w + (mb_x / 16) as usize] = t8;
3282 let cur_qp = if cbp != 0 {
3283 let d = r.qp_delta()?;
3284 if !(-26..=25).contains(&d) {
3285 return Err("mb_qp_delta out of range");
3286 }
3287 *qp = (*qp + d + 52) % 52;
3288 *qp
3289 } else {
3290 *qp
3291 };
3292 st.mb_qp[(mb_y / 16) as usize * st.mb_w + (mb_x / 16) as usize] = cur_qp;
3293
3294 add_inter_luma_residual(r, st, mb_x, mb_y, cbp_luma, cur_qp, t8)?;
3295 add_inter_chroma_residual(
3296 r,
3297 st,
3298 mb_x,
3299 mb_y,
3300 cbp_chroma,
3301 cur_qp,
3302 pps.chroma_qp_offsets(),
3303 )
3304}
3305
3306struct BCtx<'a> {
3313 l: [&'a [RefEntry<'a>]; 2],
3314 direct_8x8: bool,
3315}
3316
3317const PRED_L0: u8 = 1;
3319const PRED_L1: u8 = 2;
3320const PRED_BI: u8 = 3;
3321
3322const B_PART_PAIRS: [(u8, u8); 9] = [
3324 (PRED_L0, PRED_L0),
3325 (PRED_L1, PRED_L1),
3326 (PRED_L0, PRED_L1),
3327 (PRED_L1, PRED_L0),
3328 (PRED_L0, PRED_BI),
3329 (PRED_L1, PRED_BI),
3330 (PRED_BI, PRED_L0),
3331 (PRED_BI, PRED_L1),
3332 (PRED_BI, PRED_BI),
3333];
3334
3335const B_SUB_MB: [(u8, usize, usize); 13] = [
3337 (0, 8, 8),
3338 (PRED_L0, 8, 8),
3339 (PRED_L1, 8, 8),
3340 (PRED_BI, 8, 8),
3341 (PRED_L0, 8, 4),
3342 (PRED_L0, 4, 8),
3343 (PRED_L1, 8, 4),
3344 (PRED_L1, 4, 8),
3345 (PRED_BI, 8, 4),
3346 (PRED_BI, 4, 8),
3347 (PRED_L0, 4, 4),
3348 (PRED_L1, 4, 4),
3349 (PRED_BI, 4, 4),
3350];
3351
3352fn sub_part_offsets(w: usize, h: usize) -> &'static [(usize, usize)] {
3354 match (w, h) {
3355 (8, 8) => &[(0, 0)],
3356 (8, 4) => &[(0, 0), (0, 4)],
3357 (4, 8) => &[(0, 0), (4, 0)],
3358 _ => &[(0, 0), (4, 0), (0, 4), (4, 4)],
3359 }
3360}
3361
3362#[allow(clippy::too_many_arguments)]
3365fn mc_pred(
3366 st: &mut DecState,
3367 px: usize,
3368 py: usize,
3369 pw: usize,
3370 ph: usize,
3371 mv: [[i16; 2]; 2],
3372 ref_idx: [i8; 2],
3373 l: [&[RefEntry]; 2],
3374) -> Result<[i32; 2], &'static str> {
3375 let mut ent: [Option<RefEntry>; 2] = [None, None];
3376 for list in 0..2 {
3377 if ref_idx[list] >= 0 {
3378 ent[list] = Some(*l[list].get(ref_idx[list] as usize).ok_or("missing reference frame")?);
3379 }
3380 }
3381 match (ent[0], ent[1]) {
3382 (Some(a), None) => {
3383 mc_part(st, px, py, pw, ph, mv[0], a.yuv);
3384 weight_single(st, px, py, pw, ph, 0, ref_idx[0]);
3385 }
3386 (None, Some(b)) => {
3387 mc_part(st, px, py, pw, ph, mv[1], b.yuv);
3388 weight_single(st, px, py, pw, ph, 1, ref_idx[1]);
3389 }
3390 (Some(a), Some(b)) => {
3391 let w = st.yuv.width as usize;
3392 let cw = w / 2;
3393 let (cx, cy, cpw, cph) = (px / 2, py / 2, pw / 2, ph / 2);
3394 mc_part(st, px, py, pw, ph, mv[0], a.yuv);
3395 let mut sy = [0u8; 256];
3397 let mut su = [0u8; 64];
3398 let mut sv = [0u8; 64];
3399 for y in 0..ph {
3400 sy[y * pw..(y + 1) * pw].copy_from_slice(&st.yuv.y[(py + y) * w + px..(py + y) * w + px + pw]);
3401 }
3402 for y in 0..cph {
3403 let o = (cy + y) * cw + cx;
3404 su[y * cpw..(y + 1) * cpw].copy_from_slice(&st.yuv.u[o..o + cpw]);
3405 sv[y * cpw..(y + 1) * cpw].copy_from_slice(&st.yuv.v[o..o + cpw]);
3406 }
3407 mc_part(st, px, py, pw, ph, mv[1], b.yuv);
3408 let wts: Option<[(i32, i32, i32, i32); 3]> = match &st.wp {
3410 WpMode::Off => None,
3411 WpMode::Explicit(t) => {
3412 let e0 = t.w[0].get(ref_idx[0] as usize).ok_or("missing weight entry")?;
3413 let e1 = t.w[1].get(ref_idx[1] as usize).ok_or("missing weight entry")?;
3414 let lw = [t.luma_log2_denom as i32, t.chroma_log2_denom as i32, t.chroma_log2_denom as i32];
3415 Some(core::array::from_fn(|c| (lw[c], e0[c].0, e1[c].0, (e0[c].1 + e1[c].1 + 1) >> 1)))
3416 }
3417 WpMode::Implicit => {
3418 let (w0, w1) = implicit_weights(st.cur_poc, a.id, b.id);
3419 Some([(5, w0, w1, 0); 3])
3420 }
3421 };
3422 let comb = |c: usize, p0: u8, p1: u8| -> u8 {
3423 match wts {
3424 None => ((p0 as u16 + p1 as u16 + 1) >> 1) as u8,
3425 Some(wt) => {
3426 let (lw, w0, w1, o) = wt[c];
3427 let v = ((p0 as i32 * w0 + p1 as i32 * w1 + (1 << lw)) >> (lw + 1)) + o;
3428 v.clamp(0, 255) as u8
3429 }
3430 }
3431 };
3432 for y in 0..ph {
3433 for x in 0..pw {
3434 let o = (py + y) * w + px + x;
3435 st.yuv.y[o] = comb(0, sy[y * pw + x], st.yuv.y[o]);
3436 }
3437 }
3438 for y in 0..cph {
3439 for x in 0..cpw {
3440 let o = (cy + y) * cw + cx + x;
3441 st.yuv.u[o] = comb(1, su[y * cpw + x], st.yuv.u[o]);
3442 st.yuv.v[o] = comb(2, sv[y * cpw + x], st.yuv.v[o]);
3443 }
3444 }
3445 }
3446 (None, None) => return Err("partition without prediction list"),
3447 }
3448 Ok([ent[0].map_or(0, |e| e.id), ent[1].map_or(0, |e| e.id)])
3449}
3450
3451#[allow(clippy::too_many_arguments)]
3454fn weight_single(st: &mut DecState, px: usize, py: usize, pw: usize, ph: usize, list: usize, ref_idx: i8) {
3455 let WpMode::Explicit(t) = &st.wp else { return };
3456 let Some(e) = t.w[list].get(ref_idx as usize).copied() else { return };
3457 let lw = [t.luma_log2_denom as i32, t.chroma_log2_denom as i32, t.chroma_log2_denom as i32];
3458 let f = |c: usize, p: u8| -> u8 {
3459 let (w, o) = e[c];
3460 let v = if lw[c] >= 1 {
3461 ((p as i32 * w + (1 << (lw[c] - 1))) >> lw[c]) + o
3462 } else {
3463 p as i32 * w + o
3464 };
3465 v.clamp(0, 255) as u8
3466 };
3467 let w = st.yuv.width as usize;
3468 let cw = w / 2;
3469 for y in 0..ph {
3470 for x in 0..pw {
3471 let o = (py + y) * w + px + x;
3472 st.yuv.y[o] = f(0, st.yuv.y[o]);
3473 }
3474 }
3475 for y in 0..ph / 2 {
3476 for x in 0..pw / 2 {
3477 let o = (py / 2 + y) * cw + px / 2 + x;
3478 st.yuv.u[o] = f(1, st.yuv.u[o]);
3479 st.yuv.v[o] = f(2, st.yuv.v[o]);
3480 }
3481 }
3482}
3483
3484fn implicit_weights(cur_poc: i32, poc0: i32, poc1: i32) -> (i32, i32) {
3487 let td = (poc1 - poc0).clamp(-128, 127);
3488 if td == 0 {
3489 return (32, 32);
3490 }
3491 let tb = (cur_poc - poc0).clamp(-128, 127);
3492 let tx = (16384 + (td / 2).abs()) / td;
3493 let dsf = ((tb * tx + 32) >> 6).clamp(-1024, 1023);
3494 let w1 = dsf >> 2;
3495 if !(-64..=128).contains(&w1) {
3496 return (32, 32);
3497 }
3498 (64 - w1, w1)
3499}
3500
3501struct SpatialDirect {
3503 ref_idx: [i8; 2],
3504 mvp: [[i16; 2]; 2],
3505 zero: bool,
3507}
3508
3509fn min_positive(x: i8, y: i8) -> i8 {
3511 if x >= 0 && y >= 0 {
3512 x.min(y)
3513 } else {
3514 x.max(y)
3515 }
3516}
3517
3518fn spatial_direct(st: &DecState, mb_x: u32, mb_y: u32) -> SpatialDirect {
3521 let (px, py) = (mb_x as usize, mb_y as usize);
3522 let mut ref_idx = [-1i8; 2];
3523 for (list, ri) in ref_idx.iter_mut().enumerate() {
3524 let (a, b, c) = part_neighbors(st, px, py, 16, list);
3525 *ri = min_positive(a.ref_idx, min_positive(b.ref_idx, c.ref_idx));
3526 }
3527 if ref_idx[0] < 0 && ref_idx[1] < 0 {
3528 return SpatialDirect { ref_idx: [0, 0], mvp: [[0, 0]; 2], zero: true };
3529 }
3530 let mut mvp = [[0i16; 2]; 2];
3531 for list in 0..2 {
3532 if ref_idx[list] >= 0 {
3533 mvp[list] = mv_predict_l(st, px, py, 16, MvDir::None, ref_idx[list], list);
3534 }
3535 }
3536 SpatialDirect { ref_idx, mvp, zero: false }
3537}
3538
3539fn col_zero(col: &Motion, mb_x: u32, mb_y: u32, bx: usize, by: usize, direct_8x8: bool) -> bool {
3542 let (cx, cy) = if direct_8x8 {
3543 (if bx < 2 { 0 } else { 3 }, if by < 2 { 0 } else { 3 })
3544 } else {
3545 (bx, by)
3546 };
3547 let li = (mb_y as usize / 4 + cy) * col.blk_w + mb_x as usize / 4 + cx;
3548 let (ri, mv) = if col.refi[0].get(li).is_some_and(|&r| r >= 0) {
3549 (col.refi[0][li], col.mv[0][li])
3550 } else if col.refi[1].get(li).is_some_and(|&r| r >= 0) {
3551 (col.refi[1][li], col.mv[1][li])
3552 } else {
3553 return false; };
3555 ri == 0 && (-1..=1).contains(&mv[0]) && (-1..=1).contains(&mv[1])
3556}
3557
3558fn direct_8x8(st: &mut DecState, d: &SpatialDirect, mb_x: u32, mb_y: u32, i: usize, ctx: &BCtx) -> Result<(), &'static str> {
3560 let col = ctx.l[1].first().and_then(|e| e.motion).ok_or("B slice needs co-located motion")?;
3561 let (sx, sy) = ((i % 2) * 8, (i / 2) * 8);
3562 let (bs, offs): (usize, &[(usize, usize)]) = if ctx.direct_8x8 {
3563 (8, &[(0, 0)])
3564 } else {
3565 (4, &[(0, 0), (4, 0), (0, 4), (4, 4)])
3566 };
3567 for &(ox, oy) in offs {
3568 let (bx, by) = ((sx + ox) / 4, (sy + oy) / 4);
3569 let mut mv = [[0i16; 2]; 2];
3570 if !d.zero {
3571 let cz = col_zero(col, mb_x, mb_y, bx, by, ctx.direct_8x8);
3572 for list in 0..2 {
3573 if d.ref_idx[list] >= 0 && !(d.ref_idx[list] == 0 && cz) {
3574 mv[list] = d.mvp[list];
3575 }
3576 }
3577 }
3578 let (px, py) = (mb_x as usize + sx + ox, mb_y as usize + sy + oy);
3579 let ids = mc_pred(st, px, py, bs, bs, mv, d.ref_idx, ctx.l)?;
3580 store_part(st, px, py, bs, bs, mv, d.ref_idx, ids);
3581 }
3582 Ok(())
3583}
3584
3585fn decode_b_direct_mb(st: &mut DecState, mb_x: u32, mb_y: u32, ctx: &BCtx) -> Result<(), &'static str> {
3587 let d = spatial_direct(st, mb_x, mb_y);
3588 for i in 0..4 {
3589 direct_8x8(st, &d, mb_x, mb_y, i, ctx)?;
3590 }
3591 Ok(())
3592}
3593
3594#[allow(clippy::too_many_arguments)]
3597fn decode_mb_b<R: MbSyntax>(
3598 r: &mut R,
3599 st: &mut DecState,
3600 mb_x: u32,
3601 mb_y: u32,
3602 qp: &mut i32,
3603 pps: &Pps,
3604 ctx: &BCtx,
3605) -> Result<(), &'static str> {
3606 let mb_type = r.mb_type(st, mb_x, mb_y, SliceKind::B)?;
3607 if mb_type >= 23 {
3608 let it = mb_type - 23;
3609 if it == 25 {
3610 return decode_mb_ipcm(r, st, mb_x, mb_y);
3611 }
3612 if it == 0 {
3613 return decode_mb_i4x4(r, st, mb_x, mb_y, qp, pps);
3614 }
3615 if (1..=24).contains(&it) {
3616 return decode_mb_i16x16(r, st, mb_x, mb_y, qp, it, pps);
3617 }
3618 return Err("bad intra mb_type in B slice");
3619 }
3620 let (px, py) = (mb_x as usize, mb_y as usize);
3621 let mut t8_ok = true;
3622 match mb_type {
3623 0 => {
3624 r.mark_direct(px, py, 16, 16);
3625 decode_b_direct_mb(st, mb_x, mb_y, ctx)?;
3626 t8_ok = ctx.direct_8x8;
3627 }
3628 22 => t8_ok = decode_b8x8(r, st, mb_x, mb_y, ctx)?,
3629 _ => {
3630 let mut parts = [(0usize, 0usize, 16usize, 16usize, 0u8, MvDir::None); 2];
3632 let n = if mb_type <= 3 {
3633 parts[0].4 = mb_type as u8; 1
3635 } else {
3636 let k = (mb_type - 4) as usize;
3637 let (m0, m1) = B_PART_PAIRS[k / 2];
3638 if k.is_multiple_of(2) {
3639 parts = [(0, 0, 16, 8, m0, MvDir::B), (0, 8, 16, 8, m1, MvDir::A)];
3640 } else {
3641 parts = [(0, 0, 8, 16, m0, MvDir::A), (8, 0, 8, 16, m1, MvDir::C)];
3642 }
3643 2
3644 };
3645 let mut ri = [[-1i8; 2]; 2];
3646 let mut mvd = [[[0i16; 2]; 2]; 2];
3647 for list in 0..2 {
3648 for i in 0..n {
3649 if parts[i].4 & (1 << list) != 0 {
3650 let (ox, oy, pw, ph, _, _) = parts[i];
3651 ri[i][list] = r.ref_idx(st, list, px + ox, py + oy, pw, ph, st.num_ref[list])?;
3652 }
3653 }
3654 }
3655 for list in 0..2 {
3656 for i in 0..n {
3657 if parts[i].4 & (1 << list) != 0 {
3658 let (ox, oy, pw, ph, _, _) = parts[i];
3659 mvd[i][list] = r.mvd(st, list, px + ox, py + oy, pw, ph)?;
3660 }
3661 }
3662 }
3663 for i in 0..n {
3664 let (ox, oy, pw, ph, _, dir) = parts[i];
3665 let (ppx, ppy) = (px + ox, py + oy);
3666 let mut mv = [[0i16; 2]; 2];
3667 for list in 0..2 {
3668 if ri[i][list] >= 0 {
3669 let p = mv_predict_l(st, ppx, ppy, pw, dir, ri[i][list], list);
3670 mv[list] = [p[0].wrapping_add(mvd[i][list][0]), p[1].wrapping_add(mvd[i][list][1])];
3671 }
3672 }
3673 let ids = mc_pred(st, ppx, ppy, pw, ph, mv, ri[i], ctx.l)?;
3674 store_part(st, ppx, ppy, pw, ph, mv, ri[i], ids);
3675 }
3676 }
3677 }
3678 decode_inter_residual(r, st, mb_x, mb_y, qp, pps, t8_ok)
3679}
3680
3681fn decode_b8x8<R: MbSyntax>(r: &mut R, st: &mut DecState, mb_x: u32, mb_y: u32, ctx: &BCtx) -> Result<bool, &'static str> {
3683 let mut sub = [0usize; 4];
3684 for s in sub.iter_mut() {
3685 *s = r.sub_mb_type(SliceKind::B)? as usize;
3686 if *s >= B_SUB_MB.len() {
3687 return Err("bad B sub_mb_type");
3688 }
3689 }
3690 let (mx, my) = (mb_x as usize, mb_y as usize);
3691 for (i, &t) in sub.iter().enumerate() {
3692 if t == 0 {
3693 r.mark_direct(mx + (i % 2) * 8, my + (i / 2) * 8, 8, 8);
3694 }
3695 }
3696 let mut ri = [[-1i8; 2]; 4];
3697 for list in 0..2 {
3698 for i in 0..4 {
3699 if B_SUB_MB[sub[i]].0 & (1 << list) != 0 {
3700 ri[i][list] = r.ref_idx(st, list, mx + (i % 2) * 8, my + (i / 2) * 8, 8, 8, st.num_ref[list])?;
3701 }
3702 }
3703 }
3704 let mut mvd = [[[[0i16; 2]; 4]; 2]; 4];
3705 for list in 0..2 {
3706 for i in 0..4 {
3707 let (mode, w, h) = B_SUB_MB[sub[i]];
3708 if mode & (1 << list) != 0 {
3709 for (k, &(ox, oy)) in sub_part_offsets(w, h).iter().enumerate() {
3710 let (ppx, ppy) = (mx + (i % 2) * 8 + ox, my + (i / 2) * 8 + oy);
3711 mvd[i][list][k] = r.mvd(st, list, ppx, ppy, w, h)?;
3712 }
3713 }
3714 }
3715 }
3716 let direct = if sub.contains(&0) { Some(spatial_direct(st, mb_x, mb_y)) } else { None };
3718 for i in 0..4 {
3719 if sub[i] == 0 {
3720 if let Some(d) = &direct {
3721 direct_8x8(st, d, mb_x, mb_y, i, ctx)?;
3722 }
3723 continue;
3724 }
3725 let (_, w, h) = B_SUB_MB[sub[i]];
3726 let sx = mb_x as usize + (i % 2) * 8;
3727 let sy = mb_y as usize + (i / 2) * 8;
3728 for (k, &(ox, oy)) in sub_part_offsets(w, h).iter().enumerate() {
3729 let (ppx, ppy) = (sx + ox, sy + oy);
3730 let mut mv = [[0i16; 2]; 2];
3731 for list in 0..2 {
3732 if ri[i][list] >= 0 {
3733 let p = mv_predict_l(st, ppx, ppy, w, MvDir::None, ri[i][list], list);
3734 mv[list] = [p[0].wrapping_add(mvd[i][list][k][0]), p[1].wrapping_add(mvd[i][list][k][1])];
3735 }
3736 }
3737 let ids = mc_pred(st, ppx, ppy, w, h, mv, ri[i], ctx.l)?;
3738 store_part(st, ppx, ppy, w, h, mv, ri[i], ids);
3739 }
3740 }
3741 Ok(sub.iter().all(|&t| (1..=3).contains(&t) || (t == 0 && ctx.direct_8x8)))
3743}
3744
3745const ZIGZAG_8X8: [usize; 64] = [
3751 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14,
3752 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53,
3753 60, 61, 54, 47, 55, 62, 63,
3754];
3755
3756const SIG_CTX_8X8_FRAME: [u8; 63] = [
3758 0, 1, 2, 3, 4, 5, 5, 4, 4, 3, 3, 4, 4, 4, 5, 5, 4, 4, 4, 4, 3, 3, 6, 7, 7, 7, 8, 9, 10, 9, 8, 7, 7, 6, 11, 12,
3759 13, 11, 6, 7, 8, 9, 14, 10, 9, 8, 6, 11, 12, 13, 11, 6, 9, 14, 10, 9, 11, 12, 13, 11, 14, 10, 12,
3760];
3761
3762const LAST_CTX_8X8: [u8; 63] = [
3764 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
3765 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8,
3766];
3767
3768const NORM_ADJUST_8X8: [[i32; 6]; 6] = [
3770 [20, 18, 32, 19, 25, 24],
3771 [22, 19, 35, 21, 28, 26],
3772 [26, 23, 42, 24, 33, 31],
3773 [28, 25, 45, 26, 35, 33],
3774 [32, 28, 51, 30, 40, 38],
3775 [36, 32, 58, 34, 46, 43],
3776];
3777
3778fn norm8_class(i: usize, j: usize) -> usize {
3780 match (i & 3, j & 3) {
3781 (0, 0) => 0,
3782 (1 | 3, 1 | 3) => 1,
3783 (2, 2) => 2,
3784 (0, 1 | 3) | (1 | 3, 0) => 3,
3785 (0, 2) | (2, 0) => 4,
3786 _ => 5,
3787 }
3788}
3789
3790fn dequant_8x8(b: &mut [i32; 64], qp: i32) {
3792 let m = (qp % 6) as usize;
3793 let sh = qp / 6;
3794 for (k, c) in b.iter_mut().enumerate() {
3795 if *c == 0 {
3796 continue;
3797 }
3798 let ls = 16 * NORM_ADJUST_8X8[m][norm8_class(k / 8, k % 8)];
3799 *c = if sh >= 6 { (*c * ls) << (sh - 6) } else { (*c * ls + (1 << (5 - sh))) >> (6 - sh) };
3800 }
3801}
3802
3803fn idct8_1d(d: [i32; 8]) -> [i32; 8] {
3805 let a0 = d[0] + d[4];
3806 let a4 = d[0] - d[4];
3807 let a2 = (d[2] >> 1) - d[6];
3808 let a6 = d[2] + (d[6] >> 1);
3809 let b0 = a0 + a6;
3810 let b2 = a4 + a2;
3811 let b4 = a4 - a2;
3812 let b6 = a0 - a6;
3813 let a1 = -d[3] + d[5] - d[7] - (d[7] >> 1);
3814 let a3 = d[1] + d[7] - d[3] - (d[3] >> 1);
3815 let a5 = -d[1] + d[7] + d[5] + (d[5] >> 1);
3816 let a7 = d[3] + d[5] + d[1] + (d[1] >> 1);
3817 let b1 = a1 + (a7 >> 2);
3818 let b7 = a7 - (a1 >> 2);
3819 let b3 = a3 + (a5 >> 2);
3820 let b5 = (a3 >> 2) - a5;
3821 [b0 + b7, b2 + b5, b4 + b3, b6 + b1, b6 - b1, b4 - b3, b2 - b5, b0 - b7]
3822}
3823
3824fn inverse_transform_8x8(b: &mut [i32; 64]) {
3826 for r in 0..8 {
3827 let row: [i32; 8] = core::array::from_fn(|c| b[r * 8 + c]);
3828 let o = idct8_1d(row);
3829 b[r * 8..r * 8 + 8].copy_from_slice(&o);
3830 }
3831 for c in 0..8 {
3832 let col: [i32; 8] = core::array::from_fn(|r| b[r * 8 + c]);
3833 let o = idct8_1d(col);
3834 for r in 0..8 {
3835 b[r * 8 + c] = (o[r] + 32) >> 6;
3836 }
3837 }
3838}
3839
3840fn residual_8x8_to_pixels(scan: &[i32; 64], qp: i32) -> [i32; 64] {
3842 let mut b = [0i32; 64];
3843 for k in 0..64 {
3844 b[ZIGZAG_8X8[k]] = scan[k];
3845 }
3846 dequant_8x8(&mut b, qp);
3847 inverse_transform_8x8(&mut b);
3848 b
3849}
3850
3851impl DecState {
3852 fn predict_luma_8x8(&self, px: usize, py: usize, mode: u8) -> [i32; 64] {
3854 let w = self.yuv.width as usize;
3855 let (bx4, by4) = (px / 4, py / 4);
3856 let top = self.avail_px(px as isize, py as isize - 1);
3857 let left = self.avail_px(px as isize - 1, py as isize);
3858 let tl = self.avail_px(px as isize - 1, py as isize - 1);
3859 let tr = top
3860 && px + 8 < w
3861 && by4 > 0
3862 && self.avail_blk(bx4 as isize + 2, by4 as isize - 1)
3863 && self.decoded[self.li(bx4 + 2, by4 - 1)];
3864 let pix = |x: isize, y: isize| self.yuv.y[(py as isize + y) as usize * w + (px as isize + x) as usize] as i32;
3865 let mut t = [0i32; 16];
3866 let mut l = [0i32; 8];
3867 if top {
3868 let mut tp = [0i32; 16];
3869 for (x, v) in tp.iter_mut().enumerate() {
3870 *v = if x < 8 || tr { pix(x as isize, -1) } else { pix(7, -1) };
3871 }
3872 t[0] = ((if tl { pix(-1, -1) } else { tp[0] }) + 2 * tp[0] + tp[1] + 2) >> 2;
3873 for x in 1..15 {
3874 t[x] = (tp[x - 1] + 2 * tp[x] + tp[x + 1] + 2) >> 2;
3875 }
3876 t[15] = (tp[14] + 3 * tp[15] + 2) >> 2;
3877 }
3878 if left {
3879 let lp: [i32; 8] = core::array::from_fn(|y| pix(-1, y as isize));
3880 l[0] = ((if tl { pix(-1, -1) } else { lp[0] }) + 2 * lp[0] + lp[1] + 2) >> 2;
3881 for y in 1..7 {
3882 l[y] = (lp[y - 1] + 2 * lp[y] + lp[y + 1] + 2) >> 2;
3883 }
3884 l[7] = (lp[6] + 3 * lp[7] + 2) >> 2;
3885 }
3886 let mut q = 0;
3887 if tl {
3888 let c = pix(-1, -1);
3889 q = match (top, left) {
3890 (true, true) => (pix(0, -1) + 2 * c + pix(-1, 0) + 2) >> 2,
3891 (true, false) => (3 * c + pix(0, -1) + 2) >> 2,
3892 (false, true) => (3 * c + pix(-1, 0) + 2) >> 2,
3893 _ => c,
3894 };
3895 }
3896 let tt = |i: i32| if i < 0 { q } else { t[i as usize] };
3898 let ll = |i: i32| if i < 0 { q } else { l[i as usize] };
3899 let mut pred = [0i32; 64];
3900 for y in 0..8i32 {
3901 for x in 0..8i32 {
3902 let v = match mode {
3903 0 => tt(x),
3904 1 => ll(y),
3905 2 => match (top, left) {
3906 (true, true) => (t[..8].iter().sum::<i32>() + l.iter().sum::<i32>() + 8) >> 4,
3907 (false, true) => (l.iter().sum::<i32>() + 4) >> 3,
3908 (true, false) => (t[..8].iter().sum::<i32>() + 4) >> 3,
3909 _ => 128,
3910 },
3911 3 => {
3912 if x == 7 && y == 7 {
3913 (tt(14) + 3 * tt(15) + 2) >> 2
3914 } else {
3915 (tt(x + y) + 2 * tt(x + y + 1) + tt(x + y + 2) + 2) >> 2
3916 }
3917 }
3918 4 => {
3919 if x > y {
3920 (tt(x - y - 2) + 2 * tt(x - y - 1) + tt(x - y) + 2) >> 2
3921 } else if x < y {
3922 (ll(y - x - 2) + 2 * ll(y - x - 1) + ll(y - x) + 2) >> 2
3923 } else {
3924 (tt(0) + 2 * q + ll(0) + 2) >> 2
3925 }
3926 }
3927 5 => {
3928 let z = 2 * x - y;
3929 if z >= 0 && z % 2 == 0 {
3930 (tt(x - (y >> 1) - 1) + tt(x - (y >> 1)) + 1) >> 1
3931 } else if z >= 0 {
3932 (tt(x - (y >> 1) - 2) + 2 * tt(x - (y >> 1) - 1) + tt(x - (y >> 1)) + 2) >> 2
3933 } else if z == -1 {
3934 (ll(0) + 2 * q + tt(0) + 2) >> 2
3935 } else {
3936 (ll(y - 2 * x - 1) + 2 * ll(y - 2 * x - 2) + ll(y - 2 * x - 3) + 2) >> 2
3937 }
3938 }
3939 6 => {
3940 let z = 2 * y - x;
3941 if z >= 0 && z % 2 == 0 {
3942 (ll(y - (x >> 1) - 1) + ll(y - (x >> 1)) + 1) >> 1
3943 } else if z >= 0 {
3944 (ll(y - (x >> 1) - 2) + 2 * ll(y - (x >> 1) - 1) + ll(y - (x >> 1)) + 2) >> 2
3945 } else if z == -1 {
3946 (ll(0) + 2 * q + tt(0) + 2) >> 2
3947 } else {
3948 (tt(x - 2 * y - 1) + 2 * tt(x - 2 * y - 2) + tt(x - 2 * y - 3) + 2) >> 2
3949 }
3950 }
3951 7 => {
3952 if y % 2 == 0 {
3953 (tt(x + (y >> 1)) + tt(x + (y >> 1) + 1) + 1) >> 1
3954 } else {
3955 (tt(x + (y >> 1)) + 2 * tt(x + (y >> 1) + 1) + tt(x + (y >> 1) + 2) + 2) >> 2
3956 }
3957 }
3958 _ => {
3959 let z = x + 2 * y;
3960 if z > 13 {
3961 ll(7)
3962 } else if z == 13 {
3963 (ll(6) + 3 * ll(7) + 2) >> 2
3964 } else if z % 2 == 0 {
3965 (ll(y + (x >> 1)) + ll(y + (x >> 1) + 1) + 1) >> 1
3966 } else {
3967 (ll(y + (x >> 1)) + 2 * ll(y + (x >> 1) + 1) + ll(y + (x >> 1) + 2) + 2) >> 2
3968 }
3969 }
3970 };
3971 pred[(y * 8 + x) as usize] = v;
3972 }
3973 }
3974 pred
3975 }
3976}
3977
3978fn reconstruct_luma_4x4(st: &mut DecState, px: usize, py: usize, mode: u8, residual: &[i32; 16]) {
3980 let pred = st.predict_luma_4x4(px, py, mode);
3981 let w = st.yuv.width as usize;
3982 for yy in 0..4 {
3983 for xx in 0..4 {
3984 let v = clip1(pred[yy * 4 + xx] + residual[yy * 4 + xx]);
3985 st.yuv.y[(py + yy) * w + px + xx] = v as u8;
3986 }
3987 }
3988 let di = st.li(px / 4, py / 4);
3989 st.decoded[di] = true;
3990}
3991
3992fn decode_mb_i16x16<R: MbSyntax>(
3993 r: &mut R,
3994 st: &mut DecState,
3995 mb_x: u32,
3996 mb_y: u32,
3997 qp: &mut i32,
3998 mb_type: u32,
3999 pps: &Pps,
4000) -> Result<(), &'static str> {
4001 let m1 = mb_type - 1;
4002 let i16_pred = (m1 % 4) as u8;
4003 let cbp_chroma = (m1 / 4) % 3;
4004 let cbp_luma = if m1 / 12 != 0 { 15 } else { 0 };
4005
4006 let intra_chroma_pred_mode = r.intra_chroma_mode(st, mb_x, mb_y)?;
4007 let mb_qp_delta = r.qp_delta()?;
4008 if !(-26..=25).contains(&mb_qp_delta) {
4009 return Err("mb_qp_delta out of range");
4010 }
4011 *qp = (*qp + mb_qp_delta + 52) % 52;
4012 let cur_qp = *qp;
4013 st.mb_qp[(mb_y / 16) as usize * st.mb_w + (mb_x / 16) as usize] = cur_qp;
4014
4015 let bx0 = (mb_x / 4) as usize;
4017 let by0 = (mb_y / 4) as usize;
4018 let (dc_scan, _) = r.residual(st, ResBlock::LumaDc { bx4: bx0, by4: by0 })?;
4019 let mut dc_block = [0i32; 16];
4020 for k in 0..16 {
4021 dc_block[ZIGZAG_4X4[k]] = dc_scan[k];
4022 }
4023 inverse_hadamard_4x4(&mut dc_block);
4024 scale_luma_dc(&mut dc_block, cur_qp);
4025
4026 let mut luma_ac = [[0i32; 16]; 16];
4028 for blk in 0..16 {
4029 let (bx, by) = LUMA_4X4_BLOCK_XY[blk];
4030 let bx4 = bx0 + bx / 4;
4031 let by4 = by0 + by / 4;
4032 let li = st.li(bx4, by4);
4033 if cbp_luma != 0 {
4034 let (ac_scan, tc) = r.residual(st, ResBlock::LumaAc { bx4, by4 })?;
4035 for k in 0..15 {
4036 luma_ac[blk][ZIGZAG_4X4[k + 1]] = ac_scan[k];
4037 }
4038 st.nnz_luma[li] = tc;
4039 } else {
4040 st.nnz_luma[li] = 0;
4041 }
4042 }
4043
4044 let w = st.yuv.width as usize;
4046 let mut top = [0i32; 16];
4047 let mut left = [0i32; 16];
4048 let top_avail = st.avail_px(mb_x as isize, mb_y as isize - 1);
4049 let left_avail = st.avail_px(mb_x as isize - 1, mb_y as isize);
4050 if top_avail {
4051 for x in 0..16 {
4052 top[x] = st.yuv.y[(mb_y as usize - 1) * w + mb_x as usize + x] as i32;
4053 }
4054 }
4055 if left_avail {
4056 for y in 0..16 {
4057 left[y] = st.yuv.y[(mb_y as usize + y) * w + mb_x as usize - 1] as i32;
4058 }
4059 }
4060 let corner = if top_avail && left_avail {
4061 st.yuv.y[(mb_y as usize - 1) * w + mb_x as usize - 1] as i32
4062 } else {
4063 0
4064 };
4065 let pred = intra_16x16_predict(i16_pred, &top, corner, &left, top_avail, left_avail);
4066
4067 for blk in 0..16 {
4069 let (bx, by) = LUMA_4X4_BLOCK_XY[blk];
4070 let dc_idx = (by / 4) * 4 + (bx / 4);
4071 let mut block = luma_ac[blk];
4072 dequant_4x4(&mut block, cur_qp);
4073 block[0] = dc_block[dc_idx];
4074 inverse_transform_4x4(&mut block);
4075 for yy in 0..4 {
4076 for xx in 0..4 {
4077 let px = mb_x as usize + bx + xx;
4078 let py = mb_y as usize + by + yy;
4079 let p = pred[(by + yy) * 16 + (bx + xx)];
4080 st.yuv.y[py * w + px] = clip1(p + block[yy * 4 + xx]) as u8;
4081 }
4082 }
4083 let di = st.li((mb_x as usize + bx) / 4, (mb_y as usize + by) / 4);
4084 st.decoded[di] = true;
4085 }
4086
4087 decode_chroma(
4088 r,
4089 st,
4090 mb_x,
4091 mb_y,
4092 cbp_chroma,
4093 intra_chroma_pred_mode,
4094 cur_qp,
4095 pps.chroma_qp_offsets(),
4096 )
4097}
4098
4099fn decode_mb_i4x4<R: MbSyntax>(
4100 r: &mut R,
4101 st: &mut DecState,
4102 mb_x: u32,
4103 mb_y: u32,
4104 qp: &mut i32,
4105 pps: &Pps,
4106) -> Result<(), &'static str> {
4107 let bx0 = (mb_x / 4) as usize;
4108 let by0 = (mb_y / 4) as usize;
4109 if pps.transform_8x8_mode_flag && r.transform_8x8(st, mb_x, mb_y) {
4110 return decode_mb_i8x8(r, st, mb_x, mb_y, qp, pps);
4111 }
4112
4113 let mut modes = [0u8; 16];
4115 for blk in 0..16 {
4116 let (bx, by) = LUMA_4X4_BLOCK_XY[blk];
4117 let bx4 = bx0 + bx / 4;
4118 let by4 = by0 + by / 4;
4119 let pred_mode = st.pred_i4x4_mode(bx4, by4);
4120 let mode = match r.intra4x4_rem() {
4121 None => pred_mode,
4122 Some(rem) if rem < pred_mode => rem,
4123 Some(rem) => rem + 1,
4124 };
4125 modes[blk] = mode as u8;
4126 let li = st.li(bx4, by4);
4127 st.mode_luma[li] = mode as i8;
4128 }
4129
4130 let intra_chroma_pred_mode = r.intra_chroma_mode(st, mb_x, mb_y)?;
4131 let cbp = r.cbp(st, mb_x, mb_y, true)?;
4132 let cbp_luma = cbp & 0xf;
4133 let cbp_chroma = cbp >> 4;
4134
4135 let cur_qp = if cbp != 0 {
4136 let mb_qp_delta = r.qp_delta()?;
4137 if !(-26..=25).contains(&mb_qp_delta) {
4138 return Err("mb_qp_delta out of range");
4139 }
4140 *qp = (*qp + mb_qp_delta + 52) % 52;
4141 *qp
4142 } else {
4143 *qp
4144 };
4145 st.mb_qp[(mb_y / 16) as usize * st.mb_w + (mb_x / 16) as usize] = cur_qp;
4146
4147 for blk in 0..16 {
4149 let (bx, by) = LUMA_4X4_BLOCK_XY[blk];
4150 let bx4 = bx0 + bx / 4;
4151 let by4 = by0 + by / 4;
4152 let mut block = [0i32; 16];
4153 let li = st.li(bx4, by4);
4154 if cbp_luma & (1 << (blk / 4)) != 0 {
4155 let (scan, tc) = r.residual(st, ResBlock::Luma4x4 { bx4, by4 })?;
4156 for k in 0..16 {
4157 block[ZIGZAG_4X4[k]] = scan[k];
4158 }
4159 st.nnz_luma[li] = tc;
4160 } else {
4161 st.nnz_luma[li] = 0;
4162 }
4163 dequant_4x4(&mut block, cur_qp);
4164 inverse_transform_4x4(&mut block);
4165 reconstruct_luma_4x4(
4166 st,
4167 mb_x as usize + bx,
4168 mb_y as usize + by,
4169 modes[blk],
4170 &block,
4171 );
4172 }
4173
4174 decode_chroma(
4175 r,
4176 st,
4177 mb_x,
4178 mb_y,
4179 cbp_chroma,
4180 intra_chroma_pred_mode,
4181 cur_qp,
4182 pps.chroma_qp_offsets(),
4183 )
4184}
4185
4186fn decode_mb_i8x8<R: MbSyntax>(
4189 r: &mut R,
4190 st: &mut DecState,
4191 mb_x: u32,
4192 mb_y: u32,
4193 qp: &mut i32,
4194 pps: &Pps,
4195) -> Result<(), &'static str> {
4196 let bx0 = (mb_x / 4) as usize;
4197 let by0 = (mb_y / 4) as usize;
4198 st.mb_t8[(mb_y / 16) as usize * st.mb_w + (mb_x / 16) as usize] = true;
4199 let mut modes = [0u8; 4];
4200 for (i, m) in modes.iter_mut().enumerate() {
4201 let (bx4, by4) = (bx0 + (i % 2) * 2, by0 + (i / 2) * 2);
4202 let pred_mode = st.pred_i4x4_mode(bx4, by4);
4204 let mode = match r.intra4x4_rem() {
4205 None => pred_mode,
4206 Some(rem) if rem < pred_mode => rem,
4207 Some(rem) => rem + 1,
4208 };
4209 *m = mode as u8;
4210 for (dx, dy) in [(0, 0), (1, 0), (0, 1), (1, 1)] {
4211 let li = st.li(bx4 + dx, by4 + dy);
4212 st.mode_luma[li] = mode as i8;
4213 }
4214 }
4215 let intra_chroma_pred_mode = r.intra_chroma_mode(st, mb_x, mb_y)?;
4216 let cbp = r.cbp(st, mb_x, mb_y, true)?;
4217 let cur_qp = if cbp != 0 {
4218 let d = r.qp_delta()?;
4219 if !(-26..=25).contains(&d) {
4220 return Err("mb_qp_delta out of range");
4221 }
4222 *qp = (*qp + d + 52) % 52;
4223 *qp
4224 } else {
4225 *qp
4226 };
4227 st.mb_qp[(mb_y / 16) as usize * st.mb_w + (mb_x / 16) as usize] = cur_qp;
4228 let w = st.yuv.width as usize;
4229 for i in 0..4 {
4230 let (bx4, by4) = (bx0 + (i % 2) * 2, by0 + (i / 2) * 2);
4231 let (px, py) = (bx4 * 4, by4 * 4);
4232 let mut res = [0i32; 64];
4233 let mut cnt = [0u8; 4];
4234 if cbp & (1 << i) != 0 {
4235 let (scan, c) = r.residual8x8(st, bx4, by4)?;
4236 res = residual_8x8_to_pixels(&scan, cur_qp);
4237 cnt = c;
4238 }
4239 let pred = st.predict_luma_8x8(px, py, modes[i]);
4240 for y in 0..8 {
4241 for x in 0..8 {
4242 st.yuv.y[(py + y) * w + px + x] = clip1(pred[y * 8 + x] + res[y * 8 + x]) as u8;
4243 }
4244 }
4245 for (k, (dx, dy)) in [(0, 0), (1, 0), (0, 1), (1, 1)].into_iter().enumerate() {
4246 let li = st.li(bx4 + dx, by4 + dy);
4247 st.nnz_luma[li] = cnt[k];
4248 st.decoded[li] = true;
4249 }
4250 }
4251 decode_chroma(r, st, mb_x, mb_y, cbp >> 4, intra_chroma_pred_mode, cur_qp, pps.chroma_qp_offsets())
4252}
4253
4254fn chroma_qp(qp_y: i32, offset: i32) -> i32 {
4256 let qpi = (qp_y + offset).clamp(0, 51);
4257 if qpi < 30 {
4258 qpi
4259 } else {
4260 const MAP: [i32; 22] = [
4261 29, 30, 31, 32, 32, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 39, 39, 39, 39,
4262 ];
4263 MAP[(qpi - 30) as usize]
4264 }
4265}
4266
4267fn inverse_hadamard_2x2(c: [i32; 4]) -> [i32; 4] {
4269 [
4270 c[0] + c[1] + c[2] + c[3],
4271 c[0] - c[1] + c[2] - c[3],
4272 c[0] + c[1] - c[2] - c[3],
4273 c[0] - c[1] - c[2] + c[3],
4274 ]
4275}
4276
4277fn scale_chroma_dc(f: i32, qpc: i32) -> i32 {
4279 let ls = 16 * NORM_ADJUST_4X4[(qpc % 6) as usize][0];
4280 ((f * ls) << (qpc / 6)) >> 5
4281}
4282
4283fn chroma_nc(st: &DecState, comp: usize, cbx4: usize, cby4: usize) -> i32 {
4285 let na = if st.avail_px(cbx4 as isize * 8 - 1, cby4 as isize * 8) {
4286 st.nnz_chroma[comp][cby4 * st.cblk_w + cbx4 - 1] as i32
4287 } else {
4288 -1
4289 };
4290 let nb = if st.avail_px(cbx4 as isize * 8, cby4 as isize * 8 - 1) {
4291 st.nnz_chroma[comp][(cby4 - 1) * st.cblk_w + cbx4] as i32
4292 } else {
4293 -1
4294 };
4295 combine_nc(na, nb)
4296}
4297
4298fn decode_chroma<R: MbSyntax>(
4300 r: &mut R,
4301 st: &mut DecState,
4302 mb_x: u32,
4303 mb_y: u32,
4304 cbp_chroma: u32,
4305 chroma_pred_mode: u8,
4306 qp_y: i32,
4307 chroma_qp_offset: [i32; 2],
4308) -> Result<(), &'static str> {
4309 let cw = (st.yuv.width / 2) as usize;
4310 let cmb_x = (mb_x / 2) as usize;
4311 let cmb_y = (mb_y / 2) as usize;
4312 let cbx0 = cmb_x / 4;
4313 let cby0 = cmb_y / 4;
4314 let qpcs = [chroma_qp(qp_y, chroma_qp_offset[0]), chroma_qp(qp_y, chroma_qp_offset[1])];
4315
4316 let mut dc = [[0i32; 4]; 2];
4319 if cbp_chroma != 0 {
4320 for comp in 0..2 {
4321 let (scan, _) = r.residual(st, ResBlock::ChromaDc { comp, mb_x, mb_y })?;
4322 let raw = [scan[0], scan[1], scan[2], scan[3]];
4324 let f = inverse_hadamard_2x2(raw);
4325 for i in 0..4 {
4326 dc[comp][i] = scale_chroma_dc(f[i], qpcs[comp]);
4327 }
4328 }
4329 }
4330 let mut ac = [[[0i32; 16]; 4]; 2]; if cbp_chroma == 2 {
4332 for comp in 0..2 {
4333 for blk in 0..4 {
4334 let bx = (blk % 2) * 4;
4335 let by = (blk / 2) * 4;
4336 let cbx4 = cbx0 + bx / 4;
4337 let cby4 = cby0 + by / 4;
4338 let (scan, tc) = r.residual(st, ResBlock::ChromaAc { comp, cbx4, cby4 })?;
4339 for k in 0..15 {
4340 ac[comp][blk][ZIGZAG_4X4[k + 1]] = scan[k];
4341 }
4342 st.nnz_chroma[comp][cby4 * st.cblk_w + cbx4] = tc;
4343 }
4344 }
4345 }
4346
4347 let ca_t = st.avail_px(cmb_x as isize * 2, cmb_y as isize * 2 - 1);
4349 let ca_l = st.avail_px(cmb_x as isize * 2 - 1, cmb_y as isize * 2);
4350 for comp in 0..2 {
4351 let plane: &mut Vec<u8> = if comp == 0 {
4352 &mut st.yuv.u
4353 } else {
4354 &mut st.yuv.v
4355 };
4356 let mut ct = [0i32; 8];
4357 let mut cl = [0i32; 8];
4358 if ca_t {
4359 for x in 0..8 {
4360 ct[x] = plane[(cmb_y - 1) * cw + cmb_x + x] as i32;
4361 }
4362 }
4363 if ca_l {
4364 for y in 0..8 {
4365 cl[y] = plane[(cmb_y + y) * cw + cmb_x - 1] as i32;
4366 }
4367 }
4368 let corner = if ca_t && ca_l {
4369 plane[(cmb_y - 1) * cw + cmb_x - 1] as i32
4370 } else {
4371 0
4372 };
4373 let cpred = intra_chroma_predict(chroma_pred_mode, &ct, corner, &cl, ca_t, ca_l);
4374
4375 for blk in 0..4 {
4376 let bx = (blk % 2) * 4;
4377 let by = (blk / 2) * 4;
4378 let mut block = ac[comp][blk];
4379 dequant_4x4(&mut block, qpcs[comp]);
4380 block[0] = dc[comp][blk]; inverse_transform_4x4(&mut block);
4382 for yy in 0..4 {
4383 for xx in 0..4 {
4384 let px = cmb_x + bx + xx;
4385 let py = cmb_y + by + yy;
4386 let p = cpred[(by + yy) * 8 + (bx + xx)];
4387 plane[py * cw + px] = clip1(p + block[yy * 4 + xx]) as u8;
4388 }
4389 }
4390 }
4391 }
4392 Ok(())
4393}
4394
4395fn iclip(v: i32, lo: i32, hi: i32) -> i32 {
4398 v.clamp(lo, hi)
4399}
4400
4401fn deblock_thresh(qpav: i32, alpha_off: i32, beta_off: i32, bs: u8) -> (i32, i32, i32) {
4403 let ia = iclip(qpav + alpha_off, 0, 51) as usize;
4404 let ib = iclip(qpav + beta_off, 0, 51) as usize;
4405 let tc0 = if (1..=3).contains(&bs) {
4407 TC0_TABLE[ia][(bs - 1) as usize] as i32
4408 } else {
4409 0
4410 };
4411 (ALPHA_TABLE[ia] as i32, BETA_TABLE[ib] as i32, tc0)
4412}
4413
4414#[allow(clippy::too_many_arguments)]
4416fn deblock_luma_edge(
4417 plane: &mut [u8],
4418 w: usize,
4419 vert: bool,
4420 ex: usize,
4421 ey: usize,
4422 len: usize,
4423 bs: u8,
4424 alpha: i32,
4425 beta: i32,
4426 tc0: i32,
4427) {
4428 if bs == 0 || alpha == 0 {
4429 return;
4430 }
4431 let across: isize = if vert { 1 } else { w as isize };
4432 for i in 0..len {
4433 let p0i: isize = if vert {
4434 ((ey + i) * w + (ex - 1)) as isize
4435 } else {
4436 ((ey - 1) * w + (ex + i)) as isize
4437 };
4438 let idx = |o: isize| -> usize { (p0i + o * across) as usize };
4439 let p0 = plane[idx(0)] as i32;
4440 let p1 = plane[idx(-1)] as i32;
4441 let p2 = plane[idx(-2)] as i32;
4442 let p3 = plane[idx(-3)] as i32;
4443 let q0 = plane[idx(1)] as i32;
4444 let q1 = plane[idx(2)] as i32;
4445 let q2 = plane[idx(3)] as i32;
4446 if (p0 - q0).abs() >= alpha || (p1 - p0).abs() >= beta || (q1 - q0).abs() >= beta {
4447 continue;
4448 }
4449 let ap = (p2 - p0).abs();
4450 let aq = (q2 - q0).abs();
4451 if bs < 4 {
4452 let mut tc = tc0;
4453 if ap < beta {
4454 tc += 1;
4455 }
4456 if aq < beta {
4457 tc += 1;
4458 }
4459 let delta = iclip(((q0 - p0) * 4 + (p1 - q1) + 4) >> 3, -tc, tc);
4460 plane[idx(0)] = clip1(p0 + delta) as u8;
4461 plane[idx(1)] = clip1(q0 - delta) as u8;
4462 if ap < beta {
4463 let d = iclip((p2 + ((p0 + q0 + 1) >> 1) - 2 * p1) >> 1, -tc0, tc0);
4464 plane[idx(-1)] = clip1(p1 + d) as u8;
4465 }
4466 if aq < beta {
4467 let d = iclip((q2 + ((p0 + q0 + 1) >> 1) - 2 * q1) >> 1, -tc0, tc0);
4468 plane[idx(2)] = clip1(q1 + d) as u8;
4469 }
4470 } else {
4471 let strong = (p0 - q0).abs() < (alpha >> 2) + 2;
4472 if ap < beta && strong {
4473 plane[idx(0)] = clip1((p2 + 2 * p1 + 2 * p0 + 2 * q0 + q1 + 4) >> 3) as u8;
4474 plane[idx(-1)] = clip1((p2 + p1 + p0 + q0 + 2) >> 2) as u8;
4475 plane[idx(-2)] = clip1((2 * p3 + 3 * p2 + p1 + p0 + q0 + 4) >> 3) as u8;
4476 } else {
4477 plane[idx(0)] = clip1((2 * p1 + p0 + q1 + 2) >> 2) as u8;
4478 }
4479 if aq < beta && strong {
4480 let q3 = plane[idx(4)] as i32;
4481 plane[idx(1)] = clip1((q2 + 2 * q1 + 2 * q0 + 2 * p0 + p1 + 4) >> 3) as u8;
4482 plane[idx(2)] = clip1((q2 + q1 + q0 + p0 + 2) >> 2) as u8;
4483 plane[idx(3)] = clip1((2 * q3 + 3 * q2 + q1 + q0 + p0 + 4) >> 3) as u8;
4484 } else {
4485 plane[idx(1)] = clip1((2 * q1 + q0 + p1 + 2) >> 2) as u8;
4486 }
4487 }
4488 }
4489}
4490
4491#[allow(clippy::too_many_arguments)]
4493fn deblock_chroma_edge(
4494 plane: &mut [u8],
4495 cw: usize,
4496 vert: bool,
4497 ex: usize,
4498 ey: usize,
4499 len: usize,
4500 bs: u8,
4501 alpha: i32,
4502 beta: i32,
4503 tc0: i32,
4504) {
4505 if bs == 0 || alpha == 0 {
4506 return;
4507 }
4508 let across: isize = if vert { 1 } else { cw as isize };
4509 for i in 0..len {
4510 let p0i: isize = if vert {
4511 ((ey + i) * cw + (ex - 1)) as isize
4512 } else {
4513 ((ey - 1) * cw + (ex + i)) as isize
4514 };
4515 let idx = |o: isize| -> usize { (p0i + o * across) as usize };
4516 let p0 = plane[idx(0)] as i32;
4517 let p1 = plane[idx(-1)] as i32;
4518 let q0 = plane[idx(1)] as i32;
4519 let q1 = plane[idx(2)] as i32;
4520 if (p0 - q0).abs() >= alpha || (p1 - p0).abs() >= beta || (q1 - q0).abs() >= beta {
4521 continue;
4522 }
4523 if bs < 4 {
4524 let tc = tc0 + 1;
4525 let delta = iclip(((q0 - p0) * 4 + (p1 - q1) + 4) >> 3, -tc, tc);
4526 plane[idx(0)] = clip1(p0 + delta) as u8;
4527 plane[idx(1)] = clip1(q0 - delta) as u8;
4528 } else {
4529 plane[idx(0)] = clip1((2 * p1 + p0 + q1 + 2) >> 2) as u8;
4530 plane[idx(1)] = clip1((2 * q1 + q0 + p1 + 2) >> 2) as u8;
4531 }
4532 }
4533}
4534
4535fn boundary_strength(st: &DecState, p_li: usize, q_li: usize, is_mb_edge: bool) -> u8 {
4539 let p_intra = !st.is_inter[p_li];
4540 let q_intra = !st.is_inter[q_li];
4541 if p_intra || q_intra {
4542 return if is_mb_edge { 4 } else { 3 };
4543 }
4544 if st.has_coeffs(p_li) || st.has_coeffs(q_li) {
4545 return 2;
4546 }
4547 let far = |m: [i16; 2], n: [i16; 2]| (m[0] - n[0]).abs() >= 4 || (m[1] - n[1]).abs() >= 4;
4550 let used = |li: usize| [st.refi[0][li] >= 0, st.refi[1][li] >= 0];
4551 let (pu, qu) = (used(p_li), used(q_li));
4552 let pn = pu.iter().filter(|&&u| u).count();
4553 let qn = qu.iter().filter(|&&u| u).count();
4554 if pn != qn {
4555 return 1;
4556 }
4557 if pn == 1 {
4558 let pl = if pu[0] { 0 } else { 1 };
4559 let ql = if qu[0] { 0 } else { 1 };
4560 if st.refp[pl][p_li] != st.refp[ql][q_li] {
4561 return 1;
4562 }
4563 return far(st.mv[pl][p_li], st.mv[ql][q_li]) as u8;
4564 }
4565 let (p0, p1) = (st.refp[0][p_li], st.refp[1][p_li]);
4566 let (q0, q1) = (st.refp[0][q_li], st.refp[1][q_li]);
4567 if !((p0 == q0 && p1 == q1) || (p0 == q1 && p1 == q0)) {
4568 return 1;
4569 }
4570 let (pm0, pm1) = (st.mv[0][p_li], st.mv[1][p_li]);
4571 let (qm0, qm1) = (st.mv[0][q_li], st.mv[1][q_li]);
4572 let straight = far(pm0, qm0) || far(pm1, qm1);
4573 let crossed = far(pm0, qm1) || far(pm1, qm0);
4574 let bs = if p0 != p1 {
4575 if p0 == q0 { straight } else { crossed }
4577 } else {
4578 straight && crossed
4580 };
4581 bs as u8
4582}
4583
4584fn deblock_frame(st: &mut DecState, mb_w: usize, mb_h: usize, chroma_qp_off: [i32; 2]) {
4585 let w = st.yuv.width as usize;
4586 let cw = (st.yuv.width / 2) as usize;
4587 let blk_w = st.blk_w;
4588 for mby in 0..mb_h {
4589 for mbx in 0..mb_w {
4590 let mb_idx = mby * mb_w + mbx;
4593 let MbDeblock { disable_idc, alpha_off, beta_off } = st.mb_db[mb_idx];
4594 if disable_idc == 1 {
4595 continue;
4596 }
4597 let same_slice = |other: usize| disable_idc != 2 || st.mb_slice[other] == st.mb_slice[mb_idx];
4598 let filter_left = mbx > 0 && same_slice(mb_idx - 1);
4599 let filter_top = mby > 0 && same_slice(mb_idx - mb_w);
4600 let qp = st.mb_qp[mby * mb_w + mbx];
4601 let qp_left = if mbx > 0 {
4602 st.mb_qp[mby * mb_w + mbx - 1]
4603 } else {
4604 qp
4605 };
4606 let qp_top = if mby > 0 {
4607 st.mb_qp[(mby - 1) * mb_w + mbx]
4608 } else {
4609 qp
4610 };
4611 let qbx = mbx * 4; let qby = mby * 4;
4613
4614 let t8 = st.mb_t8[mb_idx];
4616 for k in 0..4usize {
4618 if t8 && k % 2 == 1 {
4619 continue;
4620 }
4621 let xe = k * 4;
4622 if xe == 0 && !filter_left {
4623 continue;
4624 }
4625 let is_mb_edge = xe == 0;
4626 let qp2 = if is_mb_edge { qp_left } else { qp };
4627 let qpav = (qp + qp2 + 1) >> 1;
4628 for seg in 0..4usize {
4629 let qx = qbx + k;
4630 let qy = qby + seg;
4631 let q_li = qy * blk_w + qx;
4632 let p_li = qy * blk_w + qx - 1;
4633 let bs = boundary_strength(st, p_li, q_li, is_mb_edge);
4634 if bs == 0 {
4635 continue;
4636 }
4637 let (a, b, t) = deblock_thresh(qpav, alpha_off, beta_off, bs);
4638 deblock_luma_edge(
4639 &mut st.yuv.y,
4640 w,
4641 true,
4642 mbx * 16 + xe,
4643 mby * 16 + seg * 4,
4644 4,
4645 bs,
4646 a,
4647 b,
4648 t,
4649 );
4650 }
4651 }
4652 for k in 0..4usize {
4654 if t8 && k % 2 == 1 {
4655 continue;
4656 }
4657 let ye = k * 4;
4658 if ye == 0 && !filter_top {
4659 continue;
4660 }
4661 let is_mb_edge = ye == 0;
4662 let qp2 = if is_mb_edge { qp_top } else { qp };
4663 let qpav = (qp + qp2 + 1) >> 1;
4664 for seg in 0..4usize {
4665 let qx = qbx + seg;
4666 let qy = qby + k;
4667 let q_li = qy * blk_w + qx;
4668 let p_li = (qy - 1) * blk_w + qx;
4669 let bs = boundary_strength(st, p_li, q_li, is_mb_edge);
4670 if bs == 0 {
4671 continue;
4672 }
4673 let (a, b, t) = deblock_thresh(qpav, alpha_off, beta_off, bs);
4674 deblock_luma_edge(
4675 &mut st.yuv.y,
4676 w,
4677 false,
4678 mbx * 16 + seg * 4,
4679 mby * 16 + ye,
4680 4,
4681 bs,
4682 a,
4683 b,
4684 t,
4685 );
4686 }
4687 }
4688 for comp in 0..2usize {
4690 let qpc = chroma_qp(qp, chroma_qp_off[comp]);
4692 let qpc_left = chroma_qp(qp_left, chroma_qp_off[comp]);
4693 let qpc_top = chroma_qp(qp_top, chroma_qp_off[comp]);
4694 for ck in 0..2usize {
4696 let cxe = ck * 4;
4697 let luma_k = ck * 2; if cxe == 0 && !filter_left {
4699 continue;
4700 }
4701 let is_mb_edge = cxe == 0;
4702 let qpav = (qpc + if is_mb_edge { qpc_left } else { qpc } + 1) >> 1;
4703 for seg in 0..4usize {
4704 let qx = qbx + luma_k;
4705 let qy = qby + seg;
4706 let q_li = qy * blk_w + qx;
4707 let p_li = qy * blk_w + qx - 1;
4708 let bs = boundary_strength(st, p_li, q_li, is_mb_edge);
4709 if bs == 0 {
4710 continue;
4711 }
4712 let (a, b, t) = deblock_thresh(qpav, alpha_off, beta_off, bs);
4713 let plane = if comp == 0 {
4714 &mut st.yuv.u
4715 } else {
4716 &mut st.yuv.v
4717 };
4718 deblock_chroma_edge(
4719 plane,
4720 cw,
4721 true,
4722 mbx * 8 + cxe,
4723 mby * 8 + seg * 2,
4724 2,
4725 bs,
4726 a,
4727 b,
4728 t,
4729 );
4730 }
4731 }
4732 for ck in 0..2usize {
4734 let cye = ck * 4;
4735 let luma_k = ck * 2;
4736 if cye == 0 && !filter_top {
4737 continue;
4738 }
4739 let is_mb_edge = cye == 0;
4740 let qpav = ((qpc + if is_mb_edge { qpc_top } else { qpc }) + 1) >> 1;
4741 for seg in 0..4usize {
4742 let qx = qbx + seg;
4743 let qy = qby + luma_k;
4744 let q_li = qy * blk_w + qx;
4745 let p_li = (qy - 1) * blk_w + qx;
4746 let bs = boundary_strength(st, p_li, q_li, is_mb_edge);
4747 if bs == 0 {
4748 continue;
4749 }
4750 let (a, b, t) = deblock_thresh(qpav, alpha_off, beta_off, bs);
4751 let plane = if comp == 0 {
4752 &mut st.yuv.u
4753 } else {
4754 &mut st.yuv.v
4755 };
4756 deblock_chroma_edge(
4757 plane,
4758 cw,
4759 false,
4760 mbx * 8 + seg * 2,
4761 mby * 8 + cye,
4762 2,
4763 bs,
4764 a,
4765 b,
4766 t,
4767 );
4768 }
4769 }
4770 }
4771 }
4772 }
4773}
4774
4775fn is_prefix_free(entries: &[(u8, u16)], label: &str) -> bool {
4779 let mut ok = true;
4780 for i in 0..entries.len() {
4781 for j in 0..entries.len() {
4782 if i == j {
4783 continue;
4784 }
4785 let (la, ca) = entries[i];
4786 let (lb, cb) = entries[j];
4787 if la <= lb && (cb >> (lb - la)) == ca {
4788 crate::println!(
4789 " PREFIX-CONFLICT in {}: ({},{:b}) is prefix of ({},{:b})",
4790 label,
4791 la,
4792 ca,
4793 lb,
4794 cb
4795 );
4796 ok = false;
4797 }
4798 }
4799 }
4800 ok
4801}
4802
4803fn check_token_complete(t: &[TokEntry], max_tc: u8, label: &str) -> bool {
4806 let mut ok = true;
4807 for tc in 0..=max_tc {
4808 let max_t1 = if tc == 0 { 0 } else { tc.min(3) };
4809 for t1 in 0..=max_t1 {
4810 let count = t.iter().filter(|&&(_, _, c, o)| c == tc && o == t1).count();
4811 if count != 1 {
4812 crate::println!(
4813 " TOKEN {} ({},{}) appears {} times (want 1)",
4814 label,
4815 tc,
4816 t1,
4817 count
4818 );
4819 ok = false;
4820 }
4821 }
4822 }
4823 ok
4824}
4825
4826pub fn tables_selftest() {
4828 let mut ok = true;
4829 let toks: [(&str, &[TokEntry]); 4] = [
4830 ("coeff_token_0", COEFF_TOKEN_0),
4831 ("coeff_token_2", COEFF_TOKEN_2),
4832 ("coeff_token_4", COEFF_TOKEN_4),
4833 ("coeff_token_cdc", COEFF_TOKEN_CHROMA_DC),
4834 ];
4835 for (name, t) in toks {
4836 let e: Vec<(u8, u16)> = t.iter().map(|&(l, c, _, _)| (l, c)).collect();
4837 if !is_prefix_free(&e, name) {
4838 ok = false;
4839 }
4840 }
4841 if !check_token_complete(COEFF_TOKEN_0, 16, "tok0") {
4842 ok = false;
4843 }
4844 if !check_token_complete(COEFF_TOKEN_2, 16, "tok2") {
4845 ok = false;
4846 }
4847 if !check_token_complete(COEFF_TOKEN_4, 16, "tok4") {
4848 ok = false;
4849 }
4850 if !check_token_complete(COEFF_TOKEN_CHROMA_DC, 4, "tokCDC") {
4851 ok = false;
4852 }
4853 for (i, row) in TOTAL_ZEROS_16.iter().enumerate() {
4855 let tc = i + 1;
4856 if row.len() != 17 - tc {
4857 crate::println!(
4858 " TZ16 row tc={} has {} entries (want {})",
4859 tc,
4860 row.len(),
4861 17 - tc
4862 );
4863 ok = false;
4864 }
4865 }
4866 for (i, row) in TOTAL_ZEROS_16.iter().enumerate() {
4867 if !is_prefix_free(row, "tz16") {
4868 crate::println!(" (tz16 row tc={})", i + 1);
4869 ok = false;
4870 }
4871 }
4872 for row in TOTAL_ZEROS_CHROMA.iter() {
4873 if !is_prefix_free(row, "tzC") {
4874 ok = false;
4875 }
4876 }
4877 for row in RUN_BEFORE.iter() {
4878 if !is_prefix_free(row, "run_before") {
4879 ok = false;
4880 }
4881 }
4882 if !ok {
4884 crate::println!("H264_TABLES: CONFLICTS FOUND");
4885 }
4886}
4887
4888fn run_golden(
4892 clip: &[u8],
4893 ref_yuv: &[u8],
4894) -> Result<(usize, usize, usize, usize, usize), &'static str> {
4895 let nals = split_annexb(clip);
4896 let mut sps: Option<Sps> = None;
4897 let mut pps: Option<Pps> = None;
4898 let mut reference: Option<DecodedYuv> = None;
4899 for nu in &nals {
4900 match nu.unit_type {
4901 7 => {
4902 sps = Some(parse_sps(&nu.rbsp)?);
4903 }
4904 8 => {
4905 pps = Some(parse_pps(&nu.rbsp)?);
4906 }
4907 1 | 5 => {
4908 let s = sps.as_ref().ok_or("no SPS")?;
4909 let p = pps.as_ref().ok_or("no PPS")?;
4910 let frame = decode_slice(s, p, &nu.rbsp, nu.unit_type == 5, reference.as_ref())?;
4911 reference = Some(frame);
4912 }
4913 _ => {}
4914 }
4915 }
4916 let yuv = reference.ok_or("no slice decoded")?;
4917 let yn = (yuv.width * yuv.height) as usize;
4918 let cn = yuv.u.len();
4919 let fsize = yn + 2 * cn;
4921 let nframes = ref_yuv.len() / fsize;
4922 let off = (nframes.saturating_sub(1)) * fsize;
4923 let mut ym = 0;
4924 for i in 0..yn {
4925 if yuv.y[i] == ref_yuv[off + i] {
4926 ym += 1;
4927 }
4928 }
4929 let mut um = 0;
4930 for i in 0..cn {
4931 if yuv.u[i] == ref_yuv[off + yn + i] {
4932 um += 1;
4933 }
4934 }
4935 let mut vm = 0;
4936 for i in 0..cn {
4937 if yuv.v[i] == ref_yuv[off + yn + cn + i] {
4938 vm += 1;
4939 }
4940 }
4941 Ok((ym, um, vm, yn, cn))
4942}
4943
4944fn run_golden_debug(clip: &[u8], ref_yuv: &[u8]) {
4946 let nals = split_annexb(clip);
4947 let mut sps: Option<Sps> = None;
4948 let mut pps: Option<Pps> = None;
4949 let mut reference: Option<DecodedYuv> = None;
4950 for nu in &nals {
4951 match nu.unit_type {
4952 7 => sps = parse_sps(&nu.rbsp).ok(),
4953 8 => pps = parse_pps(&nu.rbsp).ok(),
4954 1 | 5 => {
4955 if let (Some(s), Some(p)) = (sps.as_ref(), pps.as_ref()) {
4956 if let Ok(f) =
4957 decode_slice(s, p, &nu.rbsp, nu.unit_type == 5, reference.as_ref())
4958 {
4959 reference = Some(f);
4960 }
4961 }
4962 }
4963 _ => {}
4964 }
4965 }
4966 if let Some(yuv) = reference {
4967 let w = yuv.width as usize;
4968 let h = yuv.height as usize;
4969 let fsize = w * h + 2 * yuv.u.len();
4970 let off = (ref_yuv.len() / fsize).saturating_sub(1) * fsize;
4971 let mut shown = 0;
4972 'outer: for mby in (0..h).step_by(16) {
4973 for mbx in (0..w).step_by(16) {
4974 let mut bad = 0;
4975 let mut first = (0u8, 0u8, 0usize, 0usize);
4976 for yy in 0..16 {
4977 for xx in 0..16 {
4978 let i = (mby + yy) * w + mbx + xx;
4979 if yuv.y[i] != ref_yuv[off + i] {
4980 if bad == 0 {
4981 first = (yuv.y[i], ref_yuv[off + i], mbx + xx, mby + yy);
4982 }
4983 bad += 1;
4984 }
4985 }
4986 }
4987 if bad > 0 {
4988 crate::println!(
4989 " MB({},{}) bad={}/256 first@({},{}) got={} exp={}",
4990 mbx,
4991 mby,
4992 bad,
4993 first.2,
4994 first.3,
4995 first.0,
4996 first.1
4997 );
4998 shown += 1;
4999 if shown >= 8 {
5000 break 'outer;
5001 }
5002 }
5003 }
5004 }
5005 }
5006}
5007
5008pub fn golden_test() -> bool {
5010 use super::h264_golden::*;
5011 tables_selftest();
5012 let mut pass = 0usize;
5013 let mut total = 0usize;
5014 for (name, clip, refy) in [
5015 ("flat", FLAT_H264.as_slice(), FLAT_YUV.as_slice()),
5016 ("clip", CLIP_H264.as_slice(), CLIP_YUV.as_slice()),
5017 ("big", BIG_H264.as_slice(), BIG_YUV.as_slice()),
5018 ("dbclip", DBCLIP_H264.as_slice(), DBCLIP_YUV.as_slice()),
5019 ("dbbig", DBBIG_H264.as_slice(), DBBIG_YUV.as_slice()),
5020 ("pskip", PSKIP_H264.as_slice(), PSKIP_YUV.as_slice()),
5021 ("pint16", PINT16_H264.as_slice(), PINT16_YUV.as_slice()),
5022 ("psub", PSUB_H264.as_slice(), PSUB_YUV.as_slice()),
5023 ("ppart", PPART_H264.as_slice(), PPART_YUV.as_slice()),
5024 ("dbp", DBP_H264.as_slice(), DBP_YUV.as_slice()),
5025 ] {
5026 match run_golden(clip, refy) {
5027 Ok((ym, um, vm, yn, cn)) => {
5028 total += 1;
5029 if ym == yn && um == cn && vm == cn {
5030 pass += 1;
5031 } else {
5032 crate::println!(
5034 "H264_GOLDEN {}: MISMATCH Y {}/{} U {}/{} V {}/{}",
5035 name,
5036 ym,
5037 yn,
5038 um,
5039 cn,
5040 vm,
5041 cn
5042 );
5043 if ym != yn {
5044 run_golden_debug(clip, refy);
5045 }
5046 }
5047 }
5048 Err(e) => {
5049 total += 1;
5050 crate::println!("H264_GOLDEN {}: ERROR {}", name, e);
5051 }
5052 }
5053 }
5054 crate::info!("[H264] Golden test pass: {}/{}", pass, total);
5056 pass == total
5057}