Synthesizable H.264 / AVC encoder RTL with a Verilator testbench, RTL-owned Annex B bitstream generation, FFmpeg decode/remux helpers, and reproducible smoke and validation scripts.
This repository is working end to end for a constrained subset of H.264. It is not yet a full-standard H.264 encoder.
Implemented and validated now:
- RTL-owned Annex B byte-stream output
- SPS, PPS, IDR, non-IDR, macroblock headers, CAVLC, RBSP trailing bits, and emulation-prevention bytes in RTL
- I-frame and P-frame encode flow
- up to four-reference P-slice support with RTL-owned
ref_idx_l0signaling across the active-reference count - zero-residual inter-macroblock handling with deferred inter headers
- RTL-owned
P_SKIPskip-run generation on the current P-slice path - limited non-reference
B-slice support on the current intra /I_PCMpath - limited inter-coded
B_L0_16x16,B_L1_16x16, andB_BI_16x16support on the current reordered dual-list16x16B path - limited
B_DIRECT_16x16support on the current reordered dual-list16x16B path, with spatial direct derivation, a current limited temporal-direct mode, slice-level automatic temporal/spatial selection on reorderedBand reordered-BREFslices when the future picture'sList0 ref0bank maps back into the current past-reference set, and force hooks for targeted validation - limited
B_SKIPsupport on the current reordered dual-list16x16B_DIRECT_16x16path when the chosen direct macroblock reaches zero residual - limited reference-
B/BREFsupport on the current reordered dual-listB_L0_16x16/B_L1_16x16/B_BI_16x16path - header/control signaling now uses a stream-level B-slice contract: I/P-only
8-bit 4:2:0 streams stay Constrained Baseline, while B/BREF/reordered-GOP
streams advertise Main profile and
max_num_reorder_frames = 1from the first SPS; HRD andtransform_8x8signaling remain off until those lanes exist - full directional
Intra_4x4mode support in RTL Intra_16x16luma prediction and syntax support in RTL- current IDR path now routes through RTL
Intra_16x16macroblock coding rather than leaving the feature smoke-only Intra_16x16luma-DC CAVLC now derivesnCfrom the normal surrounding4x4nnz context, which re-closed the tiny non-I_PCMhigh-bit-depth decode pathIntra_16x16luma-DC forward quantization and inverse dequantization inrtl/h264_luma_dc.vnow match the current fixed-QP reconstruction path, so the current IDR-pathIntra_16x16validation is no longer only decodable; it now reconstructs near-exactly on the validated320x176all-IDR run- current non-
I_PCMstrict-decode validation now reaches320x176through10frames for10-bit 4:2:0and10-bit 4:2:2, and through24frames for8-bit 4:4:4and10-bit 4:4:4 - limited quarter-pel luma refinement and chroma fractional interpolation on the current inter path
- validated multi-frame subset runs plus current-tree near-exact
Intra_16x16IDR validation - CABAC
P_L0_16x16residual checkpoint validated as a focused coefficient-driven gate - deblock/reconstructed-frame ownership lane validated on canonical commit
dc1d47094238f8ad973cdfb5738abd4f0d2ea951with the standalone oracle, public-decoder checks, and a two-frame reference-bank-consumption proof - Docker one-frame smoke run
Still missing before full-standard completion, using the current x264
software encoder as the implementation baseline:
- full CABAC syntax integration beyond the current skip-capable plus explicit
zero-CBP / single-ref / zero-MVD
P_L0_16x16checkpoint; broader coefficient-significance/last/level coding,mb_qp_delta, chroma residuals,ref_idx/MVDcoverage, and full I/P/B CABAC remain to implement - broader
B/BREFpicture support, broader direct-mode handling, and the associated reference management - broader standards-complete sub-pel motion handling across richer inter modes
- broader inter partition coverage beyond the current High-profile 8x8 transform gates
- broader validated
4:4:4support beyond the current320x176strict-decode non-I_PCMpath and spotI_PCMcoverage - broader profile and tool coverage
- final
1280x720 @ 24 fps,10-second RTL-path completion run
See STATUS.md for the detailed repository inventory, implemented features, validated runs, and outstanding gaps.
This is the README-level checklist for getting from the current constrained RTL encoder to a full H.264/AVC encoder and then to ASIC readiness. The current repo has real RTL-owned progress, but these items must be closed before any "full" or "ASIC-ready" claim.
- CABAC: complete context initialization, binarization, significance/last/
level coding,
mb_qp_delta, chroma residuals,ref_idx, MVD coverage, and full I/P/B-slice integration beyond the current focused P-slice checkpoint. - Slice and picture types: complete IDR/non-IDR I, P, B, and BREF behavior, including reordered display/decode order, MMCO/DPB behavior, POC/frame-num wrap, and robust reference-list construction.
- Macroblock and partition modes: all required intra/inter macroblock types,
P and B partitions (
16x16,16x8,8x16,8x8, sub-macroblock modes), skip/direct paths, and transform-size decisions without software repair. - Motion estimation/compensation: broader quarter-pel luma and chroma interpolation, richer search/mode decision, multiple references, weighted prediction/weighted bipred, direct spatial/temporal prediction, and validated residual/MVD syntax for natural motion.
- Transforms/residuals: complete 4x4 and 8x8 transform/quant/dequant/inverse paths, luma/chroma DC and AC residual coverage, high-profile transform signaling, and coefficient syntax across sparse/dense/natural distributions.
- Profiles, chroma, and bit depth: Baseline/Main/High-family profile signaling and tool behavior, 8/10-bit 4:2:0/4:2:2/4:4:4 coverage as scoped, I_PCM where required, and profile/level/VUI/HRD/SEI correctness.
- In-loop filtering and reconstruction: deblocking control and filtered reconstructed-frame ownership for reference use, with decoded output matching the RTL reconstruction path rather than a testbench substitute.
- Rate/quality control: QP control, bitrate/quality modes as scoped, mode decision/RD heuristics, visual/metric quality gates, and x264-based feature comparisons where useful.
- End-to-end proof: smallest representative RTL-owned proof for each feature class, public FFmpeg decode, MP4 remux when relevant, visual/metric checks, and no software-authored final syntax.
- lint-clean synthesizable RTL with simulation-only checks isolated;
- ASIC-friendly memory architecture for frame buffers/reference banks/bitstream FIFOs with explicit SRAM/DRAM-style interfaces;
- hierarchy-preserving synthesis scripts and constraints for leaf, medium, and full-top gates;
- clock/reset/timing strategy, DFT/scan plan, and CDC review if needed;
- gate-level simulation plus timing/area/power evidence on the target flow; and
- source hygiene: no generated Verilator trees, stale worktrees, debug logs, large media dumps, or proof artifacts in the Git source tree.
The target is a full end-to-end H.264 / AVC encoder through the RTL path. The finished project must:
- generate a decodable Annex B H.264 stream from RTL output bytes
- keep final codec syntax owned by RTL rather than software helpers
- decode successfully in FFmpeg
- package the RTL-generated bitstream into MP4
- produce a visually correct result for the final target clip
Final representative target:
- clip: Big Buck Bunny
- output:
1280x720 @ 24 fps - source of truth: RTL-generated H.264 byte stream
- proof size: the smallest frame count that verifies the behavior is acceptable; 2 frames is fine when an IDR→P or similar transition proves the target path, and more frames are only required when the feature needs longer reference/GOP behavior
- longer runs such as the first 10 seconds / 240 frames are optional soak/regression evidence, not the required completion gate
Do not consider the encoder complete until the decoded final output is verified and the remaining gaps against full H.264 standard coverage are closed.
| Path | Purpose |
|---|---|
rtl/ |
Encoder RTL modules |
tb/ |
Verilator testbench and build flow |
scripts/ |
Input prep, regression, packaging, and validation helpers |
docker/ |
Docker smoke-run environment |
tools/ |
Small debug and parsing utilities |
data/ |
Local-only source media and generated YUV inputs |
output/ |
Local-only encoded streams, decoded output, and validation artifacts |
references/ |
Local-only codec specs and software reference documents |
STATUS.md |
Detailed implementation and repository inventory |
AGENTS.md |
Project rules for autonomous work in this repository |
The normative reference for codec behavior remains the H.264 / AVC
specification. For practical implementation coverage and feature-gap tracking,
this repo now uses the official VideoLAN x264 encoder source as the software
baseline.
Current local baseline:
- local path:
references/software/x264 - upstream:
https://code.videolan.org/videolan/x264 - local checkout used for this comparison:
0480cb05fa188d37ae87e8f4fd8f1aea3711f7eefrom2025-08-31
Why x264:
- it is the strongest practical H.264 software encoder baseline in common use
- its current source exposes the exact feature classes this RTL repo still
needs, including CABAC,
B-frames, reference-frame management, weighted prediction, direct motion-vector modes, sub-pel motion refinement, profiles / levels, and broader chroma / bit-depth support
Key feature evidence in the local x264 checkout:
x264.cexposes--profile,--level,--bframes,--b-pyramid,--ref,--no-deblock,--direct,--weightp,--me,--subme, and--no-cabacx264.hexposesI420,I422,I444, high-depth pixel formats, andIDR,P,BREF, andBpicture types
This baseline is used to define what is implemented now and what is still left to implement. The final claim of completion still requires the RTL path itself to generate the finished Annex B stream.
Current RTL pipeline:
fetch -> motion estimation -> prediction -> transform -> quantize -> zigzag -> CAVLC -> inverse quant -> inverse transform -> reconstruct -> bitstream
Current implemented features:
- end-to-end RTL-owned H.264 Annex B byte-stream generation
- SPS generation in RTL
- SPS
level_idcselection in RTL from frame macroblock count and target frame rate - SPS
pic_order_cnt_type = 0signaling in RTL withlog2_max_pic_order_cnt_lsb_minus4 = 5 - SPS
log2_max_frame_num_minus4 = 4signaling in RTL for an 8-bitframe_numfield - SPS VUI timing signaling in RTL with
num_units_in_tick,time_scale, andfixed_frame_rate_flag - SPS VUI bitstream-restriction signaling in RTL: I/P-only streams advertise
max_num_reorder_frames = 0, and B/BREF/reordered-GOP streams advertisemax_num_reorder_frames = 1while keeping the current four-reference buffering subset - PPS generation in RTL
- IDR slice header generation in RTL
- non-IDR slice header generation in RTL
pic_order_cnt_lsbsignaling in RTL on IDR and non-IDR slice headers- 8-bit
frame_numsignaling and 9-bitpic_order_cnt_lsbsignaling on IDR and non-IDR slice headers pic_order_cnt_lsbnow comes from a dedicated RTL input instead of being derived fromframe_num, so reordered GOPs can keep display order and reference numbering separate- macroblock header generation in RTL
- RBSP trailing bits in RTL
- emulation-prevention byte insertion in RTL
- CAVLC entropy coding in RTL
- CAVLC for luma coefficients
- CAVLC for chroma DC coefficients
- CAVLC for chroma AC coefficients
- I-frame support
- P-frame support
- non-reference
B-slice support on the current intra /I_PCMpath - limited inter-coded non-reference
B_L0_16x16,B_L1_16x16, andB_BI_16x16support on the current reordered dual-list16x16B path - limited
B_DIRECT_16x16support on the current reordered dual-list16x16B path, with spatial direct derivation from neighbor state plus colocated MB metadata captured per reference bank - current limited temporal-direct support on the reordered dual-list
16x16B path when the future reference picture'sList0 ref0bank maps back to the current past reference, including slice-level automatic temporal-direct selection on reorderedBand reordered-BREFslices plusdirect_spatial_mv_pred_flag = 0signaling in RTL - limited reference-
B/BREFsupport on the current reordered dual-listB_L0_16x16/B_L1_16x16/B_BI_16x16path - reordered
B-GOP scheduling support in the testbench / validation flow for encode orders such as0,2,1,4,3, with non-referenceBpictures reusing the sameframe_numas the surrounding reference pair while carrying their ownpic_order_cnt_lsb - current reordered B inter selection can choose past
List0, futureList1, or bidirectionalB_BI_16x16prediction per macroblock on the current limited reordered dual-list16x16B path - the current reordered dual-list
B_BI_16x16path now seeds its past-side search from the best stored past-reference/future-reference pair instead of always collapsing toList0 ref_idx 0, so reordered validation can exercise nonzeroref_idx_l0values on the limited B path - the current limited
B_BI_16x16path now writes back both motion-vector lists into neighbor state and refines each list through the quarter-pel luma path before the bidirectional average is formed - the current limited
B_DIRECT_16x16path now derives decoder-matching spatial direct vectors from neighbor state, applies the colocated zero-MV rule from per-bank MB metadata, uses an exact direct interpolation path instead of the normal qpel search loop, and can now win automatically against the current reorderedB_L0_16x16/B_L1_16x16/B_BI_16x16candidates instead of only via a force flag - reference-bank metadata now also retains picture-order and frame-level
list0-reference-bank state alongside the per-MB colocated metadata, and the
current limited temporal-direct path now consumes that metadata on reordered
B and reordered-
BREFslices - reference-bank metadata now also retains the additional stored future-picture
List0bank mappings needed for the current limited temporal-direct path, so nonzero colocated futureref_idx_l0values can map back into the current B picture's past-reference set instead of only handling futureref_idx_l0=0 - reference-bank metadata now also retains the current limited future-picture
List1 ref0bank mapping for reorderedBREFpictures, and the temporal- direct path can now derive a candidate from colocatedList1motion when that stored future mapping is the usable path back into the current past- reference set - plain
B_L1_16x16final selection now explicitly storesList1 ref_idx 0instead of leaking staleList0ref-index state into the colocated metadata, so reordered-BREFreference slots coded asB_L1_16x16can seed later temporal-direct derivation from colocatedList1 - the current limited
B_DIRECT_16x16path can now collapse zero-residual macroblocks into RTL-owned B-slice skip-run syntax through the same late deferred-header path already used for zero-residualP_SKIP - reordered GOP forcing can now emit reference-slot pictures as
BREFinstead ofP, so encode orders such as0,2,1,4,3can be driven as all-BREF non-IDR GOPs for validation - IDR + non-IDR encoded stream output
16x16macroblock raster-order processing- up to four forward reference pictures for P-slice motion search
- inter/intra macroblock decisioning for P-frames
- slice-level active reference override and per-macroblock
ref_idx_l0syntax - standards-correct
TE(v)coding forref_idx_l0when two P-slice references are active, withUE(v)fallback when three references are active - deferred inter-macroblock header emission so zero-residual inter MBs can
legally choose
cbp=0orP_SKIPbefore any residual syntax is released mb_skip_runaccumulation and flush in RTL for P-slices- zero-residual inter MB FIFO discard in RTL when no residual syntax should be emitted
- zero-residual
P_SKIPselection in RTL when the chosen inter MB isref_idx_l0 = 0and its motion vector matches the inferredP_SKIPpredictor - motion-vector-difference syntax for supported P macroblocks
- integer-pel motion estimation
- fixed search range motion estimation
- diamond-style luma motion estimation
- the integer-pel ME core now resets its per-search diamond/refine state on every new macroblock search, preventing stale candidate state from leaking between macroblocks
- quarter-pel luma refinement on the current
16x16P-macroblock inter path - luma inter prediction from the previous reconstructed frame
- chroma fractional interpolation on the current inter path
- weighted P prediction for inter luma and chroma on the RTL path
pred_weight_tableslice signaling in RTL for weighted P slices- explicit weighted B prediction on the current single-list reordered B
subpaths and limited
B_BI_16x16path, including B-slicepred_weight_tablesignaling forList0andList1 - single-list weighted
P/B/ direct qpel refinement now scores weighted luma samples during mode decision instead of scoring the unweighted predictor and applying weights only later in reconstruction - luma intra prediction:
Intra_4x4_Vertical,Intra_4x4_Horizontal,Intra_4x4_DC,Intra_4x4_Diagonal_Down_Right,Intra_4x4_Vertical_Right,Intra_4x4_Horizontal_Down,Intra_4x4_Vertical_Left, andIntra_4x4_Horizontal_Up - luma intra prediction:
Intra_16x16_Vertical,Intra_16x16_Horizontal,Intra_16x16_DC, andIntra_16x16_Plane - chroma intra prediction: DC-style path
4x4H.264 integer transform- inverse transform path
- quantization path
- inverse quantization path
- zigzag scan path
- reconstruction loop in RTL
- reference-frame writeback for reconstructed luma
- reference-frame writeback for reconstructed chroma
- in-loop deblock/reconstructed-frame ownership validated on canonical commit
dc1d47094238f8ad973cdfb5738abd4f0d2ea951; coverage includes the standalone oracle, public-decoder checks, and two-frame reference-bank consumption - standalone CABAC arithmetic coding core in
rtl/h264_cabac_core.v, plus a current final-path CABAC subset for skip-capable P slices with dual PPS emission, CABAC slice-header fields, CABAC-codedmb_skip_flag, CABAC-codedend_of_slice_flag, an explicit single-ref / zero-CBP / zero-MVDP_L0_16x16subset, and the validated focusedP_L0_16x16residual checkpoint - parameterized resolution
- parameterized bit depth
- parameterized chroma format
Implemented now relative to the chosen x264 baseline:
- Annex B bitstream ownership in RTL
- parameter-set and slice-header ownership in RTL
- CAVLC-based coefficient coding in RTL
- current CABAC final-path subset on skip-capable P slices, with CABAC PPS
selection, CABAC-coded
mb_skip_flag, CABAC-codedend_of_slice_flag, and an explicit single-ref / zero-CBP / zero-MVDP_L0_16x16subset, and the validated focusedP_L0_16x16residual checkpoint - I and P picture flow
- non-reference
B-picture syntax on the current intra /I_PCMpath - limited non-reference
B_L0_16x16,B_L1_16x16, andB_BI_16x16inter coding on the current reordered dual-list16x16B path - limited
B_DIRECT_16x16inter coding on the current reordered dual-list16x16B path, with automatic selection plus a force hook for targeted validation - limited
B_SKIPownership on the current reordered dual-list16x16direct path when a chosen direct macroblock reaches zero residual - limited reference-
B/BREFpicture support on the current reordered dual-list16x16B path - explicit weighted prediction on the current single-list reordered B subpaths
- limited spatial direct prediction on the current reordered dual-list
16x16B path, plus a current limited temporal-direct mode for reordered B slices whose future reference maps back to the current past reference - full
Intra_4x4directional luma mode coverage Intra_16x16luma prediction and syntax supportI_PCMmacroblock coding on the current IDR path and current P-slice intra path, with raw-sample byte emission owned by the RTL writer- exact
I_PCMbyte-path coverage now also reaches4:4:4on the current IDR and P-slice intra path at32x16for both8-bitand10-bit, but the dedicated strict FFmpeg4:4:4 I_PCMsmoke rows are still red on the current tree - up-to-four-reference P-slice inter flow with integer-pel search and current quarter-pel luma refinement
- zero-residual inter-MB handling and
P_SKIPskip-run ownership on the RTL path - weighted P prediction and
pred_weight_tableownership on the RTL path 8-bitand10-bitoperation for4:2:0and4:2:2
Supported and smoke-verified modes:
8-bit 4:2:08-bit 4:2:210-bit 4:2:010-bit 4:2:2
Transform / profile / color closeout from t_267d06fd:
8-bit 4:2:0I/P-only -> Constrained Baseline (output/smoke_8b_420.trace_headers.txt)8-bit 4:2:0B-direct / CABAC P16x16 -> Main (output/smoke_32x16_2f_cabac_p16x16.h264,output/smoke_8b_420_bdirect.trace_headers.txt,output/smoke_8b_420_cabac_p16x16.trace_headers.txt)10-bit 4:2:0-> High 10 (output/smoke_32x16_2f_10b.h264)8-bit 4:2:2-> High 4:2:2 (output/smoke_32x16_2f_422.h264,output/smoke_10b_422.trace_headers.txt)8-bit 4:4:4/10-bit 4:4:4-> High 4:4:4 Predictive (output/smoke_32x16_2f_444.h264,output/smoke_32x16_2f_10b_444.h264)- High-profile 8x8 smoke -> High with
transform_8x8_mode_flag = 1(output/smoke_32x16_2f_high8x8.h264,output/smoke_8b_420_high8x8.sim.log)
Validation artifacts are output/header_trace_matrix_summary_filtered.json plus the per-case trace / smoke outputs listed above.
Current additional I_PCM-byte-path coverage (the dedicated strict-FFmpeg 4:4:4 smoke rows are still red):
8-bit 4:4:410-bit 4:4:4
Current additional validated tiny non-I_PCM coverage at 32x16:
10-bit 4:2:0one-frame and two-frame IDR / P probes10-bit 4:2:2two-frame IDR / P probes8-bit 4:4:4two-frame IDR / P probes10-bit 4:4:4one-frame and two-frame IDR / P probes
Current additional validated non-I_PCM coverage at 320x176:
10-bit 4:2:0ten-frame strict-decode IDR+P run10-bit 4:2:2ten-frame strict-decode IDR+P run8-bit 4:4:4twenty-four-frame strict-decode IDR+P run10-bit 4:4:4twenty-four-frame strict-decode IDR+P run
Important non-completion gaps:
- full
CABACsyntax/context integration beyond the current skip-capable plus explicit zero-CBP / single-ref / zero-MVDP_L0_16x16P-slice subset is not implemented yet - broader inter-coded
B/BREFpicture handling is not implemented beyond the current limited reordered dual-listB_L0_16x16/B_L1_16x16/B_BI_16x1616x16path - direct prediction modes are not fully implemented beyond the current limited
B_DIRECT_16x16reordered-BREFpath - reference-picture management beyond the current four-reference P-slice subset is not implemented
- broader full-standard sub-pel motion handling beyond the current
16x16quarter-pel luma path is not implemented - broader inter partition coverage beyond the current High-profile 8x8 transform gates is not implemented
- broader
4:4:4chroma-format support beyond the current320x176strict-decode non-I_PCMpath and the still-red32x164:4:4 I_PCMsmoke rows is not implemented - full-standard profile / level / tool coverage is not implemented
- a representative
1280x720 @ 24 fpsRTL-owned proof is not closed yet; use the smallest frame count that proves the active behavior, with 240 frames / 10 seconds treated as optional soak evidence
This means the repo is currently a partial H.264 implementation, not a claim of complete H.264 standard support.
Verified validation/features around the current encoder flow:
- FFmpeg-decodable RTL-generated
.h264 - MP4 remux of the RTL-generated stream
- Docker one-frame smoke run producing RTL-generated
.h264and.mp4 - reproducible smoke matrix for fast strict-decode/profile sanity on generated
tiny
I_PCMinputs plus tiny forced spatial-direct, temporal-direct, auto temporal-direct reordered-Band reordered-BREFcases, temporal-direct reordered-BREFB_DIRECT_16x16, mixed reordered-BREFref-slot / B-slot temporal-direct cases, explicit reordered-BREFref-slotB_L1_16x16guards, multi-ref reorderedB_BI_16x16cases, and a generated flat exact-reference CABAC P-skip case plus a generated flat exact-reference explicit CABACP_L0_16x16case - multi-frame validation at
320x176 - multi-frame validation at
1280x720 - PSNR / SSIM comparison scripts
- x264 reference comparison scripts
- standalone 8x8 transform / inverse-transform / quantization / inverse-quantization gates at 8-bit and 10-bit, plus High-profile 8x8 smoke coverage
- chroma/profile/bit-depth validation on the
tpc_i_cavlc_8b420_4x4row - side-by-side decoded-vs-source image generation
- staged clean-build log capture for reproducible validation runs
- simulator log and cycle-count capture for regressions
- runtime-configurable
idr_intervalsupport in the testbench and validation scripts - runtime-configurable
force_b_slicesupport in the testbench and validation scripts for the current non-referenceB-slice path - runtime-configurable
force_bref_slicesupport in the testbench and validation scripts for the current limited reference-Bpath - runtime-configurable
reorder_b_gopsupport in the testbench and validation scripts for reordered B-picture encode order - runtime-configurable
force_b_bisupport in the testbench and validation scripts for the current limitedB_BI_16x16path - runtime-configurable
force_b_l0support in the testbench and validation scripts for targeted validation of the current limitedB_L0_16x16path - runtime-configurable
force_b_l1support in the testbench and validation scripts for targeted validation of the current limitedB_L1_16x16path - runtime-configurable
force_b_directsupport in the testbench and validation scripts for targeted validation of the current limitedB_DIRECT_16x16path - runtime-configurable
force_b_direct_temporalsupport in the testbench and validation scripts so reordered B slices can switch to the current limited temporal-direct derivation and emitdirect_spatial_mv_pred_flag = 0 - runtime-configurable slot-scoped
force_b_bi/force_b_l0/force_b_l1/force_b_direct/force_b_direct_temporalsupport on reordered reference slots and reordered B slots, so mixed reordered-BREFvalidations can pin the future reference slot toB_L0_16x16orB_L1_16x16while pinning the later B slot to temporal direct in the same run - simulator-side per-frame
b_l1_mbslogging so reordered B validation can prove that the future-referenceList1path was actually selected - simulator-side per-frame
b_bi_mbslogging so reordered B validation can prove that the bidirectionalB_BI_16x16path was actually selected - simulator-side per-frame
b_direct_mbslogging so reordered B validation can prove that the current limitedB_DIRECT_16x16path was actually selected, whether automatically or via force - staged validation JSON and smoke summaries now carry parsed
skip_mbs/b_l1_mbs/b_bi_mbs/b_direct_mbs/b_l0_refgt0_mbs/b_direct_refgt0_mbs/b_direct_l1src_mbs/cabac_p16x16_mbsaggregates so B-path behavior can be asserted without manual log scraping - reordered validation can now combine
--reorder-b-gopand--force-bref-sliceso the reference slots are emitted asBREFpictures - fast strict-decode-only validation mode in
validate_clip.pyfor longer regressions that do not need metrics or x264 comparison - RTL-owned
P_SKIPskip-run generation validated on the current P-slice path
Measured validation points:
docker_320x176_1f:816,975cycles32x16_4f_cabac_pskip_ipcmidr: strict FFmpeg-decodable CABAC skip-only P-slice validation on a flat exact-reference clip,234,131cycles,473bytes,Mainprofile,output/validation_cabac_pskip_ipcmidr_32x16_4f.h264,output/validation_cabac_pskip_ipcmidr_32x16_4f.mp4, andb_mode_summary.total_skip = 632x16_2f_cabac_p16x16: strict FFmpeg-decodable explicit CABACP_L0_16x16zero-CBP / single-ref / zero-MVD smoke,47,268cycles,74bytes,Mainprofile,output/smoke_32x16_2f_cabac_p16x16.h264, andb_mode_summary.total_cabac_p16x16 = 232x16_nonipcm_ncfix: theIntra_16x16luma-DCnCfix re-opened strict decode on tiny non-I_PCMhigh-bit-depth probes, covering10-bit 4:2:0,10-bit 4:2:2,8-bit 4:4:4, and10-bit 4:4:4through thevalidation_nonipcm_*_ncfix.jsonartifacts320x176_nonipcm_10f: strict-decode IDR+P validation now also closes at320x176through10frames for10-bit 4:2:0and10-bit 4:2:2, and through24frames for8-bit 4:4:4and10-bit 4:4:4, via thevalidation_nonipcm_*_320x176_4f_p.json,validation_nonipcm_*_320x176_10f_p.json,validation_nonipcm_8b444_320x176_24f_p_fixcbp2.json, andvalidation_nonipcm_10b444_320x176_24f_p_fixcbp2.jsonartifacts320x176_nonipcm_8b444_inter_cbp_fix: the4:4:4intercoded_block_patternpath now uses the ChromaArrayType3inter table in the RTL writer instead of the4:2:xinter code, and strict FFmpeg decode now re-closes focused extracted clips ending on the old bad picture throughvalidation_nonipcm_8b444_f16f17_2f_fixcbp.json(2frames,14,159,804cycles,5,298bytes) andvalidation_nonipcm_8b444_f14f17_4f_fixcbp.json(4frames,88,709,796cycles,10,442bytes), plusvalidation_nonipcm_8b444_f12f17_6f_fixcbp.json(6frames,212,087,014cycles,16,327bytes),validation_nonipcm_8b444_f10f17_8f_fixcbp2.json(8frames,337,204,428cycles,21,715bytes), and the full current-treevalidation_nonipcm_8b444_320x176_24f_p_fixcbp2.json(24frames,1,350,672,124cycles,58,281bytes); the matching10-bit 4:4:4current-tree run now also re-closes throughvalidation_nonipcm_10b444_320x176_24f_p_fixcbp2.json(24frames,1,336,320,075cycles,56,308bytes)320x176_10f_tefix: strict FFmpeg-decodable multi-frame validation on the current tree,253,064,186cycles, RTL PSNR avg45.745576, RTL SSIM all0.994893320x176_1f_vui: strict FFmpeg-decodable one-frame SPS/VUI timing smoke,732,748cycles, FFmpeglevel=12, and raw-stream timing metadata behavior matching a one-framex264elementary stream at the same settings320x176_1f_vui_restrict: strict FFmpeg-decodable one-frame SPS/VUI restriction smoke,732,753cycles,trace_headersconfirmingbitstream_restriction_flag = 1,motion_vectors_over_pic_boundaries_flag = 1,max_num_reorder_frames = 0, andmax_dec_frame_buffering = 4320x176_1f_frame_num8: strict FFmpeg-decodable one-frame SPS/frame-number smoke,732,751cycles,trace_headersconfirmingpic_order_cnt_type = 0,log2_max_frame_num_minus4 = 4, andlog2_max_pic_order_cnt_lsb_minus4 = 5320x176_4f_frame_num8: strict FFmpeg-decodable four-frame SPS/frame-number validation,92,027,135cycles,trace_headersconfirming 8-bitframe_numvalues0..3and 9-bitpic_order_cnt_lsbvalues0,2,4, and6320x176_4f_idr1: strict FFmpeg-decodable all-IDR validation with runtimeidr_interval = 1,2,930,968cycles,5,652bytes, and four SPS/PPS/IDR groups generated by the RTL path320x176_1f_i16_dcquantfix: strict FFmpeg-decodable one-frame IDRIntra_16x16validation on the current tree,796,556cycles,1,147bytes, RTL PSNR avg69.336543, RTL SSIM all0.999940320x176_4f_i16_dcquantfix_clean: strict FFmpeg-decodable all-IDRIntra_16x16validation on the current tree,3,186,164cycles,4,588bytes, RTL PSNR avg69.336543, RTL SSIM all0.999940ipcm_320x176_1f: strict FFmpeg-decodable forced-I_PCMIDR validation on the RTL byte path,242,396cycles,84,963bytes, and decoded YUV exactly matching the320x176source frame byte-for-byteipcm_320x176_4f: strict FFmpeg-decodable four-frame forced-I_PCMall-IDR validation on the RTL byte path,969,524cycles,339,852bytes, packaged MP4 output, and decoded YUV exactly matching the first four source frames byte-for-byteipcm_32x16_1f_422: strict FFmpeg-decodable forced-I_PCMIDR validation at32x16,8-bit 4:2:2,3,651cycles,1,071bytes, High 4:2:2 profile MP4 output, and decoded YUV exactly matching the source frame byte-for-byteipcm_p_32x16_2f: strict FFmpeg-decodable two-frame validation with frame0on the IDRI_PCMpath and frame1on the P-sliceI_PCMpath,59,889cycles,1,595bytes, packaged MP4 output, and decoded YUV exactly matching both source frames byte-for-byteipcm_32x16_1f_10b_latched: strict FFmpeg-decodable forced-I_PCMIDR validation at32x16,10-bit 4:2:0,5,965cycles,1,007bytes, and decoded YUV exactly matching the source frame byte-for-byteipcm_32x16_1f_10b_422_latched: strict FFmpeg-decodable forced-I_PCMIDR validation at32x16,10-bit 4:2:2,7,885cycles,1,327bytes, and decoded YUV exactly matching the source frame byte-for-byteipcm_p_32x16_2f_10b_latched: strict FFmpeg-decodable two-frame validation with frame0on the IDRI_PCMpath and frame1on the P-sliceI_PCMpath at32x16,10-bit 4:2:0,59,645cycles,1,980bytes, and decoded YUV exactly matching both source frames byte-for-byteipcm_p_32x16_2f_10b_422_latched: strict FFmpeg-decodable two-frame validation with frame0on the IDRI_PCMpath and frame1on the P-sliceI_PCMpath at32x16,10-bit 4:2:2,62,973cycles,2,620bytes, and decoded YUV exactly matching both source frames byte-for-byteipcm_32x16_1f_444: strict FFmpeg-decodable forced-I_PCMIDR validation at32x16,8-bit 4:4:4,5,065cycles,1,583bytes, profileHigh 4:4:4 Predictive, and decoded YUV exactly matching the source frame byte-for-byteipcm_p_32x16_2f_444: strict FFmpeg-decodable two-frame validation with frame0on the IDRI_PCMpath and frame1on the P-sliceI_PCMpath at32x16,8-bit 4:4:4,64,387cycles,3,132bytes, and decoded YUV exactly matching both source frames byte-for-byteipcm_32x16_1f_10b_444: strict FFmpeg-decodable forced-I_PCMIDR validation at32x16,10-bit 4:4:4,11,723cycles,1,968bytes, profileHigh 4:4:4 Predictive, and decoded YUV exactly matching the source frame byte-for-byteipcm_p_32x16_2f_10b_444: strict FFmpeg-decodable two-frame validation with frame0on the IDRI_PCMpath and frame1on the P-sliceI_PCMpath at32x16,10-bit 4:4:4,69,371cycles,3,901bytes, and decoded YUV exactly matching both source frames byte-for-bytebslice_ipcm_320x176_2f: strict FFmpeg-decodable two-frame validation with frame0on the IDRI_PCMpath and frame1on the non-referenceB-sliceI_PCMpath at320x176,484,677cycles,169,893bytes, packaged MP4 output, exact decoded-YUV match, andtrace_headersconfirmation ofnal_ref_idc = 0andslice_type = 1on the second picturebslice_inter_320x176_2f: strict FFmpeg-decodable two-frame validation with frame0on the IDRI_PCMpath and frame1on the non-reference inter-codedB_L0_16x16path at320x176,10,048,976cycles,85,388bytes total, exact decoded-YUV match,trace_headersconfirmation ofnal_ref_idc = 0andslice_type = 1on the second picture, and a425byte second-slice payload withENABLE_P_IPCM=0bref_inter_320x176_3f: strict FFmpeg-decodable three-frame validation with frame0on the IDRI_PCMpath and frames1and2on the reference-B/BREFinter-codedB_L0_16x16path at320x176,19,820,383cycles,85,799bytes total, exact decoded-YUV match, andtrace_headersconfirmation that both non-IDR B pictures usenal_ref_idc = 2withslice_type = 1reorderbgop_320x176_3f: strict FFmpeg-decodable reordered B-GOP validation at320x176, encode order0,2,1,20,392,794cycles, RTL PSNR avg30.444086, RTL SSIM all0.774761, with the reference P picture carryingframe_num = 1,pic_order_cnt_lsb = 4and the following non-reference B picture carryingframe_num = 1,pic_order_cnt_lsb = 2,output/validation_reorderbgop_320x176_3f.h264, andoutput/validation_reorderbgop_320x176_3f.mp4reorderbgop_320x176_5f: strict FFmpeg-decodable reordered B-GOP validation at320x176, encode order0,2,1,4,3,62,543,870cycles, decode-only strict check closed cleanly,output/validation_reorderbgop_320x176_5f.h264, andoutput/validation_reorderbgop_320x176_5f.mp4bl1_320x176_3f: strict FFmpeg-decodable reordered B-GOP validation at320x176, encode order0,2,1,37,760,283cycles,3,797bytes, RTL PSNR avg30.444086, RTL SSIM all0.774761,output/validation_bl1_320x176_3f.h264, andoutput/validation_bl1_320x176_3f.mp4bl1_force_32x16_3f: strict FFmpeg-decodable forced-B_L1_16x16reordered-B validation at32x16,3frames,129,691cycles,98bytes,output/validation_bl1_force_32x16_3f.h264, andoutput/validation_bl1_force_32x16_3f.mp4, with simulator logging showingb_l1_mbs=2on the B picturereorderbrefgop2_320x176_5f: strict FFmpeg-decodable reordered all-BREFvalidation at320x176, encode order0,2,1,4,3,93,507,221cycles,4,761bytes,output/validation_reorderbrefgop2_320x176_5f.h264, andoutput/validation_reorderbrefgop2_320x176_5f.mp4, with simulator logging showing every non-IDR picture emitted asBREFweightedb_bl1_32x16_3f: strict FFmpeg-decodable weighted-B reordered validation at32x16,3frames,130,005cycles,output/validation_weightedb_bl1_32x16_3f.h264, andoutput/validation_weightedb_bl1_32x16_3f.mp4, withtrace_headersconfirmingweighted_bipred_idc = 1in PPS and B-slicepred_weight_tableentries for bothList0andList1autobi_qpelprobe_320x176_5f: strict FFmpeg-decodable current-tree reordered all-BREFvalidation at320x176,5frames,93,525,885cycles,4,761bytes, RTL PSNR avg32.579259, RTL SSIM all0.863570,output/validation_autobi_qpelprobe_320x176_5f.h264, andoutput/validation_autobi_qpelprobe_320x176_5f.json, with simulator logging showingb_bi_mbs=0on the three non-IDR picturesforcebbi_qpelprobe_32x16_3f: strict FFmpeg-decodable current-tree forced-B_BI_16x16reordered-B validation at32x16,3frames,130,715cycles,150bytes, RTL PSNR avg30.120198, RTL SSIM all0.774794,output/validation_forcebbi_qpelprobe_32x16_3f.h264, andoutput/validation_forcebbi_qpelprobe_32x16_3f.jsonforcebbi_qpelprobe_320x176_5f: strict FFmpeg-decodable current-tree forced-B_BI_16x16reordered all-BREFvalidation at320x176,5frames,91,943,969cycles,10,281bytes, RTL PSNR avg15.889197, RTL SSIM all0.837371,output/validation_forcebbi_qpelprobe_320x176_5f.h264, andoutput/validation_forcebbi_qpelprobe_320x176_5f.json, with simulator logging showingb_bi_mbs=220on the last two non-IDR picturesforcebbi_qpelcmp_weightedbi5_320x176_5f: strict FFmpeg-decodable current-tree forced-B_BI_16x16reordered all-BREFvalidation at320x176,5frames, non-default explicit B weights (5with denom2),92,405,579cycles,19,258bytes, RTL PSNR avg32.63735, RTL SSIM all0.864016,output/validation_forcebbi_qpelcmp_weightedbi5_320x176_5f.h264, andoutput/validation_forcebbi_qpelcmp_weightedbi5_320x176_5f.json, with simulator logging showingb_bi_mbs=220on the last two non-IDR pictures andoutput/validation_forcebbi_qpelcmp_weightedbi5_320x176_5f.trace.txtconfirmingweighted_bipred_idc = 1,luma_log2_weight_denom = 2,chroma_log2_weight_denom = 2, and list0/list1 luma/chroma weights of5bmultiref_ref1win_32x16_5f_ipcmrefs: strict FFmpeg-decodable current-tree forced-B_BI_16x16reordered-B validation at32x16,5frames, exact IDR/PI_PCMreferences,329,003cycles,1,408bytes,output/validation_bmultiref_ref1win_32x16_5f_ipcmrefs.h264, andoutput/validation_bmultiref_ref1win_32x16_5f_ipcmrefs.json, withb_mode_summaryshowingtotal_bi = 4andtotal_l0_refgt0 = 2, proving the limited reordered multi-refB_BI_16x16path can now emit nonzeroList0 ref_idxvaluesautobi_qpelcmp_weightedbi5_320x176_5f: strict FFmpeg-decodable current-tree reordered all-BREFvalidation at320x176,5frames, non-default explicit B weights (5with denom2),97,793,335cycles,18,872bytes, RTL PSNR avg32.421436, RTL SSIM all0.86191,output/validation_autobi_qpelcmp_weightedbi5_320x176_5f.h264, andoutput/validation_autobi_qpelcmp_weightedbi5_320x176_5f.json, with simulator logging still showingb_l1_mbs=220on the two middle non-IDR pictures andb_bi_mbs=0across the runbdirect_force_32x16_3f: strict FFmpeg-decodable forced-B_DIRECT_16x16reordered-BREFvalidation at32x16,3frames,131,068cycles,265bytes, RTL PSNR avg27.36622, RTL SSIM all0.554193,output/validation_bdirect_force_32x16_3f.h264,output/validation_bdirect_force_32x16_3f.mp4, and simulator logging showingb_direct_mbs=2on the last picturebdirect_force_320x176_5f: strict FFmpeg-decodable forced-B_DIRECT_16x16reordered all-BREFvalidation at320x176,5frames,97,641,789cycles,25,505bytes, RTL PSNR avg13.670634, RTL SSIM all0.668749,output/validation_bdirect_force_320x176_5f.h264,output/validation_bdirect_force_320x176_5f.mp4, and simulator logging showingb_direct_mbs=220on each non-IDR picturebdirect_auto_probe_32x16_3f: strict FFmpeg-decodable non-forced autoB_DIRECT_16x16reordered-B validation at32x16,3frames,130,756cycles,122bytes, RTL PSNR avg30.120198, RTL SSIM all0.774794,output/validation_bdirect_auto_probe_32x16_3f.h264, and simulator logging showingb_direct_mbs=1on the last picturebdirect_auto_probe_320x176_5f: strict FFmpeg-decodable non-forced decode-only reordered all-BREFvalidation at320x176,5frames,93,162,228cycles,4,666bytes,output/validation_bdirect_auto_probe_320x176_5f.h264, and simulator logging showing nonzerob_direct_mbsacross all three non-IDR pictures (219,148, and31)bdirect_bskip_auto_320x176_5f_json: strict FFmpeg-decodable non-forced decode-only reordered all-BREFvalidation at320x176,5frames,93,158,455cycles,4,541bytes,output/validation_bdirect_bskip_auto_320x176_5f_json.h264, with staged JSONb_mode_summaryreportingframes_with_skip=3,total_skip=393,max_skip=219,frames_with_direct=3, and simulator skip counts of219,148, and26across the three non-IDR picturestemporal_direct_force_32x16_3f: strict FFmpeg-decodable forced temporal-direct reordered-B validation at32x16,3frames,131,063cycles,263bytes,output/validation_temporal_direct_32x16_3f.h264,output/validation_temporal_direct_32x16_3f.json, and header-trace proof ofdirect_spatial_mv_pred_flag = 0withb_direct_mbs=2temporal_direct_force_320x176_3f: strict FFmpeg-decodable decode-only forced temporal-direct reordered-B validation at320x176,3frames,37,905,407cycles,21,423bytes,output/validation_temporal_direct_320x176_3f.h264,output/validation_temporal_direct_320x176_3f.json, and header-trace proof ofdirect_spatial_mv_pred_flag = 0withb_direct_mbs=220temporal_direct_bref_force_32x16_3f: strict FFmpeg-decodable forced temporal-direct reordered-BREFvalidation at32x16,3frames,131,068cycles,265bytes,output/validation_temporal_direct_bref_fix_32x16_3f.h264,output/validation_temporal_direct_bref_fix_32x16_3f.json, and header-trace proof that both non-IDRBREFslices emitdirect_spatial_mv_pred_flag = 0while the last picture reportsb_direct_mbs=2temporal_direct_bref_force_320x176_3f: strict FFmpeg-decodable decode-only forced temporal-direct reordered-BREFvalidation at320x176,3frames,37,905,588cycles,21,534bytes,output/validation_temporal_direct_bref_fix_320x176_3f.h264,output/validation_temporal_direct_bref_fix_320x176_3f.json, and header-trace proof that both non-IDRBREFslices emitdirect_spatial_mv_pred_flag = 0while the last picture reportsb_direct_mbs=220temporal_direct_ref1_32x16_7f: strict FFmpeg-decodable decode-only forced temporal-direct reordered-B validation at32x16,7frames,608,780cycles,525bytes,output/validation_temporal_direct_ref1_32x16_7f.h264,output/validation_temporal_direct_ref1_32x16_7f.json, and header-trace proof that the B slices emitdirect_spatial_mv_pred_flag = 0, withb_mode_summaryreportingtotal_direct=6andtotal_direct_refgt0=4, proving the current limited temporal-direct path can now consume nonzero future-pictureList0 ref_idxmappingstemporal_direct_auto_32x16_7f_autoslice: strict FFmpeg-decodable decode-only auto temporal-direct reordered-B validation at32x16,7frames,608,096cycles,274bytes,output/validation_temporal_direct_b_auto_32x16_7f_autoslice.h264,output/validation_temporal_direct_b_auto_32x16_7f_autoslice.json, with header-trace proof that the reordered B slices emitdirect_spatial_mv_pred_flag = 0, with the RTL auto-switching the slice to temporal direct andb_mode_summaryreportingtotal_direct=4andtotal_direct_refgt0=4temporal_direct_bref_auto_refslotl0_32x16_7f_autoslice: strict FFmpeg-decodable decode-only auto temporal-direct reordered-BREFvalidation at32x16,7frames,707,309cycles,253bytes,output/validation_temporal_direct_bref_auto_from_refslotl0_32x16_7f_autoslice.h264,output/validation_temporal_direct_bref_auto_from_refslotl0_32x16_7f_autoslice.json, with header-trace proof that the first reorderedBREFref slot staysdirect_spatial_mv_pred_flag = 1while the later reorderedBREFslices auto-switch to0, the future reorderedBREFref slot pinned toB_L0_16x16, and the later reorderedBREFslice auto-switching to temporal direct,b_mode_summaryreportingtotal_l0_refgt0=6,total_direct=2, andtotal_direct_refgt0=2temporal_direct_bref_mixed_refslotl0_32x16_7f: strict FFmpeg-decodable decode-only mixed reordered-BREFvalidation at32x16,7frames,718,775cycles,505bytes,output/validation_temporal_direct_bref_mixed_refslotl0_32x16_7f.h264,output/validation_temporal_direct_bref_mixed_refslotl0_32x16_7f.json, and simulator-log proof that reordered reference slots ran withforce_l0=1while reordered B slots ran withforce_direct=1 force_direct_temporal=1, withb_mode_summaryreportingtotal_l0_refgt0=6,total_direct=4, andtotal_direct_refgt0=2, proving the current limited temporal-direct path can now consume nonzero futureList0mappings coming from reorderedBREFreference slots instead of only future P picturestemporal_direct_bref_mixed_refslotl0_320x176_3f: strict FFmpeg-decodable decode-only mixed reordered-BREFvalidation at320x176,3frames,37,905,588cycles,21,534bytes,output/validation_temporal_direct_bref_mixed_refslotl0_320x176_3f.h264,output/validation_temporal_direct_bref_mixed_refslotl0_320x176_3f.json, and simulator-log proof that the same slot-scoped forcing holds on the larger real clip, with the middle reorderedBREFpicture pinned toB_L0_16x16and the final reorderedBREFpicture pinned to temporal directtemporal_direct_bref_mixed_refslotbi_32x16_5f: strict FFmpeg-decodable decode-only mixed reordered-BREFvalidation at32x16,5frames,404,704cycles,1,521bytes,output/validation_temporal_direct_bref_mixed_refslotbi_32x16_5f.h264,output/validation_temporal_direct_bref_mixed_refslotbi_32x16_5f.json, and simulator-log proof that reordered reference slots ran withforce_bi=1while reordered B slots ran withforce_direct=1 force_direct_temporal=1, withb_mode_summaryreportingtotal_bi=6,total_l0_refgt0=4,total_direct=4, andtotal_direct_refgt0=2, proving the current limited temporal-direct path can also consume nonzero futureList0mappings coming from reorderedBREFreference slots that were themselves coded on the limitedB_BI_16x16pathtemporal_direct_bref_bi_ref1_l1src_32x16_5f: strict FFmpeg-decodable decode-only mixed reordered-BREFvalidation at32x16,5frames,404,573cycles,1,537bytes,output/validation_temporal_direct_bref_bi_ref1_l1src_32x16_5f.h264, andoutput/validation_temporal_direct_bref_bi_ref1_l1src_32x16_5f.json, with reordered reference slots pinned toB_BI_16x16and reordered B slots pinned to temporal direct, andb_mode_summaryreportingtotal_direct=4plustotal_direct_l1src=2, proving the current limited temporal-direct path can now derive direct macroblocks from colocatedList1on future reordered-BREFBI picturestemporal_direct_bref_bi_ref1_l1src_320x176_5f: strict FFmpeg-decodable decode-only mixed reordered-BREFvalidation at320x176,5frames,119,819,413cycles,152,910bytes,output/validation_temporal_direct_bref_bi_ref1_l1src_320x176_5f.h264,output/validation_temporal_direct_bref_bi_ref1_l1src_320x176_5f.json, and header-trace proof that the later reorderedBREFslices still emitdirect_spatial_mv_pred_flag = 0, withb_mode_summaryreportingtotal_direct=607,total_direct_refgt0=357, andtotal_direct_l1src=30temporal_direct_bref_auto_from_refslotbi_32x16_5f_l1src: strict FFmpeg-decodable decode-only mixed reordered-BREFauto probe at32x16,5frames,400,988cycles,1,497bytes,output/validation_temporal_direct_bref_auto_from_refslotbi_32x16_5f_l1src.h264, andoutput/validation_temporal_direct_bref_auto_from_refslotbi_32x16_5f_l1src.json, showing that the new colocated-List1temporal-direct path is present but the non-forced selector on this tiny probe still prefersB_BI_16x16/B_L1_16x16, withtotal_direct=0temporal_direct_bref_auto_from_refslotbi_320x176_5f_l1src: strict FFmpeg-decodable decode-only mixed reordered-BREFauto validation at320x176,5frames,121,592,814cycles,150,112bytes,output/validation_temporal_direct_bref_auto_from_refslotbi_320x176_5f_l1src.h264,output/validation_temporal_direct_bref_auto_from_refslotbi_320x176_5f_l1src.json, and header-trace proof that the later reorderedBREFslices still emitdirect_spatial_mv_pred_flag = 0, withb_mode_summaryreportingtotal_direct=337,total_direct_refgt0=167, andtotal_direct_l1src=170temporal_direct_bref_mixed_refslotl1_32x16_7f_inter_fix1: strict FFmpeg-decodable decode-only mixed reordered-BREFvalidation at32x16,7frames,724,380cycles,1,821bytes,output/validation_temporal_direct_bref_mixed_refslotl1_32x16_7f_inter_fix1.h264,output/validation_temporal_direct_bref_mixed_refslotl1_32x16_7f_inter_fix1.json, and header-trace proof inoutput/validation_temporal_direct_bref_mixed_refslotl1_32x16_7f_inter_fix1.trace_headers.txtthat later reorderedBREFslices emitdirect_spatial_mv_pred_flag = 0, with reordered reference slots pinned toB_L1_16x16, reordered B slots pinned to temporal direct, andb_mode_summaryreportingtotal_l1=4,total_direct=6, andtotal_direct_l1src=4temporal_direct_bref_auto_from_refslotl1_32x16_7f_inter_fix1: strict FFmpeg-decodable decode-only mixed reordered-BREFauto validation at32x16,7frames,739,640cycles,1,587bytes,output/validation_temporal_direct_bref_auto_from_refslotl1_32x16_7f_inter_fix1.h264,output/validation_temporal_direct_bref_auto_from_refslotl1_32x16_7f_inter_fix1.json, and header-trace proof inoutput/validation_temporal_direct_bref_auto_from_refslotl1_32x16_7f_inter_fix1.trace_headers.txtthat the first reorderedBREFslice stays spatial while later ones switch to temporal direct, withb_mode_summaryreportingtotal_l1=6,total_direct=2, andtotal_direct_l1src=2temporal_direct_bref_mixed_refslotl1_320x176_7f_fix1: strict FFmpeg-decodable decode-only mixed reordered-BREFvalidation at320x176,7frames,233,261,934cycles,129,453bytes,output/validation_temporal_direct_bref_mixed_refslotl1_320x176_7f_fix1.h264,output/validation_temporal_direct_bref_mixed_refslotl1_320x176_7f_fix1.json, and simulator-log proof that reordered reference slots pinned toB_L1_16x16can drive later temporal-direct slices through colocatedList1, withb_mode_summaryreportingtotal_l1=20,total_direct=1080,total_direct_refgt0=640, andtotal_direct_l1src=220temporal_direct_bref_auto_from_refslotl1_320x176_7f_fix1: strict FFmpeg-decodable decode-only mixed reordered-BREFauto validation at320x176,7frames,233,399,683cycles,97,921bytes,output/validation_temporal_direct_bref_auto_from_refslotl1_320x176_7f_fix1.h264,output/validation_temporal_direct_bref_auto_from_refslotl1_320x176_7f_fix1.json, and simulator-log proof that the non-forced selector now reaches the same colocated-List1temporal-direct path on the larger clip, withb_mode_summaryreportingtotal_l1=341,total_bi=759,total_direct=727,total_direct_refgt0=413, andtotal_direct_l1src=314bl0_force_ref1_32x16_7f_ipcmrefs: strict FFmpeg-decodable decode-only reordered-B validation at32x16,7frames, exact IDR/PI_PCMreferences,581,041cycles,4,234bytes,output/validation_bl0_force_ref1_32x16_7f_ipcmrefs.h264, andoutput/validation_bl0_force_ref1_32x16_7f_ipcmrefs.json, withforce_b_l0=1pinning the current limitedB_L0_16x16path andb_mode_summaryreportingtotal_l0_refgt0=2whiletotal_bi=0,total_direct=0, andtotal_direct_refgt0=0, proving the plainB_L0_16x16path can emit nonzero past-reference indices without BI/direct fallbackbdirect_auto_weighted_32x16_3f: strict FFmpeg-decodable weighted non-forced autoB_DIRECT_16x16reordered-B validation at32x16,3frames,131,078cycles,180bytes, RTL PSNR avg30.158513, RTL SSIM all0.775715,output/validation_bdirect_auto_weighted_32x16_3f.h264, and simulator logging showingb_direct_mbs=1on the last picturebdirect_bskip_auto_32x16_3f: strict FFmpeg-decodable non-forced auto reordered-BREFvalidation at32x16,3frames,130,749cycles,122bytes, RTL PSNR avg30.120198, RTL SSIM all0.774794,output/validation_bdirect_bskip_auto_32x16_3f.h264, and simulator logging showingskip_mbs=1,b_l1_mbs=2, andb_direct_mbs=1on the last picture, proving the current limitedB_DIRECT_16x16path can collapse to B-slice skip syntax on a zero-residual macroblockweightedp_small_32x16_2f: strict FFmpeg-decodable small weighted-P validation at32x16,2frames,51,117cycles,112bytes, RTL PSNR avg28.420753, RTL SSIM all0.66449, andoutput/validation_weightedp_small_32x16_2f.h26432x16_2f_444_ipcm_scripted: strict staged validation throughscripts/validate_clip.pywith--enable-idr-ipcm 1 --enable-p-ipcm 1at32x16,8-bit 4:4:4, packaged MP4 output, and JSON summary inoutput/validation_32x16_2f_444_ipcm_scripted.json320x176_4f_decodeonly: strict FFmpeg-decodable multi-frame decode-only validation on the current tree,92,028,425cycles,1,912bytes, paired staged.build.log/.sim.log, JSON validation-mode recording, and packaged MP4 output without PSNR / SSIM, x264, or side-by-side PNG work320x176_24f_tefix: strict FFmpeg-decodable multi-frame validation on the current tree,640,575,297cycles, RTL PSNR avg43.767484, RTL SSIM all0.989193320x176_10f_multiref3: strict FFmpeg-decodable three-reference P-slice validation on the current tree,367,542,946cycles,15,781bytes, SPSmax_num_ref_frames = 3, RTL PSNR avg45.752063, RTL SSIM all0.994913320x176_24f_multiref3: strict FFmpeg-decodable three-reference P-slice validation on the current tree,913,475,277cycles,51,219bytes, later P-slices withnum_ref_idx_l0_active_minus1 = 2, RTL PSNR avg43.7528, RTL SSIM all0.989176320x176_4f_multiref4: strict FFmpeg-decodable four-reference P-slice validation on the current tree,92,027,039cycles,5,058bytes, SPSmax_num_ref_frames = 4, RTL PSNR avg43.883472, RTL SSIM all0.995357320x176_6f_multiref4: strict FFmpeg-decodable four-reference P-slice validation on the current tree,217,593,800cycles,7,844bytes, later P-slices withnum_ref_idx_l0_active_minus1 = 3, RTL PSNR avg45.207556, RTL SSIM all0.996333320x176_4f_weightedp: strict FFmpeg-decodable weighted-P validation on the RTL path, Main profile stream, RTL PSNR avg25.806041, RTL SSIM all0.333568320x176_4f_pskip3: strict FFmpeg-decodable deferred-inter-header / zero-residual-P_SKIPvalidation on the RTL path,92,028,425cycles,1,912bytes, RTL PSNR avg43.883472, RTL SSIM all0.995357, and simulator-reportedP_SKIPcounts of123,152, and134across the three validated P-frames320x176_4f_multiref: earlier strict FFmpeg-decodable two-reference P-slice validation on the RTL path,50,611,399cycles, SPSmax_num_ref_frames = 2, later P-slices withnum_ref_idx_active_override_flag = 1, RTL PSNR avg25.806041, RTL SSIM all0.333568720p_4f_intra_tl_modes:522,499,266cycles, RTL PSNR avg43.871116, RTL SSIM all0.995403320x176_1f_i16x16_fix2: earlier FFmpeg-decodableIntra_16x16smoke before the luma-DC quant/dequant fix, RTL PSNR avg25.8060, RTL SSIM all0.333568
Recent correctness fix:
- a
720pchroma corruption issue was traced to raw input address overflow on the Cr fetch path and fixed by widening the raw input address width Intra_4x4most-probable-mode derivation at picture edges was fixed to follow the unavailable-neighbor rule, removing the earlier FFmpeg decode errors on the320x176multi-frame regression- two-reference P-slice
ref_idx_l0signaling was fixed to use standards- correctTE(v)coding for the two-ref case instead ofUE(v), removing the later-frame parser corruption on the strict320x176multi-frame path - the current tree now advertises
max_num_ref_frames = 3and can emit later P-slices withnum_ref_idx_l0_active_minus1 = 2 - the current tree now advertises
max_num_ref_frames = 4and later P-slices can emitnum_ref_idx_l0_active_minus1 = 3 - the current inter path already performs quarter-pel luma refinement and chroma fractional interpolation after the integer-pel motion-estimation pass
- SPS
level_idcis now selected from frame size and configured frame rate instead of the earlier small hardcoded level split - SPS VUI timing fields are now emitted from RTL for the configured frame rate
- SPS VUI bitstream-restriction fields now describe the current no-reorder, four-reference subset
- baseline/main SPS now uses
pic_order_cnt_type = 0, and the current RTL IDR / P slice headers emitpic_order_cnt_lsb - the current RTL path now advertises
log2_max_frame_num_minus4 = 4and emits 8-bitframe_numvalues in slice headers - the testbench and
validate_clip.pynow accept a runtimeidr_interval;1forces every frame to IDR, and0means only the first frame is IDR - deferred inter headers and FIFO discard now prevent illegal zero-residual
CAVLC payloads from leaking after
cbp=0orP_SKIP, fixing the first broken zero-residual inter-header attempt - the
Intra_16x16IDR path now emits mb_type values that match the residual syntax the RTL actually outputs, removing the earlier first-row FFmpeg decode failure atMB 2 0 - the current RTL writer now supports
I_PCMmacroblocks on the IDR path, byte-aligns withpcm_alignment_zero_bit, emits raw luma / Cb / Cr samples through the RTL byte path itself, and decodes back to an exact byte-for-byte match on the validated320x176 4:2:0and32x16 4:2:2all-IDR cases - the
I_PCMsource path is now latched inrtl/h264_encoder_top.vbefore the bitstream emit begins, which closes the earlier corruption where the live fetch bus could be overwritten by the next macroblock during10-bitsample emission - the current tree now supports
I_PCMon the IDR path and the current P-slice intra path for8-bitand10-bitbuilds in both4:2:0and4:2:2, and the checked-intb/MakefileexposesENABLE_IDR_IPCM,ENABLE_P_IPCM,IPCM_SAD_THRESHOLD, andINTER_SAD_THRESHOLDso the path can be reproduced without rawEXTRA_VERILATOR_ARGS - the current tree emits
4:4:4 I_PCMbytes on the IDR path and current P-slice intra path at32x16for8-bitand10-bit, and ffprobe still reportsHigh 4:4:4 Predictive, but the dedicated strict FFmpeg4:4:4 I_PCMsmoke rows are still red on the current tree - the
4:4:4inter path must use the ChromaArrayType3coded_block_patterntable rather than the4:2:xinter code; the current RTL writer now emits the correct full-residual inter code on that path, and focused strict-decode reruns ending on the old bad picture re-close at320x176for extracted2-frame and4-frame clips - the current reordered B path now carries explicit list0/list1 neighbor MV
state, list-specific MVD syntax, per-list quarter-pel luma refinement,
qpel-aware final
B_L0/B_L1/B_BIluma comparison on the dual-ref B path, and explicit weighted bipred combine on the limitedB_BI_16x16path, which re-opened forced strict-decode validation at32x16and320x176; the real320x176weighted reordered clip still selectsB_L1_16x16automatically rather thanB_BI_16x16 scripts/validate_clip.pyandscripts/rtl_runner.pynow exposeENABLE_IDR_IPCM,ENABLE_P_IPCM,IPCM_SAD_THRESHOLD, andINTER_SAD_THRESHOLDso staged validation can reproduce theI_PCMpaths instead of relying on ad-hocmakecommands- the
Intra_16x16luma-DC path inh264_luma_dc.vnow keeps the forward rounded Hadamard output, uses the DC-specific forward quant step, latches the input payload for execution, and restores the missing scaling-list factor on inverse dequant; that re-closed the current IDR-pathIntra_16x16reconstruction quality on the validated320x176all-IDR run
Recent intra prediction expansion:
- completed the full
Intra_4x4directional mode set - added
Intra_16x16luma prediction and luma DC transform / syntax handling - fixed the top-right neighbor fetch bug in the directional
Intra_4x4path
Recent entropy coding groundwork:
- added
rtl/h264_cabac_core.vimplementing the standardized CABAC arithmetic decision / bypass / terminate core as standalone RTL - CABAC context selection, syntax binarization, and full bitstream integration are still open
Recent multi-reference expansion:
- expanded the banked P-slice reference path from two forward refs to up to four forward refs on the current tree
- SPS now advertises
max_num_ref_frames = 4 - later P-slices now emit
num_ref_idx_active_override_flag = 1andnum_ref_idx_l0_active_minus1 = 3when the fourth reference is active - inter macroblock headers now emit RTL-owned
ref_idx_l0syntax for the current four-reference P-slice path
Current development and validation flows assume:
- Linux shell execution, preferably WSL Ubuntu
- Verilator
- FFmpeg /
ffprobe - Python 3
make24build threads by default on this machine
Docker is required only for the containerized smoke path.
The checked-in shell scripts are Linux-oriented. Use all available host threads
by default for build and simulation-related work unless a debugging task
clearly needs fewer. On this machine, that means 24 threads.
Be wary of simulation times. Start with the smallest valid case that can prove the issue before scaling up.
cd tb
make -j24 WIDTH=320 HEIGHT=176 BIT_DEPTH=8 CHROMA_FORMAT_IDC=1./Vh264_encoder_top \
+frames=24 \
+idr_interval=12 \
+timeout=500000000 \
+input=/path/to/input.yuv \
+output=/path/to/output.h264Set +idr_interval=1 to force every frame to IDR, or +idr_interval=0 to
use only the first frame as IDR and keep later frames as P.
python3 scripts/package_mp4.py output.h264 output.mp4 --fps 24 --width 320 --height 176./build_run.shbuilds the simulator, runs the RTL encoder on an existing YUV input, and optionally packages the result to MP4./run.shdownloads the sample clip, extracts raw YUV, builds the simulator, runs the encoder, and packages MP4 output./docker_run.shruns the one-frame Docker smoke pathpython3 scripts/regress_smoke_matrix.pyruns the current fast strict-decode/profile smoke regression matrix on generated tinyI_PCMinputs and emits paired.build.log/.sim.logartifacts per case- use
--case <name>to run only specific smoke cases; filtered runs writeoutput/smoke_matrix_summary_filtered.json
- use
python3 scripts/trace_header_matrix.pyregenerates focused smoke rows and asserts decodedtrace_headersfields for profile selection, VUI/HRD, CABAC PPS selection, B/reorder signaling, andtransform_8x8exclusions- use
--case <name>for a focused row; filtered runs writeoutput/header_trace_matrix_summary_filtered.json
- use
python3 scripts/validate_clip.pyruns staged multi-frame validation with a clean staged rebuild, strict decode checking, paired.build.log/.sim.logartifacts, MP4 output, and comparison metrics- use
--decode-onlyto keep longer strict-decode regressions cheap when you do not need PSNR / SSIM, x264 reference encode, or side-by-side PNGs - use
--skip-metrics,--skip-x264,--skip-compare, or--skip-mp4when you want finer control over which post-sim stages run
- use
Run a small local case from an existing YUV input:
WIDTH=320 HEIGHT=176 FRAMES=1 YUV_INPUT=/path/to/input.yuv ./build_run.shRun the current sample flow:
./run.shRun the Docker smoke path:
./docker_run.shSee docker/README.md for the container behavior and current limitations.
Run a faster strict-decode-only validation without metrics or x264:
python3 scripts/validate_clip.py \
--width 320 \
--height 176 \
--frames 24 \
--label fastdecode_320x176_24f \
--decode-only- always consult the H.264 / AVC specification and relevant reference material
- expected local spec path:
references/itu/T-REC-H.264-202408-I.pdf - expected local software baseline path:
references/software/x264/ - local reference PDFs are for development use and are not committed by default
- local software reference trees are for development use and are not committed by default
- prefer primary references over memory
- do not guess unless there is no practical alternative after checking the
spec, repository, local
x264reference tree, and available references
This repo is configured to keep generated and private development assets out of version control.
Committed:
- RTL, testbench, scripts, Docker files, and documentation
- lightweight README files that describe local-only folders
Ignored by default:
- source media and extracted YUV inputs in
data/ - generated
.h264,.mp4, decoded.yuv, logs, and comparison images inoutput/ - local spec PDFs and reference archives in
references/ - local software encoder source checkouts such as
references/software/x264/ - build outputs, caches, and common editor junk