Skip to content

🐛 VisionCamera + Skia frameProcessor freezes preview when toggling filter #3727

@tsmusty

Description

@tsmusty

What's happening?

When using react-native-vision-camera with useSkiaFrameProcessor and a simple Skia ColorFilter (matrix / LUT-style processing), the camera preview intermittently freezes (UI continues, but preview frame stops updating). This makes live filters unusable.

Environment

App: Expo + RN (from package.json)
react-native: 0.83.2
react: 19.2.0
react-native-vision-camera: ^4.7.3
@shopify/react-native-skia: 2.4.18
react-native-worklets-core: ^1.6.2
Platform: iOS / Android (fill in which one(s) you see it on)
Device: (fill in model + OS version)
Engine: Hermes (likely; confirm if you can)
Steps to reproduce

Render a Camera with frameProcessor={useSkiaFrameProcessor(...)}.
In the frame processor, apply a Skia color filter and call frame.render(paint).
Toggle the filter on/off a few times (or just run it for ~10–30s).
Preview freezes (no new frames), while JS/UI remains responsive.
Expected Preview remains smooth and continues updating frames.

Actual Preview freezes; sometimes recovers only after navigating away/back, sometimes requires app restart.

Reproduceable Code

import { Camera, useCameraDevice, useCameraPermission, useSkiaFrameProcessor } from "react-native-vision-camera";
import { Skia } from "@shopify/react-native-skia";

const BW = [
  0.2126, 0.7152, 0.0722, 0, 0,
  0.2126, 0.7152, 0.0722, 0, 0,
  0.2126, 0.7152, 0.0722, 0, 0,
  0, 0, 0, 1, 0,
];

export function Repro() {
  const device = useCameraDevice("back");
  const { hasPermission, requestPermission } = useCameraPermission();
  const [enabled, setEnabled] = React.useState(true);

  React.useEffect(() => { if (!hasPermission) requestPermission(); }, [hasPermission]);

  const frameProcessor = useSkiaFrameProcessor((frame) => {
    "worklet";
    if (!enabled) return;
    const paint = Skia.Paint();
    paint.setColorFilter(Skia.ColorFilter.MakeMatrix(BW));
    frame.render(paint);
  }, [enabled]);

  if (!device || !hasPermission) return null;

  return <Camera style={{ flex: 1 }} device={device} isActive photo frameProcessor={frameProcessor} />;
}

Relevant log output

N/A

Camera Device

VC_DEVICE_JSON {
  "supportsFocus": true,
  "formats": [],
  "maxZoom": 123.75,
  "supportsLowLightBoost": false,
  "hardwareLevel": "full",
  "physicalDevices": [
    "wide-angle-camera"
  ],
  "minFocusDistance": 15,
  "maxExposure": 8,
  "name": "Back Camera",
  "isMultiCam": false,
  "supportsRawCapture": false,
  "id": "com.apple.avfoundation.avcapturedevice.built-in_video:0",
  "hasTorch": true,
  "minExposure": -8,
  "sensorOrientation": "portrait",
  "hasFlash": true,
  "minZoom": 1,
  "neutralZoom": 1,
  "position": "back"
}

Device

iPhone 16

VisionCamera Version

^4.7.3

Can you reproduce this issue in the VisionCamera Example app?

I didn't try (⚠️ your issue might get ignored & closed if you don't try this)

Additional information

Metadata

Metadata

Assignees

No one assigned

    Labels

    🐛 bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions