react-native-vision-camera
react-native-vision-camera copied to clipboard
🐛 Memory Leak on camera.takePhoto after 6 six shots.
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
- [ ] I am using Expo
- [ ] I have enabled Frame Processors (react-native-worklets-core)
- [X] I have read the Troubleshooting Guide
- [X] I agree to follow this project's Code of Conduct
- [X] I searched for similar issues in this repository and found none.