Skip to content

Commit 9436209

Browse files
authored
fix(📹): useVideo fixes (#2451)
1 parent fc55cb4 commit 9436209

File tree

15 files changed

+353
-101
lines changed

15 files changed

+353
-101
lines changed

‎docs/docs/video.md

+8-9
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ interface VideoExampleProps {
3838
export const VideoExample = ({ localVideoFile }: VideoExampleProps) => {
3939
const paused = useSharedValue(false);
4040
const { width, height } = useWindowDimensions();
41-
const video = useVideo(
41+
const { currentFrame } = useVideo(
4242
require(localVideoFile),
4343
{
4444
paused,
@@ -52,7 +52,7 @@ export const VideoExample = ({ localVideoFile }: VideoExampleProps) => {
5252
<Canvas style={{ flex: 1 }}>
5353
<Fill>
5454
<ImageShader
55-
image={video}
55+
image={currentFrame}
5656
x={0}
5757
y={0}
5858
width={width}
@@ -94,12 +94,14 @@ export const useVideoFromAsset = (
9494
};
9595
```
9696

97+
## Returned Values
98+
99+
The `useVideo` hook returns `currentFrame` which contains the current video frame, as well as `currentTime`, and `rotationInDegrees`.
100+
97101
## Playback Options
98102

99103
You can seek a video via the `seek` playback option. By default, the seek option is null. If you set a value in milliseconds, it will seek to that point in the video and then set the option value to null again.
100104

101-
There is also the `currentTime` option, which is a Reanimated value that contains the current playback time of the video.
102-
103105
`looping` indicates whether the video should be looped or not.
104106

105107
`playbackSpeed` indicates the playback speed of the video (default is 1).
@@ -125,15 +127,12 @@ export const VideoExample = ({ localVideoFile }: VideoExampleProps) => {
125127
const seek = useSharedValue<null | number>(null);
126128
// Set this value to true to pause the video
127129
const paused = useSharedValue(false);
128-
// Contains the current playback time of the video
129-
const currentTime = useSharedValue(0);
130130
const { width, height } = useWindowDimensions();
131-
const video = useVideo(
131+
const {currentFrame, currentTime} = useVideo(
132132
require(localVideoFile),
133133
{
134134
seek,
135135
paused,
136-
currentTime,
137136
looping: true,
138137
playbackSpeed: 1
139138
}
@@ -145,7 +144,7 @@ export const VideoExample = ({ localVideoFile }: VideoExampleProps) => {
145144
>
146145
<Canvas style={{ flex: 1 }}>
147146
<Image
148-
image={video}
147+
image={currentFrame}
149148
x={0}
150149
y={0}
151150
width={width}

‎example/src/Examples/Video/Video.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { useVideoFromAsset } from "../../components/Animations";
1313
export const Video = () => {
1414
const paused = useSharedValue(false);
1515
const { width, height } = useWindowDimensions();
16-
const video = useVideoFromAsset(
16+
const { currentFrame } = useVideoFromAsset(
1717
require("../../Tests/assets/BigBuckBunny.mp4"),
1818
{
1919
paused,
@@ -28,7 +28,7 @@ export const Video = () => {
2828
<Canvas style={{ flex: 1 }}>
2929
<Fill>
3030
<ImageShader
31-
image={video}
31+
image={currentFrame}
3232
x={0}
3333
y={0}
3434
width={width}

‎fabricexample/src/Examples/Video/Video.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { useVideoFromAsset } from "../../components/Animations";
1313
export const Video = () => {
1414
const paused = useSharedValue(false);
1515
const { width, height } = useWindowDimensions();
16-
const video = useVideoFromAsset(
16+
const { currentFrame } = useVideoFromAsset(
1717
require("../../Tests/assets/BigBuckBunny.mp4"),
1818
{
1919
paused,
@@ -28,7 +28,7 @@ export const Video = () => {
2828
<Canvas style={{ flex: 1 }}>
2929
<Fill>
3030
<ImageShader
31-
image={video}
31+
image={currentFrame}
3232
x={0}
3333
y={0}
3434
width={width}

‎package/android/cpp/rnskia-android/RNSkAndroidVideo.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ double RNSkAndroidVideo::duration() {
6767
}
6868
return env->CallDoubleMethod(_jniVideo.get(), mid);
6969
}
70+
7071
double RNSkAndroidVideo::framerate() {
7172
JNIEnv *env = facebook::jni::Environment::current();
7273
jclass cls = env->GetObjectClass(_jniVideo.get());
@@ -89,4 +90,16 @@ void RNSkAndroidVideo::seek(double timestamp) {
8990
env->CallVoidMethod(_jniVideo.get(), mid, static_cast<jlong>(timestamp));
9091
}
9192

93+
float RNSkAndroidVideo::getRotationInDegrees() {
94+
JNIEnv *env = facebook::jni::Environment::current();
95+
jclass cls = env->GetObjectClass(_jniVideo.get());
96+
jmethodID mid = env->GetMethodID(cls, "getRotationDegrees", "()I");
97+
if (!mid) {
98+
RNSkLogger::logToConsole("getRotationDegrees method not found");
99+
return 0;
100+
}
101+
auto rotation = env->CallIntMethod(_jniVideo.get(), mid);
102+
return static_cast<float>(rotation);
103+
}
104+
92105
} // namespace RNSkia

‎package/android/cpp/rnskia-android/RNSkAndroidVideo.h

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class RNSkAndroidVideo : public RNSkVideo {
3131
double duration() override;
3232
double framerate() override;
3333
void seek(double timestamp) override;
34+
float getRotationInDegrees() override;
3435
};
3536

3637
} // namespace RNSkia

‎package/android/src/main/java/com/shopify/reactnative/skia/RNSkVideo.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public class RNSkVideo {
2929
private Surface outputSurface;
3030
private double durationMs;
3131
private double frameRate;
32+
private int rotationDegrees = 0;
3233

3334
RNSkVideo(Context context, String localUri) {
3435
this.uri = Uri.parse(localUri);
@@ -53,6 +54,9 @@ private void initializeReader() {
5354
if (format.containsKey(MediaFormat.KEY_FRAME_RATE)) {
5455
frameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
5556
}
57+
if (format.containsKey(MediaFormat.KEY_ROTATION)) {
58+
rotationDegrees = format.getInteger(MediaFormat.KEY_ROTATION);
59+
}
5660
int width = format.getInteger(MediaFormat.KEY_WIDTH);
5761
int height = format.getInteger(MediaFormat.KEY_HEIGHT);
5862
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
@@ -87,11 +91,15 @@ public double getDuration() {
8791
}
8892

8993
@DoNotStrip
90-
9194
public double getFrameRate() {
9295
return frameRate;
9396
}
9497

98+
@DoNotStrip
99+
public int getRotationDegrees() {
100+
return rotationDegrees;
101+
}
102+
95103
@DoNotStrip
96104
public HardwareBuffer nextImage() {
97105
if (!decoderOutputAvailable()) {

‎package/cpp/api/JsiVideo.h

+7
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,17 @@ class JsiVideo : public JsiSkWrappingSharedPtrHostObject<RNSkVideo> {
5353
return jsi::Value::undefined();
5454
}
5555

56+
JSI_HOST_FUNCTION(getRotationInDegrees) {
57+
auto context = getContext();
58+
auto rot = getObject()->getRotationInDegrees();
59+
return jsi::Value(static_cast<double>(rot));
60+
}
61+
5662
JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiVideo, nextImage),
5763
JSI_EXPORT_FUNC(JsiVideo, duration),
5864
JSI_EXPORT_FUNC(JsiVideo, framerate),
5965
JSI_EXPORT_FUNC(JsiVideo, seek),
66+
JSI_EXPORT_FUNC(JsiVideo, getRotationInDegrees),
6067
JSI_EXPORT_FUNC(JsiVideo, dispose))
6168

6269
JsiVideo(std::shared_ptr<RNSkPlatformContext> context,

‎package/cpp/rnskia/RNSkVideo.h

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class RNSkVideo {
1818
virtual double duration() = 0;
1919
virtual double framerate() = 0;
2020
virtual void seek(double timestamp) = 0;
21+
virtual float getRotationInDegrees() = 0;
2122
};
2223

2324
} // namespace RNSkia

‎package/ios/RNSkia-iOS/RNSkiOSVideo.h

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class RNSkiOSVideo : public RNSkVideo {
2727
double _framerate = 0;
2828
void setupReader(CMTimeRange timeRange);
2929
NSDictionary *getOutputSettings();
30+
CGAffineTransform _preferredTransform;
3031

3132
public:
3233
RNSkiOSVideo(std::string url, RNSkPlatformContext *context);
@@ -35,6 +36,7 @@ class RNSkiOSVideo : public RNSkVideo {
3536
double duration() override;
3637
double framerate() override;
3738
void seek(double timestamp) override;
39+
float getRotationInDegrees() override;
3840
};
3941

4042
} // namespace RNSkia

‎package/ios/RNSkia-iOS/RNSkiOSVideo.mm

+22-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#pragma once
2-
31
#include <memory>
42
#include <string>
53

@@ -46,6 +44,7 @@
4644
AVAssetTrack *videoTrack =
4745
[[asset tracksWithMediaType:AVMediaTypeVideo] firstObject];
4846
_framerate = videoTrack.nominalFrameRate;
47+
_preferredTransform = videoTrack.preferredTransform;
4948

5049
NSDictionary *outputSettings = getOutputSettings();
5150
AVAssetReaderTrackOutput *trackOutput =
@@ -99,6 +98,27 @@
9998
};
10099
}
101100

101+
float RNSkiOSVideo::getRotationInDegrees() {
102+
CGFloat rotationAngle = 0.0;
103+
auto transform = _preferredTransform;
104+
// Determine the rotation angle in radians
105+
if (transform.a == 0 && transform.b == 1 && transform.c == -1 &&
106+
transform.d == 0) {
107+
rotationAngle = M_PI_2; // 90 degrees
108+
} else if (transform.a == 0 && transform.b == -1 && transform.c == 1 &&
109+
transform.d == 0) {
110+
rotationAngle = -M_PI_2; // -90 degrees
111+
} else if (transform.a == -1 && transform.b == 0 && transform.c == 0 &&
112+
transform.d == -1) {
113+
rotationAngle = M_PI; // 180 degrees
114+
} else if (transform.a == 1 && transform.b == 0 && transform.c == 0 &&
115+
transform.d == 1) {
116+
rotationAngle = 0.0; // 0 degrees
117+
}
118+
// Convert the rotation angle from radians to degrees
119+
return rotationAngle * 180 / M_PI;
120+
}
121+
102122
void RNSkiOSVideo::seek(double timeInMilliseconds) {
103123
if (_reader) {
104124
[_reader cancelReading];

0 commit comments

Comments
 (0)