@shopify/react-native-skia 1.3.1 → 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 +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