Skip to content

fix: reset AV1 coding state on every key frame - #31

Open
lutyjj wants to merge 1 commit into
hgaiser:mainfrom
lutyjj:fix/av1-keyframe-rc-reset
Open

fix: reset AV1 coding state on every key frame#31
lutyjj wants to merge 1 commit into
hgaiser:mainfrom
lutyjj:fix/av1-keyframe-rc-reset

Conversation

@lutyjj

@lutyjjlutyjj commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

NVIDIA's Vulkan AV1 encoder silently emits undecodable key frames mid-session when rate control is active: the tile data doesn't match the emitted frame header, dav1d and ffmpeg reject the frame with a hard parse error, and every frame until the next key frame is lost with it. Only the first key frame of a session was valid, so any stream using CBR/VBR with on-demand IDRs (game streaming) broke permanently on the first IDR request - in practice a permanent greenscreen the moment the client asks for a recovery key frame (this is the "potential fix" I mentioned in hgaiser/moonshine#156). CQP was unaffected, so CQP-based examples never caught it.

The fix re-issues the coding-state RESET + rate control + quality level control command on every key frame instead of only the first, same shape as the existing first-frame setup. A key frame is a clean restart point, so in theory this is generic and spec-compliant behavior regardless of the vendor (though I tested only on Nvidia). Scoped to active rate control: with rate control disabled there's no state worth resetting, so CQP skips the extra control command entirely.

Verification - new rc_keyframes example following the rfi.rs pattern: AV1 + CBR + gop_size 10 so key frames land mid-stream, then a full-stream ffmpeg decode + PSNR check against the source. On current main it fails at 12.79 dB (the stream decodes but is corrupt from the first mid-stream key frame on - the soft failure mode a plain decode-success check would miss); with this fix it passes at 67.60 dB. Also verified end to end in a real moonshine session (4K/120 AV1): pre-fix greenscreens on the first recovery key frame, post-fix recovers cleanly.

Closeshgaiser/moonshine#155.


Host: NVidia 5060 Ti (driver 610.43.03), Arch

@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from 609cd1e to 116ef31CompareAugust 2, 2026 16:33
@lutyjj

lutyjj commented Aug 2, 2026

Copy link
Copy Markdown
ContributorAuthor

jfyi: the actual fix is ~3 lines in record.rs - the rest of the diff is the rc_keyframes example, so that the issue can be showcased/reproduced without a full streaming setup (fails on main at 12.79 dB, passes with the fix at 67.60 dB).

@lutyjj
lutyjj marked this pull request as draft August 2, 2026 20:18
@lutyjj

Copy link
Copy Markdown
ContributorAuthor

Putting into draft for now. For some reason started observing weird behaviour on AC4 and AV1 + HDR path again. There are no green screen artifacts anymore, but on transitioning from SDR to HDR after intro movies the game now exits fullscreen (on moonlight-qt) and just black-screens. Sound goes, stream is live, but client is unable to decode frames for whatever reason. Wasn't happening few days ago on moonshine-git, need to do a little more debugging there to claim this is the definitive fix.

@lutyjj
lutyjj marked this pull request as ready for review August 5, 2026 18:21
@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from 116ef31 to e49b3a1CompareAugust 5, 2026 18:21
@lutyjj

lutyjj commented Aug 5, 2026

Copy link
Copy Markdown
ContributorAuthor

un-drafting - the black screen wasn't this fix. did a proper bitstream capture this time (dumped the encoded stream host-side at the SDR→HDR transition):

  • stock v0.8.1: the 5 key frames after set_color_description (session params rebuild + IDR) are each invalid in isolation - dav1d refuses them outright (Error decoding frame: Invalid argument, no data decoded), frame-header region near-all-zero. The 6th key frame ~2.2s later decodes fine. That window is exactly the green screen + the client's IDR request loop. Sequence headers parse perfectly btw - it's purely the driver-emitted frame data.
  • v0.8.1 + this fix: single key frame at the transition, decodes 100% clean from a cold start, no IDR loop, no green screen.

turns out the black screen was my test bundle's fault, unrelated to this PR - with this fix in I can't repro it anymore, with or without HDR metadata OBU injection on top (un-gating that injection is a separate fix, hgaiser/moonshine#166).

rebased on main (v0.8.1), rc_keyframes still passes at 67.60 dB (RTX 5060 Ti, driver 610.43.03).

@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from e49b3a1 to 9764c4cCompareAugust 5, 2026 18:50
NVIDIA's Vulkan AV1 encoder silently emits undecodable key frames
mid-session when rate control is active: the tile data doesn't match the
emitted frame header, dav1d/ffmpeg reject the frame with a hard parse
error, and every frame until the next key frame is lost with it. Only
the first key frame of a session was valid, so any stream using CBR/VBR
with on-demand IDRs (game streaming) broke permanently on the first IDR
request. CQP was unaffected, so the CQP-based examples never caught it.
A key frame is a clean restart point, so re-issue the RESET +
ENCODE_RATE_CONTROL + ENCODE_QUALITY_LEVEL control command there (same
shape as the first-frame setup) instead of only on the first frame. In
theory this is generic, spec-compliant behavior regardless of vendor,
though tested only on NVIDIA. Scoped to active rate control: with rate
control disabled there is no state worth resetting, so CQP skips it.
The new rc_keyframes example guards the regression: CBR with a short
GOP, then a full-stream ffmpeg decode + PSNR check. It fails on current
main at 12.79 dB and passes with this fix at 67.60 dB on RTX 5060 Ti
(driver 610.43.03); CQP behavior unchanged.
@DatCaptainHorse

Copy link
Copy Markdown
Contributor

You can never hate NVIDIA enough 😅

Changes look good from quick read, unfortunately got no RTX 2060 anymore to test with, since it was mostly sitting idle draining power, I sold it on the used-market. I'll verify with the RX 9060 XT when I get the chance 👍

@lutyjj

Copy link
Copy Markdown
ContributorAuthor

@hgaiser this PR is still relevant - I'm still observing green screen when using AV1 on SteamMachine as client with Nvidia machine as server. Let me know if I need to adjust anything to get it merged :)

@hgaiserhgaiser left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, took too long to look into this PR, thanks for looking into this issue.

I managed to reproduce this bug with your example, and also by streaming using Moonshine to an Android client (macOS worked fine for some reason).

Two notes:

  1. The rc_keyframes.rs example was useful for debugging, but it should be removed before we merge this PR. It doesn't serve as a useful example in my opinion.
  2. I was getting Vulkan validation errors with this fix:
    Validation Error: [ VUID-vkCmdBeginVideoCodingKHR-pBeginInfo-08253 ] vkCmdBeginVideoCodingKHR(): No VkVideoEncodeRateControlInfoKHR structure was specified when beginning the video coding scope but the currently set video encode rate control mode ... is VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR.
    

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Greenscreen on mid-stream colorspace switch (HDR<->SDR) on AV1 path

3 participants

@lutyjj@DatCaptainHorse@hgaiser
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
fix: reset AV1 coding state on every key frame by lutyjj · Pull Request #31 · hgaiser/pixelforge · GitHub
Skip to content

fix: reset AV1 coding state on every key frame - #31

Open
lutyjj wants to merge 1 commit into
hgaiser:mainfrom
lutyjj:fix/av1-keyframe-rc-reset
Open

fix: reset AV1 coding state on every key frame#31
lutyjj wants to merge 1 commit into
hgaiser:mainfrom
lutyjj:fix/av1-keyframe-rc-reset

Conversation

@lutyjj

@lutyjjlutyjj commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

NVIDIA's Vulkan AV1 encoder silently emits undecodable key frames mid-session when rate control is active: the tile data doesn't match the emitted frame header, dav1d and ffmpeg reject the frame with a hard parse error, and every frame until the next key frame is lost with it. Only the first key frame of a session was valid, so any stream using CBR/VBR with on-demand IDRs (game streaming) broke permanently on the first IDR request - in practice a permanent greenscreen the moment the client asks for a recovery key frame (this is the "potential fix" I mentioned in hgaiser/moonshine#156). CQP was unaffected, so CQP-based examples never caught it.

The fix re-issues the coding-state RESET + rate control + quality level control command on every key frame instead of only the first, same shape as the existing first-frame setup. A key frame is a clean restart point, so in theory this is generic and spec-compliant behavior regardless of the vendor (though I tested only on Nvidia). Scoped to active rate control: with rate control disabled there's no state worth resetting, so CQP skips the extra control command entirely.

Verification - new rc_keyframes example following the rfi.rs pattern: AV1 + CBR + gop_size 10 so key frames land mid-stream, then a full-stream ffmpeg decode + PSNR check against the source. On current main it fails at 12.79 dB (the stream decodes but is corrupt from the first mid-stream key frame on - the soft failure mode a plain decode-success check would miss); with this fix it passes at 67.60 dB. Also verified end to end in a real moonshine session (4K/120 AV1): pre-fix greenscreens on the first recovery key frame, post-fix recovers cleanly.

Closeshgaiser/moonshine#155.


Host: NVidia 5060 Ti (driver 610.43.03), Arch

@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from 609cd1e to 116ef31CompareAugust 2, 2026 16:33
@lutyjj

lutyjj commented Aug 2, 2026

Copy link
Copy Markdown
ContributorAuthor

jfyi: the actual fix is ~3 lines in record.rs - the rest of the diff is the rc_keyframes example, so that the issue can be showcased/reproduced without a full streaming setup (fails on main at 12.79 dB, passes with the fix at 67.60 dB).

@lutyjj
lutyjj marked this pull request as draft August 2, 2026 20:18
@lutyjj

Copy link
Copy Markdown
ContributorAuthor

Putting into draft for now. For some reason started observing weird behaviour on AC4 and AV1 + HDR path again. There are no green screen artifacts anymore, but on transitioning from SDR to HDR after intro movies the game now exits fullscreen (on moonlight-qt) and just black-screens. Sound goes, stream is live, but client is unable to decode frames for whatever reason. Wasn't happening few days ago on moonshine-git, need to do a little more debugging there to claim this is the definitive fix.

@lutyjj
lutyjj marked this pull request as ready for review August 5, 2026 18:21
@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from 116ef31 to e49b3a1CompareAugust 5, 2026 18:21
@lutyjj

lutyjj commented Aug 5, 2026

Copy link
Copy Markdown
ContributorAuthor

un-drafting - the black screen wasn't this fix. did a proper bitstream capture this time (dumped the encoded stream host-side at the SDR→HDR transition):

  • stock v0.8.1: the 5 key frames after set_color_description (session params rebuild + IDR) are each invalid in isolation - dav1d refuses them outright (Error decoding frame: Invalid argument, no data decoded), frame-header region near-all-zero. The 6th key frame ~2.2s later decodes fine. That window is exactly the green screen + the client's IDR request loop. Sequence headers parse perfectly btw - it's purely the driver-emitted frame data.
  • v0.8.1 + this fix: single key frame at the transition, decodes 100% clean from a cold start, no IDR loop, no green screen.

turns out the black screen was my test bundle's fault, unrelated to this PR - with this fix in I can't repro it anymore, with or without HDR metadata OBU injection on top (un-gating that injection is a separate fix, hgaiser/moonshine#166).

rebased on main (v0.8.1), rc_keyframes still passes at 67.60 dB (RTX 5060 Ti, driver 610.43.03).

@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from e49b3a1 to 9764c4cCompareAugust 5, 2026 18:50
NVIDIA's Vulkan AV1 encoder silently emits undecodable key frames
mid-session when rate control is active: the tile data doesn't match the
emitted frame header, dav1d/ffmpeg reject the frame with a hard parse
error, and every frame until the next key frame is lost with it. Only
the first key frame of a session was valid, so any stream using CBR/VBR
with on-demand IDRs (game streaming) broke permanently on the first IDR
request. CQP was unaffected, so the CQP-based examples never caught it.
A key frame is a clean restart point, so re-issue the RESET +
ENCODE_RATE_CONTROL + ENCODE_QUALITY_LEVEL control command there (same
shape as the first-frame setup) instead of only on the first frame. In
theory this is generic, spec-compliant behavior regardless of vendor,
though tested only on NVIDIA. Scoped to active rate control: with rate
control disabled there is no state worth resetting, so CQP skips it.
The new rc_keyframes example guards the regression: CBR with a short
GOP, then a full-stream ffmpeg decode + PSNR check. It fails on current
main at 12.79 dB and passes with this fix at 67.60 dB on RTX 5060 Ti
(driver 610.43.03); CQP behavior unchanged.
@DatCaptainHorse

Copy link
Copy Markdown
Contributor

You can never hate NVIDIA enough 😅

Changes look good from quick read, unfortunately got no RTX 2060 anymore to test with, since it was mostly sitting idle draining power, I sold it on the used-market. I'll verify with the RX 9060 XT when I get the chance 👍

@lutyjj

Copy link
Copy Markdown
ContributorAuthor

@hgaiser this PR is still relevant - I'm still observing green screen when using AV1 on SteamMachine as client with Nvidia machine as server. Let me know if I need to adjust anything to get it merged :)

@hgaiserhgaiser left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, took too long to look into this PR, thanks for looking into this issue.

I managed to reproduce this bug with your example, and also by streaming using Moonshine to an Android client (macOS worked fine for some reason).

Two notes:

  1. The rc_keyframes.rs example was useful for debugging, but it should be removed before we merge this PR. It doesn't serve as a useful example in my opinion.
  2. I was getting Vulkan validation errors with this fix:
    Validation Error: [ VUID-vkCmdBeginVideoCodingKHR-pBeginInfo-08253 ] vkCmdBeginVideoCodingKHR(): No VkVideoEncodeRateControlInfoKHR structure was specified when beginning the video coding scope but the currently set video encode rate control mode ... is VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR.
    

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Greenscreen on mid-stream colorspace switch (HDR<->SDR) on AV1 path

3 participants

@lutyjj@DatCaptainHorse@hgaiser
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix: reset AV1 coding state on every key frame by lutyjj · Pull Request #31 · hgaiser/pixelforge · GitHub
Skip to content

fix: reset AV1 coding state on every key frame - #31

Open
lutyjj wants to merge 1 commit into
hgaiser:mainfrom
lutyjj:fix/av1-keyframe-rc-reset
Open

fix: reset AV1 coding state on every key frame#31
lutyjj wants to merge 1 commit into
hgaiser:mainfrom
lutyjj:fix/av1-keyframe-rc-reset

Conversation

@lutyjj

@lutyjjlutyjj commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

NVIDIA's Vulkan AV1 encoder silently emits undecodable key frames mid-session when rate control is active: the tile data doesn't match the emitted frame header, dav1d and ffmpeg reject the frame with a hard parse error, and every frame until the next key frame is lost with it. Only the first key frame of a session was valid, so any stream using CBR/VBR with on-demand IDRs (game streaming) broke permanently on the first IDR request - in practice a permanent greenscreen the moment the client asks for a recovery key frame (this is the "potential fix" I mentioned in hgaiser/moonshine#156). CQP was unaffected, so CQP-based examples never caught it.

The fix re-issues the coding-state RESET + rate control + quality level control command on every key frame instead of only the first, same shape as the existing first-frame setup. A key frame is a clean restart point, so in theory this is generic and spec-compliant behavior regardless of the vendor (though I tested only on Nvidia). Scoped to active rate control: with rate control disabled there's no state worth resetting, so CQP skips the extra control command entirely.

Verification - new rc_keyframes example following the rfi.rs pattern: AV1 + CBR + gop_size 10 so key frames land mid-stream, then a full-stream ffmpeg decode + PSNR check against the source. On current main it fails at 12.79 dB (the stream decodes but is corrupt from the first mid-stream key frame on - the soft failure mode a plain decode-success check would miss); with this fix it passes at 67.60 dB. Also verified end to end in a real moonshine session (4K/120 AV1): pre-fix greenscreens on the first recovery key frame, post-fix recovers cleanly.

Closeshgaiser/moonshine#155.


Host: NVidia 5060 Ti (driver 610.43.03), Arch

@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from 609cd1e to 116ef31CompareAugust 2, 2026 16:33
@lutyjj

lutyjj commented Aug 2, 2026

Copy link
Copy Markdown
ContributorAuthor

jfyi: the actual fix is ~3 lines in record.rs - the rest of the diff is the rc_keyframes example, so that the issue can be showcased/reproduced without a full streaming setup (fails on main at 12.79 dB, passes with the fix at 67.60 dB).

@lutyjj
lutyjj marked this pull request as draft August 2, 2026 20:18
@lutyjj

Copy link
Copy Markdown
ContributorAuthor

Putting into draft for now. For some reason started observing weird behaviour on AC4 and AV1 + HDR path again. There are no green screen artifacts anymore, but on transitioning from SDR to HDR after intro movies the game now exits fullscreen (on moonlight-qt) and just black-screens. Sound goes, stream is live, but client is unable to decode frames for whatever reason. Wasn't happening few days ago on moonshine-git, need to do a little more debugging there to claim this is the definitive fix.

@lutyjj
lutyjj marked this pull request as ready for review August 5, 2026 18:21
@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from 116ef31 to e49b3a1CompareAugust 5, 2026 18:21
@lutyjj

lutyjj commented Aug 5, 2026

Copy link
Copy Markdown
ContributorAuthor

un-drafting - the black screen wasn't this fix. did a proper bitstream capture this time (dumped the encoded stream host-side at the SDR→HDR transition):

  • stock v0.8.1: the 5 key frames after set_color_description (session params rebuild + IDR) are each invalid in isolation - dav1d refuses them outright (Error decoding frame: Invalid argument, no data decoded), frame-header region near-all-zero. The 6th key frame ~2.2s later decodes fine. That window is exactly the green screen + the client's IDR request loop. Sequence headers parse perfectly btw - it's purely the driver-emitted frame data.
  • v0.8.1 + this fix: single key frame at the transition, decodes 100% clean from a cold start, no IDR loop, no green screen.

turns out the black screen was my test bundle's fault, unrelated to this PR - with this fix in I can't repro it anymore, with or without HDR metadata OBU injection on top (un-gating that injection is a separate fix, hgaiser/moonshine#166).

rebased on main (v0.8.1), rc_keyframes still passes at 67.60 dB (RTX 5060 Ti, driver 610.43.03).

@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from e49b3a1 to 9764c4cCompareAugust 5, 2026 18:50
NVIDIA's Vulkan AV1 encoder silently emits undecodable key frames
mid-session when rate control is active: the tile data doesn't match the
emitted frame header, dav1d/ffmpeg reject the frame with a hard parse
error, and every frame until the next key frame is lost with it. Only
the first key frame of a session was valid, so any stream using CBR/VBR
with on-demand IDRs (game streaming) broke permanently on the first IDR
request. CQP was unaffected, so the CQP-based examples never caught it.
A key frame is a clean restart point, so re-issue the RESET +
ENCODE_RATE_CONTROL + ENCODE_QUALITY_LEVEL control command there (same
shape as the first-frame setup) instead of only on the first frame. In
theory this is generic, spec-compliant behavior regardless of vendor,
though tested only on NVIDIA. Scoped to active rate control: with rate
control disabled there is no state worth resetting, so CQP skips it.
The new rc_keyframes example guards the regression: CBR with a short
GOP, then a full-stream ffmpeg decode + PSNR check. It fails on current
main at 12.79 dB and passes with this fix at 67.60 dB on RTX 5060 Ti
(driver 610.43.03); CQP behavior unchanged.
@DatCaptainHorse

Copy link
Copy Markdown
Contributor

You can never hate NVIDIA enough 😅

Changes look good from quick read, unfortunately got no RTX 2060 anymore to test with, since it was mostly sitting idle draining power, I sold it on the used-market. I'll verify with the RX 9060 XT when I get the chance 👍

@lutyjj

Copy link
Copy Markdown
ContributorAuthor

@hgaiser this PR is still relevant - I'm still observing green screen when using AV1 on SteamMachine as client with Nvidia machine as server. Let me know if I need to adjust anything to get it merged :)

@hgaiserhgaiser left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, took too long to look into this PR, thanks for looking into this issue.

I managed to reproduce this bug with your example, and also by streaming using Moonshine to an Android client (macOS worked fine for some reason).

Two notes:

  1. The rc_keyframes.rs example was useful for debugging, but it should be removed before we merge this PR. It doesn't serve as a useful example in my opinion.
  2. I was getting Vulkan validation errors with this fix:
    Validation Error: [ VUID-vkCmdBeginVideoCodingKHR-pBeginInfo-08253 ] vkCmdBeginVideoCodingKHR(): No VkVideoEncodeRateControlInfoKHR structure was specified when beginning the video coding scope but the currently set video encode rate control mode ... is VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR.
    

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Greenscreen on mid-stream colorspace switch (HDR<->SDR) on AV1 path

3 participants

@lutyjj@DatCaptainHorse@hgaiser
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix: reset AV1 coding state on every key frame by lutyjj · Pull Request #31 · hgaiser/pixelforge · GitHub
Skip to content

fix: reset AV1 coding state on every key frame - #31

Open
lutyjj wants to merge 1 commit into
hgaiser:mainfrom
lutyjj:fix/av1-keyframe-rc-reset
Open

fix: reset AV1 coding state on every key frame#31
lutyjj wants to merge 1 commit into
hgaiser:mainfrom
lutyjj:fix/av1-keyframe-rc-reset

Conversation

@lutyjj

@lutyjjlutyjj commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

NVIDIA's Vulkan AV1 encoder silently emits undecodable key frames mid-session when rate control is active: the tile data doesn't match the emitted frame header, dav1d and ffmpeg reject the frame with a hard parse error, and every frame until the next key frame is lost with it. Only the first key frame of a session was valid, so any stream using CBR/VBR with on-demand IDRs (game streaming) broke permanently on the first IDR request - in practice a permanent greenscreen the moment the client asks for a recovery key frame (this is the "potential fix" I mentioned in hgaiser/moonshine#156). CQP was unaffected, so CQP-based examples never caught it.

The fix re-issues the coding-state RESET + rate control + quality level control command on every key frame instead of only the first, same shape as the existing first-frame setup. A key frame is a clean restart point, so in theory this is generic and spec-compliant behavior regardless of the vendor (though I tested only on Nvidia). Scoped to active rate control: with rate control disabled there's no state worth resetting, so CQP skips the extra control command entirely.

Verification - new rc_keyframes example following the rfi.rs pattern: AV1 + CBR + gop_size 10 so key frames land mid-stream, then a full-stream ffmpeg decode + PSNR check against the source. On current main it fails at 12.79 dB (the stream decodes but is corrupt from the first mid-stream key frame on - the soft failure mode a plain decode-success check would miss); with this fix it passes at 67.60 dB. Also verified end to end in a real moonshine session (4K/120 AV1): pre-fix greenscreens on the first recovery key frame, post-fix recovers cleanly.

Closeshgaiser/moonshine#155.


Host: NVidia 5060 Ti (driver 610.43.03), Arch

@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from 609cd1e to 116ef31CompareAugust 2, 2026 16:33
@lutyjj

lutyjj commented Aug 2, 2026

Copy link
Copy Markdown
ContributorAuthor

jfyi: the actual fix is ~3 lines in record.rs - the rest of the diff is the rc_keyframes example, so that the issue can be showcased/reproduced without a full streaming setup (fails on main at 12.79 dB, passes with the fix at 67.60 dB).

@lutyjj
lutyjj marked this pull request as draft August 2, 2026 20:18
@lutyjj

Copy link
Copy Markdown
ContributorAuthor

Putting into draft for now. For some reason started observing weird behaviour on AC4 and AV1 + HDR path again. There are no green screen artifacts anymore, but on transitioning from SDR to HDR after intro movies the game now exits fullscreen (on moonlight-qt) and just black-screens. Sound goes, stream is live, but client is unable to decode frames for whatever reason. Wasn't happening few days ago on moonshine-git, need to do a little more debugging there to claim this is the definitive fix.

@lutyjj
lutyjj marked this pull request as ready for review August 5, 2026 18:21
@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from 116ef31 to e49b3a1CompareAugust 5, 2026 18:21
@lutyjj

lutyjj commented Aug 5, 2026

Copy link
Copy Markdown
ContributorAuthor

un-drafting - the black screen wasn't this fix. did a proper bitstream capture this time (dumped the encoded stream host-side at the SDR→HDR transition):

  • stock v0.8.1: the 5 key frames after set_color_description (session params rebuild + IDR) are each invalid in isolation - dav1d refuses them outright (Error decoding frame: Invalid argument, no data decoded), frame-header region near-all-zero. The 6th key frame ~2.2s later decodes fine. That window is exactly the green screen + the client's IDR request loop. Sequence headers parse perfectly btw - it's purely the driver-emitted frame data.
  • v0.8.1 + this fix: single key frame at the transition, decodes 100% clean from a cold start, no IDR loop, no green screen.

turns out the black screen was my test bundle's fault, unrelated to this PR - with this fix in I can't repro it anymore, with or without HDR metadata OBU injection on top (un-gating that injection is a separate fix, hgaiser/moonshine#166).

rebased on main (v0.8.1), rc_keyframes still passes at 67.60 dB (RTX 5060 Ti, driver 610.43.03).

@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from e49b3a1 to 9764c4cCompareAugust 5, 2026 18:50
NVIDIA's Vulkan AV1 encoder silently emits undecodable key frames
mid-session when rate control is active: the tile data doesn't match the
emitted frame header, dav1d/ffmpeg reject the frame with a hard parse
error, and every frame until the next key frame is lost with it. Only
the first key frame of a session was valid, so any stream using CBR/VBR
with on-demand IDRs (game streaming) broke permanently on the first IDR
request. CQP was unaffected, so the CQP-based examples never caught it.
A key frame is a clean restart point, so re-issue the RESET +
ENCODE_RATE_CONTROL + ENCODE_QUALITY_LEVEL control command there (same
shape as the first-frame setup) instead of only on the first frame. In
theory this is generic, spec-compliant behavior regardless of vendor,
though tested only on NVIDIA. Scoped to active rate control: with rate
control disabled there is no state worth resetting, so CQP skips it.
The new rc_keyframes example guards the regression: CBR with a short
GOP, then a full-stream ffmpeg decode + PSNR check. It fails on current
main at 12.79 dB and passes with this fix at 67.60 dB on RTX 5060 Ti
(driver 610.43.03); CQP behavior unchanged.
@DatCaptainHorse

Copy link
Copy Markdown
Contributor

You can never hate NVIDIA enough 😅

Changes look good from quick read, unfortunately got no RTX 2060 anymore to test with, since it was mostly sitting idle draining power, I sold it on the used-market. I'll verify with the RX 9060 XT when I get the chance 👍

@lutyjj

Copy link
Copy Markdown
ContributorAuthor

@hgaiser this PR is still relevant - I'm still observing green screen when using AV1 on SteamMachine as client with Nvidia machine as server. Let me know if I need to adjust anything to get it merged :)

@hgaiserhgaiser left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, took too long to look into this PR, thanks for looking into this issue.

I managed to reproduce this bug with your example, and also by streaming using Moonshine to an Android client (macOS worked fine for some reason).

Two notes:

  1. The rc_keyframes.rs example was useful for debugging, but it should be removed before we merge this PR. It doesn't serve as a useful example in my opinion.
  2. I was getting Vulkan validation errors with this fix:
    Validation Error: [ VUID-vkCmdBeginVideoCodingKHR-pBeginInfo-08253 ] vkCmdBeginVideoCodingKHR(): No VkVideoEncodeRateControlInfoKHR structure was specified when beginning the video coding scope but the currently set video encode rate control mode ... is VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR.
    

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Greenscreen on mid-stream colorspace switch (HDR<->SDR) on AV1 path

3 participants

@lutyjj@DatCaptainHorse@hgaiser
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' fix: reset AV1 coding state on every key frame by lutyjj · Pull Request #31 · hgaiser/pixelforge · GitHub
Skip to content

fix: reset AV1 coding state on every key frame - #31

Open
lutyjj wants to merge 1 commit into
hgaiser:mainfrom
lutyjj:fix/av1-keyframe-rc-reset
Open

fix: reset AV1 coding state on every key frame#31
lutyjj wants to merge 1 commit into
hgaiser:mainfrom
lutyjj:fix/av1-keyframe-rc-reset

Conversation

@lutyjj

@lutyjjlutyjj commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

NVIDIA's Vulkan AV1 encoder silently emits undecodable key frames mid-session when rate control is active: the tile data doesn't match the emitted frame header, dav1d and ffmpeg reject the frame with a hard parse error, and every frame until the next key frame is lost with it. Only the first key frame of a session was valid, so any stream using CBR/VBR with on-demand IDRs (game streaming) broke permanently on the first IDR request - in practice a permanent greenscreen the moment the client asks for a recovery key frame (this is the "potential fix" I mentioned in hgaiser/moonshine#156). CQP was unaffected, so CQP-based examples never caught it.

The fix re-issues the coding-state RESET + rate control + quality level control command on every key frame instead of only the first, same shape as the existing first-frame setup. A key frame is a clean restart point, so in theory this is generic and spec-compliant behavior regardless of the vendor (though I tested only on Nvidia). Scoped to active rate control: with rate control disabled there's no state worth resetting, so CQP skips the extra control command entirely.

Verification - new rc_keyframes example following the rfi.rs pattern: AV1 + CBR + gop_size 10 so key frames land mid-stream, then a full-stream ffmpeg decode + PSNR check against the source. On current main it fails at 12.79 dB (the stream decodes but is corrupt from the first mid-stream key frame on - the soft failure mode a plain decode-success check would miss); with this fix it passes at 67.60 dB. Also verified end to end in a real moonshine session (4K/120 AV1): pre-fix greenscreens on the first recovery key frame, post-fix recovers cleanly.

Closeshgaiser/moonshine#155.


Host: NVidia 5060 Ti (driver 610.43.03), Arch

@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from 609cd1e to 116ef31CompareAugust 2, 2026 16:33
@lutyjj

lutyjj commented Aug 2, 2026

Copy link
Copy Markdown
ContributorAuthor

jfyi: the actual fix is ~3 lines in record.rs - the rest of the diff is the rc_keyframes example, so that the issue can be showcased/reproduced without a full streaming setup (fails on main at 12.79 dB, passes with the fix at 67.60 dB).

@lutyjj
lutyjj marked this pull request as draft August 2, 2026 20:18
@lutyjj

Copy link
Copy Markdown
ContributorAuthor

Putting into draft for now. For some reason started observing weird behaviour on AC4 and AV1 + HDR path again. There are no green screen artifacts anymore, but on transitioning from SDR to HDR after intro movies the game now exits fullscreen (on moonlight-qt) and just black-screens. Sound goes, stream is live, but client is unable to decode frames for whatever reason. Wasn't happening few days ago on moonshine-git, need to do a little more debugging there to claim this is the definitive fix.

@lutyjj
lutyjj marked this pull request as ready for review August 5, 2026 18:21
@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from 116ef31 to e49b3a1CompareAugust 5, 2026 18:21
@lutyjj

lutyjj commented Aug 5, 2026

Copy link
Copy Markdown
ContributorAuthor

un-drafting - the black screen wasn't this fix. did a proper bitstream capture this time (dumped the encoded stream host-side at the SDR→HDR transition):

  • stock v0.8.1: the 5 key frames after set_color_description (session params rebuild + IDR) are each invalid in isolation - dav1d refuses them outright (Error decoding frame: Invalid argument, no data decoded), frame-header region near-all-zero. The 6th key frame ~2.2s later decodes fine. That window is exactly the green screen + the client's IDR request loop. Sequence headers parse perfectly btw - it's purely the driver-emitted frame data.
  • v0.8.1 + this fix: single key frame at the transition, decodes 100% clean from a cold start, no IDR loop, no green screen.

turns out the black screen was my test bundle's fault, unrelated to this PR - with this fix in I can't repro it anymore, with or without HDR metadata OBU injection on top (un-gating that injection is a separate fix, hgaiser/moonshine#166).

rebased on main (v0.8.1), rc_keyframes still passes at 67.60 dB (RTX 5060 Ti, driver 610.43.03).

@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from e49b3a1 to 9764c4cCompareAugust 5, 2026 18:50
NVIDIA's Vulkan AV1 encoder silently emits undecodable key frames
mid-session when rate control is active: the tile data doesn't match the
emitted frame header, dav1d/ffmpeg reject the frame with a hard parse
error, and every frame until the next key frame is lost with it. Only
the first key frame of a session was valid, so any stream using CBR/VBR
with on-demand IDRs (game streaming) broke permanently on the first IDR
request. CQP was unaffected, so the CQP-based examples never caught it.
A key frame is a clean restart point, so re-issue the RESET +
ENCODE_RATE_CONTROL + ENCODE_QUALITY_LEVEL control command there (same
shape as the first-frame setup) instead of only on the first frame. In
theory this is generic, spec-compliant behavior regardless of vendor,
though tested only on NVIDIA. Scoped to active rate control: with rate
control disabled there is no state worth resetting, so CQP skips it.
The new rc_keyframes example guards the regression: CBR with a short
GOP, then a full-stream ffmpeg decode + PSNR check. It fails on current
main at 12.79 dB and passes with this fix at 67.60 dB on RTX 5060 Ti
(driver 610.43.03); CQP behavior unchanged.
@DatCaptainHorse

Copy link
Copy Markdown
Contributor

You can never hate NVIDIA enough 😅

Changes look good from quick read, unfortunately got no RTX 2060 anymore to test with, since it was mostly sitting idle draining power, I sold it on the used-market. I'll verify with the RX 9060 XT when I get the chance 👍

@lutyjj

Copy link
Copy Markdown
ContributorAuthor

@hgaiser this PR is still relevant - I'm still observing green screen when using AV1 on SteamMachine as client with Nvidia machine as server. Let me know if I need to adjust anything to get it merged :)

@hgaiserhgaiser left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, took too long to look into this PR, thanks for looking into this issue.

I managed to reproduce this bug with your example, and also by streaming using Moonshine to an Android client (macOS worked fine for some reason).

Two notes:

  1. The rc_keyframes.rs example was useful for debugging, but it should be removed before we merge this PR. It doesn't serve as a useful example in my opinion.
  2. I was getting Vulkan validation errors with this fix:
    Validation Error: [ VUID-vkCmdBeginVideoCodingKHR-pBeginInfo-08253 ] vkCmdBeginVideoCodingKHR(): No VkVideoEncodeRateControlInfoKHR structure was specified when beginning the video coding scope but the currently set video encode rate control mode ... is VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR.
    

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Greenscreen on mid-stream colorspace switch (HDR<->SDR) on AV1 path

3 participants

@lutyjj@DatCaptainHorse@hgaiser
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix: reset AV1 coding state on every key frame by lutyjj · Pull Request #31 · hgaiser/pixelforge · GitHub
Skip to content

fix: reset AV1 coding state on every key frame - #31

Open
lutyjj wants to merge 1 commit into
hgaiser:mainfrom
lutyjj:fix/av1-keyframe-rc-reset
Open

fix: reset AV1 coding state on every key frame#31
lutyjj wants to merge 1 commit into
hgaiser:mainfrom
lutyjj:fix/av1-keyframe-rc-reset

Conversation

@lutyjj

@lutyjjlutyjj commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

NVIDIA's Vulkan AV1 encoder silently emits undecodable key frames mid-session when rate control is active: the tile data doesn't match the emitted frame header, dav1d and ffmpeg reject the frame with a hard parse error, and every frame until the next key frame is lost with it. Only the first key frame of a session was valid, so any stream using CBR/VBR with on-demand IDRs (game streaming) broke permanently on the first IDR request - in practice a permanent greenscreen the moment the client asks for a recovery key frame (this is the "potential fix" I mentioned in hgaiser/moonshine#156). CQP was unaffected, so CQP-based examples never caught it.

The fix re-issues the coding-state RESET + rate control + quality level control command on every key frame instead of only the first, same shape as the existing first-frame setup. A key frame is a clean restart point, so in theory this is generic and spec-compliant behavior regardless of the vendor (though I tested only on Nvidia). Scoped to active rate control: with rate control disabled there's no state worth resetting, so CQP skips the extra control command entirely.

Verification - new rc_keyframes example following the rfi.rs pattern: AV1 + CBR + gop_size 10 so key frames land mid-stream, then a full-stream ffmpeg decode + PSNR check against the source. On current main it fails at 12.79 dB (the stream decodes but is corrupt from the first mid-stream key frame on - the soft failure mode a plain decode-success check would miss); with this fix it passes at 67.60 dB. Also verified end to end in a real moonshine session (4K/120 AV1): pre-fix greenscreens on the first recovery key frame, post-fix recovers cleanly.

Closeshgaiser/moonshine#155.


Host: NVidia 5060 Ti (driver 610.43.03), Arch

@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from 609cd1e to 116ef31CompareAugust 2, 2026 16:33
@lutyjj

lutyjj commented Aug 2, 2026

Copy link
Copy Markdown
ContributorAuthor

jfyi: the actual fix is ~3 lines in record.rs - the rest of the diff is the rc_keyframes example, so that the issue can be showcased/reproduced without a full streaming setup (fails on main at 12.79 dB, passes with the fix at 67.60 dB).

@lutyjj
lutyjj marked this pull request as draft August 2, 2026 20:18
@lutyjj

Copy link
Copy Markdown
ContributorAuthor

Putting into draft for now. For some reason started observing weird behaviour on AC4 and AV1 + HDR path again. There are no green screen artifacts anymore, but on transitioning from SDR to HDR after intro movies the game now exits fullscreen (on moonlight-qt) and just black-screens. Sound goes, stream is live, but client is unable to decode frames for whatever reason. Wasn't happening few days ago on moonshine-git, need to do a little more debugging there to claim this is the definitive fix.

@lutyjj
lutyjj marked this pull request as ready for review August 5, 2026 18:21
@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from 116ef31 to e49b3a1CompareAugust 5, 2026 18:21
@lutyjj

lutyjj commented Aug 5, 2026

Copy link
Copy Markdown
ContributorAuthor

un-drafting - the black screen wasn't this fix. did a proper bitstream capture this time (dumped the encoded stream host-side at the SDR→HDR transition):

  • stock v0.8.1: the 5 key frames after set_color_description (session params rebuild + IDR) are each invalid in isolation - dav1d refuses them outright (Error decoding frame: Invalid argument, no data decoded), frame-header region near-all-zero. The 6th key frame ~2.2s later decodes fine. That window is exactly the green screen + the client's IDR request loop. Sequence headers parse perfectly btw - it's purely the driver-emitted frame data.
  • v0.8.1 + this fix: single key frame at the transition, decodes 100% clean from a cold start, no IDR loop, no green screen.

turns out the black screen was my test bundle's fault, unrelated to this PR - with this fix in I can't repro it anymore, with or without HDR metadata OBU injection on top (un-gating that injection is a separate fix, hgaiser/moonshine#166).

rebased on main (v0.8.1), rc_keyframes still passes at 67.60 dB (RTX 5060 Ti, driver 610.43.03).

@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from e49b3a1 to 9764c4cCompareAugust 5, 2026 18:50
NVIDIA's Vulkan AV1 encoder silently emits undecodable key frames
mid-session when rate control is active: the tile data doesn't match the
emitted frame header, dav1d/ffmpeg reject the frame with a hard parse
error, and every frame until the next key frame is lost with it. Only
the first key frame of a session was valid, so any stream using CBR/VBR
with on-demand IDRs (game streaming) broke permanently on the first IDR
request. CQP was unaffected, so the CQP-based examples never caught it.
A key frame is a clean restart point, so re-issue the RESET +
ENCODE_RATE_CONTROL + ENCODE_QUALITY_LEVEL control command there (same
shape as the first-frame setup) instead of only on the first frame. In
theory this is generic, spec-compliant behavior regardless of vendor,
though tested only on NVIDIA. Scoped to active rate control: with rate
control disabled there is no state worth resetting, so CQP skips it.
The new rc_keyframes example guards the regression: CBR with a short
GOP, then a full-stream ffmpeg decode + PSNR check. It fails on current
main at 12.79 dB and passes with this fix at 67.60 dB on RTX 5060 Ti
(driver 610.43.03); CQP behavior unchanged.
@DatCaptainHorse

Copy link
Copy Markdown
Contributor

You can never hate NVIDIA enough 😅

Changes look good from quick read, unfortunately got no RTX 2060 anymore to test with, since it was mostly sitting idle draining power, I sold it on the used-market. I'll verify with the RX 9060 XT when I get the chance 👍

@lutyjj

Copy link
Copy Markdown
ContributorAuthor

@hgaiser this PR is still relevant - I'm still observing green screen when using AV1 on SteamMachine as client with Nvidia machine as server. Let me know if I need to adjust anything to get it merged :)

@hgaiserhgaiser left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, took too long to look into this PR, thanks for looking into this issue.

I managed to reproduce this bug with your example, and also by streaming using Moonshine to an Android client (macOS worked fine for some reason).

Two notes:

  1. The rc_keyframes.rs example was useful for debugging, but it should be removed before we merge this PR. It doesn't serve as a useful example in my opinion.
  2. I was getting Vulkan validation errors with this fix:
    Validation Error: [ VUID-vkCmdBeginVideoCodingKHR-pBeginInfo-08253 ] vkCmdBeginVideoCodingKHR(): No VkVideoEncodeRateControlInfoKHR structure was specified when beginning the video coding scope but the currently set video encode rate control mode ... is VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR.
    

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Greenscreen on mid-stream colorspace switch (HDR<->SDR) on AV1 path

3 participants

@lutyjj@DatCaptainHorse@hgaiser
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix: reset AV1 coding state on every key frame by lutyjj · Pull Request #31 · hgaiser/pixelforge · GitHub
Skip to content

fix: reset AV1 coding state on every key frame - #31

Open
lutyjj wants to merge 1 commit into
hgaiser:mainfrom
lutyjj:fix/av1-keyframe-rc-reset
Open

fix: reset AV1 coding state on every key frame#31
lutyjj wants to merge 1 commit into
hgaiser:mainfrom
lutyjj:fix/av1-keyframe-rc-reset

Conversation

@lutyjj

@lutyjjlutyjj commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

NVIDIA's Vulkan AV1 encoder silently emits undecodable key frames mid-session when rate control is active: the tile data doesn't match the emitted frame header, dav1d and ffmpeg reject the frame with a hard parse error, and every frame until the next key frame is lost with it. Only the first key frame of a session was valid, so any stream using CBR/VBR with on-demand IDRs (game streaming) broke permanently on the first IDR request - in practice a permanent greenscreen the moment the client asks for a recovery key frame (this is the "potential fix" I mentioned in hgaiser/moonshine#156). CQP was unaffected, so CQP-based examples never caught it.

The fix re-issues the coding-state RESET + rate control + quality level control command on every key frame instead of only the first, same shape as the existing first-frame setup. A key frame is a clean restart point, so in theory this is generic and spec-compliant behavior regardless of the vendor (though I tested only on Nvidia). Scoped to active rate control: with rate control disabled there's no state worth resetting, so CQP skips the extra control command entirely.

Verification - new rc_keyframes example following the rfi.rs pattern: AV1 + CBR + gop_size 10 so key frames land mid-stream, then a full-stream ffmpeg decode + PSNR check against the source. On current main it fails at 12.79 dB (the stream decodes but is corrupt from the first mid-stream key frame on - the soft failure mode a plain decode-success check would miss); with this fix it passes at 67.60 dB. Also verified end to end in a real moonshine session (4K/120 AV1): pre-fix greenscreens on the first recovery key frame, post-fix recovers cleanly.

Closeshgaiser/moonshine#155.


Host: NVidia 5060 Ti (driver 610.43.03), Arch

@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from 609cd1e to 116ef31CompareAugust 2, 2026 16:33
@lutyjj

lutyjj commented Aug 2, 2026

Copy link
Copy Markdown
ContributorAuthor

jfyi: the actual fix is ~3 lines in record.rs - the rest of the diff is the rc_keyframes example, so that the issue can be showcased/reproduced without a full streaming setup (fails on main at 12.79 dB, passes with the fix at 67.60 dB).

@lutyjj
lutyjj marked this pull request as draft August 2, 2026 20:18
@lutyjj

Copy link
Copy Markdown
ContributorAuthor

Putting into draft for now. For some reason started observing weird behaviour on AC4 and AV1 + HDR path again. There are no green screen artifacts anymore, but on transitioning from SDR to HDR after intro movies the game now exits fullscreen (on moonlight-qt) and just black-screens. Sound goes, stream is live, but client is unable to decode frames for whatever reason. Wasn't happening few days ago on moonshine-git, need to do a little more debugging there to claim this is the definitive fix.

@lutyjj
lutyjj marked this pull request as ready for review August 5, 2026 18:21
@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from 116ef31 to e49b3a1CompareAugust 5, 2026 18:21
@lutyjj

lutyjj commented Aug 5, 2026

Copy link
Copy Markdown
ContributorAuthor

un-drafting - the black screen wasn't this fix. did a proper bitstream capture this time (dumped the encoded stream host-side at the SDR→HDR transition):

  • stock v0.8.1: the 5 key frames after set_color_description (session params rebuild + IDR) are each invalid in isolation - dav1d refuses them outright (Error decoding frame: Invalid argument, no data decoded), frame-header region near-all-zero. The 6th key frame ~2.2s later decodes fine. That window is exactly the green screen + the client's IDR request loop. Sequence headers parse perfectly btw - it's purely the driver-emitted frame data.
  • v0.8.1 + this fix: single key frame at the transition, decodes 100% clean from a cold start, no IDR loop, no green screen.

turns out the black screen was my test bundle's fault, unrelated to this PR - with this fix in I can't repro it anymore, with or without HDR metadata OBU injection on top (un-gating that injection is a separate fix, hgaiser/moonshine#166).

rebased on main (v0.8.1), rc_keyframes still passes at 67.60 dB (RTX 5060 Ti, driver 610.43.03).

@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from e49b3a1 to 9764c4cCompareAugust 5, 2026 18:50
NVIDIA's Vulkan AV1 encoder silently emits undecodable key frames
mid-session when rate control is active: the tile data doesn't match the
emitted frame header, dav1d/ffmpeg reject the frame with a hard parse
error, and every frame until the next key frame is lost with it. Only
the first key frame of a session was valid, so any stream using CBR/VBR
with on-demand IDRs (game streaming) broke permanently on the first IDR
request. CQP was unaffected, so the CQP-based examples never caught it.
A key frame is a clean restart point, so re-issue the RESET +
ENCODE_RATE_CONTROL + ENCODE_QUALITY_LEVEL control command there (same
shape as the first-frame setup) instead of only on the first frame. In
theory this is generic, spec-compliant behavior regardless of vendor,
though tested only on NVIDIA. Scoped to active rate control: with rate
control disabled there is no state worth resetting, so CQP skips it.
The new rc_keyframes example guards the regression: CBR with a short
GOP, then a full-stream ffmpeg decode + PSNR check. It fails on current
main at 12.79 dB and passes with this fix at 67.60 dB on RTX 5060 Ti
(driver 610.43.03); CQP behavior unchanged.
@DatCaptainHorse

Copy link
Copy Markdown
Contributor

You can never hate NVIDIA enough 😅

Changes look good from quick read, unfortunately got no RTX 2060 anymore to test with, since it was mostly sitting idle draining power, I sold it on the used-market. I'll verify with the RX 9060 XT when I get the chance 👍

@lutyjj

Copy link
Copy Markdown
ContributorAuthor

@hgaiser this PR is still relevant - I'm still observing green screen when using AV1 on SteamMachine as client with Nvidia machine as server. Let me know if I need to adjust anything to get it merged :)

@hgaiserhgaiser left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, took too long to look into this PR, thanks for looking into this issue.

I managed to reproduce this bug with your example, and also by streaming using Moonshine to an Android client (macOS worked fine for some reason).

Two notes:

  1. The rc_keyframes.rs example was useful for debugging, but it should be removed before we merge this PR. It doesn't serve as a useful example in my opinion.
  2. I was getting Vulkan validation errors with this fix:
    Validation Error: [ VUID-vkCmdBeginVideoCodingKHR-pBeginInfo-08253 ] vkCmdBeginVideoCodingKHR(): No VkVideoEncodeRateControlInfoKHR structure was specified when beginning the video coding scope but the currently set video encode rate control mode ... is VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR.
    

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Greenscreen on mid-stream colorspace switch (HDR<->SDR) on AV1 path

3 participants

@lutyjj@DatCaptainHorse@hgaiser
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); fix: reset AV1 coding state on every key frame by lutyjj · Pull Request #31 · hgaiser/pixelforge · GitHub
Skip to content

fix: reset AV1 coding state on every key frame - #31

Open
lutyjj wants to merge 1 commit into
hgaiser:mainfrom
lutyjj:fix/av1-keyframe-rc-reset
Open

fix: reset AV1 coding state on every key frame#31
lutyjj wants to merge 1 commit into
hgaiser:mainfrom
lutyjj:fix/av1-keyframe-rc-reset

Conversation

@lutyjj

@lutyjjlutyjj commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

NVIDIA's Vulkan AV1 encoder silently emits undecodable key frames mid-session when rate control is active: the tile data doesn't match the emitted frame header, dav1d and ffmpeg reject the frame with a hard parse error, and every frame until the next key frame is lost with it. Only the first key frame of a session was valid, so any stream using CBR/VBR with on-demand IDRs (game streaming) broke permanently on the first IDR request - in practice a permanent greenscreen the moment the client asks for a recovery key frame (this is the "potential fix" I mentioned in hgaiser/moonshine#156). CQP was unaffected, so CQP-based examples never caught it.

The fix re-issues the coding-state RESET + rate control + quality level control command on every key frame instead of only the first, same shape as the existing first-frame setup. A key frame is a clean restart point, so in theory this is generic and spec-compliant behavior regardless of the vendor (though I tested only on Nvidia). Scoped to active rate control: with rate control disabled there's no state worth resetting, so CQP skips the extra control command entirely.

Verification - new rc_keyframes example following the rfi.rs pattern: AV1 + CBR + gop_size 10 so key frames land mid-stream, then a full-stream ffmpeg decode + PSNR check against the source. On current main it fails at 12.79 dB (the stream decodes but is corrupt from the first mid-stream key frame on - the soft failure mode a plain decode-success check would miss); with this fix it passes at 67.60 dB. Also verified end to end in a real moonshine session (4K/120 AV1): pre-fix greenscreens on the first recovery key frame, post-fix recovers cleanly.

Closeshgaiser/moonshine#155.


Host: NVidia 5060 Ti (driver 610.43.03), Arch

@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from 609cd1e to 116ef31CompareAugust 2, 2026 16:33
@lutyjj

lutyjj commented Aug 2, 2026

Copy link
Copy Markdown
ContributorAuthor

jfyi: the actual fix is ~3 lines in record.rs - the rest of the diff is the rc_keyframes example, so that the issue can be showcased/reproduced without a full streaming setup (fails on main at 12.79 dB, passes with the fix at 67.60 dB).

@lutyjj
lutyjj marked this pull request as draft August 2, 2026 20:18
@lutyjj

Copy link
Copy Markdown
ContributorAuthor

Putting into draft for now. For some reason started observing weird behaviour on AC4 and AV1 + HDR path again. There are no green screen artifacts anymore, but on transitioning from SDR to HDR after intro movies the game now exits fullscreen (on moonlight-qt) and just black-screens. Sound goes, stream is live, but client is unable to decode frames for whatever reason. Wasn't happening few days ago on moonshine-git, need to do a little more debugging there to claim this is the definitive fix.

@lutyjj
lutyjj marked this pull request as ready for review August 5, 2026 18:21
@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from 116ef31 to e49b3a1CompareAugust 5, 2026 18:21
@lutyjj

lutyjj commented Aug 5, 2026

Copy link
Copy Markdown
ContributorAuthor

un-drafting - the black screen wasn't this fix. did a proper bitstream capture this time (dumped the encoded stream host-side at the SDR→HDR transition):

  • stock v0.8.1: the 5 key frames after set_color_description (session params rebuild + IDR) are each invalid in isolation - dav1d refuses them outright (Error decoding frame: Invalid argument, no data decoded), frame-header region near-all-zero. The 6th key frame ~2.2s later decodes fine. That window is exactly the green screen + the client's IDR request loop. Sequence headers parse perfectly btw - it's purely the driver-emitted frame data.
  • v0.8.1 + this fix: single key frame at the transition, decodes 100% clean from a cold start, no IDR loop, no green screen.

turns out the black screen was my test bundle's fault, unrelated to this PR - with this fix in I can't repro it anymore, with or without HDR metadata OBU injection on top (un-gating that injection is a separate fix, hgaiser/moonshine#166).

rebased on main (v0.8.1), rc_keyframes still passes at 67.60 dB (RTX 5060 Ti, driver 610.43.03).

@lutyjj
lutyjjforce-pushed the fix/av1-keyframe-rc-reset branch from e49b3a1 to 9764c4cCompareAugust 5, 2026 18:50
NVIDIA's Vulkan AV1 encoder silently emits undecodable key frames
mid-session when rate control is active: the tile data doesn't match the
emitted frame header, dav1d/ffmpeg reject the frame with a hard parse
error, and every frame until the next key frame is lost with it. Only
the first key frame of a session was valid, so any stream using CBR/VBR
with on-demand IDRs (game streaming) broke permanently on the first IDR
request. CQP was unaffected, so the CQP-based examples never caught it.
A key frame is a clean restart point, so re-issue the RESET +
ENCODE_RATE_CONTROL + ENCODE_QUALITY_LEVEL control command there (same
shape as the first-frame setup) instead of only on the first frame. In
theory this is generic, spec-compliant behavior regardless of vendor,
though tested only on NVIDIA. Scoped to active rate control: with rate
control disabled there is no state worth resetting, so CQP skips it.
The new rc_keyframes example guards the regression: CBR with a short
GOP, then a full-stream ffmpeg decode + PSNR check. It fails on current
main at 12.79 dB and passes with this fix at 67.60 dB on RTX 5060 Ti
(driver 610.43.03); CQP behavior unchanged.
@DatCaptainHorse

Copy link
Copy Markdown
Contributor

You can never hate NVIDIA enough 😅

Changes look good from quick read, unfortunately got no RTX 2060 anymore to test with, since it was mostly sitting idle draining power, I sold it on the used-market. I'll verify with the RX 9060 XT when I get the chance 👍

@lutyjj

Copy link
Copy Markdown
ContributorAuthor

@hgaiser this PR is still relevant - I'm still observing green screen when using AV1 on SteamMachine as client with Nvidia machine as server. Let me know if I need to adjust anything to get it merged :)

@hgaiserhgaiser left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, took too long to look into this PR, thanks for looking into this issue.

I managed to reproduce this bug with your example, and also by streaming using Moonshine to an Android client (macOS worked fine for some reason).

Two notes:

  1. The rc_keyframes.rs example was useful for debugging, but it should be removed before we merge this PR. It doesn't serve as a useful example in my opinion.
  2. I was getting Vulkan validation errors with this fix:
    Validation Error: [ VUID-vkCmdBeginVideoCodingKHR-pBeginInfo-08253 ] vkCmdBeginVideoCodingKHR(): No VkVideoEncodeRateControlInfoKHR structure was specified when beginning the video coding scope but the currently set video encode rate control mode ... is VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR.
    

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Greenscreen on mid-stream colorspace switch (HDR<->SDR) on AV1 path

3 participants

@lutyjj@DatCaptainHorse@hgaiser