@shopify/react-native-skia 1.3.2 → 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. package/android/cpp/rnskia-android/RNSkAndroidVideo.cpp +59 -1
  2. package/android/cpp/rnskia-android/RNSkAndroidVideo.h +4 -0
  3. package/android/src/main/java/com/shopify/reactnative/skia/RNSkVideo.java +80 -7
  4. package/cpp/api/JsiVideo.h +32 -7
  5. package/cpp/rnskia/RNSkVideo.h +4 -0
  6. package/ios/RNSkia-iOS/RNSkiOSVideo.h +13 -4
  7. package/ios/RNSkia-iOS/RNSkiOSVideo.mm +65 -67
  8. package/lib/commonjs/dom/nodes/datatypes/Fitting.js +42 -30
  9. package/lib/commonjs/dom/nodes/datatypes/Fitting.js.map +1 -1
  10. package/lib/commonjs/external/reanimated/useVideo.d.ts +16 -4
  11. package/lib/commonjs/external/reanimated/useVideo.js +76 -14
  12. package/lib/commonjs/external/reanimated/useVideo.js.map +1 -1
  13. package/lib/commonjs/renderer/components/shapes/FitBox.d.ts +2 -10
  14. package/lib/commonjs/renderer/components/shapes/FitBox.js +32 -3
  15. package/lib/commonjs/renderer/components/shapes/FitBox.js.map +1 -1
  16. package/lib/commonjs/skia/core/Matrix.js +5 -1
  17. package/lib/commonjs/skia/core/Matrix.js.map +1 -1
  18. package/lib/commonjs/skia/types/Matrix.js +2 -0
  19. package/lib/commonjs/skia/types/Matrix.js.map +1 -1
  20. package/lib/commonjs/skia/types/Video/Video.d.ts +9 -1
  21. package/lib/commonjs/skia/types/Video/Video.js.map +1 -1
  22. package/lib/module/dom/nodes/datatypes/Fitting.js +41 -29
  23. package/lib/module/dom/nodes/datatypes/Fitting.js.map +1 -1
  24. package/lib/module/external/reanimated/useVideo.d.ts +16 -4
  25. package/lib/module/external/reanimated/useVideo.js +76 -14
  26. package/lib/module/external/reanimated/useVideo.js.map +1 -1
  27. package/lib/module/renderer/components/shapes/FitBox.d.ts +2 -10
  28. package/lib/module/renderer/components/shapes/FitBox.js +32 -3
  29. package/lib/module/renderer/components/shapes/FitBox.js.map +1 -1
  30. package/lib/module/skia/core/Matrix.js +5 -1
  31. package/lib/module/skia/core/Matrix.js.map +1 -1
  32. package/lib/module/skia/types/Matrix.js +2 -0
  33. package/lib/module/skia/types/Matrix.js.map +1 -1
  34. package/lib/module/skia/types/Video/Video.d.ts +9 -1
  35. package/lib/module/skia/types/Video/Video.js.map +1 -1
  36. package/lib/typescript/src/external/reanimated/useVideo.d.ts +16 -4
  37. package/lib/typescript/src/renderer/components/shapes/FitBox.d.ts +2 -10
  38. package/lib/typescript/src/skia/types/Video/Video.d.ts +9 -1
  39. package/package.json +1 -1
  40. package/src/dom/nodes/datatypes/Fitting.ts +28 -21
  41. package/src/external/reanimated/useVideo.ts +90 -29
  42. package/src/renderer/components/shapes/FitBox.tsx +38 -4
  43. package/src/skia/core/Matrix.ts +4 -2
  44. package/src/skia/types/Matrix.ts +1 -0
  45. package/src/skia/types/Video/Video.ts +7 -1
  46. package/lib/commonjs/external/reanimated/video.d.ts +0 -16
  47. package/lib/commonjs/external/reanimated/video.js +0 -54
  48. package/lib/commonjs/external/reanimated/video.js.map +0 -1
  49. package/lib/module/external/reanimated/video.d.ts +0 -16
  50. package/lib/module/external/reanimated/video.js +0 -46
  51. package/lib/module/external/reanimated/video.js.map +0 -1
  52. package/lib/typescript/src/external/reanimated/video.d.ts +0 -16
  53. package/src/external/reanimated/video.ts +0 -82
@@ -9,6 +9,7 @@
9
9
  #pragma clang diagnostic ignored "-Wdocumentation"
10
10
 
11
11
  #include "include/core/SkImage.h"
12
+ #include "include/core/SkSize.h"
12
13
 
13
14
  #pragma clang diagnostic pop
14
15
 
@@ -82,7 +83,7 @@ double RNSkAndroidVideo::framerate() {
82
83
  void RNSkAndroidVideo::seek(double timestamp) {
83
84
  JNIEnv *env = facebook::jni::Environment::current();
84
85
  jclass cls = env->GetObjectClass(_jniVideo.get());
85
- jmethodID mid = env->GetMethodID(cls, "seek", "(J)V");
86
+ jmethodID mid = env->GetMethodID(cls, "seek", "(D)V");
86
87
  if (!mid) {
87
88
  RNSkLogger::logToConsole("seek method not found");
88
89
  return;
@@ -102,4 +103,61 @@ float RNSkAndroidVideo::getRotationInDegrees() {
102
103
  return static_cast<float>(rotation);
103
104
  }
104
105
 
106
+ SkISize RNSkAndroidVideo::getSize() {
107
+ JNIEnv *env = facebook::jni::Environment::current();
108
+ jclass cls = env->GetObjectClass(_jniVideo.get());
109
+ jmethodID mid =
110
+ env->GetMethodID(cls, "getSize", "()Landroid/graphics/Point;");
111
+ if (!mid) {
112
+ RNSkLogger::logToConsole("getSize method not found");
113
+ return SkISize::Make(0, 0);
114
+ }
115
+ jobject jPoint = env->CallObjectMethod(_jniVideo.get(), mid);
116
+ jclass pointCls = env->GetObjectClass(jPoint);
117
+
118
+ jfieldID xFid = env->GetFieldID(pointCls, "x", "I");
119
+ jfieldID yFid = env->GetFieldID(pointCls, "y", "I");
120
+ if (!xFid || !yFid) {
121
+ RNSkLogger::logToConsole("Point class fields not found");
122
+ return SkISize::Make(0, 0);
123
+ }
124
+
125
+ jint width = env->GetIntField(jPoint, xFid);
126
+ jint height = env->GetIntField(jPoint, yFid);
127
+
128
+ return SkISize::Make(width, height);
129
+ }
130
+
131
+ void RNSkAndroidVideo::play() {
132
+ JNIEnv *env = facebook::jni::Environment::current();
133
+ jclass cls = env->GetObjectClass(_jniVideo.get());
134
+ jmethodID mid = env->GetMethodID(cls, "play", "()V");
135
+ if (!mid) {
136
+ RNSkLogger::logToConsole("play method not found");
137
+ return;
138
+ }
139
+ env->CallVoidMethod(_jniVideo.get(), mid);
140
+ }
141
+
142
+ void RNSkAndroidVideo::pause() {
143
+ JNIEnv *env = facebook::jni::Environment::current();
144
+ jclass cls = env->GetObjectClass(_jniVideo.get());
145
+ jmethodID mid = env->GetMethodID(cls, "pause", "()V");
146
+ if (!mid) {
147
+ RNSkLogger::logToConsole("pause method not found");
148
+ return;
149
+ }
150
+ env->CallVoidMethod(_jniVideo.get(), mid);
151
+ }
152
+
153
+ void RNSkAndroidVideo::setVolume(float volume) {
154
+ JNIEnv *env = facebook::jni::Environment::current();
155
+ jclass cls = env->GetObjectClass(_jniVideo.get());
156
+ jmethodID mid = env->GetMethodID(cls, "setVolume", "(F)V");
157
+ if (!mid) {
158
+ RNSkLogger::logToConsole("setVolume method not found");
159
+ return;
160
+ }
161
+ env->CallVoidMethod(_jniVideo.get(), mid, volume);
162
+ }
105
163
  } // namespace RNSkia
@@ -32,6 +32,10 @@ public:
32
32
  double framerate() override;
33
33
  void seek(double timestamp) override;
34
34
  float getRotationInDegrees() override;
35
+ SkISize getSize() override;
36
+ void play() override;
37
+ void pause() override;
38
+ void setVolume(float volume) override;
35
39
  };
36
40
 
37
41
  } // namespace RNSkia
@@ -3,14 +3,19 @@ package com.shopify.reactnative.skia;
3
3
  import android.content.Context;
4
4
  import android.graphics.ImageFormat;
5
5
  import android.hardware.HardwareBuffer;
6
- import android.media.Image;
7
- import android.media.ImageReader;
6
+ import android.media.AudioAttributes;
7
+ import android.media.AudioManager;
8
8
  import android.media.MediaCodec;
9
9
  import android.media.MediaExtractor;
10
10
  import android.media.MediaFormat;
11
+ import android.media.MediaPlayer;
12
+ import android.media.MediaSync;
13
+ import android.media.Image;
14
+ import android.media.ImageReader;
11
15
  import android.net.Uri;
12
16
  import android.os.Build;
13
17
  import android.view.Surface;
18
+ import android.graphics.Point;
14
19
 
15
20
  import androidx.annotation.RequiresApi;
16
21
 
@@ -27,9 +32,15 @@ public class RNSkVideo {
27
32
  private MediaCodec decoder;
28
33
  private ImageReader imageReader;
29
34
  private Surface outputSurface;
35
+ private MediaPlayer mediaPlayer;
36
+ private MediaSync mediaSync;
30
37
  private double durationMs;
31
38
  private double frameRate;
32
39
  private int rotationDegrees = 0;
40
+ private int width = 0;
41
+ private int height = 0;
42
+
43
+ private boolean isPlaying = false;
33
44
 
34
45
  RNSkVideo(Context context, String localUri) {
35
46
  this.uri = Uri.parse(localUri);
@@ -47,6 +58,18 @@ public class RNSkVideo {
47
58
  }
48
59
  extractor.selectTrack(trackIndex);
49
60
  MediaFormat format = extractor.getTrackFormat(trackIndex);
61
+
62
+ // Initialize MediaPlayer
63
+ mediaPlayer = new MediaPlayer();
64
+ mediaPlayer.setDataSource(context, uri);
65
+ mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
66
+ mediaPlayer.setOnPreparedListener(mp -> {
67
+ durationMs = mp.getDuration();
68
+ mp.start();
69
+ isPlaying = true;
70
+ });
71
+ mediaPlayer.prepareAsync();
72
+
50
73
  // Retrieve and store video properties
51
74
  if (format.containsKey(MediaFormat.KEY_DURATION)) {
52
75
  durationMs = format.getLong(MediaFormat.KEY_DURATION) / 1000; // Convert microseconds to milliseconds
@@ -57,8 +80,8 @@ public class RNSkVideo {
57
80
  if (format.containsKey(MediaFormat.KEY_ROTATION)) {
58
81
  rotationDegrees = format.getInteger(MediaFormat.KEY_ROTATION);
59
82
  }
60
- int width = format.getInteger(MediaFormat.KEY_WIDTH);
61
- int height = format.getInteger(MediaFormat.KEY_HEIGHT);
83
+ width = format.getInteger(MediaFormat.KEY_WIDTH);
84
+ height = format.getInteger(MediaFormat.KEY_HEIGHT);
62
85
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
63
86
  imageReader = ImageReader.newInstance(
64
87
  width,
@@ -116,15 +139,38 @@ public class RNSkVideo {
116
139
  }
117
140
 
118
141
  @DoNotStrip
119
- public void seek(long timestamp) {
120
- // Seek to the closest sync frame at or before the specified time
121
- extractor.seekTo(timestamp * 1000, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
142
+ public void seek(double timestamp) {
143
+ // Log the values for debugging
144
+
145
+ long timestampUs = (long)(timestamp * 1000); // Convert milliseconds to microseconds
146
+
147
+ extractor.seekTo(timestampUs, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
148
+ if (mediaPlayer != null) {
149
+ int timestampMs = (int) timestamp; // Convert to milliseconds
150
+ mediaPlayer.seekTo(timestampMs, MediaPlayer.SEEK_CLOSEST);
151
+ }
152
+
122
153
  // Flush the codec to reset internal state and buffers
123
154
  if (decoder != null) {
124
155
  decoder.flush();
156
+
157
+ // Decode frames until reaching the exact timestamp
158
+ boolean isSeeking = true;
159
+ while (isSeeking) {
160
+ decodeFrame();
161
+ long currentTimestampUs = extractor.getSampleTime();
162
+ if (currentTimestampUs >= timestampUs) {
163
+ isSeeking = false;
164
+ }
165
+ }
125
166
  }
126
167
  }
127
168
 
169
+ @DoNotStrip
170
+ public Point getSize() {
171
+ return new Point(width, height);
172
+ }
173
+
128
174
  private int selectVideoTrack(MediaExtractor extractor) {
129
175
  int numTracks = extractor.getTrackCount();
130
176
  for (int i = 0; i < numTracks; i++) {
@@ -179,7 +225,34 @@ public class RNSkVideo {
179
225
  }
180
226
  }
181
227
 
228
+ @DoNotStrip
229
+ public void play() {
230
+ if (mediaPlayer != null && !isPlaying) {
231
+ mediaPlayer.start();
232
+ isPlaying = true;
233
+ }
234
+ }
235
+
236
+ @DoNotStrip
237
+ public void pause() {
238
+ if (mediaPlayer != null && isPlaying) {
239
+ mediaPlayer.pause();
240
+ isPlaying = false;
241
+ }
242
+ }
243
+
244
+ @DoNotStrip
245
+ public void setVolume(float volume) {
246
+ if (mediaPlayer != null) {
247
+ mediaPlayer.setVolume(volume, volume);
248
+ }
249
+ }
250
+
182
251
  public void release() {
252
+ if (mediaPlayer != null) {
253
+ mediaPlayer.release();
254
+ mediaPlayer = null;
255
+ }
183
256
  if (decoder != null) {
184
257
  decoder.stop();
185
258
  decoder.release();
@@ -53,18 +53,43 @@ public:
53
53
  return jsi::Value::undefined();
54
54
  }
55
55
 
56
- JSI_HOST_FUNCTION(getRotationInDegrees) {
56
+ JSI_HOST_FUNCTION(rotation) {
57
57
  auto context = getContext();
58
58
  auto rot = getObject()->getRotationInDegrees();
59
59
  return jsi::Value(static_cast<double>(rot));
60
60
  }
61
61
 
62
- JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiVideo, nextImage),
63
- JSI_EXPORT_FUNC(JsiVideo, duration),
64
- JSI_EXPORT_FUNC(JsiVideo, framerate),
65
- JSI_EXPORT_FUNC(JsiVideo, seek),
66
- JSI_EXPORT_FUNC(JsiVideo, getRotationInDegrees),
67
- JSI_EXPORT_FUNC(JsiVideo, dispose))
62
+ JSI_HOST_FUNCTION(size) {
63
+ auto context = getContext();
64
+ auto size = getObject()->getSize();
65
+ auto result = jsi::Object(runtime);
66
+ result.setProperty(runtime, "width", static_cast<double>(size.width()));
67
+ result.setProperty(runtime, "height", static_cast<double>(size.height()));
68
+ return result;
69
+ }
70
+
71
+ JSI_HOST_FUNCTION(play) {
72
+ getObject()->play();
73
+ return jsi::Value::undefined();
74
+ }
75
+
76
+ JSI_HOST_FUNCTION(pause) {
77
+ getObject()->pause();
78
+ return jsi::Value::undefined();
79
+ }
80
+
81
+ JSI_HOST_FUNCTION(setVolume) {
82
+ auto volume = arguments[0].asNumber();
83
+ getObject()->setVolume(static_cast<float>(volume));
84
+ return jsi::Value::undefined();
85
+ }
86
+
87
+ JSI_EXPORT_FUNCTIONS(
88
+ JSI_EXPORT_FUNC(JsiVideo, nextImage), JSI_EXPORT_FUNC(JsiVideo, duration),
89
+ JSI_EXPORT_FUNC(JsiVideo, framerate), JSI_EXPORT_FUNC(JsiVideo, seek),
90
+ JSI_EXPORT_FUNC(JsiVideo, rotation), JSI_EXPORT_FUNC(JsiVideo, size),
91
+ JSI_EXPORT_FUNC(JsiVideo, play), JSI_EXPORT_FUNC(JsiVideo, pause),
92
+ JSI_EXPORT_FUNC(JsiVideo, setVolume), JSI_EXPORT_FUNC(JsiVideo, dispose))
68
93
 
69
94
  JsiVideo(std::shared_ptr<RNSkPlatformContext> context,
70
95
  std::shared_ptr<RNSkVideo> video)
@@ -19,6 +19,10 @@ public:
19
19
  virtual double framerate() = 0;
20
20
  virtual void seek(double timestamp) = 0;
21
21
  virtual float getRotationInDegrees() = 0;
22
+ virtual SkISize getSize() = 0;
23
+ virtual void play() = 0;
24
+ virtual void pause() = 0;
25
+ virtual void setVolume(float volume) = 0;
22
26
  };
23
27
 
24
28
  } // namespace RNSkia
@@ -9,6 +9,7 @@
9
9
  #pragma clang diagnostic ignored "-Wdocumentation"
10
10
 
11
11
  #include "include/core/SkImage.h"
12
+ #include "include/core/SkSize.h"
12
13
 
13
14
  #pragma clang diagnostic pop
14
15
 
@@ -20,14 +21,18 @@ namespace RNSkia {
20
21
  class RNSkiOSVideo : public RNSkVideo {
21
22
  private:
22
23
  std::string _url;
23
- AVAssetReader *_reader = nullptr;
24
- AVAssetReaderTrackOutput *_trackOutput = nullptr;
24
+ AVPlayer *_player = nullptr;
25
+ AVPlayerItem *_playerItem = nullptr;
26
+ AVPlayerItemVideoOutput *_videoOutput = nullptr;
25
27
  RNSkPlatformContext *_context;
26
28
  double _duration = 0;
27
29
  double _framerate = 0;
28
- void setupReader(CMTimeRange timeRange);
29
- NSDictionary *getOutputSettings();
30
+ float _videoWidth = 0;
31
+ float _videoHeight = 0;
30
32
  CGAffineTransform _preferredTransform;
33
+ bool _isPlaying = false;
34
+ void setupPlayer();
35
+ NSDictionary *getOutputSettings();
31
36
 
32
37
  public:
33
38
  RNSkiOSVideo(std::string url, RNSkPlatformContext *context);
@@ -36,7 +41,11 @@ public:
36
41
  double duration() override;
37
42
  double framerate() override;
38
43
  void seek(double timestamp) override;
44
+ void play();
45
+ void pause();
39
46
  float getRotationInDegrees() override;
47
+ SkISize getSize() override;
48
+ void setVolume(float volume);
40
49
  };
41
50
 
42
51
  } // namespace RNSkia
@@ -16,78 +16,60 @@ namespace RNSkia {
16
16
 
17
17
  RNSkiOSVideo::RNSkiOSVideo(std::string url, RNSkPlatformContext *context)
18
18
  : _url(std::move(url)), _context(context) {
19
- setupReader(CMTimeRangeMake(kCMTimeZero, kCMTimePositiveInfinity));
19
+ setupPlayer();
20
20
  }
21
21
 
22
- RNSkiOSVideo::~RNSkiOSVideo() {}
22
+ RNSkiOSVideo::~RNSkiOSVideo() {
23
+ if (_player) {
24
+ [_player pause];
25
+ }
26
+ }
23
27
 
24
- void RNSkiOSVideo::setupReader(CMTimeRange timeRange) {
25
- NSError *error = nil;
28
+ void RNSkiOSVideo::setupPlayer() {
29
+ NSURL *videoURL = [NSURL URLWithString:@(_url.c_str())];
30
+ AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:videoURL];
31
+ _player = [AVPlayer playerWithPlayerItem:playerItem];
32
+ _playerItem = playerItem;
26
33
 
27
- AVURLAsset *asset =
28
- [AVURLAsset URLAssetWithURL:[NSURL URLWithString:@(_url.c_str())]
29
- options:nil];
30
- AVAssetReader *assetReader = [[AVAssetReader alloc] initWithAsset:asset
31
- error:&error];
32
- if (error) {
33
- NSLog(@"Error initializing asset reader: %@", error.localizedDescription);
34
- return;
35
- }
34
+ NSDictionary *outputSettings = getOutputSettings();
35
+ _videoOutput =
36
+ [[AVPlayerItemVideoOutput alloc] initWithOutputSettings:outputSettings];
37
+ [playerItem addOutput:_videoOutput];
36
38
 
37
- CMTime time = [asset duration];
38
- if (time.timescale == 0) {
39
- NSLog(@"Error: Timescale of the asset is zero.");
40
- return;
39
+ CMTime time = playerItem.asset.duration;
40
+ if (time.timescale != 0) {
41
+ _duration = CMTimeGetSeconds(time) * 1000; // Store duration in milliseconds
41
42
  }
42
43
 
43
- _duration = CMTimeGetSeconds(time) * 1000; // Store duration in milliseconds
44
44
  AVAssetTrack *videoTrack =
45
- [[asset tracksWithMediaType:AVMediaTypeVideo] firstObject];
46
- _framerate = videoTrack.nominalFrameRate;
47
- _preferredTransform = videoTrack.preferredTransform;
48
-
49
- NSDictionary *outputSettings = getOutputSettings();
50
- AVAssetReaderTrackOutput *trackOutput =
51
- [[AVAssetReaderTrackOutput alloc] initWithTrack:videoTrack
52
- outputSettings:outputSettings];
53
-
54
- assetReader.timeRange = timeRange;
55
- if ([assetReader canAddOutput:trackOutput]) {
56
- [assetReader addOutput:trackOutput];
57
- [assetReader startReading];
58
- } else {
59
- NSLog(@"Cannot add output to asset reader.");
60
- return;
45
+ [[playerItem.asset tracksWithMediaType:AVMediaTypeVideo] firstObject];
46
+ if (videoTrack) {
47
+ _framerate = videoTrack.nominalFrameRate;
48
+ _preferredTransform = videoTrack.preferredTransform;
49
+ CGSize videoSize = videoTrack.naturalSize;
50
+ _videoWidth = videoSize.width;
51
+ _videoHeight = videoSize.height;
61
52
  }
62
-
63
- _reader = assetReader;
64
- _trackOutput = trackOutput;
53
+ play();
65
54
  }
66
55
 
67
56
  sk_sp<SkImage> RNSkiOSVideo::nextImage(double *timeStamp) {
68
- CMSampleBufferRef sampleBuffer = [_trackOutput copyNextSampleBuffer];
69
- if (!sampleBuffer) {
70
- NSLog(@"No sample buffer.");
71
- return nullptr;
72
- }
73
-
74
- // Extract the pixel buffer from the sample buffer
75
- CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
57
+ CMTime currentTime = [_player currentTime];
58
+ CVPixelBufferRef pixelBuffer =
59
+ [_videoOutput copyPixelBufferForItemTime:currentTime
60
+ itemTimeForDisplay:nullptr];
76
61
  if (!pixelBuffer) {
77
62
  NSLog(@"No pixel buffer.");
78
- CFRelease(sampleBuffer);
79
63
  return nullptr;
80
64
  }
81
65
 
82
- auto skImage = _context->makeImageFromNativeBuffer(
83
- reinterpret_cast<void *>(pixelBuffer));
66
+ auto skImage = _context->makeImageFromNativeBuffer((void *)pixelBuffer);
84
67
 
85
68
  if (timeStamp) {
86
- CMTime time = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
87
- *timeStamp = CMTimeGetSeconds(time);
69
+ *timeStamp = CMTimeGetSeconds(currentTime);
88
70
  }
89
71
 
90
- CFRelease(sampleBuffer);
72
+ CVPixelBufferRelease(pixelBuffer);
91
73
  return skImage;
92
74
  }
93
75
 
@@ -104,36 +86,52 @@ float RNSkiOSVideo::getRotationInDegrees() {
104
86
  // Determine the rotation angle in radians
105
87
  if (transform.a == 0 && transform.b == 1 && transform.c == -1 &&
106
88
  transform.d == 0) {
107
- rotationAngle = M_PI_2; // 90 degrees
89
+ rotationAngle = 90;
108
90
  } else if (transform.a == 0 && transform.b == -1 && transform.c == 1 &&
109
91
  transform.d == 0) {
110
- rotationAngle = -M_PI_2; // -90 degrees
92
+ rotationAngle = 270;
111
93
  } else if (transform.a == -1 && transform.b == 0 && transform.c == 0 &&
112
94
  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
95
+ rotationAngle = 180;
117
96
  }
118
- // Convert the rotation angle from radians to degrees
119
- return rotationAngle * 180 / M_PI;
97
+ return rotationAngle;
120
98
  }
121
99
 
122
100
  void RNSkiOSVideo::seek(double timeInMilliseconds) {
123
- if (_reader) {
124
- [_reader cancelReading];
125
- _reader = nil;
126
- _trackOutput = nil;
101
+ CMTime seekTime =
102
+ CMTimeMakeWithSeconds(timeInMilliseconds / 1000.0, NSEC_PER_SEC);
103
+ [_player seekToTime:seekTime
104
+ toleranceBefore:kCMTimeZero
105
+ toleranceAfter:kCMTimeZero
106
+ completionHandler:^(BOOL finished) {
107
+ if (!finished) {
108
+ NSLog(@"Seek failed or was interrupted.");
109
+ }
110
+ }];
111
+ }
112
+
113
+ void RNSkiOSVideo::play() {
114
+ if (_player) {
115
+ [_player play];
116
+ _isPlaying = true;
127
117
  }
118
+ }
128
119
 
129
- CMTime startTime =
130
- CMTimeMakeWithSeconds(timeInMilliseconds / 1000.0, NSEC_PER_SEC);
131
- CMTimeRange timeRange = CMTimeRangeMake(startTime, kCMTimePositiveInfinity);
132
- setupReader(timeRange);
120
+ void RNSkiOSVideo::pause() {
121
+ if (_player) {
122
+ [_player pause];
123
+ _isPlaying = false;
124
+ }
133
125
  }
134
126
 
135
127
  double RNSkiOSVideo::duration() { return _duration; }
136
128
 
137
129
  double RNSkiOSVideo::framerate() { return _framerate; }
138
130
 
131
+ SkISize RNSkiOSVideo::getSize() {
132
+ return SkISize::Make(_videoWidth, _videoHeight);
133
+ }
134
+
135
+ void RNSkiOSVideo::setVolume(float volume) { _player.volume = volume; }
136
+
139
137
  } // namespace RNSkia
@@ -5,12 +5,18 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.size = exports.rect2rect = exports.fitRects = void 0;
7
7
  var _typeddash = require("../../../renderer/typeddash");
8
- const size = (width = 0, height = 0) => ({
9
- width,
10
- height
11
- });
8
+ const size = (width = 0, height = 0) => {
9
+ "worklet";
10
+
11
+ return {
12
+ width,
13
+ height
14
+ };
15
+ };
12
16
  exports.size = size;
13
17
  const rect2rect = (src, dst) => {
18
+ "worklet";
19
+
14
20
  const scaleX = dst.width / src.width;
15
21
  const scaleY = dst.height / src.height;
16
22
  const translateX = dst.x - src.x * scaleX;
@@ -26,36 +32,12 @@ const rect2rect = (src, dst) => {
26
32
  }];
27
33
  };
28
34
  exports.rect2rect = rect2rect;
29
- const fitRects = (fit, rect, {
30
- x,
31
- y,
32
- width,
33
- height
34
- }) => {
35
- const sizes = applyBoxFit(fit, {
36
- width: rect.width,
37
- height: rect.height
38
- }, {
39
- width,
40
- height
41
- });
42
- const src = inscribe(sizes.src, rect);
43
- const dst = inscribe(sizes.dst, {
44
- x,
45
- y,
46
- width,
47
- height
48
- });
49
- return {
50
- src,
51
- dst
52
- };
53
- };
54
- exports.fitRects = fitRects;
55
35
  const inscribe = ({
56
36
  width,
57
37
  height
58
38
  }, rect) => {
39
+ "worklet";
40
+
59
41
  const halfWidthDelta = (rect.width - width) / 2.0;
60
42
  const halfHeightDelta = (rect.height - height) / 2.0;
61
43
  return {
@@ -66,6 +48,8 @@ const inscribe = ({
66
48
  };
67
49
  };
68
50
  const applyBoxFit = (fit, input, output) => {
51
+ "worklet";
52
+
69
53
  let src = size(),
70
54
  dst = size();
71
55
  if (input.height <= 0.0 || input.width <= 0.0 || output.height <= 0.0 || output.width <= 0.0) {
@@ -126,4 +110,32 @@ const applyBoxFit = (fit, input, output) => {
126
110
  dst
127
111
  };
128
112
  };
113
+ const fitRects = (fit, rect, {
114
+ x,
115
+ y,
116
+ width,
117
+ height
118
+ }) => {
119
+ "worklet";
120
+
121
+ const sizes = applyBoxFit(fit, {
122
+ width: rect.width,
123
+ height: rect.height
124
+ }, {
125
+ width,
126
+ height
127
+ });
128
+ const src = inscribe(sizes.src, rect);
129
+ const dst = inscribe(sizes.dst, {
130
+ x,
131
+ y,
132
+ width,
133
+ height
134
+ });
135
+ return {
136
+ src,
137
+ dst
138
+ };
139
+ };
140
+ exports.fitRects = fitRects;
129
141
  //# sourceMappingURL=Fitting.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_typeddash","require","size","width","height","exports","rect2rect","src","dst","scaleX","scaleY","translateX","x","translateY","y","fitRects","fit","rect","sizes","applyBoxFit","inscribe","halfWidthDelta","halfHeightDelta","input","output","Math","min","aspectRatio","exhaustiveCheck"],"sources":["Fitting.ts"],"sourcesContent":["import { exhaustiveCheck } from \"../../../renderer/typeddash\";\nimport type { SkRect } from \"../../../skia/types\";\nimport type { Fit } from \"../../types\";\n\nexport interface Size {\n width: number;\n height: number;\n}\n\nexport const size = (width = 0, height = 0) => ({ width, height });\n\nexport const rect2rect = (\n src: SkRect,\n dst: SkRect\n): [\n { translateX: number },\n { translateY: number },\n { scaleX: number },\n { scaleY: number }\n] => {\n const scaleX = dst.width / src.width;\n const scaleY = dst.height / src.height;\n const translateX = dst.x - src.x * scaleX;\n const translateY = dst.y - src.y * scaleY;\n return [{ translateX }, { translateY }, { scaleX }, { scaleY }];\n};\n\nexport const fitRects = (\n fit: Fit,\n rect: SkRect,\n { x, y, width, height }: SkRect\n) => {\n const sizes = applyBoxFit(\n fit,\n { width: rect.width, height: rect.height },\n { width, height }\n );\n const src = inscribe(sizes.src, rect);\n const dst = inscribe(sizes.dst, {\n x,\n y,\n width,\n height,\n });\n return { src, dst };\n};\n\nconst inscribe = (\n { width, height }: Size,\n rect: { x: number; y: number; width: number; height: number }\n) => {\n const halfWidthDelta = (rect.width - width) / 2.0;\n const halfHeightDelta = (rect.height - height) / 2.0;\n return {\n x: rect.x + halfWidthDelta,\n y: rect.y + halfHeightDelta,\n width,\n height,\n };\n};\n\nconst applyBoxFit = (fit: Fit, input: Size, output: Size) => {\n let src = size(),\n dst = size();\n if (\n input.height <= 0.0 ||\n input.width <= 0.0 ||\n output.height <= 0.0 ||\n output.width <= 0.0\n ) {\n return { src, dst };\n }\n switch (fit) {\n case \"fill\":\n src = input;\n dst = output;\n break;\n case \"contain\":\n src = input;\n if (output.width / output.height > src.width / src.height) {\n dst = size((src.width * output.height) / src.height, output.height);\n } else {\n dst = size(output.width, (src.height * output.width) / src.width);\n }\n break;\n case \"cover\":\n if (output.width / output.height > input.width / input.height) {\n src = size(input.width, (input.width * output.height) / output.width);\n } else {\n src = size((input.height * output.width) / output.height, input.height);\n }\n dst = output;\n break;\n case \"fitWidth\":\n src = size(input.width, (input.width * output.height) / output.width);\n dst = size(output.width, (src.height * output.width) / src.width);\n break;\n case \"fitHeight\":\n src = size((input.height * output.width) / output.height, input.height);\n dst = size((src.width * output.height) / src.height, output.height);\n break;\n case \"none\":\n src = size(\n Math.min(input.width, output.width),\n Math.min(input.height, output.height)\n );\n dst = src;\n break;\n case \"scaleDown\":\n src = input;\n dst = input;\n const aspectRatio = input.width / input.height;\n if (dst.height > output.height) {\n dst = size(output.height * aspectRatio, output.height);\n }\n if (dst.width > output.width) {\n dst = size(output.width, output.width / aspectRatio);\n }\n break;\n default:\n exhaustiveCheck(fit);\n }\n return { src, dst };\n};\n"],"mappings":"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"}
1
+ {"version":3,"names":["_typeddash","require","size","width","height","exports","rect2rect","src","dst","scaleX","scaleY","translateX","x","translateY","y","inscribe","rect","halfWidthDelta","halfHeightDelta","applyBoxFit","fit","input","output","Math","min","aspectRatio","exhaustiveCheck","fitRects","sizes"],"sources":["Fitting.ts"],"sourcesContent":["import { exhaustiveCheck } from \"../../../renderer/typeddash\";\nimport type { SkRect } from \"../../../skia/types\";\nimport type { Fit } from \"../../types\";\n\nexport interface Size {\n width: number;\n height: number;\n}\n\nexport const size = (width = 0, height = 0) => {\n \"worklet\";\n return { width, height };\n};\n\nexport const rect2rect = (\n src: SkRect,\n dst: SkRect\n): [\n { translateX: number },\n { translateY: number },\n { scaleX: number },\n { scaleY: number }\n] => {\n \"worklet\";\n const scaleX = dst.width / src.width;\n const scaleY = dst.height / src.height;\n const translateX = dst.x - src.x * scaleX;\n const translateY = dst.y - src.y * scaleY;\n return [{ translateX }, { translateY }, { scaleX }, { scaleY }];\n};\n\nconst inscribe = (\n { width, height }: Size,\n rect: { x: number; y: number; width: number; height: number }\n) => {\n \"worklet\";\n const halfWidthDelta = (rect.width - width) / 2.0;\n const halfHeightDelta = (rect.height - height) / 2.0;\n return {\n x: rect.x + halfWidthDelta,\n y: rect.y + halfHeightDelta,\n width,\n height,\n };\n};\n\nconst applyBoxFit = (fit: Fit, input: Size, output: Size) => {\n \"worklet\";\n let src = size(),\n dst = size();\n if (\n input.height <= 0.0 ||\n input.width <= 0.0 ||\n output.height <= 0.0 ||\n output.width <= 0.0\n ) {\n return { src, dst };\n }\n switch (fit) {\n case \"fill\":\n src = input;\n dst = output;\n break;\n case \"contain\":\n src = input;\n if (output.width / output.height > src.width / src.height) {\n dst = size((src.width * output.height) / src.height, output.height);\n } else {\n dst = size(output.width, (src.height * output.width) / src.width);\n }\n break;\n case \"cover\":\n if (output.width / output.height > input.width / input.height) {\n src = size(input.width, (input.width * output.height) / output.width);\n } else {\n src = size((input.height * output.width) / output.height, input.height);\n }\n dst = output;\n break;\n case \"fitWidth\":\n src = size(input.width, (input.width * output.height) / output.width);\n dst = size(output.width, (src.height * output.width) / src.width);\n break;\n case \"fitHeight\":\n src = size((input.height * output.width) / output.height, input.height);\n dst = size((src.width * output.height) / src.height, output.height);\n break;\n case \"none\":\n src = size(\n Math.min(input.width, output.width),\n Math.min(input.height, output.height)\n );\n dst = src;\n break;\n case \"scaleDown\":\n src = input;\n dst = input;\n const aspectRatio = input.width / input.height;\n if (dst.height > output.height) {\n dst = size(output.height * aspectRatio, output.height);\n }\n if (dst.width > output.width) {\n dst = size(output.width, output.width / aspectRatio);\n }\n break;\n default:\n exhaustiveCheck(fit);\n }\n return { src, dst };\n};\n\nexport const fitRects = (\n fit: Fit,\n rect: SkRect,\n { x, y, width, height }: SkRect\n) => {\n \"worklet\";\n const sizes = applyBoxFit(\n fit,\n { width: rect.width, height: rect.height },\n { width, height }\n );\n const src = inscribe(sizes.src, rect);\n const dst = inscribe(sizes.dst, {\n x,\n y,\n width,\n height,\n });\n return { src, dst };\n};\n"],"mappings":"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"}