feat: Draw onto Frame as if it was a Skia Canvas (#1479)

* Create Shaders.ts

* Add `previewType` and `enableFpsGraph`

* Add RN Skia native dependency

* Add Skia Preview View on iOS

* Pass 1

* Update FrameHostObject.mm

* Wrap Canvas

* Lockfiles

* fix: Fix stuff

* chore: Upgrade RNWorklets

* Add `previewType` to set the Preview

* feat: Add Example

* Update project.pbxproj

* `enableFpsGraph`

* Cache the `std::shared_ptr<FrameHostObject>`

* Update CameraView+RecordVideo.swift

* Update SkiaMetalCanvasProvider.mm

* Android: Integrate Skia Dependency

* fix: Use new Prefix

* Add example for rendering shader

* chore: Upgrade CameraX

* Remove KTX

* Enable `viewBinding`

* Revert "Enable `viewBinding`"

This reverts commit f2a603f53b33ea4311a296422ffd1a910ce03f9e.

* Revert "chore: Upgrade CameraX"

This reverts commit 8dc832cf8754490d31a6192e6c1a1f11cdcd94fe.

* Remove unneeded `ProcessCameraProvider.getInstance()` call

* fix: Add REA hotfix patch

* fix: Fix FrameHostObject dead in runAsync

* fix: Make `runAsync` run truly async by dropping new Frames while executing

* chore: Upgrade RN Worklets to latest

* chore: Upgrade RN Skia

* Revert "Remove KTX"

This reverts commit 253f586633f7af2da992d2279fc206dc62597129.

* Make Skia optional in CMake

* Fix import

* Update CMakeLists.txt

* Update build.gradle

* Update CameraView.kt

* Update CameraView.kt

* Update CameraView.kt

* Update Shaders.ts

* Center Blur

* chore: Upgrade RN Worklets

* feat: Add `toByteArray()`, `orientation`, `isMirrored` and `timestamp` to `Frame` (#1487)

* feat: Implement `orientation` and `isMirrored` on Frame

* feat: Add `toArrayBuffer()` func

* perf: Do faster buffer copy

* feat: Implement `toArrayBuffer()` on Android

* feat: Add `orientation` and `isMirrored` to Android

* feat: Add `timestamp` to Frame

* Update Frame.ts

* Update JImageProxy.h

* Update FrameHostObject.cpp

* Update FrameHostObject.cpp

* Update CameraPage.tsx

* fix: Format Swift
This commit is contained in:
Marc Rousavy
2023-02-21 15:00:48 +01:00
committed by GitHub
parent 1f7a2e07f2
commit 12f850c8e1
49 changed files with 2166 additions and 85 deletions

View File

@@ -1,6 +1,6 @@
import * as React from 'react';
import { useRef, useState, useMemo, useCallback } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { Platform, StyleSheet, Text, View } from 'react-native';
import { PinchGestureHandler, PinchGestureHandlerGestureEvent, TapGestureHandler } from 'react-native-gesture-handler';
import {
CameraDeviceFormat,
@@ -25,6 +25,8 @@ import { examplePlugin } from './frame-processors/ExamplePlugin';
import type { Routes } from './Routes';
import type { NativeStackScreenProps } from '@react-navigation/native-stack';
import { useIsFocused } from '@react-navigation/core';
import { Skia } from '@shopify/react-native-skia';
import { FACE_SHADER } from './Shaders';
const ReanimatedCamera = Reanimated.createAnimatedComponent(Camera);
Reanimated.addWhitelistedNativeProps({
@@ -196,11 +198,37 @@ export function CameraPage({ navigation }: Props): React.ReactElement {
console.log('re-rendering camera page without active camera');
}
const frameProcessor = useFrameProcessor((frame) => {
'worklet';
const values = examplePlugin(frame);
console.log(`Return Values: ${JSON.stringify(values)}`);
}, []);
const radius = (format?.videoHeight ?? 1080) * 0.1;
const width = radius;
const height = radius;
const x = (format?.videoHeight ?? 1080) / 2 - radius / 2;
const y = (format?.videoWidth ?? 1920) / 2 - radius / 2;
const centerX = x + width / 2;
const centerY = y + height / 2;
const runtimeEffect = Skia.RuntimeEffect.Make(FACE_SHADER);
if (runtimeEffect == null) throw new Error('Shader failed to compile!');
const shaderBuilder = Skia.RuntimeShaderBuilder(runtimeEffect);
shaderBuilder.setUniform('r', [width]);
shaderBuilder.setUniform('x', [centerX]);
shaderBuilder.setUniform('y', [centerY]);
shaderBuilder.setUniform('resolution', [1920, 1080]);
const imageFilter = Skia.ImageFilter.MakeRuntimeShader(shaderBuilder, null, null);
const paint = Skia.Paint();
paint.setImageFilter(imageFilter);
const isIOS = Platform.OS === 'ios';
const frameProcessor = useFrameProcessor(
(frame) => {
'worklet';
console.log(`Width: ${frame.width}`);
if (isIOS) frame.render(paint);
else console.log('Drawing to the Frame is not yet available on Android. WIP PR');
},
[isIOS, paint],
);
return (
<View style={styles.container}>
@@ -224,6 +252,8 @@ export function CameraPage({ navigation }: Props): React.ReactElement {
photo={true}
video={true}
audio={hasMicrophonePermission}
enableFpsGraph={true}
previewType="skia"
frameProcessor={device.supportsParallelVideoProcessing ? frameProcessor : undefined}
orientation="portrait"
/>