相机滤镜掉帧用VisionCamera实时帧处理跑通60FPS【免费下载链接】react-native-vision-camera A powerful, high-performance React Native Camera library.项目地址: https://gitcode.com/GitHub_Trending/re/react-native-vision-camera在 React Native 相机应用里做实时滤镜最怕的就是画面一糊一卡处理回调一旦挤进 JS 主线程帧数据还要反复序列化掉帧几乎是必然的。有没有办法让相机帧不经过 JS 桥、直接在你的代码里被处理并且稳定跑满 60FPS有办法答案就是 react-native-vision-camera 的 Frame Output帧输出机制配合 SkiaGPU 加速的 2D 图形库渲染。读完后你能直接做三件事跑通一个真实时帧输出的 Demo、用 Skia 在相机帧上绘制实时滤镜贴纸、用分辨率与像素格式两个旋钮把 60FPS 调稳。理解Frame Output的核心机制传统做法里相机帧先拷贝到 JS 线程再处理每一帧都在排队等序列化VisionCamera 的 Frame Output 相当于把处理回调直接搬进相机管线内部——useFrameOutput()的onFrame回调以 Worklet在独立线程运行的 JS 函数身份运行在相机原生线程上Frame则是一个 GPU 帧缓冲的句柄交给 Skia 时零拷贝导入绘制全程不离开 GPU。整条链路里不存在帧数据过 JS 桥这一步这正是它能跑满 60FPS 的原因。VisionCamera 文档站首页的相机预览画面示意实时帧处理的目标观感对比维度传统 JS 桥方案VisionCamera 帧处理帧数据路径拷贝到 JS 主线程再序列化相机线程内直接处理零拷贝处理线程JS 主线程易被 UI 抢占独立相机线程绘制能力基本依赖 Canvas 2DSkia 硬件加速 2D 绘制开发者负担手动管理回调时序仍需手动dispose()帧见后文最后一行值得留意库替你把管线搭好了但帧缓冲池只有几个用完不归还管线就会主动丢帧。这是后文所有调优问题的主线。安装依赖并配置最小可运行环境useFrameOutput()依赖 worklet 运行时所以除核心库外还要装 worklets 桥接包与 Skia 集成包这段命令解决onFrame 回调跑在哪里、谁来绘制两个问题npm install react-native-vision-camera # 原生模块与图像类型支持 npm install react-native-nitro-modules react-native-nitro-image # worklet 运行时 VisionCamera 的 worklets 桥接 npm install react-native-worklets react-native-vision-camera-worklets # Skia 图形渲染高级绘制场景需要 npm install shopify/react-native-skia react-native-vision-camera-skiareact-native-worklets 的 Babel 转换配置请以 react-native-worklets 官方文档为准。配置iOS相机权限在ios/Info.plist的CFBundleLocalizations同级字典里补上相机用途描述解决冷启动直接崩溃、系统不弹授权框的问题改完执行cd ios pod install重新构建原生层dict !-- 缺少此 key 时请求相机会直接失败而非弹窗 -- keyNSCameraUsageDescription/key string$(PRODUCT_NAME) 需要访问相机以实时处理画面/string /dict配置Android相机权限在android/app/src/main/AndroidManifest.xml中声明相机权限解决SecurityException崩溃问题manifest xmlns:androidhttp://schemas.android.com/apk/res/android !-- 缺此行时 getCameraDevice 会直接抛 SecurityException -- uses-permission android:nameandroid.permission.CAMERA / !-- 可选仅录视频才需要 RECORD_AUDIO -- /manifest配好后useCameraDevice(back)返回设备、useFrameOutput()订阅相机帧就是全部的最小集。官方 simple-camera 示例应用的相机帧预览效果展示实时帧处理的目标形态实战场景一渲染实时相机帧输出目标让相机预览上屏并确认你的 JS 回调真的在每帧被调用。关键APIuseCameraDevice(position)按位置back/front拿到可用的CameraDevice。useFrameOutput(options)创建帧输出onFrame以 Worklet 形式运行在相机线程。Camera /把frameOutput挂进outputs数组即开始推帧。实现// tsx import { StyleSheet, View } from react-native import { Camera, useCameraDevice, useFrameOutput } from react-native-vision-camera function App() { const device useCameraDevice(back) const frameOutput useFrameOutput({ onFrame(frame) { worklet // 必须声明回调要运行在相机线程而非主线程 console.log(收到 ${frame.width}x${frame.height} 帧) frame.dispose() // 归还缓冲缺失它管线很快会丢帧 } }) if (device null) return View / return ( View style{styles.container} Camera style{StyleSheet.absoluteFill} device{device} isActive{true} outputs{[frameOutput]} // 挂载帧输出相机才开始推帧 / /View ) }效果与注意控制台应稳定打印帧尺寸预览正常上屏。最典型的坑漏掉frame.dispose()后几秒内就会收到out-of-buffers丢帧告警——缓冲区被未释放的帧占满管线只能丢新帧。画框上屏只是起点。想让滤镜真正画在相机帧上就得把 Skia 的 GPU 画布接进帧管线。实战场景二用Skia在GPU上绘制实时滤镜目标在相机帧上叠加一个 GPU 加速的滤镜贴纸全程不离开 GPU。关键APISkiaCamera /Skia 版相机视图自带离屏 Skia 画布忘记绘制时它是黑屏画面必须手动画。render({ frameTexture, canvas })把Frame包装成纹理frameTexture交给你在canvas上自由绘制。Skiashopify/react-native-skia暴露的绘制 API文本、矩形、图片、着色器都在此。实现// tsx import { SkiaCamera } from react-native-vision-camera-skia import { Skia } from shopify/react-native-skia function App() { const paint Skia.Paint() // 声明在外部避免每帧新建原生对象 return ( SkiaCamera style{StyleSheet.absoluteFill} isActive{true} deviceback onFrame{(frame, render) { worklet render(({ frameTexture, canvas }) { // 先把原始帧画上去否则画面是纯黑 canvas.drawImage(frameTexture, 0, 0) // 叠加滤镜贴纸GPU 加速文本绘制 paint.setColor(Skia.Color(#FF3B30)) paint.setTextSize(48) canvas.drawText(REALTIME FILTER, 60, 200, paint) }) frame.dispose() }} / ) }效果与注意预览之上会实时叠加红色文字贴纸。一个容易踩的坑SkiaCamera /不自动上屏render回调里不画frameTexture就是黑屏——它把画什么的权力完全交给了你旋转与镜像补偿已在库内部完成见 a-frames-nativebuffer 的 NativeBuffer 说明。贴纸目前还不会跟随交互。加上点按对焦滤镜应用才算有了操作感。实战场景三实现点按对焦与坐标转换交互目标点屏幕哪里镜头就对焦哪里并且坐标自动落在帧坐标系内。关键APISkiaCameraRef.convertViewPointToNormalizedPoint(viewPoint)把视图坐标转成0...1的归一化坐标。Frame.convertCameraPointToFramePoint(point)把归一化坐标映射回当前帧的像素坐标。focusTo(viewPoint)把焦点与测光移到指定帧坐标。实现// tsx import { useRef } from react import { StyleSheet } from react-native import { SkiaCamera, type SkiaCameraRef } from react-native-vision-camera-skia function App() { const ref useRefSkiaCameraRef(null) return ( SkiaCamera ref{ref} style{StyleSheet.absoluteFill} isActive{true} deviceback onLongPressGestureHandler{(evt) { worklet // 点按位置转成帧坐标系避免横竖屏/镜像下的坐标错位 const cameraPoint ref.current .convertViewPointToNormalizedPoint({ x: evt.localX, y: evt.localY }) ref.current?.focusTo(cameraPoint) }} onFrame{(frame, render) { worklet render(({ frameTexture, canvas }) { canvas.drawImage(frameTexture, 0, 0) }) frame.dispose() }} / ) }效果与注意长按屏幕任意位置焦点环会出现在你点的位置参考 tap-to-focus。注意focusTo的坐标是帧坐标系已含旋转/镜像补偿直接塞屏幕像素坐标在横屏时会点错地方——这也是仓库里 coordinate-systems 文档专门讲的事。以上三段代码在 iOS 与 Android 上完全一致平台差异由库内部消化差异项iOSAndroid底层相机栈AVFoundationCameraXGPU 缓冲导入系统像素缓冲外部纹理Skia 支持private格式你的代码同一份 TS 代码同一份 TS 代码排查高频问题并调优60FPS性能问题1帧输出持续告警out-of-buffers现象控制台反复打印 Frame Dropped预览明显卡顿。 根因帧缓冲池只有几个dispose()调用太晚池被未归还的帧占满。 解法把frame.dispose()放进finally保证异常路径也归还缓冲onFrame(frame) { worklet try { // 处理逻辑 } finally { frame.dispose() } }问题2SkiaCamera /黑屏现象预览区域全黑但相机会话日志显示已启动。 根因Skia 视图不会替你画帧render里没绘制frameTexture。 解法回调里第一行就canvas.drawImage(frameTexture, 0, 0)。问题3前置摄像头画面左右镜像与贴纸错位现象贴纸位置看起来反了。 根因输出镜像模式与像素缓冲实际镜像不一致你按屏幕直觉算了坐标。 解法mirrorMode设为auto前置自动镜像坐标一律走transformPoint/归一化坐标 API别手算。问题4人脸等原生模型识别精度低、耗时高现象同样的模型在 VisionCamera 里比原生 App 慢且糊。 根因pixelFormat选了rgb每帧多一次转换且占用约 2.6 倍于yuv的带宽。 解法按模型选格式——MLKit/OpenCV 直接用yuvLiteRT 内部会转 RGB直接给rgb更省完整对照见 pixel-formats-map。性能调优策略单帧处理耗时超过 16ms60FPS 预算时优先降分辨率或换像素格式最后才降帧率。像素数据量与分辨率面积成正比把targetResolution从CommonResolutions.FHD_16_91080×1920降到HD_16_9720×1280单帧数据量减少约 60%const frameOutput useFrameOutput({ targetResolution: CommonResolutions.HD_16_9, // 720p滤镜场景性价比最高的档位 pixelFormat: yuv, // 比 rgb 少一次转换带宽低约 2.6 倍 onFrame(frame) { worklet // ... frame.dispose() } })资源释放时机容易被忽视Skia 离屏 Surface 缓存会在 15 秒无操作后自动释放见 SurfacesCache但频繁进出相机页时建议显式调用clearSurfacesCache()立即归还 GPU 显存。onFrame必须是同步 workletworklet指令声明后回调运行在独立相机线程在主线程里做的任何等待都会直接表现为丢帧。从相机帧跑进相机线程、用 Skia 画在 GPU 上到分辨率与像素格式两个旋钮调稳 60FPS——Frame Output、Skia 绘制与性能调优三件事现在都已落地。继续深入可以看这几篇仓库文档Frame Output 指南Skia Frame Processors像素格式对照表NativeBuffer 零拷贝帧帧率与分辨率约束如果这篇对你有帮助欢迎点赞收藏关于用着色器写 GPU 滤镜的深入实践我们下篇见。【免费下载链接】react-native-vision-camera A powerful, high-performance React Native Camera library.项目地址: https://gitcode.com/GitHub_Trending/re/react-native-vision-camera创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考