# Off-screen rendering

> Use processed frame output when another camera, encoder, WebRTC stack, or live-streaming SDK needs the Nosmai-rendered result.

> For AI agents: the complete documentation index is at https://nosmai.com/llms/effects.txt

Product: Nosmai Effects
Group: core-concepts
Source: https://nosmai.com/docs/effects/concepts/off-screen-rendering/

## When to use it

Use off-screen rendering when Nosmai does not own the final display or media
transport. Common cases include a custom camera source, a WebRTC encoder, a
video-call SDK, or a server upload pipeline that already consumes native
frames.

![Off-screen rendering from a camera or external source to preview, recording, and streaming consumers](/images/docs/off-screen-rendering-flow-v1.svg)

## Supported native paths

| Platform | Input or output | Format |
| --- | --- | --- |
| Android external input | Synchronous processed planes | Direct planar I420 buffers with explicit strides |
| Android camera output | CPU callback or shared GPU texture | SDK frame metadata or EGL-shared texture |
| iOS external input | Submitted pixel or sample buffers | `kCVPixelFormatType_32BGRA` |
| iOS camera output | Processed live-frame callback | `CVPixelBufferRef` |
| Flutter | Maintained provider bridge | Native GPU texture on Android and `CVPixelBuffer` on iOS |
| React Native | Bounded analysis sampling only | Base64 `i420`, `rgba8888`, `bgra8888`, or `nv12` |

React Native sampling is limited to 1 through 5 FPS and is not a live-streaming
transport. The public Flutter API does not accept arbitrary external I420 or
pixel-buffer input.

## Frame ownership

Real-time output needs clear ownership:

1. Keep at most one expensive operation in progress.
2. Keep the newest waiting frame instead of building a queue.
3. Preserve the input timestamp for the downstream encoder.
4. Retain an iOS output buffer only when the consumer outlives the callback.
5. Return every Android texture slot after sampling it.
6. Clear callbacks before releasing the camera or graphics context.

## Preview and processed output

Android provides `PREVIEW_ONLY`, `STREAMING_ONLY`, and `DUAL_OUTPUT` render
modes. iOS provides a live processed-frame callback while the normal camera is
running. Dual output costs more than preview alone, so measure the combined
effect and encoder load on target hardware.

## Streaming compatibility

| Consumer | Status | Route |
| --- | --- | --- |
| Agora | Verified | [Native and Flutter guides](/docs/effects/integrations/live-streaming/) |
| LiveKit | Verified | [Native and Flutter guides](/docs/effects/integrations/live-streaming/) |
| Raw WebRTC | Verified on native Android and iOS | [Native guides and examples](/docs/effects/integrations/live-streaming/) |
| Other video SDKs | Integration-dependent | Use a custom video source that accepts the documented native format |

Do not describe an untested provider as verified. Format, orientation,
timestamp, and buffer ownership must be validated with the exact provider
version used by the application.

## Next steps

- [Render frames off-screen in Android](/docs/effects/guides/streaming/render-frames-off-screen/android/)
- [Render frames off-screen in iOS](/docs/effects/guides/streaming/render-frames-off-screen/ios/)
- [Choose a live-streaming integration](/docs/effects/integrations/live-streaming/)
- [Stream Flutter effects through Agora](/docs/effects/integrations/agora/flutter/)
- [Stream Flutter effects through LiveKit](/docs/effects/integrations/livekit/flutter/)
- [Review performance limits](/docs/effects/limits-and-performance/)

## References

- [How the rendering pipeline works](/docs/effects/concepts/how-the-pipeline-works/)
- [Platform support](/docs/effects/platform-support/)
