A Godot plugin that provides a unified camera capture interface for Android and iOS using native platform APIs. It enables real‑time camera frame streaming directly into Godot with configurable resolution, rotation, frame skipping, horizontal/vertical mirroring, and optional grayscale output.
Key Features:
- Unified GDScript API for Android and iOS
- Enumerate available cameras and their supported output sizes
- Start and stop native camera frame streaming
- Receive raw frame buffers or ready‑to‑use
Imageobjects - Configurable resolution, rotation, frame skipping, horizontal/vertical mirroring, grayscale capture, and post-capture scaling
- Designed for real‑time use cases (CV, AR preprocessing, custom rendering)
- Installation
- Usage
- Signals
- Methods
- Classes
- Platform-Specific Notes
- Links
- All Plugins
- Credits
- Contributing
Before installing this plugin, make sure to uninstall any previous versions of the same plugin.
If installing both Android and iOS versions of the plugin in the same project, ensure that both versions use the same addon interface version.
There are two ways to install the NativeCamera plugin into your project:
- Through the Godot Editor AssetLib
- Manually by downloading archives from GitHub
Steps:
-
Search for NativeCamera in the Godot Editor AssetLib
-
Click Download
-
In the installation dialog:
- Keep Change Install Folder set to your project root
- Keep Ignore asset root checked
- Click Install
-
Enable the plugin from Project → Project Settings → Plugins
When installing both platforms via AssetLib, Godot may warn that some files conflict and will not be installed. This is expected and safe to ignore, as both platforms share the same addon interface code.
Steps:
- Download the release archive from GitHub
- Unzip the archive
- Copy the contents into your Godot project root
- Enable the plugin via Project → Project Settings → Plugins
Add a NativeCamera node to your main scene or register it as an autoload (singleton).
Typical workflow:
- Query available cameras using
get_cameras() - Choose a camera and desired output size
- Create a
FeedRequestto configure the stream - Start the camera feed
- Receive frames via signals
@onready var camera := $NativeCamera
func _ready():
camera.camera_permission_granted.connect(_on_camera_permission_granted)
camera.camera_permission_denied.connect(_on_camera_permission_denied)
camera.frame_available.connect(_on_frame_available)
camera.request_camera_permission()
func _on_camera_permission_granted() -> void:
var cameras := camera.get_all_cameras()
if cameras.is_empty():
return
var cam: CameraInfo = cameras[0]
var request := FeedRequest.new()
.set_camera_id(cam.get_camera_id())
.set_width(1280)
.set_height(720)
.set_rotation(90)
.set_grayscale(false)
.set_mirror_horizontal(true) # flip left-right (e.g. selfie camera preview)
.set_mirror_vertical(false)
.set_scale_width(640) # downscale to 640×360 before emitting
.set_scale_height(360)
camera.start(request)
func _on_camera_permission_denied() -> void:
push_error("Camera permission denied")
func _on_frame_available(frame: FrameInfo) -> void:
var img := frame.get_image()
# Use the image or raw buffer hereRegister listeners on the NativeCamera node:
-
camera_permission_granted()- Emitted when camera permission is granted by the user
-
camera_permission_denied()- Emitted when camera permission is denied by the user
-
frame_available(frame: FrameInfo)- Emitted when a new camera frame is available
-
has_camera_permission() -> bool- Returns whether camera permission has already been granted
-
request_camera_permission()- Requests camera permission from the OS
-
get_all_cameras() -> Array[CameraInfo]- Returns a list of available cameras
-
create_feed_request() -> FeedRequest- Creates a
FeedRequestpre-populated with the node's exported property values (frame_width,frame_height,frames_to_skip,frame_rotation,is_grayscale,mirror_horizontal,mirror_vertical,scale_width,scale_height)
- Creates a
-
start(request: FeedRequest)- Starts the camera feed with the given configuration
-
stop()- Stops the active camera feed
This section documents the GDScript interface classes implemented and exposed by the plugin.
Encapsulates camera metadata provided by the mobile OS.
Properties / Methods:
get_camera_id() -> Stringis_front_facing() -> boolget_output_sizes() -> Array[FrameSize]
Defines configuration parameters for starting a camera feed.
Configurable options:
- Camera ID
- Output width and height
- Frames to skip (performance tuning)
- Rotation (degrees: 0, 90, 180, 270 — applied first)
- Grayscale capture
- Horizontal mirror (
mirror_horizontal) — flips the frame left-to-right after rotation - Vertical mirror (
mirror_vertical) — flips the frame top-to-bottom after rotation - Scale width and height (
scale_width,scale_height) — resizes the pixel buffer to the given dimensions as the final post-processing step (after rotation and mirroring); both must be non-zero for scaling to take effect; defaults to 0 (disabled)
Both mirror flags default to false and can be combined independently with any rotation value. Mirroring is applied as a post-processing step after rotation on both Android and iOS, so the axis labels always refer to the final upright image.
Scaling is applied after mirroring and uses nearest-neighbour interpolation, making it suitable for real-time use cases such as downscaling before CV inference. Setting either scale_width or scale_height to 0 disables scaling entirely.
Supports fluent chaining via setter methods.
Setter methods:
set_camera_id(value: String) -> FeedRequestset_width(value: int) -> FeedRequestset_height(value: int) -> FeedRequestset_frames_to_skip(value: int) -> FeedRequestset_rotation(value: int) -> FeedRequestset_grayscale(value: bool) -> FeedRequestset_mirror_horizontal(value: bool) -> FeedRequestset_mirror_vertical(value: bool) -> FeedRequestset_scale_width(value: int) -> FeedRequestset_scale_height(value: int) -> FeedRequest
Represents a single captured frame.
Accessors:
get_buffer() -> PackedByteArrayget_width() -> intget_height() -> intget_rotation() -> intis_grayscale() -> boolget_image() -> Image
Represents a supported camera output resolution.
Accessors:
get_width() -> intget_height() -> intget_raw_data() -> Dictionary
- Ensure Android export templates are installed
- Enable Gradle build in export settings
- Camera permission is required at runtime
- The "Two-Strike" Rule: Starting in Android 11, if a user taps "Deny" for a specific permission more than once during the app's lifetime on the device, the system will no longer show the dialog for future requests. Once this two-strike threshold is reached, any subsequent calls to request the permission will immediately be denied without showing any dialogs.
Troubleshooting:
- Logs (Linux/macOS):
adb logcat | grep godot - Logs (Windows):
adb.exe logcat | select-string "godot"
Helpful resources:
- Godot Android export documentation
- Android Studio & ADB documentation
- Follow Godot’s iOS export instructions
- Camera permission must be declared in the generated Xcode project
- Use Xcode console logs for debugging
| ✦ | Plugin | Android | iOS | Latest Release | Downloads | Stars |
|---|---|---|---|---|---|---|
| Admob | ✅ | ✅ | ||||
| Connection State | ✅ | ✅ | ||||
| Deeplink | ✅ | ✅ | ||||
| Firebase | ⏰ | ⏰ | 🔜 | - | ||
| In-App Review | ✅ | ✅ | ||||
| Native Camera | ✅ | ✅ | ||||
| Notification Scheduler | ✅ | ✅ | ||||
| OAuth 2.0 | ✅ | ✅ | ||||
| QR | ✅ | ✅ | ||||
| Share | ✅ | ✅ | ||||
| Vision | ✅ | ✅ |
Developed by Cengiz
Based on Godot Mobile Plugin Template v7
Original repository: Godot Native Camera Plugin
Contributions are welcome. Please see the contributing guide in the repository for details.
If this plugin has helped you, consider supporting its development! Every bit of support helps keep the plugin updated and bug-free.
| ✦ | Ways to Help | How to do it |
|---|---|---|
| ✨⭐ | Spread the Word | Star this repo to help others find it. |
| 💡✨ | Give Feedback | Open an issue or suggest a feature. |
| 🧩 | Contribute | Submit a PR to help improve the codebase. |
| ❤️ | Buy a Coffee | Support the maintainers on GitHub Sponsors or other platforms. |

