mrousavy / react-native-vision-camera

πŸ“Έ A powerful, high-performance React Native Camera library.
https://react-native-vision-camera.com
MIT License
7.34k stars 1.07k forks source link

πŸ› Fatal signal: SIGSEGV when using `runAsync` in Frame Processor #2589

Closed luicfrr closed 5 months ago

luicfrr commented 7 months ago

What's happening?

Trying to open the app on production mode react-native run-android --variant=release makes app crash when opening camera view.

I'm using example app, didn't add any new library but I removed some props in CameraPage.tsx I don't need (capture photo button, etc...).

IMPORTANT: This crash only happens if the app is fresh installed on the device or if you clean app data and open app. If you keep reopening app after some crashes (in my case 2 crashes) there's no crash anymore BUT runAsync is NOT called. Everything inside frame processor is called except runAsync.

EDIT: Fatal signal crash changes, they are not always the same, I tryed reinstalling the app right now and crash code error was Fatal signal 11 (SIGSEGV), code 2, fault addr 0xc87f3f60 in tid 27643 (ionCamera.video)

Some notes in my real app: If I use any reanimated functions the app don't crash but nothing inside runAsync are called. If I try to add any svg from react-native-svg in my app it crash with a similar error in this issue. Doesn't matter if is reaniamted creating a svg or if I just import and add it to screen, both ways crash with a similar error:

import Svg from 'react-native-svg'
const AnimatedSvg = Animated.createAnimatedComponent( Svg )

// or

return (
  <Camera
    ....
  />
  <Svg>
    ...
  </Svg>
)

Reproduceable Code

import * as React from 'react'
import { useRef } from 'react'
import { StyleSheet, View, useWindowDimensions, Text } from 'react-native'
import {
  useCameraDevice,
  useCameraFormat,
  useFrameProcessor,
  runAsync,
  Camera,
  useCameraPermission
} from 'react-native-vision-camera'
import Reanimated, { useSharedValue } from 'react-native-reanimated'
import { useIsFocused } from '@react-navigation/core'

import { useIsForeground } from './hooks/useIsForeground'
import { examplePlugin } from './frame-processors/ExamplePlugin'
import { exampleKotlinSwiftPlugin } from './frame-processors/ExampleKotlinSwiftPlugin'

const ReanimatedCamera = Reanimated.createAnimatedComponent( Camera )
Reanimated.addWhitelistedNativeProps( {
  zoom: true
} )

export function CameraPage(): React.ReactElement {
  const camera = useRef<Camera>( null )
  const zoom = useSharedValue( 1 )

  // check if camera page is active
  const isFocussed = useIsFocused()
  const isForeground = useIsForeground()
  const isActive = isFocussed && isForeground

  // camera device settings
  let device = useCameraDevice( 'front' )
  const { hasPermission, requestPermission } = useCameraPermission()

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

  const {
    width: windowWidth,
    height: windowHeight
  } = useWindowDimensions()
  const screenAspectRatio = windowHeight / windowWidth
  const format = useCameraFormat( device, [
    { fps: 30 },
    { videoAspectRatio: screenAspectRatio },
    { videoResolution: 'max' },
    { photoAspectRatio: screenAspectRatio },
    { photoResolution: 'max' },
  ] )
  const fps = Math.min( format?.maxFps ?? 30 )

  const frameProcessor = useFrameProcessor( ( frame ) => {
    'worklet'
    console.log( 'frame processor call' )
    exampleKotlinSwiftPlugin( frame )
    runAsync( frame, () => {
      'worklet'
      console.log( ' ' )
      console.log( ' ' )
      console.log( 'runAsync call' )
      examplePlugin( frame )
      console.log( ' ' )
      console.log( ' ' )
    } )
  }, [] )

  return ( <View style={ styles.container }>
    { hasPermission && device ? (
      <Reanimated.View style={ StyleSheet.absoluteFill }>
        <ReanimatedCamera
          style={ StyleSheet.absoluteFill }
          device={ device }
          isActive={ isActive }
          ref={ camera }
          onStarted={ () => 'Camera started!' }
          onStopped={ () => 'Camera stopped!' }
          format={ format }
          fps={ fps }
          enableZoomGesture={ false }
          exposure={ 0 }
          enableFpsGraph={ true }
          orientation="portrait"
          photo={ true }
          video={ true }
          frameProcessor={ frameProcessor }
          zoom={ zoom.value }
        />
      </Reanimated.View>
    ) : <Text
      style={ {
        backgroundColor: 'rgb(255,0,0)',
        color: 'white'
      } }
    >
      No camera device or permission
    </Text> }
  </View> )
}

const styles = StyleSheet.create( {
  container: {
    flex: 1,
    backgroundColor: 'black',
  }
} )

Relevant log output

23276-23292 CameraManagerGlobal                 Connecting to camera service
23276-23292 VendorTagDescriptor                 addVendorDescriptor: vendor tag id 3854507339 added
23276-23296 OpenGLRenderer                      HWUI GL Pipeline
23276-23276 InputTransport                      Input channel constructed: fd=57
23276-23276 ViewRootImpl@98a7bca[MainActivity]  setView = DecorView@a7805b1[MainActivity] TM=true MM=false
23276-23276 ViewRootImpl@98a7bca[MainActivity]  dispatchAttachedToWindow
23276-23292 unknown:ReactContext                initializeMessageQueueThreads() is called.
23276-23276 Surface                             sf_framedrop debug : 0x4f4c, game : false, logging : 0
23276-23276 ViewRootImpl@98a7bca[MainActivity]  Relayout returned: old=[0,0][0,0] new=[0,0][720,1280] result=0x7 surface={valid=true 3364714496} changed=true
23276-23296 OpenGLRenderer                      Initialized EGL, version 1.4
23276-23296 OpenGLRenderer                      Swap behavior 2
23276-23296 libGLESv1                           STS_GLApi : DTS, ODTC are not allowed for Package : com.mrousavy.camera.example
23276-23296 mali_winsys                         EGLint new_window_surface(egl_winsys_display *, void *, EGLSurface, EGLConfig, egl_winsys_surface **, egl_color_buffer_format *, EGLBoolean) returns 0x3000,  [720x1280]-format:1
23276-23296 OpenGLRenderer                      eglCreateWindowSurface = 0xc5cdd2c0
23276-23294 CameraSession                       configure { ... }: Updating CameraSession Configuration... Difference(deviceChanged=false, outputsChanged=false, sidePropsChanged=false, isActiveChanged=true)
23276-23294 PersistentCameraCaptureSession      --> setIsActive(false)
23276-23294 PersistentCameraCaptureSession      Configure() with isActive: false, ID: 1, device: android.hardware.camera2.impl.CameraDeviceImpl@d2a5131, session: android.hardware.camera2.impl.CameraCaptureSessionImpl@ca7b016
23276-23294 PersistentCameraCaptureSession      Stopping repeating request...
23276-23294 PersistentCameraCaptureSession      Configure() done! isActive: false, ID: 1, device: android.hardware.camera2.impl.CameraDeviceImpl@d2a5131, session: android.hardware.camera2.impl.CameraCaptureSessionImpl@ca7b016
23276-23294 CameraSession                       configure { ... }: Completed CameraSession Configuration! (isActive: true, isRunning: false)
23276-23276 ViewRootImpl@98a7bca[MainActivity]  Relayout returned: old=[0,0][720,1280] new=[0,0][720,1280] result=0x1 surface={valid=true 3364714496} changed=false
23276-23276 SurfaceView                         BG show() Surface(name=Background for - SurfaceView - com.mrousavy.camera.example/com.mrousavy.camera.example.MainActivity@b221460@0) com.mrousavy.camera.core.PreviewView{b221460 V.E...... ......ID -778,0-1498,1280}
23276-23276 Surface                             sf_framedrop debug : 0x4f4c, game : false, logging : 0
23276-23276 SurfaceView                         surfaceCreated 2 #8 com.mrousavy.camera.core.PreviewView{b221460 V.E...... ......ID -778,0-1498,1280}
23276-23276 CameraSession                       PreviewView Surface created! Surface(name=null)/@0xe7c8b84
23276-23276 CameraSession                       Setting Preview Output...
23276-23276 SurfaceView                         surfaceChanged (720,1280) 2 #8 com.mrousavy.camera.core.PreviewView{b221460 V.E...... ......ID -778,0-1498,1280}
23276-23276 CameraSession                       PreviewView Surface updated! Surface(name=null)/@0xe7c8b84 720 x 1280
23276-23294 CameraSession                       configure { ... }: Waiting for lock...
23276-23294 CameraSession                       configure { ... }: Updating CameraSession Configuration... Difference(deviceChanged=false, outputsChanged=true, sidePropsChanged=true, isActiveChanged=true)
23276-23294 CameraSession                       Destroying previous outputs...
23276-23294 SurfaceOutput                       Closing 2560x1440 PHOTO ImageReader..
23276-23294 SurfaceOutput                       Closing 1920x1080 Video Pipeline..
23276-23294 CameraSession                       Creating outputs for Camera #1...
23276-23294 CameraManager                       getCameraCharacteristics : cameraId = 1
23276-23294 CameraSession                       Adding 2560x1440 Photo Output in JPEG...
23276-23294 Surface                             sf_framedrop debug : 0x4f4c, game : false, logging : 0
23276-23294 CameraSession                       Adding 1920x1080 Video Output in YUV_420_888...
23276-23294 VideoPipeline                       Initializing 1920 x 1080 Video Pipeline (format: YUV)
23276-23294 Surface                             sf_framedrop debug : 0x4f4c, game : false, logging : 0
23276-23294 VideoPipeline                       Using ImageReader round-trip (format: #35)
23276-23294 VideoPipeline                       Creating ImageReader with default usage flags...
23276-23294 Surface                             sf_framedrop debug : 0x4f4c, game : false, logging : 0
23276-23294 VideoPipeline                       Creating ImageWriter with default format...
23276-23294 Surface                             sf_framedrop debug : 0x4f4c, game : false, logging : 0
23276-23294 CameraSession                       Adding 1280x720 Preview Output...
23276-23276 ViewRootImpl@98a7bca[MainActivity]  Relayout returned: old=[0,0][720,1280] new=[0,0][720,1280] result=0x1 surface={valid=true 3364714496} changed=false
23276-23276 VisionCameraProxy                   Finding view 3...
23276-23276 VisionCameraProxy                   Found view 3!
23276-23276 ViewRootImpl@98a7bca[MainActivity]  Relayout returned: old=[0,0][720,1280] new=[0,0][720,1280] result=0x1 surface={valid=true 3364714496} changed=false
23276-23276 PreviewView                         Input Orientation changed: LANDSCAPE_LEFT -> LANDSCAPE_RIGHT
23276-23276 SurfaceHolder                       Resizing SurfaceHolder to 1280 x 720...
23276-23276 SurfaceView                         setPackageUsesOwnResolution() (Java SurfaceView) for com.mrousavy.camera.example: 1280x720 (true)
23276-23276 SurfaceView                         BG show() Surface(name=Background for - SurfaceView - com.mrousavy.camera.example/com.mrousavy.camera.example.MainActivity@b221460@0) com.mrousavy.camera.core.PreviewView{b221460 V.E...... ......I. -778,0-1498,1280}
23276-23276 SurfaceView                         surfaceChanged (1280,720) 3 #8 com.mrousavy.camera.core.PreviewView{b221460 V.E...... ......I. -778,0-1498,1280}
23276-23276 PreviewView                         Surface Size changed: 720x1280 -> 1280x720
23276-23276 CameraSession                       PreviewView Surface updated! Surface(name=null)/@0xe7c8b84 1280 x 720
23276-23276 SurfaceHolder                       Resized SurfaceHolder to 1280 x 720!
23276-23276 PreviewView                         PreviewView is 720x1232, rendering 720x1280 content (LANDSCAPE_RIGHT). Resizing to: 720x1280 (COVER)
23276-23276 ViewRootImpl@98a7bca[MainActivity]  Relayout returned: old=[0,0][720,1280] new=[0,0][720,1280] result=0x1 surface={valid=true 3364714496} changed=false
23276-23294 PersistentCameraCaptureSession      --> setOutputs([PHOTO (2560x1440 in JPEG), VIDEO (1920x1080 in YUV), PREVIEW (1280 x 720)])
23276-23294 CameraSession                       Successfully configured Session with 3 outputs for Camera #1!
23276-23294 CameraSession                       Updating Video Outputs...
23276-23294 VideoPipeline                       Removing RecordingSession Output...
23276-23294 PersistentCameraCaptureSession      --> setRepeatingRequest(...)
23276-23294 PersistentCameraCaptureSession      --> setIsActive(true)
23276-23294 PersistentCameraCaptureSession      Configure() with isActive: true, ID: 1, device: android.hardware.camera2.impl.CameraDeviceImpl@d2a5131, session: null
23276-23294 PersistentCameraCaptureSession      Creating new session...
23276-23294 CameraManager                       getCameraCharacteristics : cameraId = 1
23276-23294 CreateCaptureSession                Camera #1: Creating Capture Session #2... (Hardware Level: 0 | Outputs: [PHOTO (2560x1440 in JPEG), VIDEO (1920x1080 in YUV), PREVIEW (1280 x 720)])
23276-23294 CreateCaptureSession                Using legacy API (<28)
23276-23276 ViewRootImpl@98a7bca[MainActivity]  Relayout returned: old=[0,0][720,1280] new=[0,0][720,1280] result=0x1 surface={valid=true 3364714496} changed=false
23276-23295 CreateCaptureSession                Camera #1: CameraCaptureSession #1 has been closed.
23276-23295 PersistentCameraCaptureSession      Session android.hardware.camera2.impl.CameraCaptureSessionImpl@ca7b016 closed!
23276-23295 CreateCaptureSession                Camera #1: Successfully created CameraCaptureSession #2!
23276-23294 PersistentCameraCaptureSession      Updating repeating request...
23276-23294 CameraManager                       getCameraCharacteristics : cameraId = 1
23276-23294 PersistentCameraCaptureSession      Configure() done! isActive: true, ID: 1, device: android.hardware.camera2.impl.CameraDeviceImpl@d2a5131, session: android.hardware.camera2.impl.CameraCaptureSessionImpl@5a7c71c
23276-23294 CameraSession                       configure { ... }: Completed CameraSession Configuration! (isActive: true, isRunning: true)
23276-23294 CameraView                          invokeOnStarted()
23276-23295 VideoPipeline                       ImageReader::onImageAvailable!
23276-23297 ReactNativeJS                       frame processor call
23276-23295 ExampleKotlinPlugin                 1920 x 1080 Image with format #35. Logging 5 parameters:
23276-23295 ExampleKotlinPlugin                   -> 42.0 (java.lang.Double)
23276-23295 ExampleKotlinPlugin                   -> true (java.lang.Boolean)
23276-23295 ExampleKotlinPlugin                   -> {test=0.0, second=test} (java.util.HashMap)
23276-23295 ExampleKotlinPlugin                   -> hello! (java.lang.String)
23276-23295 ExampleKotlinPlugin                   -> [another test, 5.0] (java.util.ArrayList)
23276-23295 libc                                Fatal signal 11 (SIGSEGV), code 1, fault addr 0x18 in tid 23295 (ionCamera.video)

Camera Device

{
  "hardwareLevel": "limited",
  "minExposure": -20,
  "neutralZoom": 1,
  "minZoom": 1,
  "supportsFocus": false,
  "formats": [],
  "supportsLowLightBoost": false,
  "hasTorch": false,
  "supportsRawCapture": false,
  "minFocusDistance": 0,
  "sensorOrientation": "landscape-right",
  "maxZoom": 4,
  "physicalDevices": [
    "wide-angle-camera"
  ],
  "isMultiCam": false,
  "position": "front",
  "id": "1",
  "hasFlash": false,
  "maxExposure": 20,
  "name": "FRONT (1)"
}

Device

Galaxy J5 Android 8

VisionCamera Version

3.9.0

Can you reproduce this issue in the VisionCamera Example app?

Yes, I can reproduce the same issue in the Example app here

Additional information

mrousavy commented 7 months ago

If you remove runAsync it works as expected?

mrousavy commented 7 months ago

If yes, then this is related to https://github.com/mrousavy/react-native-vision-camera/issues/2579 and maybe also even https://github.com/mrousavy/react-native-vision-camera/issues/2153.

luicfrr commented 7 months ago

Yes, if I remove runAsync there's no crash anymore but I need this runAsync method to run heavy work without blocking preview frame rate.

But for me this crash only happens on production mode, on dev mode everything works really fine.

bglgwyng commented 7 months ago

If the usage of runAsync causes this behavior, then it could be the same problem with #2153. I also observed that runAsync caused the crash described in #2153 a few times.

mrousavy commented 7 months ago

@nonam4 can you test if @bglgwyng's PR (#2591) fixes the issue for you?

luicfrr commented 7 months ago

@mrousavy I tested it and no, #2591 PR doesn't fix the issue. I have cleared the project using clean.sh script and rebuilt it but still crashing.

In this test I noticed an interestant thing: If camera preview is stretched when I open the app it doesn't crash but runAsync is not called. If I reopen the app and preview is correct the app will crash on first atempt to call runAsync event.

chrfalch commented 7 months ago

Hi, @nonam4 - you say "If I use any reanimated functions the app don't crash but nothing inside runAsync are called." - what does this mean? Could you describe the steps you use to use reanimated functions?

luicfrr commented 7 months ago

@chrfalch I mean that this code (without any reanimated method) works fine:

const frameProcessor = useFrameProcessor( ( frame ) => {
    'worklet'
    runAsync( frame, () => {
      'worklet'
      console.log( 'runAsync call' )
    } )
  }, [] )
...
return ( <Camera
  frameProcessor={ frameProcessor }
/>)

But this (with reanimated methods) doesn't:

const ReanimatedCamera = Reanimated.createAnimatedComponent( Camera )
...
return (<ReanimatedCamera
  frameProcessor={ frameProcessor }
/>)

Neither this:

return (<Reanimated.View>
  <Camera
    frameProcessor={ frameProcessor }
  />
</Reanimated.View>)

If I'm not using reanimated with vision camera (no matter if it's installed on my project) runAsync is called in production (react-native run-android --variant=release) builds, but if I try to use anything of reanimated in same component as vison camera (even if reaniamted is inside another component that is imported and rendered with camera) sometimes the app crash with issue's error and sometimes there's no crash but runAsync is simply not called.

Another thing that makes my app crash is adding react-native-svg together with vision camera, doesn't matter if I use reaniamted or not.. but the real problem is that I need to use both together πŸ˜… I need to create an animated svg to be rendered above my camera preview and this makes my app crash every time.

import Svg from 'react-native-svg'
...
return (
  <Camera
    frameProcessor={ frameProcessor }
  />
  <Svg>
    ...
  </Svg>
)
jonjamz commented 7 months ago

@nonam4 What versions of Reanimated / React Native SVG are you using?

luicfrr commented 7 months ago

@jonjamz In this issue I'm using reanimated version of example app but in my real app I'm using latest version of all dependencies (I always check for dependencies updates if anything is wrong before opening issues). Here's my whole package.json:

{
  "name": "myapp",
  "version": "1",
  "private": true,
  "scripts": {
    "lint": "yarn test && eslint --quiet --fix --ext .js,.ts,.tsx,.jsx .",
    "test": "tsc",
    "prebuild": "npx expo prebuild",
    "prebuild:clean": "npx expo prebuild --clean",
    "android": "yarn prebuild && npx expo run:android -d",
    "android:prod": "yarn prebuild &&  npx expo run:android -d --variant release",
    "ios": "yarn prebuild && npx expo run:ios -d",
    "ios:prod": "yarn prebuild && npx expo run:ios -d --configuration Release",
    "android:clean": "yarn prebuild:clean && npx expo run:android -d --no-build-cache",
    "ios:clean": "yarn prebuild:clean && npx expo run:ios -d --no-build-cache",
    "start": "expo start --dev-client"
  },
  "main": "index.js",
  "dependencies": {
    "@react-native-community/hooks": "^3.0.0",
    "@react-navigation/native": "^6.1.9",
    "expo": "~50.0.6",
    "expo-application": "~5.8.3",
    "expo-build-properties": "~0.11.1",
    "expo-constants": "~15.4.5",
    "expo-dev-client": "~3.3.8",
    "react": "18.2.0",
    "react-native": "0.73.4",
    "react-native-gesture-handler": "~2.14.1",
    "react-native-hole-view": "^3.0.0-alpha4",
    "react-native-reanimated": "~3.7.1",
    "react-native-safe-area-context": "4.8.2",
    "react-native-svg": "^14.1.0",
    "react-native-vector-icons": "^10.0.3",
    "react-native-vision-camera": "3.9.0-beta.6",
    "react-native-vision-camera-face-detector": "^1.2.3",
    "react-native-worklets-core": "^0.3.0"
  },
  "devDependencies": {
    "@babel/core": "^7.23.9",
    "@babel/preset-env": "^7.22.10",
    "@babel/runtime": "^7.23.9",
    "@react-native/metro-config": "^0.72.9",
    "@react-native/typescript-config": "^0.73.0",
    "@types/react": "~18.2.48",
    "@types/react-native-vector-icons": "^6.4.13",
    "@typescript-eslint/eslint-plugin": "^6.19.1",
    "@typescript-eslint/parser": "^6.19.1",
    "babel-plugin-module-resolver": "^5.0.0",
    "eslint": "^8.56.0",
    "eslint-config-google": "^0.14.0",
    "eslint-config-next": "^14.1.0",
    "eslint-plugin-import": "^2.29.1",
    "eslint-plugin-react": "^7.33.2",
    "metro-react-native-babel-preset": "^0.77.0",
    "typescript": "^5.3.3"
  },
  "resolutions": {
    "@expo/config-plugins": "^7.8.0"
  }
}
luicfrr commented 7 months ago

@mrousavy I made a little progress, at least my app is not crashing anymore... I created a custom runAsync method inside my function but using useWorklet and useSharedValue hookd from worklets core. With this change my app stop crashing and my custom runAsync is called everytime.

This is my code at this moment.

Maybe there's a problem with Worklets.createContext method because this is the only method that (I think) is not used in this workaround.

robertyulisman commented 7 months ago

@mrousavy I made a little progress, at least my app is not crashing anymore... I created a custom runAsync method inside my function but using useWorklet and useSharedValue hookd from worklets core. With this change my app stop crashing and my custom runAsync is called everytime.

This is my code at this moment.

Maybe there's a problem with Worklets.createContext method because this is the only method that (I think) is not used in this workaround.

hay @nonam4 i am using your lib react-native-vision-camera-face-detector, but still get error that say

"Frame Processor Error: Regular javascript function '' cannot be shared. Try decorating the function with the 'worklet' keyword to allow the javascript function to be used as a worklet., js engine: VisionCamera", i am following example from documentation, can you help me, btw its a great lib

this is the code :

 const handleDetectionWorklet = Worklets.createRunInJsFn((result: DetectionResult) => {
    console.log('detection result', result);
  });

  const frameProcessor = useFrameProcessor(
    (frame) => {
      'worklet';
      console.log('frame.toString()', frame.toString());
      runAsync(frame, () => {
        'worklet';
        detectFaces(frame, handleDetectionWorklet, {
          performanceMode: 'accurate',
          landmarkMode: 'all',
          contourMode: 'all',
          convertFrame: true,
        });
      });
    },
    [handleDetectionWorklet],
  );

image

image

bglgwyng commented 7 months ago

@robertyulisman I had the same problem. If you are using reanimated in your project, you need to add processNestedWorklets: true in your babel configuration.

robertyulisman commented 7 months ago

@bglgwyng still not working, my app get crashed image

luicfrr commented 7 months ago

still not working, my app get crashed

Take a look into native logs and see if they are the same as those on this issue... if yes then wellcome to the club πŸ˜… You can try my workaround in this comment and see if it works for you.

Also, take a look here, maybe you're just missing a cache reset

chrfalch commented 7 months ago

Sorry for the delay, @nonam4 - but why would you create a reanimated component of the camera? This is AFAIK not something that should be needed (wrap it in a parent animated view if you want to animate it) and might lead to undefined behaviors (as you are seeing):

const ReanimatedCamera = Reanimated.createAnimatedComponent( Camera )

if you don’t use the above and add react-native-svg - does your app still crash?

luicfrr commented 7 months ago

@chrfalch I’m following example app and it have a reanimated camera.

About crashes, I found a workaround. I suppose my app was crashing because of Worklets.createContext method. In my workaround it’s not crashing anymore

mrousavy commented 7 months ago

why would you create a reanimated component of the camera? This is AFAIK not something that should be needed

@chrfalch it is - that's for when you want to animate zoom or exposure using Reanimated :)

mrousavy commented 5 months ago

I think this has been fixed in react-native-worklets-core 1.x.x.! πŸŽ‰