Skip to content

feat: Add media foundation backend#180

Draft
OleRoss wants to merge 15 commits into
kekyo:mainfrom
OleRoss:feat/add-media-foundation-backend
Draft

feat: Add media foundation backend#180
OleRoss wants to merge 15 commits into
kekyo:mainfrom
OleRoss:feat/add-media-foundation-backend

Conversation

@OleRoss

@OleRoss OleRoss commented Jul 17, 2026

Copy link
Copy Markdown

I decided to follow your suggestion in #179 and implement the Media Framework backend in a separate PR before we go for complete AOT compatibility.

How it was implemented

The WMF backend is now implemented for netstandard2.0, netstandard2.1, net48, net5.0, and newer.

I am using CsWin32 with raw, unsafe bindings. That allows me not to use the GeneratedComInterface I mentioned before, which should solve the issue of being restricted to >= net8.0 🥳 (sry, I did not know before).

The COM implementation in FlashCap is consistent: our policy is to either manually configure the automatically generated code or write it entirely by hand.

Since we generate very low-level bindings, are you fine with using CsWin32 here? You can configure the output a lot to your requirements:

{
  "$schema": "https://aka.ms/CsWin32.schema.json",
  "allowMarshaling": false, // The Win32 generator emits only raw, blittable structs with COM interfaces being emitted as interfaces. This gives us AOT compatibility
  "friendlyOverloads": {
    "enabled": true, // Enables generation of overloads with e.g., out parameters, ...
    "comOutPtrGenericOverloads": false // We don't require the generic overloads so this reduces compilation overhead
  },
  "useSafeHandles": false, // Enables (or requires :D) explicit control over cleanup, ...
  "comInterop": {
    "preserveSigMethods": [ "*" ] // Methods return their native HRESULT, ...
  }
}

Short Disclaimer: While I reviewed the code and the architecture, and the higher-level code comes from me, the details of the Media Framework interop were implemented by AI. I tested the code in both the Avalonia app on net48 and net8.0, as well as our production project published with AOT, and so far it seems to work.

Additional libraries

The netstandard2.0 and net48 targets now depends on System.Memory and System.Runtime.CompilerServices.Unsafe. This requirement comes straight from CsWin32. If you would like to avoid this, I suggest dropping the netstandard2.0/net48 support for WMF.

Breaking change

There are no breaking changes I am aware of. However, right now, we annotate OnEnumerateDescriptors with RequiresUnreferencedCode and then manually ignore that in the MediaFoundationCaptureDevices overwrite. This kinda works, but it's really not nice. Its probably best to think of a better API here in the future which allowes different backends to have different annotations regarding trimming capabilities.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6d408abdfb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread FlashCap.Core/CaptureDevices.cs Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c0e9858729

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

var rows = checked(height + (format == PixelFormats.NV12 ? (height + 1) / 2 : 0));
var rgb = format is PixelFormats.RGB15 or PixelFormats.RGB16 or
PixelFormats.RGB24 or PixelFormats.RGB32 or PixelFormats.ARGB32;
var bottomUp = defaultStride < 0 || defaultStride is null && rgb;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Calculate the missing Media Foundation stride

When a capture media type does not include MF_MT_DEFAULT_STRIDE, ConfigureReader passes null into this code and the defaultStride is null && rgb branch assumes RGB buffers are bottom-up. Media Foundation's uncompressed-buffer guidance says to calculate the default stride when the attribute is absent because the stride sign carries top-down vs. bottom-up orientation; on RGB cameras that omit the attribute this will normalize frames with the wrong row order and produce vertically flipped images. Use MFGetStrideForBitmapInfoHeader or another explicit orientation source instead of treating null as bottom-up.

Useful? React with 👍 / 👎.

…ng COM

COM Interfaces do not require dynamic code but unreferenced code. That means they are relevant for trimming as well, not just for aot
@OleRoss
OleRoss marked this pull request as draft July 20, 2026 08:50
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.

1 participant