跳转到主要内容

视频

React Native Skia 提供了一种将视频帧加载为图像的方法,从而在您的应用程序中实现丰富的多媒体体验。视频帧可以用于任何接受 Skia 图像的地方:ImageImageShaderAtlas。Web 也支持视频。

要求

  • Reanimated 版本 3 或更高版本。
  • Android: API 级别 26 或更高版本。

示例

以下是如何在 React Native Skia 中使用视频支持的示例。此示例演示如何在画布中加载和显示视频帧,并应用颜色矩阵以获得视觉效果。点击屏幕将暂停和播放视频。

视频可以是远程 (http://...) 或本地 URL (file://),也可以是来自捆绑包的视频

tsx
import React from "react";
import {
Canvas,
ColorMatrix,
Fill,
ImageShader,
useVideo
} from "@shopify/react-native-skia";
import { Pressable, useWindowDimensions } from "react-native";
import { useSharedValue } from "react-native-reanimated";
 
export const VideoExample = () => {
const paused = useSharedValue(false);
const { width, height } = useWindowDimensions();
const { currentFrame } = useVideo(
"https://bit.ly/skia-video",
{
paused,
}
);
return (
<Pressable
style={{ flex: 1 }}
onPress={() => (paused.value = !paused.value)}
>
<Canvas style={{ flex: 1 }}>
<Fill>
<ImageShader
image={currentFrame}
x={0}
y={0}
width={width}
height={height}
fit="cover"
/>
<ColorMatrix
matrix={[
0.95, 0, 0, 0, 0.05, 0.65, 0, 0, 0, 0.15, 0.15, 0, 0, 0, 0.5, 0,
0, 0, 1, 0,
]}
/>
</Fill>
</Canvas>
</Pressable>
);
};
tsx
import React from "react";
import {
Canvas,
ColorMatrix,
Fill,
ImageShader,
useVideo
} from "@shopify/react-native-skia";
import { Pressable, useWindowDimensions } from "react-native";
import { useSharedValue } from "react-native-reanimated";
 
export const VideoExample = () => {
const paused = useSharedValue(false);
const { width, height } = useWindowDimensions();
const { currentFrame } = useVideo(
"https://bit.ly/skia-video",
{
paused,
}
);
return (
<Pressable
style={{ flex: 1 }}
onPress={() => (paused.value = !paused.value)}
>
<Canvas style={{ flex: 1 }}>
<Fill>
<ImageShader
image={currentFrame}
x={0}
y={0}
width={width}
height={height}
fit="cover"
/>
<ColorMatrix
matrix={[
0.95, 0, 0, 0, 0.05, 0.65, 0, 0, 0, 0.15, 0.15, 0, 0, 0, 0.5, 0,
0, 0, 1, 0,
]}
/>
</Fill>
</Canvas>
</Pressable>
);
};

返回值

useVideo Hook 返回 currentFrame,其中包含当前视频帧,以及 currentTimerotationsize

播放选项

下表描述了 useVideo Hook 可用的播放选项

选项描述
seek允许以毫秒为单位跳转到视频中的特定点。默认值为 null
paused指示视频是否暂停。
looping指示视频是否应该循环播放。
volume一个从 0 到 1 的值,表示音量级别 (0 为静音,1 为最大音量)。

在下面的示例中,每次我们点击视频时,都会将视频的跳转位置设置为 2 秒。

tsx
import React from "react";
import {
Canvas,
Fill,
Image,
useVideo
} from "@shopify/react-native-skia";
import { Pressable, useWindowDimensions } from "react-native";
import { useSharedValue } from "react-native-reanimated";
 
export const VideoExample = () => {
const seek = useSharedValue<null | number>(null);
// Set this value to true to pause the video
const paused = useSharedValue(false);
const { width, height } = useWindowDimensions();
const {currentFrame, currentTime} = useVideo(
"https://bit.ly/skia-video",
{
seek,
paused,
looping: true
}
);
return (
<Pressable
style={{ flex: 1 }}
onPress={() => (seek.value = 2000)}
>
<Canvas style={{ flex: 1 }}>
<Image
image={currentFrame}
x={0}
y={0}
width={width}
height={height}
fit="cover"
/>
</Canvas>
</Pressable>
);
};
tsx
import React from "react";
import {
Canvas,
Fill,
Image,
useVideo
} from "@shopify/react-native-skia";
import { Pressable, useWindowDimensions } from "react-native";
import { useSharedValue } from "react-native-reanimated";
 
export const VideoExample = () => {
const seek = useSharedValue<null | number>(null);
// Set this value to true to pause the video
const paused = useSharedValue(false);
const { width, height } = useWindowDimensions();
const {currentFrame, currentTime} = useVideo(
"https://bit.ly/skia-video",
{
seek,
paused,
looping: true
}
);
return (
<Pressable
style={{ flex: 1 }}
onPress={() => (seek.value = 2000)}
>
<Canvas style={{ flex: 1 }}>
<Image
image={currentFrame}
x={0}
y={0}
width={width}
height={height}
fit="cover"
/>
</Canvas>
</Pressable>
);
};

旋转视频

rotation 属性可以是 090180270。我们提供了一个 fitbox 函数,可以帮助旋转和缩放视频。

tsx
import React from "react";
import {
Canvas,
Image,
useVideo,
fitbox,
rect
} from "@shopify/react-native-skia";
import { Pressable, useWindowDimensions } from "react-native";
import { useSharedValue } from "react-native-reanimated";
 
export const VideoExample = () => {
const paused = useSharedValue(false);
const { width, height } = useWindowDimensions();
const { currentFrame, rotation, size } = useVideo("https://bit.ly/skia-video");
const src = rect(0, 0, size.width, size.height);
const dst = rect(0, 0, width, height)
const transform = fitbox("cover", src, dst, rotation);
return (
<Canvas style={{ flex: 1 }}>
<Image
image={currentFrame}
x={0}
y={0}
width={width}
height={height}
fit="none"
transform={transform}
/>
</Canvas>
);
};
tsx
import React from "react";
import {
Canvas,
Image,
useVideo,
fitbox,
rect
} from "@shopify/react-native-skia";
import { Pressable, useWindowDimensions } from "react-native";
import { useSharedValue } from "react-native-reanimated";
 
export const VideoExample = () => {
const paused = useSharedValue(false);
const { width, height } = useWindowDimensions();
const { currentFrame, rotation, size } = useVideo("https://bit.ly/skia-video");
const src = rect(0, 0, size.width, size.height);
const dst = rect(0, 0, width, height)
const transform = fitbox("cover", src, dst, rotation);
return (
<Canvas style={{ flex: 1 }}>
<Image
image={currentFrame}
x={0}
y={0}
width={width}
height={height}
fit="none"
transform={transform}
/>
</Canvas>
);
};

使用资源

下面是一个示例,我们使用 expo-asset 从捆绑包加载视频文件。

tsx
import { useVideo } from "@shopify/react-native-skia";
import { useAssets } from "expo-asset";
 
// Example usage:
// const video = useVideoFromAsset(require("./BigBuckBunny.mp4"));
export const useVideoFromAsset = (
mod: number,
options?: Parameters<typeof useVideo>[1]
) => {
const [assets, error] = useAssets([mod]);
if (error) {
throw error;
}
return useVideo(assets ? assets[0].localUri : null, options);
};
tsx
import { useVideo } from "@shopify/react-native-skia";
import { useAssets } from "expo-asset";
 
// Example usage:
// const video = useVideoFromAsset(require("./BigBuckBunny.mp4"));
export const useVideoFromAsset = (
mod: number,
options?: Parameters<typeof useVideo>[1]
) => {
const [assets, error] = useAssets([mod]);
if (error) {
throw error;
}
return useVideo(assets ? assets[0].localUri : null, options);
};

视频编码

要从 Skia 图像编码视频,您可以使用 ffmpeg,也可以查看 react-native-skia-video