Whether a capture device is currently open and streaming. Takes no parameters.
camera
Read-only. Everything the capture card reports about itself — its name, the live frame format, and every format it advertises — plus one thing the user tells us: source(). A USB capture card exposes nothing about the game, the source console, or signal presence, so anything content-aware must come from the pixels (via OnFrameReceived); the source label is the one exception, and it's user-declared, not detected. The table is locked: assigning to it or replacing its metatable raises an error.
The device's name, e.g. "UGREEN-25854" — the card's USB name, not the console or game. nil if no device is open. Takes no parameters.
The user-declared label for whatever HDMI device is plugged into this card, e.g. "Nintendo Switch". The card cannot detect this — the user types it in Options → Connected device, and it's remembered per card name. nil until they set it. Useful for source-specific mods: if camera.source() == "Nintendo Switch" then …. Takes no parameters.
Width in pixels of the live frame format (0 if none). Takes no parameters.
Height in pixels of the live frame format (0 if none). Takes no parameters.
Pixel format name of the live frame, e.g. "SDL_PIXELFORMAT_NV12". Matches frame:format(). nil if none. Takes no parameters.
Frame rate of the live format in frames per second (0 if unknown). Takes no parameters.
The frame colorspace as SDL's numeric SDL_Colorspace enum value (0 if none). Niche — most mods won't need it. Takes no parameters.
Where the video actually is, in window pixels. The picture is letterboxed: it keeps the card's own shape and is centred, so it does not fill the window unless the two happen to match. Anything you draw on the game — a marker glued to a menu entry, a panel that has to sit beside a health bar — has to map through this rectangle, or it slides into the black bars the moment the window is resized. Anything you draw on the app (a settings panel, a note) wants window coordinates as before and should ignore this. Returns four zeroes until the first frame has been drawn, which means "no picture yet" rather than "the picture is at 0,0". Takes no parameters.
-- a native GBA point, in screen pixels
local px, py, pw, ph = camera.pictureRect()
if pw > 0 then
local x = px + (gx / 240) * pw
local y = py + (gy / 160) * ph
end
Where the picture is coming from, as one of "card" (a capture device), "window" (another program's window — how an emulator stands in for the console), "still" (a saved frame, used by the test harness) or "none" (nothing open yet, so the picker is showing).
It matters because the same pixels mean different things by source, and nothing in the image says which. A picture filling the entire frame is the console's own UI on a card — a lockscreen, the home screen — and is the game itself from a window, where the emulator's client area is the picture and only carries black bars when it is keeping the aspect ratio. A mod that measures the frame has to know which it is looking at before it decides what the shape means.
Read-only, like the rest of camera: this reports the picture, it does not choose it. Takes no parameters.
-- a full-frame picture is only "not the game" on a card
if camera.sourceKind() ~= "window" and fillsTheFrame then
return nil -- console menu, not the GBA
end
Every format/resolution/framerate the device advertises, as an array of tables. A fresh copy each call — safe to modify. Takes no parameters.
| Field of each entry | Type | Notes |
|---|---|---|
| width, height | number | Resolution in pixels. |
| fps | number | Frame rate for this combination. |
| format | string | Pixel format name, e.g. "SDL_PIXELFORMAT_MJPG". |
if camera.isOpen() then
log(camera.name() .. ": " .. camera.width() .. "x" .. camera.height()
.. " " .. camera.format() .. " @ " .. camera.fps() .. " fps")
log("advertises " .. #camera.formats() .. " formats")
end