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:
@@ -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"
|
||||
/>
|
||||
|
Reference in New Issue
Block a user