docs: write down the camera port and the live-view plan

CAMERA_PORT_ANDROID.md lists only what the web build has that Android does
not, one row per gap, with the web file to read next to the Android one.
The plan alongside it is the sketch for a live camera with a Skia filter
on the frame thread.
This commit is contained in:
2026-09-28 17:36:30 +07:00
parent 8dc409777e
commit 3312facd82
2 changed files with 364 additions and 0 deletions
@@ -0,0 +1,106 @@
# Kế hoạch: Real-time Skia filter trên camera live view dùng vision-camera v4
## Vấn đề
`expo-camera` render camera preview lên native surface (PreviewView/SurfaceView) không thể intercept bằng Skia. Periodic capture bị từ chối vì mất live view.
## Giải pháp
Dùng `react-native-vision-camera@4.7.3` với `useSkiaFrameProcessor` — frame processor chạy native thread, mỗi frame camera được vẽ qua Skia với ColorMatrix trước khi hiển thị.
## Các bước thực hiện
### Bước 1: Cài react-native-vision-camera@4.7.3
```bash
npm install react-native-vision-camera@4.7.3
```
- v4.7.3 là latest v4, có export `useSkiaFrameProcessor` và `frameProcessor` prop trên `Camera`
- v5+ đã xoá Skia integration, không dùng được
### Bước 2: Thêm Expo Config Plugin
Sửa `app.json`:
- Thay `expo-camera` plugin bằng `react-native-vision-camera` plugin (v4 có plugin riêng)
- Thêm `withEnableFrameProcessorsAndroid` để bật frame processor trên Android
```json
"plugins": [
"react-native-vision-camera",
[
"expo-camera",
{
"cameraPermission": "..."
}
]
]
```
Cần kiểm tra: v4 có expo plugin riêng (`withVisionCamera`) hay dùng thẳng tên package.
### Bước 3: Cập nhật App.tsx
- Import `useCameraPermission` từ `react-native-vision-camera` thay vì `useCameraPermissions` từ `expo-camera`
- Props: `hasPermission`, `requestPermission`
### Bước 4: Viết lại Viewfinder.tsx
Component mới dùng:
- `Camera` từ vision-camera với prop `frameProcessor={frameProcessor}`
- `useSkiaFrameProcessor` hook — worklet chạy native, mỗi frame:
1. Tạo `Skia.Paint()` với `Skia.ColorFilter.MakeMatrix(colorMatrix)`
2. Gọi `frame.render(paint)` — vẽ frame qua color filter
- `colorMatrix` là `SharedValue` từ react-native-reanimated (để worklet đọc được)
- Grain noise, frame border, GPS watermark: giữ nguyên overlay React Native / Skia Canvas trên top
```tsx
const App = () => {
const frameProcessor = useSkiaFrameProcessor((frame) => {
'worklet';
const paint = Skia.Paint();
paint.setColorFilter(Skia.ColorFilter.MakeMatrix(colorMatrixSV.value));
frame.render(paint);
}, [colorMatrixSV]);
return (
<Camera
style={StyleSheet.absoluteFill}
device={device}
isActive={true}
frameProcessor={frameProcessor}
/>
);
};
```
### Bước 5: Loại bỏ expo-camera khỏi code
- `CameraView` → `Camera` (vision-camera)
- Xoá imports không dùng
- Giữ `expo-camera` trong package.json (không gỡ, tránh lỗi autolinking)
### Bước 6: Re-prebuild & build APK
```bash
rm -rf android
npx expo prebuild --platform android
echo "sdk.dir=/home/locpham/android-sdk" > android/local.properties
cd android && ./gradlew assembleDebug
```
(Không chạy `clean` — tránh lỗi CMake codegen paths)
## API đã xác nhận (v4.7.3)
| Export | Path |
|---|---|
| `Camera` | `react-native-vision-camera` |
| `useCameraDevice` | `react-native-vision-camera` |
| `useCameraPermission` | `react-native-vision-camera` |
| `useSkiaFrameProcessor` | `react-native-vision-camera` |
| `SkiaCameraCanvas` | `react-native-vision-camera` |
| Expo plugin (`withVisionCamera`) | `lib/module/expo-plugin/withVisionCamera` |
## Rủi ro & Xử lý
| Rủi ro | Xử lý |
|---|---|
| `react-native-worklets-core` conflict | Đã có sẵn qua `react-native-reanimated` dependency |
| CameraX dependency (`NoClassDefFoundError`) | v4 dùng `CameraX` không phải Nitro — build an toàn hơn v5 |
| CMake codegen paths lỗi sau `clean` | Không dùng `./gradlew clean`, dùng `--rerun-tasks` nếu cần |
| Frame processor không chạy trên Android | Bật flag qua Expo plugin: `withEnableFrameProcessorsAndroid` |
## Kiểm thử
1. Build APK thành công
2. Camera live view hiển thị với filter:
- B&W/monochrome → true grayscale
- Saturation, temp, tint, exposure thay đổi real-time
3. Grain noise, frame border, GPS watermark vẫn hoạt động
4. Library mode không bị ảnh hưởng