mrousavy / react-native-vision-camera

📸 A powerful, high-performance React Native Camera library.
https://react-native-vision-camera.com
MIT License
7.46k stars 1.09k forks source link

🐛 runAsync(..) cannot be used #3255

Open kHanHnq4901 opened 2 days ago

kHanHnq4901 commented 2 days ago

What's happening?

Screenshot_1729485004

Reproduceable Code

import React, { useCallback, useEffect, useRef, useState } from 'react';
import { StyleSheet, View, Text, Button, StatusBar, Alert, TouchableOpacity } from 'react-native';
import { onEndPress, onResetPress, onStartPress ,onSavePress, onDisconnectPress, changeSaturation} from './handle';
import { store, GetHookProps } from './controller';
import { Camera, runAtTargetFps, useSkiaFrameProcessor,  useCameraFormat, getCameraDevice,runAsync, CameraPermissionRequestResult, useFrameProcessor } from "react-native-vision-camera";
import { Points, Skia } from '@shopify/react-native-skia';
import { openCv } from './controller';
import { useIsFocused } from '@react-navigation/native';
import LinearGradient from 'react-native-linear-gradient'; 
import { onSavePressSetting } from '../setting/handle';
import Slider from '@react-native-community/slider';
import { Worklets, useSharedValue } from 'react-native-worklets-core';

const Header = () => (
  <View style={styles.header}>
    <Text style={styles.headerText}>Phần mềm kiểm sai số Đồng hồ nước</Text>
  </View>
);

const App =(props: { navigation: any }) => {
  GetHookProps();
  const { navigation } = props;
  const isFocused = useIsFocused();
  const [appState] = useState("active");
  const isActive = isFocused && appState === "active";
  const [hasCameraPermission, setHasCameraPermission] = useState<boolean>(false);
  const [cameraKey, setCameraKey] = useState(0);
  const [zoom, setZoom] = useState(false);
  const [lastPress, setLastPress] = useState(0);
  const onZoomPress = () => {
    const now = Date.now();
    if (now - lastPress < 1000) { // 3 giây
      Alert.alert('Thông báo', 'Thao tác quá nhanh');
      return;
    }
    setLastPress(now);
    setZoom(!zoom);
  };

  useEffect(() => {
    const unsubscribe = navigation.addListener('focus', () => {
      // Hàm này sẽ được gọi khi màn hình ScanQrCodeScreen được focus (hiển thị)

      console.log('App Screen is focused');
      setCameraKey(prevKey => prevKey + 1);// Update cameraKey to refresh the camera
      setZoom(false)
    });

    const checkPermissions = async () => {
      const status: CameraPermissionRequestResult = await Camera.requestCameraPermission();

      if (status === 'granted') {
          setHasCameraPermission(true);
      } else {
          setHasCameraPermission(false);
          Alert.alert('Quyền truy cập camera đã bị từ chối, vui lòng cấp quyền cho camera.');
      }
  };
    checkPermissions();
    return unsubscribe;
  }, [navigation]);
  const devices = Camera.getAvailableCameraDevices()
  const device = getCameraDevice(devices, 'back', {
    physicalDevices: [
      'wide-angle-camera',
    ]
  })
// Bộ xử lý khung
const frameProcessor = useFrameProcessor((frame) => {
  'worklet'

  runAsync(frame, () => {
    'worklet'
    console.log("I'm running asynchronously, possibly at a lower FPS rate!")
  })
}, [])

  const format = useCameraFormat(device, [

    { videoResolution: { width: 640, height: 480 } },

  ])

  return (
    <View style={styles.container}>
      <StatusBar barStyle="dark-content" hidden={false} backgroundColor="#3498db" translucent={true} />
      <Header />
      <View style={styles.statusContainer}>
        <Text style={styles.statusText}>Trạng thái kết nối:</Text>
        <View
          style={[
            styles.statusDot,
            { backgroundColor: store.state.isConnected ? 'green' : 'red' }, // Green if connected, red if disconnected

          ]}
        />
      </View>
      <View style={styles.body}>
        <View style={styles.cameraContainer}>
          {hasCameraPermission === false ? (
            <Text>Vui lòng cấp quyền truy cập camera...</Text>
          ) : (
            device && (
              <Camera
                key={cameraKey}
                style={StyleSheet.absoluteFill}
                device={device}
                isActive={isActive}
                zoom={zoom ? 10 : 1}
                frameProcessor={frameProcessor}
                enableFpsGraph={true}
                format={format}
                fps={[30, 30]}
                enableBufferCompression = {true}
            />
            )
          )}
          <View style={styles.infoContainer}>
            <Text style={styles.text}>Serial: {store.state.serial}</Text>
            <Text style={styles.text}>Dàn: {store.state.staging}</Text>
            <Text style={styles.text}>Loại: {store.state.type === 1 ? 'Kiểm' : 'Mẫu'}</Text>
            {/* <Text style={styles.text}>Kim : {store.state.color === 1 ? 'Đỏ Nhạt ' : store.state.color === 2 ? 'Đỏ Tươi' : 'Đỏ Đậm'}</Text> */}
            <Text style={styles.text}>Sai số dh mẫu: {store.state.error} %</Text>
            <Text style={styles.text}>
            Lưu lượng kiểm: {store.state.tai === 1 ? 'QI' : store.state.tai === 2 ? 'QII' : store.state.tai === 3 ? 'QIII' : 'Q3'}
            </Text>
            <Text style={styles.text}>Lưu lượng thực tế: {store.state.flow.toFixed(4)} m3/h</Text>
          </View>
        </View>
      </View>
      <View style={styles.buttons}>
        <TouchableOpacity style={styles.button} onPress={onZoomPress}>
          <Text style={styles.buttonText}>{zoom ? 'Thu nhỏ' : 'Phóng to'}</Text>
        </TouchableOpacity>
        {store.state.type === 0 && (
          <>
            <TouchableOpacity
              style={[
                styles.button,
                { backgroundColor: store.state.isStart === false ? '#FF0000' : '#008000' } // Red for 'Kết thúc', Green for 'Bắt đầu'
              ]}
              onPress={store.state.isStart === false ? onEndPress : onStartPress}
            >
              <Text style={styles.buttonText}>
                {store.state.isStart === false ? 'Kết thúc' : 'Bắt đầu'}
              </Text>
            </TouchableOpacity>
            <TouchableOpacity style={styles.button} onPress={onSavePress}>
              <Text style={styles.buttonText}>Lưu</Text>
            </TouchableOpacity>
            <TouchableOpacity style={styles.button} onPress={onResetPress}>
              <Text style={styles.buttonText}>Làm mới</Text>
            </TouchableOpacity>
          </>
        )}
      </View>
      {/* {(store.state.color === 1 || store.state.color === 2) && ( */}
          <View>
            <Text>Điều chỉnh độ bão hòa: {store.state.saturation}</Text>
            <Slider
              style={{width: '100%', height: 40}}
              minimumValue={50}
              maximumValue={255}
              minimumTrackTintColor="#000000"
              maximumTrackTintColor="#000000"
              step={1}
              value={store.state.saturation}
              onValueChange={(value) => {
                store.setState({
                  ...store.state,
                  saturation: value,
                });
                changeSaturation(value); // Call the function to update saturation
              }}
            />
          </View>
        {/* )} */}
       <View style={styles.footer}>
        <View style={styles.footerItem}>
          <Text style={styles.footerTitle}>Lượng nước</Text>
          <Text style={[styles.footerValue, { color: 'green' }]}>
            {store.state.round.toString().slice(0, store.state.round.toString().indexOf('.') + 4)} lít
          </Text>
        </View>
        <View style={styles.footerItem}>
          <Text style={styles.footerTitle}>Chênh lệch</Text>
          <Text style={[styles.footerValue, { color: store.state.correction > 1 || store.state.correction < -1 ? 'red' : 'green' }]}>
            {store.state.false.toString().slice(0, store.state.false.toString().indexOf('.') + 4)} lít

          </Text>
        </View>
        <View style={styles.footerItem}>
          <Text style={styles.footerTitle}>Tỉ lệ</Text>
          <Text style={[styles.footerValue, { color: store.state.correction > 1 || store.state.correction < -1 ? 'red' : 'green' }]}>
            {store.state.ratio.toString().slice(0, store.state.false.toString().indexOf('.') + 4)} %
          </Text>
        </View>
        <View style={styles.footerItem}>
          <Text style={styles.footerTitle}>Sai số</Text>
          <Text style={[styles.footerValue, { color: store.state.correction > 1 || store.state.correction < -1 ? 'red' : 'green' }]}>
            {store.state.type === 0 ? (
              store.state.error + '%'
            ) : (
              store.state.correction.toString().slice(0, store.state.false.toString().indexOf('.') + 4) + '%'
            )}
          </Text>
        </View>
        <View style={styles.footerItem}>
          <Text style={styles.footerTitle}>Kết quả</Text>
          <Text style={[styles.footerValue, { color: store.state.correction > 1|| store.state.correction < -1 ? 'red' : 'green' }]}>
            {store.state.correction >1 || store.state.correction < -1 ? 'Không đạt' : 'Đạt'}
          </Text>
        </View>
      </View>
    </View>
  );
};

Relevant log output

ERROR  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

Camera Device

{
  "formats": [],
  "hardwareLevel": "limited",
  "hasFlash": false,
  "hasTorch": false,
  "id": "10",
  "isMultiCam": false,
  "maxExposure": 6,
  "maxZoom": 1,
  "minExposure": -6,
  "minFocusDistance": 999.999985098839,
  "minZoom": 1,
  "name": "10 (BACK) androidx.camera.camera2",
  "neutralZoom": 1,
  "physicalDevices": [
    "ultra-wide-angle-camera"
  ],
  "position": "back",
  "sensorOrientation": "landscape-left",
  "supportsFocus": true,
  "supportsLowLightBoost": false,
  "supportsRawCapture": false
}

Device

Samsung Galaxy A03s

VisionCamera Version

4.5.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

maintenance-hans[bot] commented 2 days ago

Guten Tag, Hans here! 🍻

It looks like you are having some trouble with runAsync(..). One important thing, your log shows an error indicating that a regular JavaScript function cannot be shared. Make sure that you are decorating your function with the 'worklet' keyword to allow it to be used as a worklet.

Also, I see that you did not try to reproduce this issue in the VisionCamera Example app. It's important to do that, as it could help narrow down the problem. If the issue persists after trying the example app, please make sure to provide any relevant logs from there.

If you're not sure how to gather these logs, for Android you can use adb logcat, and for iOS, check the logs in Xcode. This information is crucial for mrousavy to help you!

Feel free to update your issue with more details, and we can take a closer look!

Note: If you think I made a mistake, please ping @mrousavy to take a look.

NFSMONSTR commented 1 day ago

May be related to #2820

Also for me helped setting babel.config like this

...
 plugins: [
      ['react-native-worklets-core/plugin'],
      ['react-native-reanimated/plugin', {processNestedWorklets: true}]
...      
kHanHnq4901 commented 18 hours ago

@NFSMONSTR I have set up babel.config like that and got this error Screenshot_1729645579