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.

functioncamera.isOpen() → boolean

Whether a capture device is currently open and streaming. Takes no parameters.

functioncamera.name() → string | nil

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.

functioncamera.source() → string | nil

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.

functioncamera.width() → number

Width in pixels of the live frame format (0 if none). Takes no parameters.

functioncamera.height() → number

Height in pixels of the live frame format (0 if none). Takes no parameters.

functioncamera.format() → string | nil

Pixel format name of the live frame, e.g. "SDL_PIXELFORMAT_NV12". Matches frame:format(). nil if none. Takes no parameters.

functioncamera.fps() → number

Frame rate of the live format in frames per second (0 if unknown). Takes no parameters.

functioncamera.colorspace() → number

The frame colorspace as SDL's numeric SDL_Colorspace enum value (0 if none). Niche — most mods won't need it. Takes no parameters.

functioncamera.pictureRect() → x, y, w, h

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
functioncamera.sourceKind() → string

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
functioncamera.formats() → table[]

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 entryTypeNotes
width, heightnumberResolution in pixels.
fpsnumberFrame rate for this combination.
formatstringPixel 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
One page of the MCCP modding reference. Every section is its own document; search covers all of them.