@shopify/react-native-skia 1.3.1 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/android/cpp/rnskia-android/RNSkAndroidVideo.cpp +72 -1
  2. package/android/cpp/rnskia-android/RNSkAndroidVideo.h +5 -0
  3. package/android/src/main/java/com/shopify/reactnative/skia/RNSkVideo.java +89 -8
  4. package/cpp/api/JsiVideo.h +37 -5
  5. package/cpp/rnskia/RNSkVideo.h +5 -0
  6. package/ios/RNSkia-iOS/RNSkiOSVideo.h +14 -3
  7. package/ios/RNSkia-iOS/RNSkiOSVideo.mm +78 -60
  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 +14 -5
  11. package/lib/commonjs/external/reanimated/useVideo.js +90 -58
  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 -0
  21. package/lib/commonjs/skia/types/Video/Video.js.map +1 -1
  22. package/lib/commonjs/skia/types/index.d.ts +1 -0
  23. package/lib/commonjs/skia/types/index.js +11 -0
  24. package/lib/commonjs/skia/types/index.js.map +1 -1
  25. package/lib/module/dom/nodes/datatypes/Fitting.js +41 -29
  26. package/lib/module/dom/nodes/datatypes/Fitting.js.map +1 -1
  27. package/lib/module/external/reanimated/useVideo.d.ts +14 -5
  28. package/lib/module/external/reanimated/useVideo.js +91 -59
  29. package/lib/module/external/reanimated/useVideo.js.map +1 -1
  30. package/lib/module/renderer/components/shapes/FitBox.d.ts +2 -10
  31. package/lib/module/renderer/components/shapes/FitBox.js +32 -3
  32. package/lib/module/renderer/components/shapes/FitBox.js.map +1 -1
  33. package/lib/module/skia/core/Matrix.js +5 -1
  34. package/lib/module/skia/core/Matrix.js.map +1 -1
  35. package/lib/module/skia/types/Matrix.js +2 -0
  36. package/lib/module/skia/types/Matrix.js.map +1 -1
  37. package/lib/module/skia/types/Video/Video.d.ts +9 -0
  38. package/lib/module/skia/types/Video/Video.js.map +1 -1
  39. package/lib/module/skia/types/index.d.ts +1 -0
  40. package/lib/module/skia/types/index.js +1 -0
  41. package/lib/module/skia/types/index.js.map +1 -1
  42. package/lib/typescript/src/external/reanimated/useVideo.d.ts +14 -5
  43. package/lib/typescript/src/renderer/components/shapes/FitBox.d.ts +2 -10
  44. package/lib/typescript/src/skia/types/Video/Video.d.ts +9 -0
  45. package/lib/typescript/src/skia/types/index.d.ts +1 -0
  46. package/package.json +1 -1
  47. package/src/dom/nodes/datatypes/Fitting.ts +28 -21
  48. package/src/external/reanimated/useVideo.ts +86 -73
  49. package/src/renderer/components/shapes/FitBox.tsx +38 -4
  50. package/src/skia/core/Matrix.ts +4 -2
  51. package/src/skia/types/Matrix.ts +1 -0
  52. package/src/skia/types/Video/Video.ts +7 -0
  53. package/src/skia/types/index.ts +1 -0
@@ -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
 
@@ -67,6 +68,7 @@ double RNSkAndroidVideo::duration() {
67
68
  }
68
69
  return env->CallDoubleMethod(_jniVideo.get(), mid);
69
70
  }
71
+
70
72
  double RNSkAndroidVideo::framerate() {
71
73
  JNIEnv *env = facebook::jni::Environment::current();
72
74
  jclass cls = env->GetObjectClass(_jniVideo.get());
@@ -81,7 +83,7 @@ double RNSkAndroidVideo::framerate() {
81
83
  void RNSkAndroidVideo::seek(double timestamp) {
82
84
  JNIEnv *env = facebook::jni::Environment::current();
83
85
  jclass cls = env->GetObjectClass(_jniVideo.get());
84
- jmethodID mid = env->GetMethodID(cls, "seek", "(J)V");
86
+ jmethodID mid = env->GetMethodID(cls, "seek", "(D)V");
85
87
  if (!mid) {
86
88
  RNSkLogger::logToConsole("seek method not found");
87
89
  return;
@@ -89,4 +91,73 @@ void RNSkAndroidVideo::seek(double timestamp) {
89
91
  env->CallVoidMethod(_jniVideo.get(), mid, static_cast<jlong>(timestamp));
90
92
  }
91
93
 
94
+ float RNSkAndroidVideo::getRotationInDegrees() {
95
+ JNIEnv *env = facebook::jni::Environment::current();
96
+ jclass cls = env->GetObjectClass(_jniVideo.get());
97
+ jmethodID mid = env->GetMethodID(cls, "getRotationDegrees", "()I");
98
+ if (!mid) {
99
+ RNSkLogger::logToConsole("getRotationDegrees method not found");
100
+ return 0;
101
+ }
102
+ auto rotation = env->CallIntMethod(_jniVideo.get(), mid);
103
+ return static_cast<float>(rotation);
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
+ }
92
163
  } // namespace RNSkia
@@ -31,6 +31,11 @@ public:
31
31
  double duration() override;
32
32
  double framerate() override;
33
33
  void seek(double timestamp) override;
34
+ float getRotationInDegrees() override;
35
+ SkISize getSize() override;
36
+ void play() override;
37
+ void pause() override;
38
+ void setVolume(float volume) override;
34
39
  };
35
40
 
36
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,8 +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;
39
+ private int rotationDegrees = 0;
40
+ private int width = 0;
41
+ private int height = 0;
42
+
43
+ private boolean isPlaying = false;
32
44
 
33
45
  RNSkVideo(Context context, String localUri) {
34
46
  this.uri = Uri.parse(localUri);
@@ -46,6 +58,18 @@ public class RNSkVideo {
46
58
  }
47
59
  extractor.selectTrack(trackIndex);
48
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
+
49
73
  // Retrieve and store video properties
50
74
  if (format.containsKey(MediaFormat.KEY_DURATION)) {
51
75
  durationMs = format.getLong(MediaFormat.KEY_DURATION) / 1000; // Convert microseconds to milliseconds
@@ -53,8 +77,11 @@ public class RNSkVideo {
53
77
  if (format.containsKey(MediaFormat.KEY_FRAME_RATE)) {
54
78
  frameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
55
79
  }
56
- int width = format.getInteger(MediaFormat.KEY_WIDTH);
57
- int height = format.getInteger(MediaFormat.KEY_HEIGHT);
80
+ if (format.containsKey(MediaFormat.KEY_ROTATION)) {
81
+ rotationDegrees = format.getInteger(MediaFormat.KEY_ROTATION);
82
+ }
83
+ width = format.getInteger(MediaFormat.KEY_WIDTH);
84
+ height = format.getInteger(MediaFormat.KEY_HEIGHT);
58
85
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
59
86
  imageReader = ImageReader.newInstance(
60
87
  width,
@@ -87,11 +114,15 @@ public class RNSkVideo {
87
114
  }
88
115
 
89
116
  @DoNotStrip
90
-
91
117
  public double getFrameRate() {
92
118
  return frameRate;
93
119
  }
94
120
 
121
+ @DoNotStrip
122
+ public int getRotationDegrees() {
123
+ return rotationDegrees;
124
+ }
125
+
95
126
  @DoNotStrip
96
127
  public HardwareBuffer nextImage() {
97
128
  if (!decoderOutputAvailable()) {
@@ -108,15 +139,38 @@ public class RNSkVideo {
108
139
  }
109
140
 
110
141
  @DoNotStrip
111
- public void seek(long timestamp) {
112
- // Seek to the closest sync frame at or before the specified time
113
- 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
+
114
153
  // Flush the codec to reset internal state and buffers
115
154
  if (decoder != null) {
116
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
+ }
117
166
  }
118
167
  }
119
168
 
169
+ @DoNotStrip
170
+ public Point getSize() {
171
+ return new Point(width, height);
172
+ }
173
+
120
174
  private int selectVideoTrack(MediaExtractor extractor) {
121
175
  int numTracks = extractor.getTrackCount();
122
176
  for (int i = 0; i < numTracks; i++) {
@@ -171,7 +225,34 @@ public class RNSkVideo {
171
225
  }
172
226
  }
173
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
+
174
251
  public void release() {
252
+ if (mediaPlayer != null) {
253
+ mediaPlayer.release();
254
+ mediaPlayer = null;
255
+ }
175
256
  if (decoder != null) {
176
257
  decoder.stop();
177
258
  decoder.release();
@@ -53,11 +53,43 @@ public:
53
53
  return jsi::Value::undefined();
54
54
  }
55
55
 
56
- JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiVideo, nextImage),
57
- JSI_EXPORT_FUNC(JsiVideo, duration),
58
- JSI_EXPORT_FUNC(JsiVideo, framerate),
59
- JSI_EXPORT_FUNC(JsiVideo, seek),
60
- JSI_EXPORT_FUNC(JsiVideo, dispose))
56
+ JSI_HOST_FUNCTION(rotation) {
57
+ auto context = getContext();
58
+ auto rot = getObject()->getRotationInDegrees();
59
+ return jsi::Value(static_cast<double>(rot));
60
+ }
61
+
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))
61
93
 
62
94
  JsiVideo(std::shared_ptr<RNSkPlatformContext> context,
63
95
  std::shared_ptr<RNSkVideo> video)
@@ -18,6 +18,11 @@ public:
18
18
  virtual double duration() = 0;
19
19
  virtual double framerate() = 0;
20
20
  virtual void seek(double timestamp) = 0;
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;
21
26
  };
22
27
 
23
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,12 +21,17 @@ 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);
30
+ float _videoWidth = 0;
31
+ float _videoHeight = 0;
32
+ CGAffineTransform _preferredTransform;
33
+ bool _isPlaying = false;
34
+ void setupPlayer();
29
35
  NSDictionary *getOutputSettings();
30
36
 
31
37
  public:
@@ -35,6 +41,11 @@ public:
35
41
  double duration() override;
36
42
  double framerate() override;
37
43
  void seek(double timestamp) override;
44
+ void play();
45
+ void pause();
46
+ float getRotationInDegrees() override;
47
+ SkISize getSize() override;
48
+ void setVolume(float volume);
38
49
  };
39
50
 
40
51
  } // namespace RNSkia
@@ -1,5 +1,3 @@
1
- #pragma once
2
-
3
1
  #include <memory>
4
2
  #include <string>
5
3
 
@@ -18,77 +16,60 @@ namespace RNSkia {
18
16
 
19
17
  RNSkiOSVideo::RNSkiOSVideo(std::string url, RNSkPlatformContext *context)
20
18
  : _url(std::move(url)), _context(context) {
21
- setupReader(CMTimeRangeMake(kCMTimeZero, kCMTimePositiveInfinity));
19
+ setupPlayer();
22
20
  }
23
21
 
24
- RNSkiOSVideo::~RNSkiOSVideo() {}
22
+ RNSkiOSVideo::~RNSkiOSVideo() {
23
+ if (_player) {
24
+ [_player pause];
25
+ }
26
+ }
25
27
 
26
- void RNSkiOSVideo::setupReader(CMTimeRange timeRange) {
27
- 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;
28
33
 
29
- AVURLAsset *asset =
30
- [AVURLAsset URLAssetWithURL:[NSURL URLWithString:@(_url.c_str())]
31
- options:nil];
32
- AVAssetReader *assetReader = [[AVAssetReader alloc] initWithAsset:asset
33
- error:&error];
34
- if (error) {
35
- NSLog(@"Error initializing asset reader: %@", error.localizedDescription);
36
- return;
37
- }
34
+ NSDictionary *outputSettings = getOutputSettings();
35
+ _videoOutput =
36
+ [[AVPlayerItemVideoOutput alloc] initWithOutputSettings:outputSettings];
37
+ [playerItem addOutput:_videoOutput];
38
38
 
39
- CMTime time = [asset duration];
40
- if (time.timescale == 0) {
41
- NSLog(@"Error: Timescale of the asset is zero.");
42
- return;
39
+ CMTime time = playerItem.asset.duration;
40
+ if (time.timescale != 0) {
41
+ _duration = CMTimeGetSeconds(time) * 1000; // Store duration in milliseconds
43
42
  }
44
43
 
45
- _duration = CMTimeGetSeconds(time) * 1000; // Store duration in milliseconds
46
44
  AVAssetTrack *videoTrack =
47
- [[asset tracksWithMediaType:AVMediaTypeVideo] firstObject];
48
- _framerate = videoTrack.nominalFrameRate;
49
-
50
- NSDictionary *outputSettings = getOutputSettings();
51
- AVAssetReaderTrackOutput *trackOutput =
52
- [[AVAssetReaderTrackOutput alloc] initWithTrack:videoTrack
53
- outputSettings:outputSettings];
54
-
55
- assetReader.timeRange = timeRange;
56
- if ([assetReader canAddOutput:trackOutput]) {
57
- [assetReader addOutput:trackOutput];
58
- [assetReader startReading];
59
- } else {
60
- NSLog(@"Cannot add output to asset reader.");
61
- 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;
62
52
  }
63
-
64
- _reader = assetReader;
65
- _trackOutput = trackOutput;
53
+ play();
66
54
  }
67
55
 
68
56
  sk_sp<SkImage> RNSkiOSVideo::nextImage(double *timeStamp) {
69
- CMSampleBufferRef sampleBuffer = [_trackOutput copyNextSampleBuffer];
70
- if (!sampleBuffer) {
71
- NSLog(@"No sample buffer.");
72
- return nullptr;
73
- }
74
-
75
- // Extract the pixel buffer from the sample buffer
76
- CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
57
+ CMTime currentTime = [_player currentTime];
58
+ CVPixelBufferRef pixelBuffer =
59
+ [_videoOutput copyPixelBufferForItemTime:currentTime
60
+ itemTimeForDisplay:nullptr];
77
61
  if (!pixelBuffer) {
78
62
  NSLog(@"No pixel buffer.");
79
- CFRelease(sampleBuffer);
80
63
  return nullptr;
81
64
  }
82
65
 
83
- auto skImage = _context->makeImageFromNativeBuffer(
84
- reinterpret_cast<void *>(pixelBuffer));
66
+ auto skImage = _context->makeImageFromNativeBuffer((void *)pixelBuffer);
85
67
 
86
68
  if (timeStamp) {
87
- CMTime time = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
88
- *timeStamp = CMTimeGetSeconds(time);
69
+ *timeStamp = CMTimeGetSeconds(currentTime);
89
70
  }
90
71
 
91
- CFRelease(sampleBuffer);
72
+ CVPixelBufferRelease(pixelBuffer);
92
73
  return skImage;
93
74
  }
94
75
 
@@ -99,21 +80,58 @@ NSDictionary *RNSkiOSVideo::getOutputSettings() {
99
80
  };
100
81
  }
101
82
 
102
- void RNSkiOSVideo::seek(double timeInMilliseconds) {
103
- if (_reader) {
104
- [_reader cancelReading];
105
- _reader = nil;
106
- _trackOutput = nil;
83
+ float RNSkiOSVideo::getRotationInDegrees() {
84
+ CGFloat rotationAngle = 0.0;
85
+ auto transform = _preferredTransform;
86
+ // Determine the rotation angle in radians
87
+ if (transform.a == 0 && transform.b == 1 && transform.c == -1 &&
88
+ transform.d == 0) {
89
+ rotationAngle = 90;
90
+ } else if (transform.a == 0 && transform.b == -1 && transform.c == 1 &&
91
+ transform.d == 0) {
92
+ rotationAngle = 270;
93
+ } else if (transform.a == -1 && transform.b == 0 && transform.c == 0 &&
94
+ transform.d == -1) {
95
+ rotationAngle = 180;
107
96
  }
97
+ return rotationAngle;
98
+ }
108
99
 
109
- CMTime startTime =
100
+ void RNSkiOSVideo::seek(double timeInMilliseconds) {
101
+ CMTime seekTime =
110
102
  CMTimeMakeWithSeconds(timeInMilliseconds / 1000.0, NSEC_PER_SEC);
111
- CMTimeRange timeRange = CMTimeRangeMake(startTime, kCMTimePositiveInfinity);
112
- setupReader(timeRange);
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;
117
+ }
118
+ }
119
+
120
+ void RNSkiOSVideo::pause() {
121
+ if (_player) {
122
+ [_player pause];
123
+ _isPlaying = false;
124
+ }
113
125
  }
114
126
 
115
127
  double RNSkiOSVideo::duration() { return _duration; }
116
128
 
117
129
  double RNSkiOSVideo::framerate() { return _framerate; }
118
130
 
131
+ SkISize RNSkiOSVideo::getSize() {
132
+ return SkISize::Make(_videoWidth, _videoHeight);
133
+ }
134
+
135
+ void RNSkiOSVideo::setVolume(float volume) { _player.volume = volume; }
136
+
119
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