Skip to content

Add CameraFeed support for Windows#108538

Open
shiena wants to merge 1 commit intogodotengine:masterfrom
shiena:feature/support-windows-camera
Open

Add CameraFeed support for Windows#108538
shiena wants to merge 1 commit intogodotengine:masterfrom
shiena:feature/support-windows-camera

Conversation

@shiena
Copy link
Copy Markdown
Contributor

@shiena shiena commented Jul 11, 2025

Following #105476

This adds CameraFeed support for Windows.
The added implementation includes:


@shiena shiena requested review from a team as code owners July 11, 2025 23:22
@shiena shiena changed the title Feature/support windows camera Add CameraFeed support for Windows Jul 11, 2025
@shiena shiena force-pushed the feature/support-windows-camera branch from 3224072 to c86119e Compare July 11, 2025 23:25
@AThousandShips AThousandShips added this to the 4.x milestone Jul 12, 2025
@shiena shiena force-pushed the feature/support-windows-camera branch 3 times, most recently from aab5a80 to 1563b1b Compare July 17, 2025 21:12
@shiena shiena force-pushed the feature/support-windows-camera branch from 1563b1b to c0b419d Compare July 19, 2025 09:16
@vonweller
Copy link
Copy Markdown

I want to know how much longer we need to wait for camera support on Windows (:

@Calinou
Copy link
Copy Markdown
Member

Calinou commented Aug 4, 2025

I want to know how much longer we need to wait for camera support on Windows (:

4.5 is in feature freeze, so new features can only be merged in 4.6 at the earliest.

If you need this feature right now, you can compile a custom build from the fork's branch (remember to compile both the editor and Windows export templates if you're exporting the project).

@shiena shiena force-pushed the feature/support-windows-camera branch from c0b419d to ad4f88d Compare August 11, 2025 15:44
@shiena shiena force-pushed the feature/support-windows-camera branch 2 times, most recently from b191f1f to 0fda140 Compare September 1, 2025 16:30
AlexOkafor added a commit to AlexOkafor/godot that referenced this pull request Sep 5, 2025

// need to add something that will react to devices being connected/removed...
void CameraWindows::set_monitoring_feeds(bool p_monitoring_feeds) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hello! Was testing this on my windows machine and ran into an infinite loop. It appears in the other platforms there's a check to see if we're actually changing the feed monitoring status and returning early:

if (p_monitoring_feeds == monitoring_feeds) {
	return;
}

Without if you do a CameraTexture.new() it'll invoke set_monitoring_feed(true), which in turn will trigger the update feed signals, etc:

CameraTexture::CameraTexture() {
	// Note: When any CameraTexture is created, we need to automatically activate monitoring
	//       of camera feeds. This may incur a small lag spike, so it may be preferable to
	//       enable it manually before creating the camera texture.
	CameraServer::get_singleton()->set_monitoring_feeds(true);
}

and any code (like allocating a camera texture) in those signal handlers will trigger it again.

Comment thread modules/camera/camera_win.cpp Outdated

// need to add something that will react to devices being connected/removed...
void CameraWindows::set_monitoring_feeds(bool p_monitoring_feeds) {
monitoring_feeds = p_monitoring_feeds;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

might be worth calling CameraServer::set_monitoring_feeds(p_monitoring_feeds); instead of direct assignment for consistency as the other platforms?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thank you for the review. I've fixed set_monitoring_feeds to follow the same processing pattern as other platforms.

@shiena shiena force-pushed the feature/support-windows-camera branch 4 times, most recently from e720563 to 3ef5fd5 Compare September 6, 2025 14:59
Copy link
Copy Markdown
Member

@Calinou Calinou left a comment

Choose a reason for hiding this comment

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

Tested locally on Windows 11 24H2 with a Logitech C922 Pro webcam, it works as expected. Code looks good to me (aside of the requested style changes).

Performance seems good (I can use the 1280x720 @ 60 FPS or 1920x1080 @ 30 FPS modes without issue, while the project still renders at 240 FPS with V-Sync). Note that certain webcams will decrease their effective FPS in low light conditions to improve brightness, so you may have to disable this feature in the webcam's settings to ensure you see the maximum framerate of the stream.

List of formats available in https://github.com/shiena/godot-camerafeed-demo:

Details
UY2 - 640x480 : 1 / 30
YUY2 - 640x480 : 1 / 24
YUY2 - 640x480 : 1 / 20
YUY2 - 640x480 : 1 / 15
YUY2 - 640x480 : 1 / 10
YUY2 - 640x480 : 1333333 / 10000000
YUY2 - 640x480 : 1 / 5
YUY2 - 160x90 : 1 / 30
YUY2 - 160x90 : 1 / 24
YUY2 - 160x90 : 1 / 20
YUY2 - 160x90 : 1 / 15
YUY2 - 160x90 : 1 / 10
YUY2 - 160x90 : 1333333 / 10000000
YUY2 - 160x90 : 1 / 5
YUY2 - 160x120 : 1 / 30
YUY2 - 160x120 : 1 / 24
YUY2 - 160x120 : 1 / 20
YUY2 - 160x120 : 1 / 15
YUY2 - 160x120 : 1 / 10
YUY2 - 160x120 : 1333333 / 10000000
YUY2 - 160x120 : 1 / 5
YUY2 - 176x144 : 1 / 30
YUY2 - 176x144 : 1 / 24
YUY2 - 176x144 : 1 / 20
YUY2 - 176x144 : 1 / 15
YUY2 - 176x144 : 1 / 10
YUY2 - 176x144 : 1333333 / 10000000
YUY2 - 176x144 : 1 / 5
YUY2 - 320x180 : 1 / 30
YUY2 - 320x180 : 1 / 24
YUY2 - 320x180 : 1 / 20
YUY2 - 320x180 : 1 / 15
YUY2 - 320x180 : 1 / 10
YUY2 - 320x180 : 1333333 / 10000000
YUY2 - 320x180 : 1 / 5
YUY2 - 320x240 : 1 / 30
YUY2 - 320x240 : 1 / 24
YUY2 - 320x240 : 1 / 20
YUY2 - 320x240 : 1 / 15
YUY2 - 320x240 : 1 / 10
YUY2 - 320x240 : 1333333 / 10000000
YUY2 - 320x240 : 1 / 5
YUY2 - 352x288 : 1 / 30
YUY2 - 352x288 : 1 / 24
YUY2 - 352x288 : 1 / 20
YUY2 - 352x288 : 1 / 15
YUY2 - 352x288 : 1 / 10
YUY2 - 352x288 : 1333333 / 10000000
YUY2 - 352x288 : 1 / 5
YUY2 - 432x240 : 1 / 30
YUY2 - 432x240 : 1 / 24
YUY2 - 432x240 : 1 / 20
YUY2 - 432x240 : 1 / 15
YUY2 - 432x240 : 1 / 10
YUY2 - 432x240 : 1333333 / 10000000
YUY2 - 432x240 : 1 / 5
YUY2 - 640x360 : 1 / 30
YUY2 - 640x360 : 1 / 24
YUY2 - 640x360 : 1 / 20
YUY2 - 640x360 : 1 / 15
YUY2 - 640x360 : 1 / 10
YUY2 - 640x360 : 1333333 / 10000000
YUY2 - 640x360 : 1 / 5
YUY2 - 800x448 : 1 / 30
YUY2 - 800x448 : 1 / 24
YUY2 - 800x448 : 1 / 20
YUY2 - 800x448 : 1 / 15
YUY2 - 800x448 : 1 / 10
YUY2 - 800x448 : 1333333 / 10000000
YUY2 - 800x448 : 1 / 5
YUY2 - 800x600 : 1 / 24
YUY2 - 800x600 : 1 / 20
YUY2 - 800x600 : 1 / 15
YUY2 - 800x600 : 1 / 10
YUY2 - 800x600 : 1333333 / 10000000
YUY2 - 800x600 : 1 / 5
YUY2 - 864x480 : 1 / 24
YUY2 - 864x480 : 1 / 20
YUY2 - 864x480 : 1 / 15
YUY2 - 864x480 : 1 / 10
YUY2 - 864x480 : 1333333 / 10000000
YUY2 - 864x480 : 1 / 5
YUY2 - 960x720 : 1 / 15
YUY2 - 960x720 : 1 / 10
YUY2 - 960x720 : 1333333 / 10000000
YUY2 - 960x720 : 1 / 5
YUY2 - 1024x576 : 1 / 15
YUY2 - 1024x576 : 1 / 10
YUY2 - 1024x576 : 1333333 / 10000000
YUY2 - 1024x576 : 1 / 5
YUY2 - 1280x720 : 1 / 10
YUY2 - 1280x720 : 1333333 / 10000000
YUY2 - 1280x720 : 1 / 5
YUY2 - 1600x896 : 1333333 / 10000000
YUY2 - 1600x896 : 1 / 5
YUY2 - 1920x1080 : 1 / 5
YUY2 - 2304x1296 : 2499999 / 5000000
YUY2 - 2304x1536 : 2499999 / 5000000
NV12 - 800x600 : 1 / 30
NV12 - 864x480 : 1 / 30
NV12 - 960x720 : 1 / 30
NV12 - 960x720 : 1 / 24
NV12 - 960x720 : 1 / 20
NV12 - 1024x576 : 1 / 30
NV12 - 1024x576 : 1 / 24
NV12 - 1024x576 : 1 / 20
NV12 - 1280x720 : 1 / 30
NV12 - 1280x720 : 1 / 60
NV12 - 1280x720 : 1 / 24
NV12 - 1280x720 : 1 / 20
NV12 - 1280x720 : 1 / 15
NV12 - 1600x896 : 1 / 30
NV12 - 1600x896 : 1 / 24
NV12 - 1600x896 : 1 / 20
NV12 - 1600x896 : 1 / 15
NV12 - 1600x896 : 1 / 10
NV12 - 1920x1080 : 1 / 30
NV12 - 1920x1080 : 1 / 24
NV12 - 1920x1080 : 1 / 20
NV12 - 1920x1080 : 1 / 15
NV12 - 1920x1080 : 1 / 10
NV12 - 1920x1080 : 1333333 / 10000000

Note that if another app is reading the webcam, you get this error:

E 0:00:08:423   CameraFeedWindows::read: ReadSample failed: 0xc00d3704
  <C++ Source>  modules\camera\camera_win.cpp:492 @ CameraFeedWindows::read()

We could perhaps detect this specific error code and display a human-readable message for it:

Check that no other applications are currently using the camera.

Comment thread modules/camera/camera_win.cpp Outdated
Comment thread modules/camera/camera_win.cpp Outdated
Comment thread modules/camera/camera_win.cpp Outdated
Comment thread modules/camera/camera_win.cpp Outdated
Comment thread modules/camera/camera_win.cpp Outdated
Comment thread modules/camera/camera_win.cpp Outdated
Comment thread modules/camera/camera_win.cpp Outdated
Comment thread modules/camera/camera_win.cpp Outdated
Comment thread modules/camera/camera_win.cpp Outdated
Comment thread modules/camera/camera_win.cpp Outdated
@shiena shiena force-pushed the feature/support-windows-camera branch 3 times, most recently from 843617e to a899268 Compare September 9, 2025 08:19
@shiena shiena force-pushed the feature/support-windows-camera branch 3 times, most recently from d00b9f5 to 8659d11 Compare November 27, 2025 13:32
@shiena
Copy link
Copy Markdown
Contributor Author

shiena commented Nov 27, 2025

@AThousandShips
Thanks for the review. I've applied all your suggestions.

@shiena shiena force-pushed the feature/support-windows-camera branch 2 times, most recently from 553939c to d66722a Compare November 28, 2025 19:41
@gaudimancer-creator
Copy link
Copy Markdown

It looks nice ! Do you know when this will be added ? I kinda need it for a team project but I don't have any skill with compiling.

@shiena
Copy link
Copy Markdown
Contributor Author

shiena commented Dec 24, 2025

@gaudimancer-creator
Since 4.6 is currently in feature freeze, if this gets merged, it would be for 4.7 or later.

@gaudimancer-creator
Copy link
Copy Markdown

@shiena
Okayyy thank you !
Since I need it quickly, I will try to compile this. Any advice ?

@shiena shiena force-pushed the feature/support-windows-camera branch 3 times, most recently from a279902 to 1460278 Compare January 4, 2026 14:27
@shiena shiena force-pushed the feature/support-windows-camera branch 2 times, most recently from be93939 to 0e8527e Compare January 7, 2026 04:56
@gaudimancer-creator
Copy link
Copy Markdown

I want to know how much longer we need to wait for camera support on Windows (:

I found out that you can actually download the release related to a commit with the new Actions tab :
image
so what I basically did is that I searched the last commit of the PR and I downloaded the windows-editor :
https://github.com/godotengine/godot/actions/runs/20771073072
Have a good day yall

@shiena shiena force-pushed the feature/support-windows-camera branch 3 times, most recently from 658596c to 513097c Compare January 29, 2026 14:08
@AThousandShips
Copy link
Copy Markdown
Member

No it isn't?

Please don't bump without contributing significant new information. Use the 👍 reaction button on the first post instead.

@brandonhare
Copy link
Copy Markdown
Contributor

I gave this a try and found a crash with my setup, but I was able to find a fix and I've submitted a PR for this PR here: shiena#2
Everything seems to work great otherwise!

@shiena shiena force-pushed the feature/support-windows-camera branch from 513097c to 5a34df5 Compare February 11, 2026 20:55
@shiena
Copy link
Copy Markdown
Contributor Author

shiena commented Feb 11, 2026

@brandonhare Thank you for reporting the crash and your detailed investigation!

I've applied a fix based on your findings, but with a more fundamental approach instead of the workaround in your PR.

The issue:
IMF2DBuffer::Lock2D returns ppbScanline0 pointing to the last row and a negative pitch for bottom-up (flipped)
images.

Your proposed fix (workaround):
Detect flipped images and manually adjust the pointer back to the buffer start.

Applied fix (fundamental approach):
Use the pitch value directly as Microsoft recommends: scan_line0 + y * pitch. When pitch is negative, this naturally
iterates backward through the buffer, eliminating the need for manual flip detection.

Additionally, I found that the buffer->Lock() fallback path also requires bottom-up handling when using Media Foundation
conversion (RGB format).

@shiena shiena force-pushed the feature/support-windows-camera branch from 5a34df5 to 752bda3 Compare March 5, 2026 12:44
@shiena shiena force-pushed the feature/support-windows-camera branch 2 times, most recently from b95a29c to 8aa01eb Compare March 22, 2026 17:49
@shiena shiena force-pushed the feature/support-windows-camera branch from 8aa01eb to bdff61f Compare March 31, 2026 16:45
@shiena shiena force-pushed the feature/support-windows-camera branch 2 times, most recently from 8cbabc4 to f476000 Compare April 11, 2026 17:17
Implements camera capture using Media Foundation (IMFSourceReader).
Supports NV12, YUY2, and RGB24 formats via BufferDecoder pipeline.
RGB24 uses BGR byte order per DirectShow convention, so BGR-to-RGB
conversion is applied. Image orientation is detected via IMF2DBuffer
pitch sign (negative = top-down).

Reference: https://learn.microsoft.com/en-us/windows/win32/directshow/uncompressed-rgb-video-subtypes

Co-authored-by: Leo de Penning <leo.depenning@illuminoo.com>
Co-authored-by: Andrés Botero <0xafbf@gmail.com>
@shiena shiena force-pushed the feature/support-windows-camera branch from f476000 to a39190b Compare April 11, 2026 17:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants