react-brain
Browse decisions
React & language foundations 3App architecture 9UI 12Platform & native 9Build, test, observe, secure 6AI in React apps 3stack composerdecision recordscensusstaleness bencharchitecturechangelogmethodologyroadmap

entriesplatform-native · verified 2026-07-13 · react + react-native

Camera, video & real-time media (WebRTC, frame processing, filters)

reviewedconfidence: lowtrack: weakenedearly: 1/12 of this tier graded so far (0 overturned) — the public scorecard →

related decisions: native

re-verified 4× — 2026-07-13 · 2026-07-10 · 2026-07-09 · 2026-07-06 · changelog

recommendation

Camera → VisionCamera (frame processors) or expo-camera (managed); video calling → LiveKit (open-source) or a hosted SDK (Daily/Agora/Stream); real-time filters → process VisionCamera frames + GPU-composite and inject into the WebRTC source; image display → expo-image over core <Image>. Calling-SDK specifics are lightly vetted (confidence: low) — prototype perf per-device before committing.

  • custom real-time effects (blur / segmentation / virtual bg) → VisionCamera frame processors + Skia/Metal + MediaPipe/Vision
  • self-hosted / open-source calling → LiveKit; fastest managed setup → Daily / Agora / Stream
  • just capture photos / scan codes → expo-camera (or VisionCamera for advanced)
  • shipping camera to prod NOW → VisionCamera v5 (GA 2026-04) is still stabilizing: open iOS-26 teardown/race crashes + an AE regression vs v4, and ~85% of installs remain on v4 (2026-07) — adopt v5 pinned-patch with a device-matrix pass; don't linger on v4 (frozen since 2025-11)
  • displaying images (caching, blurhash placeholders, transitions) → expo-image, not core <Image>
  • video/audio playback → expo-video / expo-audio; migrate off expo-av (deprecated, unpatched, out of Expo Go since SDK 55)
  • audio PROCESSING (graphs, effects, filters, real-time) → react-native-audio-api (Web Audio API); real-time discipline → rt-audio-pipeline-audit
  • real-time pipeline correctness & perf → react-native-jsi (frame processors) + rt-audio-pipeline-audit (the real-time discipline transfers from audio)

Low confidence — fast-moving or lightly-vetted domain: treat the pick as a vetted lead and prototype before committing.

Options & tradeoffs

the field considered — and why each one isn’t the default here

optiontradeoffevidence
VisionCamera (v5, Nitro)RN camera with JSI frame processors; v5 rebuilt on Nitro; the base for custom real-time frame pipelines (see RB-E-NATIVE)525k/wk · ships in 6/34
expo-cameramanaged camera for Expo apps; simpler, fewer real-time hooks than VisionCamera1.4M/wk · ships in 5/34
react-native-webrtclow-level WebRTC bindings; you wire signaling/SFU yourself; near-dormant (2 releases since mid-2024, pinned to Chromium M124) — strengthens the SDK-over-raw-WebRTC advice166k/wk · ships in 2/34
LiveKit / Daily / Agora / Stream VideoWebRTC conferencing SDKs (RN + web); LiveKit is open-source + self-hostable, the others are hosted infra
Skia / Metal + MediaPipe / Vision / ML KitGPU compositing (Skia/Metal) + on-device segmentation/detection (MediaPipe on Android, Vision on iOS) for filters/effects
expo-video / expo-audiomedia PLAYBACK (not capture or calling) — the replacements for expo-av, which is DEPRECATED (removed from Expo Go in SDK 55, no longer patched); expo-video splits player logic (VideoPlayer) from view (VideoView)1.4M/wk · ships in 2/34
expo-imageimage DISPLAY — the modern replacement for core <Image>: disk/memory caching, blurhash/thumbhash placeholders, transitions, faster decode; works in bare RN, not just Expo2.8M/wk · ships in 3/34
react-native-audio-api (Software Mansion)Web Audio API for RN — audio graphs, effects/filters via MediaElementAudioSourceNode; 0.13 (2026-07, verified vs npm) ships a stable <Audio/> component; the AUDIO-processing layer (playback-only needs → expo-audio)86k/wk

evidence: npm weekly downloads (signals snapshot) · “ships in n/D” = adoption across the production-app census, honest denominators

Migration lines

version and deprecation lines this decision tracks — for YOUR repo's sequenced plan: the doctor or npx -y @heart-it/react-brain migrate .

expo-av → expo-video (playback) + expo-audio [deprecated · effort M]

expo-av is DEPRECATED — removed from Expo Go in SDK 55 and no longer patched; expo-video splits player logic (VideoPlayer) from view (VideoView), expo-audio covers audio playback

expo.dev/changelog/sdk-55

npm weekly downloads (from the corpus's last signals run): react-native-vision-camera 525k · expo-camera 1.4M · react-native-webrtc 166k · expo-av 645k · expo-video 1.4M · react-native-audio-api 86k · react-native-qrcode-svg 739k · expo-image-picker 2.8M

Verified notes

NEW domain entry (2026-06-25), surfaced by a Margelo deep-dive (see `reading`) the index previously had nowhere to put. Durable real-time lesson it teaches: DON'T fork the WebRTC stack — intercept camera frames, run segmentation/detection OFF the hot path (~20-30ms, "latest mask wins" rather than blocking), GPU-composite, and inject the result into the EXISTING WebRTC VideoSource (the source doesn't care who produces frames). VisionCamera v5 (Nitro/JSI) is the frame-processor base (consistent with RB-E-NATIVE). Options are lightly vetted — recommend tentatively (confidence: low) and prototype on-device; calling-SDK specifics (pricing, features) are not yet verified here.

Canonical reading

Editorial annotations on why each piece matters — the articles themselves are the originals; read them there.

Building a video call app with filtersRitesh Shukla (Margelo)

Architecture deep-dive: real-time RN video-call filters (background blur, virtual backgrounds, Center Stage auto-zoom, live drawing) by injecting processed VisionCamera frames into LiveKit's WebRTC VideoSource without touching encoder/transport/signaling. Covers off-thread segmentation (MediaPipe/Vision), Metal/Skia compositing, YUV↔I420/NV12 conversion, and the monotonic-timestamp + buffer-pooling gotchas.

MoQKit: a native mobile SDK for MoQ on iOS and AndroidJakub Perżyło (Software Mansion)

Architectural intro to Media over QUIC for mobile — the session/namespace/track model, why moq-lite over moq-transport, and where it sits between WebRTC and HLS. A durable real-time-media transport reference.

What's New in VisionCamera V5?Marc Rousavy (Margelo; VisionCamera creator)

The canonical v5 reference for this entry's default camera pick: the full Nitro rewrite (−3k LOC of hand-written JSI, ~15x lower call latency vs Turbo Modules), the Constraints API replacing Formats, in-memory photo capture, depth/RAW/multi-cam, and modular frame-processor plugins. Read before betting real-time work on v5.

QR and Barcode Scanning in React Native with VisionCamera V5Marc Rousavy (Margelo; VisionCamera creator)

By VisionCamera's creator: three scanning APIs (CodeScanner / useBarcodeScannerOutput / frame processors), narrowing barcodeFormats and outputResolution for latency, the frame-vs-preview coordinate gotcha, and MLKit vs Apple's native AVCaptureMetadataOutput vs commercial SDKs. The reference for RN code scanning.

Sources

Depth (in-domain rules) is owned by the react-native-jsi skill — this entry is selection breadth.

The full explanation

The reviewed long-form essay behind this entry — the why, not a how-to. Also on GitHub.

About camera, video & real-time media (WebRTC, frame processing, filters)

Diataxis: Explanation. This page builds understanding of why capture, playback, and calling get different answers. It is not an integration guide. Frame-processor depth is owned by react-native-jsi; real-time discipline by rt-audio-pipeline-audit; the Nitro/JSI story by RB-E-NATIVE. A new, lightly vetted domain (confidence: low) — picks are starting points to prototype on-device.

The one principle that organises everything: three problems, one pipeline you must not fork

"Media" is three problems wearing one name. Capture is a camera problem. Playback is a decoding-and-display problem. Calling is a transport problem you almost always buy as an SDK. The durable lesson at the hardest intersection — real-time effects inside a call — is: don't fork the WebRTC stack. Intercept camera frames, run segmentation/detection off the hot path (~20–30ms, so "latest mask wins" rather than blocking), GPU-composite, and inject back into the existing WebRTC VideoSource — the source doesn't care who produces frames, so you get filters without touching encoder, transport, or signaling.

The default, and why

Camera → VisionCamera (frame processors) or expo-camera (managed); video calling → LiveKit (open-source) or a hosted SDK (Daily/Agora/Stream); real-time filters → process VisionCamera frames + GPU-composite and inject into the WebRTC source; image display → expo-image over core <Image>. Calling-SDK specifics are lightly vetted (confidence: low) — prototype perf per-device before committing.

Each sub-problem gets its own tool. VisionCamera because its JSI frame processors are the base for custom real-time frame pipelines (v5 rebuilt on Nitro, consistent with RB-E-NATIVE); expo-camera when the job is just capturing photos or scanning codes. Calling goes through an SDK because raw react-native-webrtc is low-level (you wire signaling/SFU yourself) and near-dormant — 2 releases since mid-2024, pinned to Chromium M124 — which strengthens the SDK-over-raw-WebRTC advice; LiveKit is the open-source, self-hostable pick, Daily/Agora/Stream the hosted ones. The caveat is part of the default, not an apology.

The landscape, and when each piece earns its place

VisionCamera (v5, Nitro) — the RN camera with JSI frame processors; the base for custom real-time pipelines. Timing matters: v5 went GA 2026-04 and is still stabilizing — open iOS-26 teardown/race crashes plus an AE regression vs v4, with ~85% of installs still on v4 (2026-07). Ship it pinned-patch with a device-matrix pass; don't linger on v4 either (frozen since 2025-11).

expo-camera — managed camera for Expo apps; simpler, fewer real-time hooks; the capture / scan-codes answer.

react-native-webrtc — low-level bindings; near-dormant (above); inject into, don't build on.

LiveKit / Daily / Agora / Stream Video — WebRTC conferencing SDKs (RN + web). LiveKit open-source + self-hostable; the others hosted infra.

Skia / Metal + MediaPipe / Vision / ML Kit — the effects layer: GPU compositing (Skia/Metal) plus on-device segmentation/detection (MediaPipe on Android, Vision on iOS) for filters/effects.

expo-video / expo-audio — media playback (not capture or calling); replace deprecated expo-av (out of Expo Go in SDK 55, unpatched); expo-video splits VideoPlayer (player logic) from VideoView (view).

expo-image — image display; the modern replacement for core <Image>: disk/memory caching, blurhash/thumbhash placeholders, transitions, faster decode. Works in bare RN too.

react-native-audio-api (Software Mansion) — Web Audio API for RN: audio graphs, effects/filters via MediaElementAudioSourceNode; 0.13 (2026-07, verified vs npm) ships a stable <Audio/> component. The audio-processing layer — playback-only needs go to expo-audio.

Tradeoffs and failure modes to name out loud

  • Forking the pipeline for filters. Rebuilding encoder/transport/signaling to add effects is the anti-pattern this entry exists to prevent; inject into the existing VideoSource instead.
  • Blocking the hot path with ML. Segmentation runs ~20–30ms — latest mask wins; composite the freshest mask rather than stalling the frame.
  • Skipping the boring conversions. The reference architecture names YUV↔I420/NV12 conversion, monotonic timestamps, and buffer pooling as the real gotchas of frame injection.
  • Betting on v5 blind — or hiding on v4. v5 is stabilizing (crashes + AE regression above); adopt it pinned-patch with a device-matrix pass. But v4 is frozen, so staying is also a cost.
  • Staying on expo-av. Deprecated, unpatched, out of Expo Go since SDK 55 — migrate.
  • Raw react-native-webrtc as your calling foundation. DIY calling on a near-dormant layer.
  • Over-trusting this entry. Confidence is low: options lightly vetted, calling-SDK pricing/features unverified — prototyping per-device is part of the recommendation.

How it interacts with the rest of the stack

  • Native modules (RB-E-NATIVE). VisionCamera v5's Nitro rewrite is part of the Nitro consolidation that entry tracks; frame processors are its JSI story applied to camera frames.
  • Frame-processor correctness (react-native-jsi). The defer skill — native-pipeline depth.
  • Real-time discipline (rt-audio-pipeline-audit). The hot-path discipline transfers from audio; the entry routes real-time correctness and perf review there.

In one paragraph

Camera, playback, and calling are three different problems: capture with VisionCamera (v5 on Nitro, GA 2026-04 but still stabilizing — pin a patch, run a device matrix) or expo-camera; play back with expo-video/expo-audio (expo-av is deprecated, out of Expo Go since SDK 55), display images with expo-image; buy calling as an SDK — LiveKit for open-source/self-hosted — because raw react-native-webrtc is near-dormant. For real-time effects the durable rule is don't fork the pipeline: segment off the hot path ("latest mask wins"), GPU-composite with Skia/Metal + MediaPipe/Vision, and inject processed VisionCamera frames into the existing WebRTC VideoSource. Confidence is low — prototype per-device first.


See also: RB-E-NATIVE (Nitro/JSI foundation for frame processors). Depth: the react-native-jsi skill and rt-audio-pipeline-audit (real-time discipline). Reference architecture: Margelo's video-call-filters deep-dive; on the horizon, per the entry's reading, MoQ (Media over QUIC) via Software Mansion's MoQKit — between WebRTC and HLS, not yet a pick.

Related in platform-native: native · storage · native-ui · keyboard · payments · brownfield · games · alt-frameworks