Error: App crashes due to EXC_BAD_ACCESS error at ResizePlugin.mm
code to reproduce:
Just a simple skia frame processor to detect face and crop it.
const frameProcessor = useSkiaFrameProcessor(frame => {
'worklet'
frame.render()
const _faces = detectFaces(frame)
_faces.forEach((face, idx) => {
const faceContainerPath = Skia.Path.Make()
if (face.bounds) {
const rect = Skia.XYWHRect(
face.bounds.x,
face.bounds.y,
face.bounds.height,
face.bounds.width,
)
faceContainerPath.addOval(rect)
faceContainerPath.trim(0, scanProgressWorkletSharedValue.value, false)
frame.save()
if (!faceContainerPaints.value[idx]) {
faceContainerPaints.value[idx] = Skia.Paint()
faceContainerPaints.value[idx].setStyle(PaintStyle.Stroke)
faceContainerPaints.value[idx].setStrokeWidth(4)
faceContainerPaints.value[idx].setColor(Skia.Color('red'))
}
faceContainerPaints.value[idx].setColor(
Skia.Color(face.yawAngle >= 8 || face.yawAngle <= -8 ? 'green' : 'red'),
)
frame.drawPath(faceContainerPath, faceContainerPaints.value[idx])
frame.restore()
runAtTargetFps(1, () => {
'worklet'
try {
const resized = resize(frame, {
scale: {
width: 112,
height: 112,
},
crop: {
x: face.bounds.x,
y: face.bounds.y,
width: Math.max(face.bounds.width, face.bounds.height),
height: Math.max(face.bounds.width, face.bounds.height),
},
pixelFormat: 'rgb',
dataType: 'uint8',
})
onFaceResized(resized)
} catch (error) {
ErrorHandler.processWithoutFeedback(error)
}
})
}
})
}, [])
logs:
I've tried to run it inside "runAsync" and without it, but the most stable variant was runAtTargetFps, so now this error happens not every time. Also starting metro server with empty cache helps. But anyway this error keep throwing after few second.
dependencies:
- "react-native": "0.76.5",
- "expo": "52.0.18",
- "react-native-vision-camera": "4.6.3",
- "react-native-vision-camera-face-detector": "^1.8.1",
- "vision-camera-resize-plugin": "^3.2.0",
- "react-native-worklets-core": "1.5.0",
- "react-native-reanimated": "3.16.3",
- "@shopify/react-native-skia": "^1.11.7",
tested on iphone 16 pro device
UPD:
current workaround i found from this post
// Cache array buffer to avoid it being constantly re-allocated
const CACHE_ID = '__cachedArrayForResizer'
function getArrayFromCache(size: number): Uint8Array {
'worklet'
if (global[CACHE_ID] == null || global[CACHE_ID].length != size) {
global[CACHE_ID] = new Uint8Array(size)
}
return global[CACHE_ID]
}
type ResizeOptions = {
width: number // target width, e.g., 256
height: number // target height, e.g., 256
cropX: number // starting x coordinate of the crop in the source frame
cropY: number // starting y coordinate
cropWidth: number // width of the crop region (e.g., face.bounds.width)
cropHeight: number // height of the crop region
}
// Resize any Frame to the target width and height in RGB format.
export function resize(frame: Frame, opts: ResizeOptions): Uint8Array {
'worklet'
const inputWidth = frame.width
const inputHeight = frame.height
const arrayData = frame.toArrayBuffer()
const outputSize = opts.width * opts.height * 3 // 3 for RGB
const outputFrame = getArrayFromCache(outputSize)
for (let y = 0; y < opts.height; y++) {
for (let x = 0; x < opts.width; x++) {
const srcX = Math.floor(opts.cropX + (x / opts.width) * opts.cropWidth)
const srcY = Math.floor(opts.cropY + (y / opts.height) * opts.cropHeight)
// Compute the source and destination index
const srcIndex = (srcY * inputWidth + srcX) * 4 // 4 for BGRA
const destIndex = (y * opts.width + x) * 3 // 3 for RGB
// Convert from BGRA to RGB
outputFrame[destIndex] = arrayData[srcIndex + 2] // R
outputFrame[destIndex + 1] = arrayData[srcIndex + 1] // G
outputFrame[destIndex + 2] = arrayData[srcIndex] // B
}
}
return outputFrame
}
upd: turn out i've made resize plugins work more stable if i delay frame processing by couple seconds. But in a minute app crashes anyway.
Error: App crashes due to EXC_BAD_ACCESS error at ResizePlugin.mm
code to reproduce:
Just a simple skia frame processor to detect face and crop it.
logs:
I've tried to run it inside "runAsync" and without it, but the most stable variant was runAtTargetFps, so now this error happens not every time. Also starting metro server with empty cache helps. But anyway this error keep throwing after few second.
dependencies:
tested on iphone 16 pro device
UPD:
current workaround i found from this post
upd: turn out i've made resize plugins work more stable if i delay frame processing by couple seconds. But in a minute app crashes anyway.