Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

馃悰 Memory Leak on camera.takePhoto after 6 six shots. #2866

Open
3 of 5 tasks
mdottavi opened this issue May 9, 2024 · 3 comments
Open
3 of 5 tasks

馃悰 Memory Leak on camera.takePhoto after 6 six shots. #2866

mdottavi opened this issue May 9, 2024 · 3 comments
Labels
馃悰 bug Something isn't working

Comments

@mdottavi
Copy link

mdottavi commented May 9, 2024

What's happening?

I integrated latest RNVC 4.0.3 in my project.

After taking 6 photos correctly (I checked files are saved in cache folder of the device)
the takePhoto method get systematically stuck at the seventh execution (await props.camera.current.takePhoto does never end).

If I switch to another View and get back to the Camera View it resets and I can still get 6 goot photos before stucking again.

I tried to give some time from one shot and another but it does not change the issue. Fully reproducable Code is provided.

Devices: Motorola G84 5G

The error from LogCat at seventh shot is:
ImageReader-4080x3072f22m9-8855-21 waitForFreeSlotThenRelock TIMED_OUT dequeuedCount=0, acquiredCount=3, mMaxAcquiredBufferCount=9, mMaxDequeuedBufferCount=8
ImageReader-4080x3072f22m9-8855-21 dequeueBuffer: No free buffer is found!
getBufferLockedCommon: Stream 3: Can't dequeue next output buffer: Connection timed out (-110)

From the traces it look some buffer is not flushed after image acquisition.
Do I need to flush/empty some data ?

Reproduceable Code

import React, { useRef, useState, useCallback, useEffect } from 'react';
import Ripple from 'react-native-material-ripple';
import { View } from 'react-native';
import { Camera, useCameraDevice, useCameraPermission}  from 'react-native-vision-camera';


const CameraStyles = {
    containerPortrait: {flex: 1,backgroundColor: '#000000' },
    cameraWrapperPortrait: {flex: 1,justifyContent: 'center',alignItems: 'center',overflow: 'hidden' },
    cameraPortrait: { flex: 1, aspectRatio: 3/4 },
    buttonBarPortrait: { height: 90, padding: 10 },
    buttonsPortrait: { flexDirection: 'row',flex: 1, justifyContent: 'space-between', alignItems: 'center' },
    captureButton: { width: 40, height: 40, borderRadius: 20, backgroundColor: 'rgba(140, 140, 140, 0.3)', borderColor: 'white', borderWidth: 5}
};

function _TakePictureButton ( props){
    console.log("TakePictureButton Rendering...");
    const takePhoto = useCallback(async () => {
        console.log("takePhoto: started");
        try {
          if (props.camera.current == null) throw new Error('Camera ref is null!')
    
          console.log('Taking photo...')
          const photo = await props.camera.current.takePhoto({
            qualityPrioritization: 'quality',
            flash: props.flash,
            enableShutterSound: true,
          })
          console.log('Photo Taken!')
          props.onClick(photo, 'photo')
        } catch (e) {
          console.error('Failed to take photo!', e)
        }
      }, [props.camera, props.flash, props.flash]);
    
    return (
        <Ripple style={CameraStyles.captureButton} 
            rippleColor='rgb(256, 256, 256)' 
            rippleOpacity={1} 
            rippleDuration={400} 
            rippleCentered={true}
            rippleSize={78} 
            onPress={takePhoto}
            >
        </Ripple>
    );
}
const TakePictureButton = React.memo(_TakePictureButton);

function App(props) {
    console.log("Rendering ...");

    const camera = useRef(null);
    const [orientation, setOrientation] = useState('Portrait');
    const { hasPermission, requestPermission } = useCameraPermission();

    useEffect(() => {
        async function getPermission() {
            const newCameraPermission = await requestPermission();
            console.log("getPermission returned: " + newCameraPermission);
            if (!newCameraPermission) {
                logger.error("getPermission returned: " + newCameraPermission);
            }
        }
        if (!hasPermission) {
            getPermission();
        }
    }, []);

    const [flash, setFlash] = useState('off');
    const device = useCameraDevice('back');

    // Camera callbacks
    const onError = useCallback((error) => {
        logger.error(error);
    }, []);

    const onInitialized = useCallback(() => {
        console.log('Camera initialized!');
    }, []);

    const onMediaCaptured = useCallback(
        async (media, type) => {
            try {
                console.log(`onMediaCaptured: Image captured. ${type} src=${media.path}`);
            } catch (err) {
                    logger.error("EXCEPTION: takePicture:", err);
            }            
        });

    if (device != null ) {
        console.log(`Rendering TakePicture with camera device: "${device.name}" photo Flash: ${flash}`);
    } else {
        console.log('Rendering TakePicture without active camera');
    }

    return (
        <View style={CameraStyles.containerPortrait}>
            {device != null && (<>
                <View style={CameraStyles.cameraWrapperPortrait}>
                        <Camera
                            style={CameraStyles.cameraPortrait}
                            device={device}
                            isActive={true}
                            ref={camera}
                            onInitialized={onInitialized}
                            onError={onError}
                            onStarted={() => 'Camera started!'}
                            onStopped={() => 'Camera stopped!'}
                            orientation={orientation}
                            lowLightBoost={false}
                            enableZoomGesture={false}
                            exposure={0}
                            photo={true}
                            video={false}
                            audio={false}
                            torch={flash}
                        />
                </View>
                <View style={CameraStyles.buttonBarPortrait}>
                    <View style={CameraStyles.buttonsPortrait}>
                        <TakePictureButton
                            camera={camera}
                            onClick={onMediaCaptured}
                            flash={false}
                        />
                    </View>
                </View>
            </>
            )}

        </View>
    );
}
export default App;

Relevant log output

Log from the app:
==============================================
 LOG  Running "appname" with {"rootTag":61}
 LOG  Rendering ...
 LOG  Rendering TakePicture with camera device: "0 (BACK) androidx.camera.camera2" photo Flash: off
 LOG  TakePictureButton Rendering...
 LOG  Rendering ...
 LOG  Rendering TakePicture with camera device: "0 (BACK) androidx.camera.camera2" photo Flash: off
 LOG  TakePictureButton Rendering...
 LOG  Rendering ...
 LOG  Rendering TakePicture with camera device: "0 (BACK) androidx.camera.camera2" photo Flash: off
 LOG  Camera initialized!
 LOG  takePhoto: started
 LOG  Taking photo...
 LOG  Photo Taken!
 LOG  onMediaCaptured: Image captured. photo src=/data/user/0/com.appname/cache/mrousavy-6048323629045401133.jpg
 LOG  takePhoto: started
 LOG  Taking photo...
 LOG  Photo Taken!
 LOG  onMediaCaptured: Image captured. photo src=/data/user/0/com.appname/cache/mrousavy-5487193471359461827.jpg
 LOG  takePhoto: started
 LOG  Taking photo...
 LOG  Photo Taken!
 LOG  onMediaCaptured: Image captured. photo src=/data/user/0/com.appname/cache/mrousavy-1734632536699059492.jpg
 LOG  takePhoto: started
 LOG  Taking photo...
 LOG  Photo Taken!
 LOG  onMediaCaptured: Image captured. photo src=/data/user/0/com.appname/cache/mrousavy-8567952871727161939.jpg
 LOG  takePhoto: started
 LOG  Taking photo...
 LOG  Photo Taken!
 LOG  onMediaCaptured: Image captured. photo src=/data/user/0/com.appname/cache/mrousavy-3879283333994109308.jpg
 LOG  takePhoto: started
 LOG  Taking photo...
 LOG  Photo Taken!
 LOG  onMediaCaptured: Image captured. photo src=/data/user/0/com.appname/cache/mrousavy-1440988497951052873.jpg
 LOG  takePhoto: started
 LOG  Taking photo...
 LOG  takePhoto: started
 LOG  Taking photo...

LOGCAT OUTPUT: when the problem happens.
========================================================

2024-05-09 15:04:40.033  8855-10023 BufferQueueProducer     com.appname                  D  [ImageReader-4080x3072f22m9-8855-21](id:22970000002d,api:4,p:1476,c:8855) waitForFreeSlotThenRelock TIMED_OUT dequeuedCount=0, acquiredCount=3, mMaxAcquiredBufferCount=9, mMaxDequeuedBufferCount=8
2024-05-09 15:04:40.033  8855-10023 BufferQueueProducer     com.appname                  D  [ImageReader-4080x3072f22m9-8855-21](id:22970000002d,api:4,p:1476,c:8855) dequeueBuffer: No free buffer is found!
2024-05-09 15:04:40.034  1228-1477  SurfaceFlinger          surfaceflinger                       E  Permission Denial: can't access SurfaceFlinger pid=8855, uid=10521
2024-05-09 15:04:40.034  1476-19614 Camera3-OutputStream    cameraserver                         E  getBufferLockedCommon: Stream 3: Can't dequeue next output buffer: Connection timed out (-110)
2024-05-09 15:04:40.275  8855-19610 CameraView              com.appname                  I  invokeOnAverageFpsChanged(0.0)
2024-05-09 15:04:40.818  2684-2684  StatusBarIconController com.android.systemui                 D  ignoring old pipeline callback because the new wifi icon is enabled
2024-05-09 15:04:41.035  8855-8870  BufferQueueProducer     com.appname                  D  [ImageReader-4080x3072f22m9-8855-21](id:22970000002d,api:4,p:1476,c:8855) waitForFreeSlotThenRelock TIMED_OUT dequeuedCount=0, acquiredCount=3, mMaxAcquiredBufferCount=9, mMaxDequeuedBufferCount=8
2024-05-09 15:04:41.035  8855-8870  BufferQueueProducer     com.appname                  D  [ImageReader-4080x3072f22m9-8855-21](id:22970000002d,api:4,p:1476,c:8855) dequeueBuffer: No free buffer is found!
2024-05-09 15:04:41.036  1228-1477  SurfaceFlinger          surfaceflinger                       E  Permission Denial: can't access SurfaceFlinger pid=8855, uid=10521
2024-05-09 15:04:41.037  1476-19614 Camera3-OutputStream    cameraserver                         E  getBufferLockedCommon: Stream 3: Can't dequeue next output buffer: Connection timed out (-110)

Camera Device

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

Device

Motorola G84 5G

VisionCamera Version

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

@mdottavi mdottavi added the 馃悰 bug Something isn't working label May 9, 2024
@mdottavi
Copy link
Author

mdottavi commented May 9, 2024

Motorola G84 5G (Android 14)
Same thing happens (6 photos good) seventh stucks also on Android OnePlus Nord 3 (Android 14)

@mdottavi
Copy link
Author

The issue does not show up in the CameraExample as it is....
BUT just removing the
format={format}
parameter passed to the Camera Component it happens exactly the same.

@mrousavy
Copy link
Owner

hm interesting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
馃悰 bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants