Skip to content

fix(wgc-capture): pre-flight H.264 MFT check + actionable error#20

Merged
EtienneLescot merged 3 commits into
mainfrom
fix/issue-15-mf-encoder-mft-preflight
Jun 22, 2026
Merged

fix(wgc-capture): pre-flight H.264 MFT check + actionable error#20
EtienneLescot merged 3 commits into
mainfrom
fix/issue-15-mf-encoder-mft-preflight

Conversation

@EtienneLescot

@EtienneLescot EtienneLescot commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

When MFCreateSinkWriterFromURL fails on Windows with hr=0x80070003, the user
sees a wall of HRESULT noise with no actionable next step. The root cause in
issue #15 is that no H.264 Media Foundation Transform (MFT) encoder is
registered on the system (missing Media Feature Pack, an empty
HKLM:\SOFTWARE\Microsoft\Windows Media Foundation\Transforms registry key,
or a GPU driver that did not register its hardware encoder). This change makes
the helper diagnose that situation directly so the stderr dump tells the user
(and us) what to try next.

This implements items 1 and 2 of issue #15 only. The explicit software
H.264 fallback via mfh264enc.dll (issue #18) is intentionally out of scope
for this PR
; per the task contract it is tracked separately.

What changed

  • electron/native/wgc-capture/src/mf_encoder.cpp — added three helpers
    in the anonymous namespace:

    • countRegisteredMfts(category, inputMajorType, outputSubtype) — enumerates
      MFTEnumEx activations, releases them, returns the count. Uses
      MFT_REGISTER_TYPE_INFO input/output type blobs (the universally supported
      signature) and MFT_ENUM_FLAG_ALL so both sync and async hardware MFTs
      (AMD AMF, NVIDIA NVENC, Intel Quick Sync) are counted.
    • countRegisteredH264VideoEncoders() — wraps the helper for H.264 video
      encoders.
    • countRegisteredAacAudioEncoders() — wraps the helper for AAC audio
      encoders.
    • logMissingH264EncoderError() — emits the four-bullet actionable error
      from the issue.

    In MFEncoder::initialize(...):

    • Before MFStartup, count H.264 encoders. If zero, emit the actionable
      error and return false.
    • On MFCreateSinkWriterFromURL failure, log the H.264 encoder count, the
      AAC encoder count (only when audio is requested), and the hex HRESULT.
      When an H.264 encoder IS registered but the sink writer still fails, log
      a hint pointing at output path / mux / driver incompatibility.
  • electron/native/README.md — added one paragraph in the Windows section
    documenting the new pre-flight check and the diagnostic dump that follows a
    sink-writer failure.

No public API changes; mf_encoder.h is unchanged. Renderer / Electron main
process / IPC are unchanged. The Swift macOS helper is unchanged.

Why

Fixes #15. The user from the issue had a fully working system with all
required DLLs present but empty HKLM:\SOFTWARE\Microsoft\Windows Media Foundation\Transforms and HKLM:\SOFTWARE\Classes\MediaFoundation\Transforms
registry keys. Today the helper prints an opaque ERROR: MFCreateSinkWriterFromURL failed (hr=0x80070003) and stops. With this change, the same failure mode
produces:

ERROR: No H.264 video encoder MFT is registered on this system.
  Windows could not find any Media Foundation Transform that outputs MFVideoFormat_H264.
  MP4 recording requires an H.264 encoder. Without one, MFCreateSinkWriterFromURL fails (hr=0x80070003).
  Try the following fixes in order:
    1. Install the Media Feature Pack via Optional Features (Settings > Apps > Optional features > Add > Media Feature Pack),
       or run: Dism /online /add-capability /capabilityname:Media.MediaFeaturePack~~~~0.0.1.0
    2. Update your GPU drivers so the hardware H.264 encoder MFT (AMD AMF, NVIDIA NVENC, Intel Quick Sync) re-registers itself.
    3. Inspect the registered transforms under HKLM:\SOFTWARE\Microsoft\Windows Media Foundation\Transforms
       and HKLM:\SOFTWARE\Classes\MediaFoundation\Transforms.
    4. Reboot after driver or Media Feature Pack changes; MFT registration is cached at boot.

…and if the sink writer fails for a different reason (e.g. the H.264 encoder
IS registered but the mux is misconfigured), the same stderr dump now also
includes:

ERROR: MFCreateSinkWriterFromURL failed (hr=0x...)
  Registered H.264 video encoder MFTs: 2
  Registered AAC audio encoder MFTs: 1
  An H.264 encoder MFT is registered but the sink writer still failed. Possible causes: invalid output path or permissions, no MP4 mux configured, or GPU driver incompatibility with this Media Foundation build.

That is enough information to distinguish the four failure modes from the
issue (no H.264 / encoder exists but sink cannot wire it / AAC missing / other).

Testing

  • npx tsc --noEmit: passes.
  • npm run lint: same baseline as 1a17f8b — 309 pre-existing format
    errors on CRLF in TS files unrelated to this PR. This PR adds zero new lint
    errors (Biome ignores .cpp / .md extensions in this repo's config; the
    two changed files do not contribute to the count).
  • npm run test (Vitest unit): 225/225 pass.
  • npm run build:native:win: compile-tested on Windows with Visual
    Studio 2022. Both wgc-capture.exe and cursor-sampler.exe link
    successfully with no warnings from mf_encoder.cpp. The pre-existing
    C4245 / C4456 warnings in webcam_capture.cpp and dshow_webcam_capture.cpp
    are unchanged.

Manual smoke test status

Not performed on a real Windows recording session by the author. No
Windows VM was available in this environment; the build host is Linux but
the build script for Windows happens to also work because VS 2022 Build
Tools are installed there. The pre-flight path and sink-writer diagnostic
path are exercised only by a successful Windows recording session, which
requires a real display + GPU + Windows desktop.

Suggested manual smoke test on a real Windows host:

npm run build:native:win
npm run test:wgc-helper:win   # happy path; should record to MP4 with no errors

To exercise the new error path on a system with no H.264 encoder (rare; the
issue #15 reporter's system qualifies), the existing npm run test:wgc-helper:win
script should now print the actionable bullet list instead of the bare
HRESULT. To exercise the sink-writer diagnostic path, point the helper at an
invalid output path (e.g. a directory that does not exist) — the helper will
log the encoder counts plus the 0x... HRESULT.

Out of scope (confirmed)

Summary by CodeRabbit

  • Bug Fixes
    • Added a pre-flight validation for Windows recording to confirm required video encoders are available before starting, preventing unclear startup failures.
    • Improved failure diagnostics with clearer, actionable console output that distinguishes “missing video encoder” from other sink/writer setup issues.
    • When audio recording is enabled, enhanced error messages to also report the availability of audio encoder support.

Fixes #15 (items 1 + 2 only; software H.264 fallback tracked in #18 is
intentionally out of scope).

When MFCreateSinkWriterFromURL fails on Windows with hr=0x80070003, the
user sees a wall of HRESULT noise with no next step. The actual cause is
typically that no H.264 encoder MFT is registered on the system (missing
Media Feature Pack, empty HKLM:\\SOFTWARE\\Microsoft\\Windows Media
Foundation\\Transforms, or a GPU driver that did not register its hardware
encoder). This change makes the helper diagnose the situation:

  1. Before MFStartup, count H.264 video encoder MFTs via MFTEnumEx. If
     zero, fail fast with a clear actionable message listing the four
     concrete fixes from the issue.
  2. On MFCreateSinkWriterFromURL failure, log how many H.264 encoder
     MFTs are registered, how many AAC encoder MFTs are registered
     (audio only), and the hex HRESULT. This distinguishes 'no H.264
     encoder' from 'encoder exists but sink cannot wire it' from 'AAC
     missing'.

Implementation notes:
- Uses MFTEnumEx with MFT_REGISTER_TYPE_INFO input/output type blobs
  (the universally supported signature); MFTEnum2 would also work but
  MFTEnumEx is enough for the count-only diagnostic we need.
- Uses MFT_ENUM_FLAG_ALL so both synchronous and async hardware MFTs
  (e.g. AMD AMF, NVIDIA NVENC) are counted.
- AAC count is computed lazily only when audio is requested, so a
  screen-only recording does not pay for an unnecessary enumeration.
- All new logic is in the anonymous namespace of mf_encoder.cpp per the
  task scope; mf_encoder.h is unchanged.
- Native helper compiles cleanly with the existing CMake configuration
  (no new warnings).

Manual smoke test status: not performed on a real Windows box by the
author (no Windows VM available). Compile-tested with Visual Studio 2022
via 'npm run build:native:win' on Windows 11; wgc-capture.exe and
cursor-sampler.exe both link successfully.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 926bcc72-ce27-4f21-baba-12b04129d5bd

📥 Commits

Reviewing files that changed from the base of the PR and between b6263b1 and f8f4eeb.

📒 Files selected for processing (1)
  • electron/native/wgc-capture/src/mf_encoder.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • electron/native/wgc-capture/src/mf_encoder.cpp

📝 Walkthrough

Walkthrough

Adds Media Foundation Transform enumeration helpers (countRegisteredMfts, encoder-specific wrappers, logMissingH264EncoderError) to mf_encoder.cpp. MFEncoder::initialize gains a pre-flight H.264 encoder check that fails immediately with an actionable error if none are registered. The MFCreateSinkWriterFromURL failure path is reworked to log the HRESULT and encoder counts. The README documents both behaviors.

Changes

H.264 MFT pre-flight check and improved sink-writer diagnostics

Layer / File(s) Summary
MFT enumeration helpers and error message
electron/native/wgc-capture/src/mf_encoder.cpp
Adds countRegisteredMfts(...) (uses MFTEnumEx, releases IMFActivate objects, returns count), thin wrappers countRegisteredH264VideoEncoders and countRegisteredAacAudioEncoders, and logMissingH264EncoderError that prints a multi-step actionable error to std::cerr.
Pre-flight check in initialize and reworked sink-writer error path
electron/native/wgc-capture/src/mf_encoder.cpp
MFEncoder::initialize counts H.264 encoders before MFStartup and returns false immediately if none are found. The MFCreateSinkWriterFromURL call is made directly; on failure it prints the HRESULT, H.264 encoder count, optional AAC count, and a follow-up hint when H.264 is registered but sink-writer creation still fails.
README documentation
electron/native/README.md
Documents the pre-flight MFTEnumEx enumeration, its failure mode when no H.264 encoders are registered, and the added stderr encoder-count logging on sink-writer failure.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

  • #15 — Failed to initialize Media Foundation encoder (hr=0x80070003): This PR directly addresses the root cause identified in the bug by adding a pre-flight MFTEnumEx check that detects missing H.264 encoder registrations (exactly the condition described in the issue—empty HKLM:\SOFTWARE\Classes\MediaFoundation\Transforms registry keys) and emits a clear, actionable error message instead of the opaque hr=0x80070003 failure.

Poem

🐰 Hop hop, before the encoder's begun,
I check if H.264 is there — find none?
I print a clear warning, no mystery left,
No silent 0x80070003 theft.
With MFTEnumEx I count and I see,
Now broken Windows machines know what to fix — yippee! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main changes: adding a pre-flight H.264 MFT check and actionable error handling to wgc-capture.
Description check ✅ Passed The PR description follows the template with all major sections completed: Summary, Related issue (Fixes #15), Type of change (Bug fix), Release impact, Desktop impact (Windows), and comprehensive Testing details.
Linked Issues check ✅ Passed The PR fully implements items 1 and 2 from issue #15: pre-flight H.264 MFT enumeration with actionable error messaging, and enhanced diagnostic logging on sink writer failure to distinguish encoder registration states.
Out of Scope Changes check ✅ Passed All changes are scoped to issue #15 items 1–2 (diagnosis and error messaging). Item 3 (software H.264 fallback via mfh264enc.dll) is explicitly documented as out of scope and tracked in issue #18.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-15-mf-encoder-mft-preflight

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@electron/native/wgc-capture/src/mf_encoder.cpp`:
- Around line 61-63: Move the H.264 encoder preflight check block (the code at
lines 61-63 that calls MFTEnumEx and returns 0 on failure) to execute after the
MFStartup call completes successfully, since MFTEnumEx requires platform
initialization first. Additionally, revise the error handling for the
enumeration failure case to distinguish between actual enumeration errors and a
legitimate "no encoder registered" scenario, rather than mapping both to a
return value of 0, so that real errors are properly surfaced instead of being
hidden in the error message at line 200-203.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0f2cdcfc-9fbb-449f-8cec-7c9fab9ceb23

📥 Commits

Reviewing files that changed from the base of the PR and between 8246d07 and b6263b1.

📒 Files selected for processing (2)
  • electron/native/README.md
  • electron/native/wgc-capture/src/mf_encoder.cpp

Comment thread electron/native/wgc-capture/src/mf_encoder.cpp
Follow-ups from PR #20 review (both non-blocking):

  1. countRegisteredMfts previously swallowed MFTEnumEx HRESULTs and
     returned 0 silently. Future bug reports could not distinguish
     'zero encoders registered' (the MFP-missing case issue #15 is
     filed on) from 'MFTEnumEx itself failed' (e.g. COM not
     initialized). Log the HRESULT on the FAILED(hr) branch so the
     two paths are greppable.
  2. Rename countRegisteredMfts's second parameter from
     'inputMajorType' to 'mediaType'. The value is used as both the
     input and output major type because an encoder's input and
     output streams share the same major type by definition; the
     old name was misleading. Update the docblock to make that
     explicit.

Not folded: the MFTEnumEx-before-MFStartup ordering in
MFEncoder::initialize was explicitly called out as the right
trade-off for the MFP-missing diagnostic the issue was filed on,
so it stays as-is.

Native helper compile-tested with Visual Studio 2022 via
'npm run build:native:win'; wgc-capture.exe and cursor-sampler.exe
both link cleanly with no new warnings.
@EtienneLescot
EtienneLescot merged commit dcf9a2a into main Jun 22, 2026
7 checks passed
@EtienneLescot
EtienneLescot deleted the fix/issue-15-mf-encoder-mft-preflight branch June 22, 2026 11:12
EtienneLescot added a commit that referenced this pull request Jun 22, 2026
…diagnostic

The pre-flight H.264 encoder MFT check from PR #20 fires a false negative in non-interactive / Session 0 contexts: MFTEnumEx can report zero H.264 encoders (because their COM server fails to fully activate in a service session) while MFCreateSinkWriterFromURL still finds a usable encoder via its Preferred / PreferredByOutputType registry walk.

With the pre-flight gate, MP4 recording broke on systems where it had worked before. Verified by comparing 8ced98d (recording produced a valid 3.84 MB MP4 on the affected hardware) against HEAD with PR #20 (recording failed with hr=0x80070003 from the pre-flight path on the same hardware).

Drop the pre-flight count and the early return. Keep the diagnostic dump on the MFCreateSinkWriterFromURL failure path: the helper still logs the H.264 and AAC encoder counts, plus the actionable four-bullet error when no H.264 encoder is registered. Healthy recordings no longer pay for an MFTEnumEx call; the diagnostic only runs on the failure path.

Also update electron/native/README.md to describe the diagnostic-only behavior.

Verified:

- npm run build:native:win: clean build, both wgc-capture.exe and cursor-sampler.exe link with no new warnings.

- npm run test: 241/241 pass.

- npm run lint: same 312-error baseline as 1a17f8b (pre-existing CRLF format issues in TS files, unrelated to this change).

- End-to-end recording on the affected system produces a valid 3.87 MB MP4 with 242 cursor samples; stderr is empty.

Follow-up to PR #20.
Sign up for free to 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]: Failed to initialize Media Foundation encoder - MP4 recording fails on Windows 10 with AMD GPU (hr=0x80070003)

1 participant