oxideav-av1 0.1.21

Pure-Rust AV1 codec — orphan-rebuild scaffold pending clean-room re-implementation.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
//! Conformance-grade B-pyramid GOP encoder (r415, deepened r424).
//!
//! Extends the r411-r413 KEY + P GOP driver ([`super::inter_frame`])
//! with OUT-OF-ORDER coding. r415 introduced the fixed two-level
//! mini-GOP (up to four frames: ALT + MID + shown Bs +
//! `show_existing_frame` chains); r424 generalizes the planner to a
//! RECURSIVE DYADIC PYRAMID of arbitrary depth (mini-GOPs up to
//! [`PyramidTuning::max_mini_gop`] frames, four temporal layers at
//! the default 16), adds per-layer quantiser offsets, threads the
//! r423 §5.9.2 primary-reference carry through the pyramid's refresh
//! graph with a per-frame exact-bytes election, and adds the
//! content-adaptive mini-GOP driver
//! ([`encode_adaptive_gop_yuv420_with_q`]).
//!
//! ## The recursive plan
//!
//! A mini-GOP of `l` frames after anchor display position `A`
//! (`hi = A + l`) codes:
//!
//! 1. the **ALT frame** (`hi`) FIRST as a decoded-not-shown reference
//!    (`show_frame = 0`, `showable_frame = 1`), forward-predicted
//!    from the anchor;
//! 2. the interval `(A, hi)` recursively: its **midpoint** as a
//!    decoded-not-shown MID reference predicting forward from the
//!    interval's low anchor (`LAST_FRAME`) and backward from the
//!    interval's high anchor and the enclosing anchors
//!    (`BWDREF_FRAME` / `ALTREF2_FRAME` / `ALTREF_FRAME` — §7.8 sign
//!    bias 1, §6.10 reference roles), then the left half, a
//!    `show_existing_frame` unit for the midpoint, then the right
//!    half;
//! 3. gap-2 intervals bottom out as **shown B leaves** (no refresh),
//!    with bidirectional COMPOUND_AVERAGE pairs in the RD ladder
//!    (§5.11.25 `BIDIR_COMP_REFERENCE` cascade) and §5.9.22
//!    forward/backward skip mode;
//! 4. a final `show_existing_frame` unit displays the ALT frame.
//!
//! Backward reference roles per coded frame come from the recursion's
//! ENCLOSING-ANCHOR CHAIN (nearest first): `BWDREF` reads the nearest
//! coded future frame, `ALTREF2` the next enclosing one, `ALTREF` the
//! mini-GOP's ALT. Reference rotation runs on all eight §7.20 slots
//! with order-hint-tracked state: the anchor slot holds the previous
//! mini-GOP's last frame, one slot per live pyramid level is
//! allocated from a free list, and the ALT slot becomes the next
//! mini-GOP's anchor.
//!
//! ## Per-layer quantisers (r424)
//!
//! With [`PyramidTuning::layer_q_offsets`] on (the default) each
//! role's frame quantiser is offset from the GOP `base_q_idx` by its
//! temporal layer: the ALT anchor codes slightly FINER (more frames
//! predict from it), midpoints slightly coarser per level, and
//! non-reference B leaves coarsest. Offsets are disabled at
//! `base_q_idx == 0` (lossless) and clamped to `1..=255` otherwise —
//! per-frame `base_q_idx` is plain §5.9.12 header state, so every
//! stream stays conformant.
//!
//! ## Primary-reference carry (r424)
//!
//! With [`PyramidTuning::primary_ref`] on, every coded frame elects a
//! §5.9.2 `primary_ref_frame` over the encoder-side §7.20 carry store
//! (frame-end CDFs / segment ids / gm params per slot — the r423
//! [`RefSlotCarry`] state): the search runs under the LAST-slot carry
//! (the interval's low anchor — the frame's most-relevant coded
//! predecessor), and the committed trees are then replayed bit-exactly
//! under the nearest-BACKWARD anchor's carry and under the
//! per-frame-defaults (`PRIMARY_REF_NONE`) state; the smallest total
//! frame wins ([`InterFrameConfig::alt_primaries`] — a pure-rate
//! election, the reconstruction is identical by construction).
//!
//! Every inter frame keeps the r413 session shape —
//! non-error-resilient headers, 7-bit order hints,
//! `use_ref_frame_mvs = 1` (§7.9 temporal projection over the
//! encoder-side §7.20 motion-field store, which tracks refreshes by
//! slot exactly like the decoder's).
//!
//! Display-order structure examples (anchor at display position `A`,
//! coding order left to right; `SEF(x)` = the `show_existing_frame`
//! unit displaying `x`):
//!
//! ```text
//! L = 1:  P(A+1, shown)
//! L = 2:  ALT(A+2), B(A+1, shown), SEF(A+2)
//! L = 4:  ALT(A+4), MID(A+2), B(A+1, shown), SEF(A+2),
//!         B(A+3, shown), SEF(A+4)
//! L = 8:  ALT(A+8), MID1(A+4), MID2(A+2), B(A+1), SEF(A+2), B(A+3),
//!         SEF(A+4), MID2'(A+6), B(A+5), SEF(A+6), B(A+7), SEF(A+8)
//! ```
//!
//! Spec provenance: `docs/video/av1/av1-spec.txt` §5.9.2
//! (`show_existing_frame`, `showable_frame`, `refresh_frame_flags`,
//! `ref_frame_idx`, `primary_ref_frame`), §5.9.22 (skip mode),
//! §6.10.24 / §5.11.25 (bidirectional compound reference groups),
//! §6.8.21 (`load_cdfs`), §7.8 (reference frame sign bias), §7.9 /
//! §7.19 / §7.20 (motion fields + reference update), §7.21
//! (`load_previous`).

use std::rc::Rc;

use crate::cdf::QuantizerParams;
use crate::encoder::film_grain_elect::grain_seed_for;
use crate::encoder::frame_obu::write_frame_header_obu;
use crate::encoder::inter_frame::{
    elect_film_grain, encode_inter_frame_generic, narrow_gop_8bit, EncodedGop, EncodedGopYuv,
    GopFrameReconYuv, InterFrameConfig, RefSlotCarry, SavedMotionField, GOP_MAX_FRAMES,
};
use crate::encoder::ivf::{IvfWriter, FOURCC_AV01};
use crate::encoder::key_frame::lambda_for;
use crate::encoder::key_frame::KeyExtras;
use crate::encoder::obu::{build_temporal_unit, ObuFrame};
use crate::encoder::rate_twin::RateModel;
use crate::encoder::yuv_frame::YuvFrame;
use crate::encoder::yuv_frame::{build_intra_only_yuv420_8bit_fh_with_q, Yuv420Frame};
use crate::frame_header::{FrameHeader, FrameType, PRIMARY_REF_NONE};
use crate::obu::ObuType;
use crate::sequence_header::SequenceHeader;
use crate::uncompressed_header_tail::FilmGrainParams;
use crate::Error;

/// r424 — the B-pyramid encoder's tuning switches, kept public
/// (hidden) so the measurement harnesses can A/B each feature against
/// its baseline on identical inputs. Production entry points use
/// [`PyramidTuning::default`] (everything on, mini-GOPs up to 16).
#[doc(hidden)]
#[derive(Debug, Clone, Copy)]
pub struct PyramidTuning {
    /// RD-election rate model (r421).
    pub model: RateModel,
    /// Mini-GOP frame cap (`1..=32`). `4` reproduces the r415-r423
    /// two-level pyramid chunking; the r424 default `16` codes up to
    /// four temporal layers per mini-GOP.
    pub max_mini_gop: usize,
    /// r424 — per-layer quantiser offsets (see the module docs).
    /// Inert at `base_q_idx == 0`.
    pub layer_q_offsets: bool,
    /// r424 — §5.9.2 primary-reference carry + per-frame exact-bytes
    /// election through the pyramid. `false` keeps `PRIMARY_REF_NONE`
    /// per-frame default state on every frame (the r423 baseline).
    pub primary_ref: bool,
    /// r428 — §5.9.2 `allow_high_precision_mv` arm: eighth-pel MV
    /// search + wire precision, with the per-frame exact-bytes
    /// replay election back to the quarter-pel arm. `false` keeps
    /// the pre-r428 quarter-pel shape on every frame (the A/B
    /// baseline).
    pub high_precision_mv: bool,
    /// r428 — §5.9.17 per-superblock delta-q election on unsegmented
    /// lossy frames (complexity-probe plan + frame-level exact-bytes
    /// arm election). `false` keeps the single-quantiser shape on
    /// every frame (the A/B baseline).
    pub delta_q: bool,
    /// r439 — §5.9.12 quantizer-matrix election (see
    /// [`super::inter_frame::GopTuning::qm`]). `false` keeps the
    /// flat-quantiser shape on every frame (the A/B baseline).
    pub qm: bool,
    /// r428 — frame-level §5.9.19/§7.15 CDEF election on lossy
    /// frames (KEY + every pyramid role). `false` keeps the
    /// all-zero-strength shape on every frame (the A/B baseline).
    pub cdef: bool,
    /// r429 — allow `cdef_bits > 0` (per-64×64 §5.11.56 strength
    /// ids; tile re-emitted with the exact literals). `false` caps
    /// the election at the frame-level arm. Inert while
    /// [`Self::cdef`] is off.
    pub cdef_units: bool,
    /// r429 — §5.9.20/§7.17 loop-restoration election (see the GOP
    /// tuning's field of the same name). `false` keeps the
    /// all-RESTORE_NONE shape on every frame (the A/B baseline).
    pub lr: bool,
    /// r433 — the §5.9.15 uniform tile layout `(TileColsLog2,
    /// TileRowsLog2)` coded on EVERY frame of the pyramid (KEY, ALT,
    /// MID, B). `(0, 0)` is the single-tile shape (bit-identical to
    /// the pre-r433 streams); must sit inside the §5.9.15 legal
    /// window for the frame size.
    pub tiles: (u32, u32),
    /// r433 — §5.11.1 tile-group packaging on every coded frame (see
    /// [`super::inter_frame::GopTuning::tile_groups`]). `0` / `1`
    /// keep the single-`OBU_FRAME` shape.
    pub tile_groups: u32,
    /// r439 — §6.8.14 `context_update_tile_id` election through the
    /// pyramid's refresh graph (the out-of-order sibling of
    /// [`super::inter_frame::GopTuning::ctx_update_elect`]): a coded
    /// frame whose elected §5.9.2 primary reference offers the full
    /// donor set replays its committed trees from EACH tile's
    /// frame-end CDF state and keeps the start state realizing the
    /// smallest assembled §5.11.1 body; a win patches the donor
    /// frame's already-emitted fixed-width field in place — inside a
    /// still-pending multi-frame temporal unit or an already-flushed
    /// one. A slot's donor set FREEZES at its first consumption
    /// (whether or not the election won — the consumer's bytes chain
    /// off the donation as it stood), swept by pointer identity
    /// across every §7.20 slot holding the same frame's carry.
    /// `false` keeps the tile-0 donation on every frame (the A/B
    /// baseline; bit-identical to the pre-r439 streams). Inert on
    /// single-tile layouts or with [`Self::primary_ref`] off.
    pub ctx_update_elect: bool,
    /// r444 — §5.9.8 SUPERRES election on the pyramid KEY (see
    /// [`super::inter_frame::GopTuning::superres`]): inside the
    /// measured win regime the KEY may code at a §5.9.8 downscaled
    /// width; every later frame of the pyramid predicts from its
    /// UPSCALED §7.20 reconstruction at the full extent (the KEY's
    /// intra motion-field / carry seeds are extent-inert, exactly as
    /// on the plain-GOP driver). Single-tile pyramids only (the KEY
    /// election's own gate); `false` keeps the flat-width KEY (the
    /// A/B baseline; bit-identical outside an elected win).
    pub superres: bool,
    /// r452 — §5.9.30 FILM-GRAIN election on lossy pyramids whose
    /// content passes the noise probe (see
    /// [`super::inter_frame::GopTuning::film_grain`]): the grain arm
    /// re-runs the WHOLE out-of-order refresh graph over the DENOISED
    /// frames with full §5.9.30 parameters on every coded header
    /// (KEY, ALT, MID, B — each seeded at its own `order_hint`, so a
    /// decoded-not-shown frame's later `show_existing_frame` output
    /// carries the §7.21 `load_grain_params()` synthesis of THAT
    /// frame) and publishes §7.18.3-synthesized output planes; the
    /// perceptually-neutral-rate objective settles it. `false` keeps
    /// the no-grain shape (the A/B baseline; probe-failing content
    /// is bit-identical either way).
    pub film_grain: bool,
    /// r453 — §5.9.2 `frame_refs_short_signaling = 1` through the
    /// out-of-order refresh graph (the pyramid sibling of
    /// [`super::inter_frame::GopTuning::short_ref_signaling`]): a
    /// coded role whose §7.8 `set_frame_refs()` derivation over the
    /// TRUE stored `RefOrderHint[]` state — seeded from the role's
    /// LAST / GOLDEN slot — still NAMES every slot the role's RD
    /// ladder searches (the ALT anchor, the nearest backward
    /// midpoint, the enclosing midpoint) adopts the derived map and
    /// re-addresses its search ordinals, primary-reference candidates
    /// and §6.8.14 donor settlement onto the ordinals the derivation
    /// gave those slots; the header then codes only `last_frame_idx`
    /// / `gold_frame_idx` (7 wire bits replace the explicit 22) and
    /// both sides run the identical §7.8 algorithm in lockstep. A
    /// role whose searched slot the derivation cannot reach keeps the
    /// explicit shape. `false` keeps the explicit map on every frame
    /// (the A/B baseline; bit-identical to the pre-r453 streams).
    pub short_ref_signaling: bool,
}

impl Default for PyramidTuning {
    fn default() -> Self {
        PyramidTuning {
            model: RateModel::Twin,
            max_mini_gop: 16,
            layer_q_offsets: true,
            primary_ref: true,
            high_precision_mv: true,
            delta_q: true,
            qm: true,
            cdef: true,
            cdef_units: true,
            lr: true,
            tiles: (0, 0),
            tile_groups: 1,
            ctx_update_elect: true,
            superres: true,
            film_grain: true,
            short_ref_signaling: true,
        }
    }
}

/// r424 (hidden) — [`EncodedGop`] plus the pyramid election traces:
/// the committed mini-GOP lengths and, per coded inter frame in
/// CODING order, the elected §5.9.2 `primary_ref_frame` ordinal
/// (`PRIMARY_REF_NONE` when the per-frame-defaults candidate won or
/// the carry was off). [`EncodedGop`] itself stays field-stable.
#[doc(hidden)]
#[derive(Debug, Clone)]
pub struct TunedPyramidGop {
    /// r452 — the §5.9.30 film-grain arm won (see
    /// [`PyramidTuning::film_grain`]).
    pub film_grain_elected: bool,
    pub gop: EncodedGop,
    pub chunk_lengths: Vec<usize>,
    pub primary_elections: Vec<(u32, u8)>,
    /// r439 — per coded inter frame in CODING order: `(order_hint,
    /// Some(t))` when the frame elected tile `t != 0` of its primary
    /// frame as the §6.8.14 CDF donor (the donor frame's
    /// `context_update_tile_id` was patched to `t` on the wire);
    /// `None` when the tile-0 donation stood.
    pub ctx_donor_elections: Vec<(u32, Option<u32>)>,
}

/// r427 (hidden) — general-format sibling of [`TunedPyramidGop`].
#[doc(hidden)]
#[derive(Debug, Clone)]
pub struct TunedPyramidGopYuv {
    /// r452 — the §5.9.30 film-grain arm won (see
    /// [`PyramidTuning::film_grain`]).
    pub film_grain_elected: bool,
    pub gop: EncodedGopYuv,
    pub chunk_lengths: Vec<usize>,
    pub primary_elections: Vec<(u32, u8)>,
    /// r439 — see [`TunedPyramidGop::ctx_donor_elections`].
    pub ctx_donor_elections: Vec<(u32, Option<u32>)>,
}

/// One coded (non-KEY) pyramid frame's role.
struct Role {
    /// Display position (== §5.9.2 `order_hint`).
    display: usize,
    /// §5.9.2 `show_frame`.
    show: bool,
    /// §7.20 slot this frame refreshes (`None` = `refresh_frame_flags
    /// = 0`, a pure non-reference frame).
    refresh: Option<usize>,
    /// Slot the forward references (`LAST_FRAME..=GOLDEN_FRAME`) read.
    last_slot: usize,
    /// Slot `BWDREF_FRAME` reads (the nearest coded future frame);
    /// `None` = forward-only (maps to `last_slot`).
    bwd_slot: Option<usize>,
    /// Slot `ALTREF2_FRAME` reads (the next enclosing backward
    /// anchor); `None` falls back to `bwd_slot`.
    alt2_slot: Option<usize>,
    /// Slot `ALTREF_FRAME` reads (the mini-GOP's ALT); `None` falls
    /// back to `bwd_slot`.
    alt_ref_slot: Option<usize>,
    /// r424 — signed per-layer quantiser offset (see
    /// [`PyramidTuning::layer_q_offsets`]).
    q_off: i32,
    /// RD ladder (see `PSearchCtx::single_refs` /
    /// `PSearchCtx::compound_pairs`).
    singles: Vec<i8>,
    pairs: Vec<[i8; 2]>,
}

/// One coding-order step of a mini-GOP plan.
enum Step {
    /// Encode a frame.
    Code(Role),
    /// Emit a `show_existing_frame` header displaying the given slot.
    Show(usize),
}

/// A role's backward reference assignment + RD ladder, derived from
/// the enclosing-anchor chain by [`backward_roles`].
struct BackwardRoles {
    bwd: Option<usize>,
    alt2: Option<usize>,
    alt_ref: Option<usize>,
    singles: Vec<i8>,
    pairs: Vec<[i8; 2]>,
}

/// Build a role's backward reference assignment + RD ladder from the
/// enclosing-anchor `chain` (nearest coded future frame first, the
/// mini-GOP ALT last).
fn backward_roles(chain: &[usize]) -> BackwardRoles {
    let bwd = chain.first().copied();
    let alt_ref = if chain.len() >= 2 {
        chain.last().copied()
    } else {
        None
    };
    let alt2 = if chain.len() >= 3 {
        Some(chain[1])
    } else {
        None
    };
    let mut singles: Vec<i8> = vec![1];
    let mut pairs: Vec<[i8; 2]> = Vec::new();
    if bwd.is_some() {
        singles.push(5);
        pairs.push([1, 5]);
    }
    if alt2.is_some() {
        singles.push(6);
        pairs.push([1, 6]);
    }
    if alt_ref.is_some() {
        singles.push(7);
        pairs.push([1, 7]);
    }
    BackwardRoles {
        bwd,
        alt2,
        alt_ref,
        singles,
        pairs,
    }
}

/// r424 — per-layer quantiser offset schedule: the ALT anchor codes
/// finer (every pyramid frame predicts from it), midpoints coarser
/// per level, non-reference B leaves coarsest. `level` is the
/// midpoint recursion depth (1 = the mini-GOP's top interval).
fn mid_q_off(level: u32) -> i32 {
    match level {
        1 => 2,
        2 => 4,
        _ => 6,
    }
}

/// Recursive interval planner: emit the coding-order steps for the
/// frames STRICTLY between display positions `lo` and `hi` (already
/// coded, held in `lo_slot` / `hi_slot`). `chain` is the
/// enclosing-anchor slot chain visible to this interval's frames
/// (nearest first — `chain[0] == hi_slot`); `level` the midpoint
/// recursion depth; `free` the slot free list.
fn plan_interval(
    lo: usize,
    hi: usize,
    lo_slot: usize,
    chain: &[usize],
    level: u32,
    free: &mut Vec<usize>,
    steps: &mut Vec<Step>,
) {
    let gap = hi - lo;
    if gap <= 1 {
        return;
    }
    if gap == 2 {
        // Shown non-reference B leaf.
        let br = backward_roles(chain);
        steps.push(Step::Code(Role {
            display: lo + 1,
            show: true,
            refresh: None,
            last_slot: lo_slot,
            bwd_slot: br.bwd,
            alt2_slot: br.alt2,
            alt_ref_slot: br.alt_ref,
            q_off: 8,
            singles: br.singles,
            pairs: br.pairs,
        }));
        return;
    }
    // Decoded-not-shown midpoint reference.
    let mid = (lo + hi).div_ceil(2);
    let mid_slot = free.pop().expect("slot free list exhausted (depth > 6)");
    let br = backward_roles(chain);
    steps.push(Step::Code(Role {
        display: mid,
        show: false,
        refresh: Some(mid_slot),
        last_slot: lo_slot,
        bwd_slot: br.bwd,
        alt2_slot: br.alt2,
        alt_ref_slot: br.alt_ref,
        q_off: mid_q_off(level),
        singles: br.singles,
        pairs: br.pairs,
    }));
    // Left half sees the midpoint as its nearest backward anchor.
    let mut inner_chain = Vec::with_capacity(chain.len() + 1);
    inner_chain.push(mid_slot);
    inner_chain.extend_from_slice(chain);
    plan_interval(lo, mid, lo_slot, &inner_chain, level + 1, free, steps);
    steps.push(Step::Show(mid_slot));
    // Right half: the midpoint is its LOW anchor; the backward chain
    // is unchanged (nearest future frame is still `hi`).
    plan_interval(mid, hi, mid_slot, chain, level + 1, free, steps);
    free.push(mid_slot);
}

/// The coding-order plan for one mini-GOP of `l` frames starting at
/// display position `pos` (anchor at `pos - 1` in `anchor_slot`).
/// Returns the steps and the ALT slot (the next chunk's anchor).
fn plan_mini_gop(pos: usize, l: usize, anchor_slot: usize) -> (Vec<Step>, usize) {
    let mut free: Vec<usize> = (0..8usize).rev().filter(|&s| s != anchor_slot).collect();
    let alt_slot = free.pop().expect("eight slots, one anchor");
    let mut steps = Vec::new();
    if l == 1 {
        steps.push(Step::Code(Role {
            display: pos,
            show: true,
            refresh: Some(alt_slot),
            last_slot: anchor_slot,
            bwd_slot: None,
            alt2_slot: None,
            alt_ref_slot: None,
            q_off: 0,
            singles: vec![1],
            pairs: vec![],
        }));
        return (steps, alt_slot);
    }
    let hi = pos + l - 1;
    steps.push(Step::Code(Role {
        display: hi,
        show: false,
        refresh: Some(alt_slot),
        last_slot: anchor_slot,
        bwd_slot: None,
        alt2_slot: None,
        alt_ref_slot: None,
        q_off: -3,
        singles: vec![1],
        pairs: vec![],
    }));
    plan_interval(
        pos - 1,
        hi,
        anchor_slot,
        &[alt_slot],
        1,
        &mut free,
        &mut steps,
    );
    steps.push(Step::Show(alt_slot));
    (steps, alt_slot)
}

/// r424 — the pyramid encoder's running session state: the KEY-seeded
/// §7.20 stores (motion fields, r423 carry, order hints, display
/// map), the anchor slot, the display-order reconstructions and the
/// emitted temporal units. `Clone` is cheap enough for the adaptive
/// driver's trial chunks (the carry store is `Rc`-shared).
#[derive(Clone)]
struct PyramidSession {
    /// r452 — the armed §5.9.30 parameter set (per-frame seeds are
    /// stamped at each role's `order_hint`); `None` = no grain.
    film_grain: Option<FilmGrainParams>,
    seq: SequenceHeader,
    base_q: u8,
    tuning: PyramidTuning,
    mf_store: [SavedMotionField; 8],
    carry_store: [Rc<RefSlotCarry>; 8],
    slot_hints: [u32; 8],
    slot_display: [usize; 8],
    anchor_slot: usize,
    recons: Vec<Option<GopFrameReconYuv>>,
    temporal_units: Vec<Vec<u8>>,
    chunk_lengths: Vec<usize>,
    primary_elections: Vec<(u32, u8)>,
    /// r439 — where each §7.20 slot's carried frame sits on the wire:
    /// `(temporal-unit index, frame ordinal within the unit)` — the
    /// §6.8.14 donor patch target once the unit has FLUSHED. `None`
    /// while the frame is still pending inside the current chunk's
    /// open unit (the patch then rewrites the pending OBU body
    /// directly). Every mini-GOP plan ends flushed, so `None` never
    /// crosses a chunk boundary.
    slot_wire: [Option<(usize, usize)>; 8],
    /// r439 — donor-election trace (see
    /// [`TunedPyramidGop::ctx_donor_elections`]).
    ctx_donor_elections: Vec<(u32, Option<u32>)>,
}

impl PyramidSession {
    /// r439 — the §6.8.14 donor election arms on multi-tile pyramids
    /// with the primary-reference carry live (single-tile frames
    /// carry no `context_update_tile_id` field; without a primary
    /// chain nobody consumes the donation).
    fn donor_armed(tuning: &PyramidTuning) -> bool {
        tuning.ctx_update_elect && tuning.primary_ref && tuning.tiles != (0, 0)
    }

    /// Encode the KEY frame and seed every §7.20 slot with its state.
    fn new(
        frames: &[YuvFrame],
        base_q: u8,
        tuning: PyramidTuning,
        film_grain: Option<&FilmGrainParams>,
    ) -> Result<Self, Error> {
        let n = frames.len();
        let (width, height) = (frames[0].width, frames[0].height);
        // r452 — the KEY's per-frame §5.9.30 seed rides the shared
        // schedule at display position 0 (opening the sequence gate
        // for the whole pyramid).
        let key_fg: Option<FilmGrainParams> = film_grain.map(|base| {
            let mut f = base.clone();
            f.grain_seed = grain_seed_for(0);
            f
        });
        let (key, key_carry) = crate::encoder::key_frame::encode_key_frame_yuv_full(
            &frames[0],
            base_q,
            tuning.model,
            &[],
            None,
            tuning.cdef,
            tuning.cdef_units,
            tuning.lr,
            &KeyExtras {
                // r433 — the pyramid-wide §5.9.15 tile layout +
                // §5.11.1 tile-group packaging (KEY delta-q stays
                // default-on, as the pre-r433
                // `encode_key_frame_yuv_seg_carry` shape).
                tiles: tuning.tiles,
                tile_groups: tuning.tile_groups,
                delta_q: true,
                // r439 — the KEY rides the pyramid's §5.9.12 QM switch.
                qm: tuning.qm,
                // r444 — the §5.9.8 superres election rides the
                // pyramid KEY: the out-of-order refresh graph reads
                // only the KEY's UPSCALED reconstruction (full extent)
                // and its extent-inert intra motion-field / carry
                // seeds, exactly like the plain-GOP driver.
                superres_elect: tuning.superres,
                // r452 — the armed §5.9.30 parameter set.
                film_grain: key_fg.as_ref(),
                // r439 — the KEY donates too: collect its per-tile end
                // CDFs so the first consumer can run the §6.8.14
                // election.
                collect_donor_cdfs: Self::donor_armed(&tuning),
                ..KeyExtras::default()
            },
        )?;
        let seq = key.seq.clone();
        let mut recons: Vec<Option<GopFrameReconYuv>> = (0..n).map(|_| None).collect();
        recons[0] = Some(GopFrameReconYuv {
            y: key.recon_y,
            u: key.recon_u,
            v: key.recon_v,
        });
        let key_mi = {
            let fh0 = build_intra_only_yuv420_8bit_fh_with_q(&seq, width, height, base_q);
            let fs0 = fh0.frame_size.expect("KEY builder always sizes");
            (fs0.mi_rows, fs0.mi_cols)
        };
        let key_carry = Rc::new(key_carry);
        Ok(PyramidSession {
            film_grain: film_grain.cloned(),
            seq,
            base_q,
            tuning,
            mf_store: core::array::from_fn(|_| SavedMotionField::intra(key_mi.0, key_mi.1)),
            carry_store: core::array::from_fn(|_| key_carry.clone()),
            slot_hints: [0u32; 8],
            slot_display: [0usize; 8],
            anchor_slot: 0,
            recons,
            temporal_units: vec![key.temporal_unit_bytes],
            chunk_lengths: Vec::new(),
            primary_elections: Vec::new(),
            // r439 — the KEY frame is temporal unit 0, frame ordinal
            // 0; its `allFrames` refresh seeds every slot.
            slot_wire: [Some((0, 0)); 8],
            ctx_donor_elections: Vec::new(),
        })
    }

    /// r453 — the §7.8 `set_frame_refs()` adoption: derive the map
    /// the DECODER will compute from `rfi[ 0 ]` / `rfi[ 3 ]` over the
    /// true stored hints and, when every slot the ladder searches
    /// (each ordinal of `singles` / `pairs`, and the nearest-backward
    /// slot at `bwd_ordinal`) is still reachable on the derived map,
    /// commit it: `rfi` becomes the derivation and the ordinals are
    /// re-addressed (same ordinal when it still names the slot, else
    /// the first ordinal that does). Returns `false` — nothing
    /// touched — when a searched slot is unreachable.
    #[allow(clippy::too_many_arguments)]
    fn adopt_short_refs(
        rfi: &mut [u8; 7],
        singles: &mut Vec<i8>,
        pairs: &mut Vec<[i8; 2]>,
        bwd_ordinal: &mut u8,
        order_hint: u32,
        order_hint_bits: u8,
        slot_hints: &[u32; 8],
    ) -> bool {
        let derived = crate::frame_header::set_frame_refs(
            rfi[0],
            rfi[3],
            order_hint,
            order_hint_bits,
            true,
            slot_hints,
        );
        // Ordinal (1-based, `LAST_FRAME..=ALTREF_FRAME`) on the
        // derived map that names the slot the explicit ordinal `o`
        // holds.
        let remap = |o: i8| -> Option<i8> {
            let slot = rfi[(o - 1) as usize];
            if derived[(o - 1) as usize] == slot {
                Some(o)
            } else {
                derived.iter().position(|&d| d == slot).map(|i| i as i8 + 1)
            }
        };
        let mut new_singles = Vec::with_capacity(singles.len());
        for &o in singles.iter() {
            match remap(o) {
                Some(n) => new_singles.push(n),
                None => return false,
            }
        }
        let mut new_pairs = Vec::with_capacity(pairs.len());
        for &[a, b] in pairs.iter() {
            match (remap(a), remap(b)) {
                (Some(x), Some(y)) if x != y => new_pairs.push([x, y]),
                _ => return false,
            }
        }
        let Some(new_bwd) = remap(*bwd_ordinal as i8 + 1) else {
            return false;
        };
        *rfi = derived;
        *singles = new_singles;
        *pairs = new_pairs;
        *bwd_ordinal = (new_bwd - 1) as u8;
        true
    }

    /// The role's frame quantiser (per-layer offsets, clamped to the
    /// lossy range; inert at `base_q == 0`).
    fn role_q(&self, role: &Role) -> u8 {
        if self.base_q == 0 || !self.tuning.layer_q_offsets {
            return self.base_q;
        }
        (i32::from(self.base_q) + role.q_off).clamp(1, 255) as u8
    }

    /// Encode one mini-GOP of `l` frames starting at display `pos`
    /// (anchor at `pos - 1`).
    fn encode_chunk(&mut self, frames: &[YuvFrame], pos: usize, l: usize) -> Result<(), Error> {
        let donor_armed = Self::donor_armed(&self.tuning);
        let (steps, alt_slot) = plan_mini_gop(pos, l, self.anchor_slot);
        // §7.5 bitstream conformance: each temporal unit must carry
        // EXACTLY ONE shown frame — decoded-not-shown pyramid frames
        // accumulate here and ride the next shown frame's unit.
        let mut pending: Vec<ObuFrame> = Vec::new();
        // r439 — per slot, the index into `pending` of the refreshed
        // frame's header-carrying OBU while its temporal unit is
        // still open (the donor patch then rewrites the pending body
        // directly; a flush resolves the slot to `slot_wire`).
        let mut pending_slot_idx: [Option<usize>; 8] = [None; 8];
        for step in steps {
            match step {
                Step::Code(role) => {
                    // §5.9.2 `ref_frame_idx[]` from the role's slots.
                    let mut rfi = [role.last_slot as u8; 7];
                    if let Some(b) = role.bwd_slot {
                        rfi[4] = b as u8;
                        rfi[5] = b as u8;
                    }
                    if let Some(a2) = role.alt2_slot {
                        rfi[5] = a2 as u8;
                    }
                    if let Some(a) = role.alt_ref_slot.or(role.bwd_slot) {
                        rfi[6] = a as u8;
                    }
                    // r453 — §5.9.2 short signaling (see
                    // [`PyramidTuning::short_ref_signaling`]): adopt
                    // the §7.8 derivation whenever it still names
                    // every slot the ladder searches, re-addressing
                    // the ordinals onto the derived map.
                    let mut singles = role.singles.clone();
                    let mut pairs = role.pairs.clone();
                    // §5.9.2 primary-reference ordinal naming the
                    // nearest-backward slot (`ref_frame_idx[ 4 ]` =
                    // BWDREF on the explicit map).
                    let mut bwd_ordinal: u8 = 4;
                    let short_ref_signaling = self.tuning.short_ref_signaling
                        && self.seq.enable_order_hint
                        && Self::adopt_short_refs(
                            &mut rfi,
                            &mut singles,
                            &mut pairs,
                            &mut bwd_ordinal,
                            role.display as u32,
                            self.seq.order_hint_bits,
                            &self.slot_hints,
                        );
                    // Distinct reference reconstructions + the full
                    // 8-slot map onto them (each slot resolves to the
                    // display frame it truly holds).
                    let mut displays: Vec<usize> = Vec::new();
                    let mut slot_to_plane = [0usize; 8];
                    for (plane, &d) in slot_to_plane.iter_mut().zip(&self.slot_display) {
                        *plane = displays.iter().position(|&x| x == d).unwrap_or_else(|| {
                            displays.push(d);
                            displays.len() - 1
                        });
                    }
                    let refs: Vec<&GopFrameReconYuv> = displays
                        .iter()
                        .map(|&d| self.recons[d].as_ref().expect("slot holds a coded frame"))
                        .collect();
                    // r424 — §5.9.2 primary-reference candidates: the
                    // search runs under the LAST-slot carry (the
                    // frame's most-relevant coded predecessor in its
                    // own prediction chain); the nearest-backward
                    // anchor's carry and the per-frame defaults are
                    // exact-bytes replay alternatives.
                    let last_carry;
                    let bwd_carry;
                    let (primary_ref_frame, primary_carry, alt_primaries) =
                        if self.tuning.primary_ref {
                            last_carry = self.carry_store[role.last_slot].clone();
                            let mut alts: Vec<(u8, Option<&RefSlotCarry>)> =
                                vec![(PRIMARY_REF_NONE, None)];
                            match role.bwd_slot {
                                Some(b) if b != role.last_slot => {
                                    bwd_carry = self.carry_store[b].clone();
                                    alts.push((bwd_ordinal, Some(&*bwd_carry)));
                                }
                                _ => {}
                            }
                            (0u8, Some(&*last_carry), alts)
                        } else {
                            (PRIMARY_REF_NONE, None, Vec::new())
                        };
                    // r452 — the role's per-frame §5.9.30 seed rides
                    // the shared schedule at its own order_hint.
                    let role_fg: Option<FilmGrainParams> = self.film_grain.as_ref().map(|b| {
                        let mut f = b.clone();
                        f.grain_seed = grain_seed_for(role.display as u32);
                        f
                    });
                    let cfg = InterFrameConfig {
                        order_hint: role.display as u32,
                        show_frame: role.show,
                        refresh_frame_flags: role.refresh.map_or(0, |s| 1u8 << s),
                        ref_frame_idx: rfi,
                        short_ref_signaling,
                        slot_hints: self.slot_hints,
                        single_refs: singles,
                        compound_pairs: pairs,
                        refs,
                        slot_to_plane,
                        primary_ref_frame,
                        primary_carry,
                        allow_temporal_seg: false,
                        alt_primaries,
                        exact_mask: None,
                        auto_lossless: false,
                        seg_extras: None,
                        high_precision_mv: self.tuning.high_precision_mv,
                        delta_q: self.tuning.delta_q,
                        cdef: self.tuning.cdef,
                        cdef_units: self.tuning.cdef_units,
                        lr: self.tuning.lr,
                        freeze_cdfs: false,
                        tiles: self.tuning.tiles,
                        tile_groups: self.tuning.tile_groups,
                        // r439 — collect only on REFERENCE frames (a
                        // non-reference B leaf's donation is never
                        // consumed); elect whenever the primary carry
                        // offers candidates.
                        collect_donor_cdfs: donor_armed && role.refresh.is_some(),
                        elect_donor: donor_armed,
                        explicit_tiles: None,
                        qm: self.tuning.qm,
                        film_grain: role_fg.as_ref(),
                        s_frame: false,
                        error_resilient: false,
                        tile_spans: false,
                        superres: None,
                        superres_source: None,
                        ref_dims: Vec::new(),
                    };
                    let q = self.role_q(&role);
                    let (obus, rc, saved, carry, aux) = encode_inter_frame_generic(
                        &frames[role.display],
                        &self.seq,
                        q,
                        &cfg,
                        &[],
                        &self.mf_store,
                        self.tuning.model,
                    )?;
                    self.primary_elections
                        .push((role.display as u32, aux.primary_ref));
                    // r439 — §6.8.14 donor settlement. The slot whose
                    // carry this frame's committed bytes chain off is
                    // the ELECTED primary's (§5.9.2 ordinal 0 = the
                    // LAST slot, 4 = the BWDREF slot; PRIMARY_REF_NONE
                    // consumes nothing). THE MULTI-CONSUMER RULE: that
                    // slot's donor set freezes at this first
                    // consumption whether or not the election won — a
                    // later consumer re-electing would silently
                    // re-start this frame's already-committed §8.3.1
                    // chain. On a win (only possible when the MAIN
                    // primary survived) the donor frame's
                    // already-emitted `context_update_tile_id` is
                    // patched in place — inside the current chunk's
                    // still-open temporal unit or an already-flushed
                    // one — and every §7.20 slot holding the same
                    // frame's carry is swept by pointer identity.
                    // (r453: the ordinal resolves through the CODED
                    // map — explicit or §7.8-derived alike.)
                    let consumed_slot: Option<usize> = if self.tuning.primary_ref {
                        match aux.primary_ref {
                            PRIMARY_REF_NONE => None,
                            o => Some(rfi[o as usize] as usize),
                        }
                    } else {
                        None
                    };
                    if let Some(slot) = consumed_slot {
                        if self.carry_store[slot].donor_cdfs.len() > 1 {
                            let consumed = self.carry_store[slot].clone();
                            let fixed_cdfs = match aux.donor_elected {
                                Some(t) => {
                                    let span = consumed
                                        .ctx_update_span
                                        .expect("donor election only fires on multi-tile frames");
                                    match pending_slot_idx[slot] {
                                        Some(idx) => {
                                            // Pending `OBU_FRAME` /
                                            // `OBU_FRAME_HEADER` bodies
                                            // start with the header bits.
                                            crate::encoder::inter_frame::patch_bits_at(
                                                &mut pending[idx].body,
                                                0,
                                                span,
                                                t,
                                            );
                                        }
                                        None => {
                                            let (tu, ord) = self.slot_wire[slot]
                                                .expect("flushed frame located on the wire");
                                            crate::encoder::inter_frame::patch_ctx_update_in_tu_frame(
                                                &mut self.temporal_units[tu],
                                                ord,
                                                span,
                                                t,
                                            );
                                        }
                                    }
                                    consumed.donor_cdfs[t as usize].clone()
                                }
                                None => consumed.cdfs.clone(),
                            };
                            let fixed = Rc::new(RefSlotCarry {
                                cdfs: fixed_cdfs,
                                segment_ids: consumed.segment_ids.clone(),
                                mi_rows: consumed.mi_rows,
                                mi_cols: consumed.mi_cols,
                                gm_params: consumed.gm_params,
                                donor_cdfs: Vec::new(),
                                ctx_update_span: None,
                            });
                            for s in self.carry_store.iter_mut() {
                                if Rc::ptr_eq(s, &consumed) {
                                    *s = fixed.clone();
                                }
                            }
                        }
                    }
                    if donor_armed {
                        self.ctx_donor_elections
                            .push((role.display as u32, aux.donor_elected));
                    }
                    // r439 — locate this frame's header OBU inside the
                    // open unit before extending the pending list.
                    let header_idx = pending.len()
                        + obus
                            .iter()
                            .position(|o| {
                                matches!(o.header.obu_type, ObuType::Frame | ObuType::FrameHeader)
                            })
                            .expect("coded frame carries a header OBU");
                    pending.extend(obus);
                    self.recons[role.display] = Some(rc);
                    // §7.20 reference frame update (the wire location
                    // records BEFORE the flush so the flush resolves
                    // it to `slot_wire`).
                    if let Some(s) = role.refresh {
                        self.mf_store[s] = saved;
                        self.carry_store[s] = Rc::new(carry);
                        self.slot_hints[s] = role.display as u32;
                        self.slot_display[s] = role.display;
                        pending_slot_idx[s] = Some(header_idx);
                        self.slot_wire[s] = None;
                    }
                    if role.show {
                        self.flush_pending(&mut pending, &mut pending_slot_idx);
                    }
                }
                Step::Show(slot) => {
                    pending.push(show_existing_obu(&self.seq, slot as u8));
                    self.flush_pending(&mut pending, &mut pending_slot_idx);
                }
            }
        }
        debug_assert!(pending.is_empty(), "every mini-GOP plan ends shown");
        self.anchor_slot = alt_slot;
        self.chunk_lengths.push(l);
        Ok(())
    }

    /// r439 — close the current §7.5 temporal unit: resolve every
    /// slot whose refreshed frame rides this unit to its final wire
    /// location `(temporal-unit index, frame ordinal within the
    /// unit)`, then serialize and clear the pending list. The frame
    /// ordinal counts header-carrying OBUs (`OBU_FRAME` /
    /// `OBU_FRAME_HEADER`) in emission order — `build_temporal_unit`
    /// only prepends a temporal delimiter, which the patch walk
    /// skips.
    fn flush_pending(
        &mut self,
        pending: &mut Vec<ObuFrame>,
        pending_slot_idx: &mut [Option<usize>; 8],
    ) {
        let tu_idx = self.temporal_units.len();
        for (s, slot) in pending_slot_idx.iter_mut().enumerate() {
            if let Some(idx) = slot.take() {
                let ord = pending[..idx]
                    .iter()
                    .filter(|o| matches!(o.header.obu_type, ObuType::Frame | ObuType::FrameHeader))
                    .count();
                self.slot_wire[s] = Some((tu_idx, ord));
            }
        }
        self.temporal_units.push(build_temporal_unit(None, pending));
        pending.clear();
    }

    /// Sum of coded bytes across all emitted temporal units.
    fn total_bytes(&self) -> usize {
        self.temporal_units.iter().map(Vec::len).sum()
    }

    /// Squared-error distortion of the committed reconstructions over
    /// display positions `range` (all three planes).
    fn distortion_over(&self, frames: &[YuvFrame], range: core::ops::Range<usize>) -> u64 {
        let mut d = 0u64;
        for pos in range {
            let rc = self.recons[pos].as_ref().expect("range coded");
            let f = &frames[pos];
            for (a, b) in
                rc.y.iter()
                    .zip(&f.y)
                    .chain(rc.u.iter().zip(&f.u))
                    .chain(rc.v.iter().zip(&f.v))
            {
                let diff = i64::from(*a) - i64::from(*b);
                d += (diff * diff) as u64;
            }
        }
        d
    }

    /// IVF v0 wrap + [`EncodedGop`] assembly. Each temporal unit shows
    /// exactly one frame and the units are emitted in display order,
    /// so the record index IS the display PTS.
    fn finish(self, width: u32, height: u32) -> Result<TunedPyramidGopYuv, Error> {
        let mut ivf_bytes: Vec<u8> = Vec::new();
        {
            let cursor = std::io::Cursor::new(&mut ivf_bytes);
            let mut iw = IvfWriter::new(cursor, FOURCC_AV01, width as u16, height as u16, 25, 1)
                .map_err(|_| Error::PartitionWalkOutOfRange)?;
            for (idx, tu) in self.temporal_units.iter().enumerate() {
                iw.write_frame(tu, idx as u64)
                    .map_err(|_| Error::PartitionWalkOutOfRange)?;
            }
            iw.patch_frame_count()
                .map_err(|_| Error::PartitionWalkOutOfRange)?;
        }
        Ok(TunedPyramidGopYuv {
            film_grain_elected: false,
            gop: EncodedGopYuv {
                ivf_bytes,
                temporal_units: self.temporal_units,
                recon: self
                    .recons
                    .into_iter()
                    .map(|r| r.expect("every display position coded"))
                    .collect(),
                seq: self.seq,
            },
            chunk_lengths: self.chunk_lengths,
            primary_elections: self.primary_elections,
            ctx_donor_elections: self.ctx_donor_elections,
        })
    }
}

/// Shared input validation for the GOP drivers.
pub(crate) fn validate_gop_input(frames: &[YuvFrame]) -> Result<(u32, u32), Error> {
    if frames.is_empty() || frames.len() > GOP_MAX_FRAMES {
        return Err(Error::PartitionWalkOutOfRange);
    }
    let (width, height) = (frames[0].width, frames[0].height);
    let (bit_depth, format) = (frames[0].bit_depth, frames[0].format);
    if frames.iter().any(|f| {
        f.width != width || f.height != height || f.bit_depth != bit_depth || f.format != format
    }) {
        return Err(Error::PartitionWalkOutOfRange);
    }
    Ok((width, height))
}

/// Lossless (`base_q_idx = 0`) B-pyramid GOP encode — see
/// [`encode_pyramid_gop_yuv420_with_q`].
pub fn encode_pyramid_gop_yuv420(frames: &[Yuv420Frame]) -> Result<EncodedGop, Error> {
    encode_pyramid_gop_yuv420_with_q(frames, 0)
}

/// Encode a KEY + B-pyramid GOP of 8-bit 4:2:0 frames at `base_q_idx`
/// into a spec-conformant IVF stream (see the module docs for the
/// exact structure).
///
/// The returned [`EncodedGop`]'s `temporal_units` hold one §7.5 unit
/// per DISPLAY frame: each unit carries exactly one shown frame (the
/// bitstream-conformance rule), so decoded-not-shown ALT / MID frames
/// ride the unit of the next shown frame and `show_existing_frame`
/// headers form their own units. `recon` is in DISPLAY order, one
/// entry per input frame — the decoded output equals it byte-for-byte
/// (and the inputs too at `base_q_idx == 0`).
///
/// ## Errors
///
/// * Empty input, more than [`GOP_MAX_FRAMES`] frames, mismatched
///   dimensions across frames, or dimensions outside the KEY-frame
///   rules — [`Error::PartitionWalkOutOfRange`].
pub fn encode_pyramid_gop_yuv420_with_q(
    frames: &[Yuv420Frame],
    base_q_idx: u8,
) -> Result<EncodedGop, Error> {
    encode_pyramid_gop_yuv420_with_q_tuned(frames, base_q_idx, PyramidTuning::default())
        .map(|t| t.gop)
}

/// r421 — [`encode_pyramid_gop_yuv420_with_q`] with an explicit
/// [`RateModel`], kept public (hidden) so the sweep harnesses can A/B
/// the twin-priced elections against the pre-r421 heuristic baseline.
#[doc(hidden)]
pub fn encode_pyramid_gop_yuv420_with_q_rate_model(
    frames: &[Yuv420Frame],
    base_q_idx: u8,
    model: RateModel,
) -> Result<EncodedGop, Error> {
    encode_pyramid_gop_yuv420_with_q_tuned(
        frames,
        base_q_idx,
        PyramidTuning {
            model,
            ..PyramidTuning::default()
        },
    )
    .map(|t| t.gop)
}

/// r424 — [`encode_pyramid_gop_yuv420_with_q`] with explicit
/// [`PyramidTuning`] switches (the measurement-harness entry point):
/// fixed maximal chunking at `tuning.max_mini_gop`.
#[doc(hidden)]
pub fn encode_pyramid_gop_yuv420_with_q_tuned(
    frames: &[Yuv420Frame],
    base_q_idx: u8,
    tuning: PyramidTuning,
) -> Result<TunedPyramidGop, Error> {
    let wide: Vec<YuvFrame> = frames.iter().map(YuvFrame::from_yuv420_8bit).collect();
    let t = encode_pyramid_gop_yuv_with_q_tuned(&wide, base_q_idx, tuning)?;
    Ok(TunedPyramidGop {
        film_grain_elected: t.film_grain_elected,
        gop: narrow_gop_8bit(t.gop),
        chunk_lengths: t.chunk_lengths,
        primary_elections: t.primary_elections,
        ctx_donor_elections: t.ctx_donor_elections,
    })
}

/// r427 — encode a KEY + B-pyramid GOP at any conformant (bit depth,
/// chroma format) pairing: the general-format sibling of
/// [`encode_pyramid_gop_yuv420_with_q`].
pub fn encode_pyramid_gop_yuv_with_q(
    frames: &[YuvFrame],
    base_q_idx: u8,
) -> Result<EncodedGopYuv, Error> {
    encode_pyramid_gop_yuv_with_q_tuned(frames, base_q_idx, PyramidTuning::default()).map(|t| t.gop)
}

/// r427 — the general-format pyramid core (fixed maximal chunking at
/// `tuning.max_mini_gop`).
#[doc(hidden)]
pub fn encode_pyramid_gop_yuv_with_q_tuned(
    frames: &[YuvFrame],
    base_q_idx: u8,
    tuning: PyramidTuning,
) -> Result<TunedPyramidGopYuv, Error> {
    let plain = encode_pyramid_core(frames, base_q_idx, tuning, None)?;
    film_grain_settle(frames, base_q_idx, tuning, plain, |denoised, fg| {
        encode_pyramid_core(denoised, base_q_idx, tuning, Some(fg))
    })
}

/// r452 — the §5.9.30 film-grain settlement shared by the pyramid
/// and adaptive drivers: gates (the tuning switch, a lossy
/// twin-model encode of at least two frames), then the
/// driver-agnostic [`elect_film_grain`] ladder over `encode_arm`
/// (the same driver re-run on the DENOISED frames with an armed
/// parameter set). A win publishes the §7.18.3-synthesized planes
/// as the reconstruction and flags `film_grain_elected`.
fn film_grain_settle<F>(
    frames: &[YuvFrame],
    base_q_idx: u8,
    tuning: PyramidTuning,
    plain: TunedPyramidGopYuv,
    encode_arm: F,
) -> Result<TunedPyramidGopYuv, Error>
where
    F: FnMut(&[YuvFrame], &FilmGrainParams) -> Result<TunedPyramidGopYuv, Error>,
{
    if !(tuning.film_grain
        && base_q_idx > 0
        && tuning.model == RateModel::Twin
        && frames.len() >= 2)
    {
        return Ok(plain);
    }
    let elected = elect_film_grain(
        frames,
        base_q_idx,
        plain.gop.seq.color_config.matrix_coefficients,
        plain.gop.ivf_bytes.len(),
        &plain.gop.recon,
        encode_arm,
        |c: &TunedPyramidGopYuv| (c.gop.ivf_bytes.len(), c.gop.recon.as_slice()),
    )?;
    match elected {
        Some((cand, grained)) => {
            let mut out = cand;
            out.gop.recon = grained;
            out.film_grain_elected = true;
            Ok(out)
        }
        None => Ok(plain),
    }
}

/// One complete pyramid encode (KEY + every mini-GOP) with an optional
/// armed §5.9.30 parameter set riding every coded header;
/// reconstructions stay PRE-grain.
fn encode_pyramid_core(
    frames: &[YuvFrame],
    base_q_idx: u8,
    tuning: PyramidTuning,
    film_grain: Option<&FilmGrainParams>,
) -> Result<TunedPyramidGopYuv, Error> {
    let (width, height) = validate_gop_input(frames)?;
    if tuning.max_mini_gop == 0 || tuning.max_mini_gop > 32 {
        return Err(Error::PartitionWalkOutOfRange);
    }
    let n = frames.len();
    let mut session = PyramidSession::new(frames, base_q_idx, tuning, film_grain)?;
    let mut pos = 1usize;
    while pos < n {
        let l = (n - pos).min(tuning.max_mini_gop);
        session.encode_chunk(frames, pos, l)?;
        pos += l;
    }
    session.finish(width, height)
}

// ---------------------------------------------------------------------
// r424 — content-adaptive mini-GOP sizing.
// ---------------------------------------------------------------------

/// r424 — the adaptive driver's tuning switches (hidden — the
/// measurement harnesses A/B the election against fixed chunking).
#[doc(hidden)]
#[derive(Debug, Clone, Copy)]
pub struct AdaptiveTuning {
    pub pyramid: PyramidTuning,
    /// Trial-encode boundary election between the class-picked
    /// mini-GOP shape and its half-depth split (twin-consistent
    /// `D + λ·R` scoring over the identical frame span). `false`
    /// commits the class pick directly.
    pub elect: bool,
}

impl Default for AdaptiveTuning {
    fn default() -> Self {
        AdaptiveTuning {
            pyramid: PyramidTuning::default(),
            elect: true,
        }
    }
}

/// r427 (hidden) — general-format sibling of [`TunedAdaptiveGop`].
#[doc(hidden)]
#[derive(Debug, Clone)]
pub struct TunedAdaptiveGopYuv {
    /// r452 — the §5.9.30 film-grain arm won (see
    /// [`PyramidTuning::film_grain`]).
    pub film_grain_elected: bool,
    pub gop: EncodedGopYuv,
    pub chunk_lengths: Vec<usize>,
    pub mc_mads: Vec<f64>,
    pub cuts: Vec<bool>,
    pub elections: Vec<(usize, usize, usize, usize)>,
    pub primary_elections: Vec<(u32, u8)>,
    /// r439 — see [`TunedPyramidGop::ctx_donor_elections`].
    pub ctx_donor_elections: Vec<(u32, Option<u32>)>,
}

/// r424 (hidden) — [`EncodedGop`] plus the adaptive election traces.
#[doc(hidden)]
#[derive(Debug, Clone)]
pub struct TunedAdaptiveGop {
    /// r452 — the §5.9.30 film-grain arm won (see
    /// [`PyramidTuning::film_grain`]).
    pub film_grain_elected: bool,
    pub gop: EncodedGop,
    /// Committed mini-GOP lengths, in order.
    pub chunk_lengths: Vec<usize>,
    /// Per-transition motion-compensated mean-absolute-difference
    /// (`mc_mad[k]` = frames `k → k+1`, `k` in `0..n-1`).
    pub mc_mads: Vec<f64>,
    /// Scene-cut flags per transition (same indexing).
    pub cuts: Vec<bool>,
    /// Boundary elections: `(pos, deep_len, split_len, chosen_len)`.
    pub elections: Vec<(usize, usize, usize, usize)>,
    /// Per coded inter frame in coding order: `(order_hint, elected
    /// §5.9.2 primary_ref_frame ordinal)` — see
    /// [`TunedPyramidGop::primary_elections`].
    pub primary_elections: Vec<(u32, u8)>,
    /// r439 — see [`TunedPyramidGop::ctx_donor_elections`].
    pub ctx_donor_elections: Vec<(u32, Option<u32>)>,
}

/// Half-resolution luma (2×2 box filter) for the motion probe.
fn half_res_luma(f: &YuvFrame) -> (Vec<u16>, usize, usize) {
    let (w, h) = (f.width as usize, f.height as usize);
    let (hw, hh) = (w / 2, h / 2);
    let mut out = vec![0u16; hw * hh];
    for i in 0..hh {
        for j in 0..hw {
            let s = u32::from(f.y[(2 * i) * w + 2 * j])
                + u32::from(f.y[(2 * i) * w + 2 * j + 1])
                + u32::from(f.y[(2 * i + 1) * w + 2 * j])
                + u32::from(f.y[(2 * i + 1) * w + 2 * j + 1]);
            out[i * hw + j] = ((s + 2) / 4) as u16;
        }
    }
    (out, hw, hh)
}

/// Motion-compensated MAD probe: the minimum mean absolute luma
/// difference between `prev` and `cur` over global integer shifts of
/// up to ±3 half-resolution samples (±6 full-resolution) per axis —
/// a cheap predictability measure that stays small under pure
/// translation and large across scene cuts / noise.
fn mc_mad(prev: &[u16], cur: &[u16], w: usize, h: usize) -> f64 {
    let mut best = f64::INFINITY;
    for dy in -3i32..=3 {
        for dx in -3i32..=3 {
            let y0 = dy.max(0) as usize;
            let y1 = (h as i32 + dy.min(0)) as usize;
            let x0 = dx.max(0) as usize;
            let x1 = (w as i32 + dx.min(0)) as usize;
            if y1 <= y0 || x1 <= x0 {
                continue;
            }
            let mut sum = 0u64;
            for i in y0..y1 {
                let pi = (i as i32 - dy) as usize;
                for j in x0..x1 {
                    let pj = (j as i32 - dx) as usize;
                    sum += u64::from(cur[i * w + j].abs_diff(prev[pi * w + pj]));
                }
            }
            let mad = sum as f64 / ((y1 - y0) * (x1 - x0)) as f64;
            if mad < best {
                best = mad;
            }
        }
    }
    best
}

/// Scene-cut threshold on the motion-compensated MAD probe.
const CUT_MC_MAD: f64 = 20.0;

/// Motion-class mini-GOP target from the window's mean probe value.
fn class_len(mean_mc_mad: f64, cap: usize) -> usize {
    let target = if mean_mc_mad < 1.5 {
        16
    } else if mean_mc_mad < 6.0 {
        8
    } else if mean_mc_mad < 12.0 {
        4
    } else if mean_mc_mad < CUT_MC_MAD {
        2
    } else {
        1
    };
    target.min(cap).max(1)
}

/// Encode a KEY + adaptive mini-GOP stream: content-driven mini-GOP
/// sizing (scene-cut / motion-probe classes choosing between pyramid
/// depths and flat P-runs, with a twin-consistent `D + λ·R`
/// trial-encode election at the class boundary — see the module
/// docs). Same output contract as
/// [`encode_pyramid_gop_yuv420_with_q`].
pub fn encode_adaptive_gop_yuv420_with_q(
    frames: &[Yuv420Frame],
    base_q_idx: u8,
) -> Result<EncodedGop, Error> {
    encode_adaptive_gop_yuv420_with_q_tuned(frames, base_q_idx, AdaptiveTuning::default())
        .map(|t| t.gop)
}

/// r424 — [`encode_adaptive_gop_yuv420_with_q`] with explicit
/// [`AdaptiveTuning`] (the measurement-harness entry point).
#[doc(hidden)]
pub fn encode_adaptive_gop_yuv420_with_q_tuned(
    frames: &[Yuv420Frame],
    base_q_idx: u8,
    tuning: AdaptiveTuning,
) -> Result<TunedAdaptiveGop, Error> {
    let wide: Vec<YuvFrame> = frames.iter().map(YuvFrame::from_yuv420_8bit).collect();
    let t = encode_adaptive_gop_yuv_with_q_tuned(&wide, base_q_idx, tuning)?;
    Ok(TunedAdaptiveGop {
        film_grain_elected: t.film_grain_elected,
        gop: narrow_gop_8bit(t.gop),
        chunk_lengths: t.chunk_lengths,
        mc_mads: t.mc_mads,
        cuts: t.cuts,
        elections: t.elections,
        primary_elections: t.primary_elections,
        ctx_donor_elections: t.ctx_donor_elections,
    })
}

/// r427 — encode a KEY + adaptive mini-GOP stream at any conformant
/// (bit depth, chroma format) pairing: the general-format sibling of
/// [`encode_adaptive_gop_yuv420_with_q`].
pub fn encode_adaptive_gop_yuv_with_q(
    frames: &[YuvFrame],
    base_q_idx: u8,
) -> Result<EncodedGopYuv, Error> {
    encode_adaptive_gop_yuv_with_q_tuned(frames, base_q_idx, AdaptiveTuning::default())
        .map(|t| t.gop)
}

/// r427 — the general-format adaptive core. The motion-probe MAD is
/// normalized to 8-bit units (`>> (BitDepth - 8)`) so the class
/// thresholds hold at every depth.
#[doc(hidden)]
pub fn encode_adaptive_gop_yuv_with_q_tuned(
    frames: &[YuvFrame],
    base_q_idx: u8,
    tuning: AdaptiveTuning,
) -> Result<TunedAdaptiveGopYuv, Error> {
    let plain = encode_adaptive_core(frames, base_q_idx, tuning, None)?;
    // r452 — the §5.9.30 election over the adaptive driver: the arm
    // re-runs the whole cut / mini-GOP election over the DENOISED
    // frames (its motion probe sees the denoised content, exactly
    // what the grain arm codes).
    let plain_pyr = TunedPyramidGopYuv {
        film_grain_elected: false,
        gop: plain.gop,
        chunk_lengths: plain.chunk_lengths,
        primary_elections: plain.primary_elections,
        ctx_donor_elections: plain.ctx_donor_elections,
    };
    let (mc_mads, cuts, elections) = (plain.mc_mads, plain.cuts, plain.elections);
    let mut arm_trace: Option<AdaptiveTrace> = None;
    let settled = film_grain_settle(frames, base_q_idx, tuning.pyramid, plain_pyr, |den, fg| {
        let t = encode_adaptive_core(den, base_q_idx, tuning, Some(fg))?;
        arm_trace = Some((t.mc_mads, t.cuts, t.elections));
        Ok(TunedPyramidGopYuv {
            film_grain_elected: false,
            gop: t.gop,
            chunk_lengths: t.chunk_lengths,
            primary_elections: t.primary_elections,
            ctx_donor_elections: t.ctx_donor_elections,
        })
    })?;
    let (mc_mads, cuts, elections) = if settled.film_grain_elected {
        arm_trace.expect("an elected arm ran the adaptive driver")
    } else {
        (mc_mads, cuts, elections)
    };
    Ok(TunedAdaptiveGopYuv {
        film_grain_elected: settled.film_grain_elected,
        gop: settled.gop,
        chunk_lengths: settled.chunk_lengths,
        mc_mads,
        cuts,
        elections,
        primary_elections: settled.primary_elections,
        ctx_donor_elections: settled.ctx_donor_elections,
    })
}

/// The adaptive driver's per-run election trace: `(mc_mads, cuts,
/// elections)` (see [`TunedAdaptiveGopYuv`]).
type AdaptiveTrace = (Vec<f64>, Vec<bool>, Vec<(usize, usize, usize, usize)>);

/// One complete adaptive encode with an optional armed §5.9.30
/// parameter set (see [`encode_pyramid_core`]).
fn encode_adaptive_core(
    frames: &[YuvFrame],
    base_q_idx: u8,
    tuning: AdaptiveTuning,
    film_grain: Option<&FilmGrainParams>,
) -> Result<TunedAdaptiveGopYuv, Error> {
    let (width, height) = validate_gop_input(frames)?;
    if tuning.pyramid.max_mini_gop == 0 || tuning.pyramid.max_mini_gop > 32 {
        return Err(Error::PartitionWalkOutOfRange);
    }
    let n = frames.len();

    // Per-transition motion probe (`mc_mads[k]`: frame k -> k+1).
    let halves: Vec<(Vec<u16>, usize, usize)> = frames.iter().map(half_res_luma).collect();
    let depth_scale = f64::from(1u32 << (frames[0].bit_depth - 8));
    let mc_mads: Vec<f64> = (0..n.saturating_sub(1))
        .map(|k| {
            let (p, w, h) = &halves[k];
            let (c, _, _) = &halves[k + 1];
            mc_mad(p, c, *w, *h) / depth_scale
        })
        .collect();
    let cuts: Vec<bool> = mc_mads.iter().map(|&m| m > CUT_MC_MAD).collect();

    let lambda = lambda_for(&QuantizerParams::neutral(base_q_idx, frames[0].bit_depth));
    let mut session = PyramidSession::new(frames, base_q_idx, tuning.pyramid, film_grain)?;
    let mut elections: Vec<(usize, usize, usize, usize)> = Vec::new();

    let mut pos = 1usize;
    while pos < n {
        let remaining = n - pos;
        // Cut-free window: the chunk `pos..pos+l-1` must not contain a
        // cut transition strictly inside its prediction span
        // (`pos..pos+l-1`); a cut right at the anchor (`cuts[pos-1]`)
        // forces a flat P step that absorbs the discontinuity.
        let mut w = 1usize;
        if !cuts[pos - 1] {
            while w < remaining.min(tuning.pyramid.max_mini_gop) && !cuts[pos + w - 1] {
                w += 1;
            }
        }
        let l_main = if cuts[pos - 1] {
            1
        } else {
            let mean = mc_mads[pos - 1..pos + w - 1].iter().sum::<f64>() / w as f64;
            class_len(mean, w)
        };
        let l_alt = l_main / 2;
        if !tuning.elect || l_alt == 0 || l_alt == l_main {
            session.encode_chunk(frames, pos, l_main)?;
            pos += l_main;
            continue;
        }
        // Twin-consistent boundary election over the IDENTICAL frame
        // span `pos..pos+l_main`: one deep chunk vs. half-depth
        // splits. `D + λ·R` in `score256` units (exact realized bytes
        // — 8·256 rate units per byte); at `base_q_idx == 0` both
        // reconstructions are the input, so the comparison reduces to
        // pure rate.
        let base_bytes = session.total_bytes();
        let mut deep = session.clone();
        deep.encode_chunk(frames, pos, l_main)?;
        let mut split = session.clone();
        let mut covered = 0usize;
        while covered < l_main {
            let step = l_alt.min(l_main - covered);
            split.encode_chunk(frames, pos + covered, step)?;
            covered += step;
        }
        let deep_j = deep.distortion_over(frames, pos..pos + l_main) * 256
            + lambda * ((deep.total_bytes() - base_bytes) as u64 * 8 * 256);
        let split_j = split.distortion_over(frames, pos..pos + l_main) * 256
            + lambda * ((split.total_bytes() - base_bytes) as u64 * 8 * 256);
        let chosen = if deep_j <= split_j { l_main } else { l_alt };
        elections.push((pos, l_main, l_alt, chosen));
        session = if deep_j <= split_j { deep } else { split };
        pos += l_main;
    }

    let tuned = session.finish(width, height)?;
    Ok(TunedAdaptiveGopYuv {
        film_grain_elected: false,
        gop: tuned.gop,
        chunk_lengths: tuned.chunk_lengths,
        mc_mads,
        cuts,
        elections,
        primary_elections: tuned.primary_elections,
        ctx_donor_elections: tuned.ctx_donor_elections,
    })
}

/// §5.9.2 short-form `show_existing_frame` OBU: an
/// `OBU_FRAME_HEADER` whose body is `show_existing_frame = 1` +
/// `frame_to_show_map_idx` (+ §5.3.4 trailing bits).
fn show_existing_obu(seq: &SequenceHeader, map_idx: u8) -> ObuFrame {
    let fh = FrameHeader {
        show_existing_frame: true,
        frame_to_show_map_idx: Some(map_idx),
        display_frame_id: None,
        frame_type: FrameType::Inter,
        frame_is_intra: false,
        show_frame: true,
        showable_frame: false,
        error_resilient_mode: false,
        disable_cdf_update: false,
        allow_screen_content_tools: false,
        force_integer_mv: false,
        current_frame_id: 0,
        frame_size_override_flag: false,
        order_hint: 0,
        primary_ref_frame: PRIMARY_REF_NONE,
        refresh_frame_flags: 0,
        ref_order_hints: None,
        frame_size: None,
        allow_intrabc: false,
        disable_frame_end_update_cdf: false,
        tile_info: None,
        quantization_params: None,
        segmentation_params: None,
        delta_q_params: None,
        delta_lf_params: None,
        loop_filter_params: None,
        cdef_params: None,
        lr_params: None,
        tx_mode: None,
        reference_select: None,
        skip_mode_present: None,
        skip_mode_frame: None,
        allow_warped_motion: None,
        reduced_tx_set: None,
        global_motion_params: None,
        film_grain_params: None,
        inter_refs: None,
        bits_consumed: 0,
    };
    let body = write_frame_header_obu(&fh, seq);
    ObuFrame::new(ObuType::FrameHeader, body)
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::encoder::yuv_frame::ChromaFormat;

    /// 8-bit view of a `u16` recon plane for byte-comparisons against
    /// the spec driver's 8-bit output surface.
    fn plane8(p: &[u16]) -> Vec<u8> {
        p.iter().map(|&s| s as u8).collect()
    }

    /// Deterministic textured frame with translation `(sy, sx)` — the
    /// shared GOP-test generator.
    fn moving_gradient(w: u32, h: u32, shift_y: usize, shift_x: usize, seed: u32) -> YuvFrame {
        let (wu, hu) = (w as usize, h as usize);
        let s = seed as usize;
        let mut f = YuvFrame::filled(w, h, 8, ChromaFormat::Yuv420, 0);
        for i in 0..hu {
            for j in 0..wu {
                let (si, sj) = (i + shift_y, j + shift_x);
                f.y[i * wu + j] = ((si * 5 + sj * 3 + (si / 16) * (sj / 16) + s) % 256) as u16;
            }
        }
        let (cw, ch) = (wu / 2, hu / 2);
        for i in 0..ch {
            for j in 0..cw {
                let (si, sj) = (i + shift_y / 2, j + shift_x / 2);
                f.u[i * cw + j] = ((128 + si * 2 + sj + s) % 256) as u16;
                f.v[i * cw + j] = ((64 + si + sj * 2 + s) % 256) as u16;
            }
        }
        f
    }

    fn assert_pyramid_round_trip(frames: &[YuvFrame], q: u8) -> EncodedGopYuv {
        let (w, h) = (frames[0].width, frames[0].height);
        let enc = encode_pyramid_gop_yuv_with_q(frames, q)
            .unwrap_or_else(|e| panic!("{w}x{h} q={q}: pyramid encode failed: {e:?}"));
        assert_eq!(enc.recon.len(), frames.len());
        let decoded = crate::decoder::decode_av1_spec(&enc.ivf_bytes)
            .unwrap_or_else(|e| panic!("{w}x{h} q={q}: spec driver rejected pyramid GOP: {e:?}"));
        assert_eq!(
            decoded.len(),
            frames.len(),
            "{w}x{h} q={q}: one shown frame per input (display order)"
        );
        for (idx, f) in decoded.iter().enumerate() {
            assert_eq!((f.width, f.height), (w, h));
            let rc = &enc.recon[idx];
            assert_eq!(
                f.planes[0],
                plane8(&rc.y),
                "{w}x{h} q={q} display {idx}: luma"
            );
            assert_eq!(f.planes[1], plane8(&rc.u), "{w}x{h} q={q} display {idx}: U");
            assert_eq!(f.planes[2], plane8(&rc.v), "{w}x{h} q={q} display {idx}: V");
            if q == 0 {
                assert_eq!(
                    f.planes[0],
                    plane8(&frames[idx].y),
                    "lossless {idx}: luma != input"
                );
                assert_eq!(
                    f.planes[1],
                    plane8(&frames[idx].u),
                    "lossless {idx}: U != input"
                );
                assert_eq!(
                    f.planes[2],
                    plane8(&frames[idx].v),
                    "lossless {idx}: V != input"
                );
            }
        }
        enc
    }

    /// One full L=4 mini-GOP (5 frames): ALT + MID + two shown Bs +
    /// two show_existing units, lossy.
    #[test]
    fn r415_pyramid_len5_lossy_round_trips() {
        let frames: Vec<YuvFrame> = (0..5)
            .map(|k| moving_gradient(64, 64, 2 * k, 3 * k, 11))
            .collect();
        let enc = assert_pyramid_round_trip(&frames, 60);
        // One temporal unit per DISPLAY frame (each unit carries
        // exactly one shown frame; ALT/MID ride their B's unit).
        assert_eq!(enc.temporal_units.len(), 5);
    }

    /// Lossless single-level pyramid (L=2 tail): 3 frames = KEY +
    /// ALT + B + SEF.
    #[test]
    fn r415_pyramid_len3_lossless_round_trips() {
        let frames: Vec<YuvFrame> = (0..3)
            .map(|k| moving_gradient(64, 64, 3 * k, 5 * k, 9))
            .collect();
        let enc = assert_pyramid_round_trip(&frames, 0);
        // 1 KEY unit + (L=2: [ALT + B] + [SEF]) = 3 units, one per
        // display frame.
        assert_eq!(enc.temporal_units.len(), 3);
    }

    /// r424: one full three-level mini-GOP (9 frames = KEY + L=8):
    /// ALT + MID1 + two MID2s + four shown B leaves, distinct
    /// BWDREF / ALTREF2 / ALTREF backward roles on the deepest
    /// leaves, per-layer q offsets and the primary-reference
    /// election live.
    #[test]
    fn r424_pyramid_len9_three_levels_round_trips() {
        let frames: Vec<YuvFrame> = (0..9)
            .map(|k| moving_gradient(64, 64, 2 * k, 3 * k, 23))
            .collect();
        let enc = assert_pyramid_round_trip(&frames, 60);
        assert_eq!(enc.temporal_units.len(), 9);
    }

    /// r424: the recursive planner reproduces the r415 two-level
    /// shapes at `max_mini_gop = 4` and codes every display position
    /// exactly once at every depth cap.
    #[test]
    fn r424_planner_covers_every_position_once() {
        for max in [1usize, 2, 3, 4, 8, 16] {
            for n in 1..=17usize {
                let mut covered = vec![false; n + 1];
                let mut pos = 1usize;
                let mut anchor = 0usize;
                while pos <= n {
                    let l = (n + 1 - pos).min(max);
                    let (steps, alt) = plan_mini_gop(pos, l, anchor);
                    let mut shows = 0usize;
                    for s in &steps {
                        match s {
                            Step::Code(role) => {
                                assert!(
                                    !covered[role.display],
                                    "max={max} n={n}: display {} coded twice",
                                    role.display
                                );
                                covered[role.display] = true;
                                if let Some(r) = role.refresh {
                                    assert_ne!(r, anchor, "must not clobber the live anchor");
                                }
                                if role.show {
                                    shows += 1;
                                }
                            }
                            Step::Show(_) => shows += 1,
                        }
                    }
                    assert_eq!(shows, l, "max={max} n={n}: one display per chunk frame");
                    pos += l;
                    anchor = alt;
                }
                assert!(
                    covered[1..=n].iter().all(|&c| c),
                    "max={max} n={n}: every position coded"
                );
            }
        }
    }

    /// r424: adaptive driver on scene-cut content — the cut is
    /// detected, no mini-GOP spans it, and the stream round-trips.
    #[test]
    fn r424_adaptive_scene_cut_round_trips() {
        let n = 9usize;
        let frames: Vec<YuvFrame> = (0..n)
            .map(|k| {
                if k >= n / 2 {
                    // Different texture family after the cut.
                    moving_gradient(64, 64, 40 + 2 * k, 70 + 3 * k, 901)
                } else {
                    moving_gradient(64, 64, 2 * k, 3 * k, 5)
                }
            })
            .collect();
        let tuned = encode_adaptive_gop_yuv_with_q_tuned(&frames, 60, AdaptiveTuning::default())
            .expect("adaptive encode");
        assert!(
            tuned.cuts.iter().any(|&c| c),
            "the constructed cut must trip the probe: {:?}",
            tuned.mc_mads
        );
        let decoded = crate::decoder::decode_av1_spec(&tuned.gop.ivf_bytes)
            .expect("spec driver accepts adaptive stream");
        assert_eq!(decoded.len(), n);
        for (idx, f) in decoded.iter().enumerate() {
            assert_eq!(
                f.planes[0],
                plane8(&tuned.gop.recon[idx].y),
                "display {idx} luma"
            );
        }
    }
}