Repository navigation
Motion macroblocking: cause and fixes #288
mauricio-gg
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Summary. A user reported heavy macroblocking (blocky, smeared video) the moment the player started moving, absent in static scenes and unaffected by the bitrate setting. Two causes were found and both planned fixes shipped: PR #186 (the receiver's reference-frame window now matches the Vita decoder's 8 frames) and PR #187 (an IDR keyframe is requested on the first unrecoverable missing reference, not the third). Both are on
main. Two further ideas from the investigation were never built.Symptom
A Reddit user reported, on both PS4 and PS5 Remote Play:
Mechanism
Static scenes produce small P-frames (a few UDP packets). Burst loss on Vita Wi-Fi rarely exceeds the FEC parity the PS5 chose for such small frames, so FEC repairs them and the reference chain stays whole. Motion produces large P-frames (20-50+ packets of ~1000 bytes). The same burst loss now exceeds the parity, FEC fails (
CHIAKI_ERR_FEC_FAILEDinlib/src/frameprocessor.c), the frame is dropped, and every later P-frame that references it breaks. Until the next keyframe, the output is wrong. This is the same chain collapse described in the "Why FPS drops" thread, shown as visual corruption instead of lost frames.Candidate causes, ranked at the time, and their outcome
REF_FRAMES 8,vita/include/video.h:35). A P-frame referencing a frame 9-16 back passed the receiver's check, but the decoder had already evicted that reference, so it decoded against the wrong picture with no error flag to trigger recovery.CASCADE_SKIP_THRESHOLD(3) consecutive unrecoverable missing references. At 30 fps that is about 100 ms of certain corruption before the console is even asked for a keyframe.fec_fail_kf=,lib/src/videoreceiver.c:968), which partly covers the data-collection idea.sceAvcdecDecodenever returned an error across 22 hardware logs, and moved to a different strategy: decide on the receiver side which frames to submit.The two fixes that shipped
fix(video): align receiver ref-frame window to 8 slots matching Vita HW decoder DPB).reference_frames[]shrank from 16 to 8 via a newCHIAKI_VIDEO_RECEIVER_REF_SLOTSconstant, used byadd_ref_frame,have_ref_frameand the alternate-reference scan. A P-frame whose reference the decoder has already evicted is now seen as "missing" and enters the recovery path, instead of decoding silently against the wrong picture. Today:lib/include/chiaki/videoreceiver.h:22(with a comment tying it tovita/include/video.h:REF_FRAMES), used inlib/src/videoreceiver.c:10, 96-120.fix(video): request IDR on first unrecoverable missing ref, not third). Added avideo_receiver_maybe_request_idr(..., "missing_ref")call inside the not-recovered branch of the frame flush, so an IDR is requested on the first unrecoverable missing reference. The existing 100 ms cooldown prevents flooding, and the cascade skip at depth 3 remains as a backstop. Today:lib/src/videoreceiver.c:826.The plan staged them deliberately: #186 first and validated on device, then #187, because without #186 the missing-reference path fires less often and #187 has little to act on. The plan also noted a guard to add if
Requesting IDR (missing_ref)fired more than about 5 times per second in stable streaming (limit the request toconsecutive_missing_ref == 1). It was not needed as far as the repo shows.What the investigation got wrong or that has aged
lib/src/videoreceiver.c:821-846).false(lib/src/bitstream.c:457-458; 0 successes in 112 attempts).videoreceiver.c:49-50),CASCADE_SKIP_THRESHOLDis 3 (:51), the receiver reference store is 8 (not 16), and the video jitter ceiling on the Vita is 40 ms (lib/src/takion.c:85, not 100 ms). The reorder queue is 256 entries and handles control messages only (takion.c:69); video and audio bypass it. The 200 ms congestion report interval and 10% loss clamp are unchanged (lib/src/congestioncontrol.c:5, 11).PIPE/STAGE skips=not rising,Requesting IDR (missing_ref)appearing within one frame of onset). In the PRs those boxes are unchecked and I found no recorded before/after measurement in the repo, so treat the benefit as expected rather than measured.How to check this on a log
grep -a "Requesting IDR (missing_ref)"should show requests close to motion onset (not onlycascade_skip).PIPE/STAGE skips=should not rise compared with before the change.grep -a, not plaingrep: BSD grep treats these logs as binary and silently returns nothing.Source: docs/ai/MOTION_MACROBLOCKING_INVESTIGATION.md and docs/superpowers/plans/2026-06-25-motion-macroblocking-fix.md (deleted from the repo in #281; recoverable from git history at commit 0e9dd13)
All reactions