@shopify/react-native-skia 1.2.3 → 1.3.1
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.
- package/android/CMakeLists.txt +1 -0
- package/android/cpp/jni/JniPlatformContext.cpp +23 -0
- package/android/cpp/jni/include/JniPlatformContext.h +2 -0
- package/android/cpp/rnskia-android/RNSkAndroidPlatformContext.h +6 -0
- package/android/cpp/rnskia-android/RNSkAndroidVideo.cpp +92 -0
- package/android/cpp/rnskia-android/RNSkAndroidVideo.h +36 -0
- package/android/cpp/rnskia-android/SkiaOpenGLSurfaceFactory.cpp +3 -3
- package/android/src/main/java/com/shopify/reactnative/skia/PlatformContext.java +5 -0
- package/android/src/main/java/com/shopify/reactnative/skia/RNSkVideo.java +185 -0
- package/cpp/api/JsiSkApi.h +2 -0
- package/cpp/api/JsiVideo.h +87 -0
- package/cpp/rnskia/RNSkPlatformContext.h +3 -0
- package/cpp/rnskia/RNSkVideo.h +23 -0
- package/ios/RNSkia-iOS/RNSkiOSPlatformContext.h +2 -0
- package/ios/RNSkia-iOS/RNSkiOSPlatformContext.mm +6 -0
- package/ios/RNSkia-iOS/RNSkiOSVideo.h +40 -0
- package/ios/RNSkia-iOS/RNSkiOSVideo.mm +119 -0
- package/ios/RNSkia-iOS/RNSkiOSView.mm +37 -0
- package/lib/commonjs/external/reanimated/index.d.ts +1 -0
- package/lib/commonjs/external/reanimated/index.js +11 -0
- package/lib/commonjs/external/reanimated/index.js.map +1 -1
- package/lib/commonjs/external/reanimated/useVideo.d.ts +12 -0
- package/lib/commonjs/external/reanimated/useVideo.js +105 -0
- package/lib/commonjs/external/reanimated/useVideo.js.map +1 -0
- package/lib/commonjs/mock/index.js +2 -1
- package/lib/commonjs/mock/index.js.map +1 -1
- package/lib/commonjs/skia/types/Skia.d.ts +2 -0
- package/lib/commonjs/skia/types/Skia.js.map +1 -1
- package/lib/commonjs/skia/types/Video/Video.d.ts +8 -0
- package/lib/commonjs/skia/types/Video/Video.js +6 -0
- package/lib/commonjs/skia/types/Video/Video.js.map +1 -0
- package/lib/commonjs/skia/types/Video/index.d.ts +1 -0
- package/lib/commonjs/skia/types/Video/index.js +17 -0
- package/lib/commonjs/skia/types/Video/index.js.map +1 -0
- package/lib/commonjs/skia/web/JsiSkia.js +4 -1
- package/lib/commonjs/skia/web/JsiSkia.js.map +1 -1
- package/lib/module/external/reanimated/index.d.ts +1 -0
- package/lib/module/external/reanimated/index.js +1 -0
- package/lib/module/external/reanimated/index.js.map +1 -1
- package/lib/module/external/reanimated/useVideo.d.ts +12 -0
- package/lib/module/external/reanimated/useVideo.js +97 -0
- package/lib/module/external/reanimated/useVideo.js.map +1 -0
- package/lib/module/mock/index.js +2 -1
- package/lib/module/mock/index.js.map +1 -1
- package/lib/module/skia/types/Skia.d.ts +2 -0
- package/lib/module/skia/types/Skia.js.map +1 -1
- package/lib/module/skia/types/Video/Video.d.ts +8 -0
- package/lib/module/skia/types/Video/Video.js +2 -0
- package/lib/module/skia/types/Video/Video.js.map +1 -0
- package/lib/module/skia/types/Video/index.d.ts +1 -0
- package/lib/module/skia/types/Video/index.js +2 -0
- package/lib/module/skia/types/Video/index.js.map +1 -0
- package/lib/module/skia/web/JsiSkia.js +4 -1
- package/lib/module/skia/web/JsiSkia.js.map +1 -1
- package/lib/typescript/src/external/reanimated/index.d.ts +1 -0
- package/lib/typescript/src/external/reanimated/useVideo.d.ts +12 -0
- package/lib/typescript/src/skia/types/Skia.d.ts +2 -0
- package/lib/typescript/src/skia/types/Video/Video.d.ts +8 -0
- package/lib/typescript/src/skia/types/Video/index.d.ts +1 -0
- package/package.json +1 -1
- package/scripts/setup-canvaskit.js +1 -1
- package/src/external/reanimated/index.ts +1 -0
- package/src/external/reanimated/useVideo.ts +130 -0
- package/src/mock/index.ts +1 -0
- package/src/skia/types/Skia.ts +2 -0
- package/src/skia/types/Video/Video.ts +9 -0
- package/src/skia/types/Video/index.ts +1 -0
- package/src/skia/web/JsiSkia.ts +3 -0
package/android/CMakeLists.txt
CHANGED
@@ -48,6 +48,7 @@ add_library(
|
|
48
48
|
"${PROJECT_SOURCE_DIR}/cpp/rnskia-android/SkiaOpenGLSurfaceFactory.cpp"
|
49
49
|
"${PROJECT_SOURCE_DIR}/cpp/rnskia-android/GrAHardwareBufferUtils.cpp"
|
50
50
|
"${PROJECT_SOURCE_DIR}/cpp/rnskia-android/AHardwareBufferUtils.cpp"
|
51
|
+
"${PROJECT_SOURCE_DIR}/cpp/rnskia-android/RNSkAndroidVideo.cpp"
|
51
52
|
|
52
53
|
"${PROJECT_SOURCE_DIR}/../cpp/jsi/JsiHostObject.cpp"
|
53
54
|
"${PROJECT_SOURCE_DIR}/../cpp/jsi/JsiValue.cpp"
|
@@ -75,6 +75,29 @@ TSelf JniPlatformContext::initHybrid(jni::alias_ref<jhybridobject> jThis,
|
|
75
75
|
return makeCxxInstance(jThis, pixelDensity);
|
76
76
|
}
|
77
77
|
|
78
|
+
jni::global_ref<jobject>
|
79
|
+
JniPlatformContext::createVideo(const std::string &url) {
|
80
|
+
jni::ThreadScope ts; // Manages JNI thread attachment/detachment
|
81
|
+
|
82
|
+
// Get the JNI environment
|
83
|
+
JNIEnv *env = facebook::jni::Environment::current();
|
84
|
+
|
85
|
+
// Convert std::string to jstring
|
86
|
+
jstring jUrl = env->NewStringUTF(url.c_str());
|
87
|
+
|
88
|
+
// Get the method ID for the createVideo method
|
89
|
+
// Replace "Lcom/yourpackage/RNSkVideo;" with the actual return type
|
90
|
+
// descriptor
|
91
|
+
static auto method =
|
92
|
+
javaPart_->getClass()->getMethod<jobject(jstring)>("createVideo");
|
93
|
+
|
94
|
+
// Call the method and receive a local reference to the video object
|
95
|
+
auto videoObject = method(javaPart_.get(), jUrl);
|
96
|
+
// Clean up the jstring local reference
|
97
|
+
auto result = jni::make_global(videoObject);
|
98
|
+
return result;
|
99
|
+
}
|
100
|
+
|
78
101
|
sk_sp<SkImage> JniPlatformContext::takeScreenshotFromViewTag(size_t tag) {
|
79
102
|
// Call the java method for creating a view screenshot as a bitmap:
|
80
103
|
auto env = jni::Environment::current();
|
@@ -11,6 +11,7 @@
|
|
11
11
|
|
12
12
|
#include "AHardwareBufferUtils.h"
|
13
13
|
#include "JniPlatformContext.h"
|
14
|
+
#include "RNSkAndroidVideo.h"
|
14
15
|
#include "RNSkPlatformContext.h"
|
15
16
|
#include "SkiaOpenGLSurfaceFactory.h"
|
16
17
|
|
@@ -57,6 +58,11 @@ public:
|
|
57
58
|
return SkiaOpenGLSurfaceFactory::makeImageFromHardwareBuffer(buffer);
|
58
59
|
}
|
59
60
|
|
61
|
+
std::shared_ptr<RNSkVideo> createVideo(const std::string &url) override {
|
62
|
+
auto jniVideo = _jniPlatformContext->createVideo(url);
|
63
|
+
return std::make_shared<RNSkAndroidVideo>(jniVideo);
|
64
|
+
}
|
65
|
+
|
60
66
|
void releaseNativeBuffer(uint64_t pointer) override {
|
61
67
|
#if __ANDROID_API__ >= 26
|
62
68
|
AHardwareBuffer *buffer = reinterpret_cast<AHardwareBuffer *>(pointer);
|
@@ -0,0 +1,92 @@
|
|
1
|
+
#include <memory>
|
2
|
+
#include <string>
|
3
|
+
|
4
|
+
#if __ANDROID_API__ >= 26
|
5
|
+
#include <android/hardware_buffer_jni.h>
|
6
|
+
#endif
|
7
|
+
|
8
|
+
#pragma clang diagnostic push
|
9
|
+
#pragma clang diagnostic ignored "-Wdocumentation"
|
10
|
+
|
11
|
+
#include "include/core/SkImage.h"
|
12
|
+
|
13
|
+
#pragma clang diagnostic pop
|
14
|
+
|
15
|
+
#include "RNSkAndroidVideo.h"
|
16
|
+
#include "SkiaOpenGLSurfaceFactory.h"
|
17
|
+
|
18
|
+
namespace RNSkia {
|
19
|
+
|
20
|
+
namespace jsi = facebook::jsi;
|
21
|
+
namespace jni = facebook::jni;
|
22
|
+
|
23
|
+
RNSkAndroidVideo::RNSkAndroidVideo(jni::global_ref<jobject> jniVideo)
|
24
|
+
: _jniVideo(jniVideo) {
|
25
|
+
#if __ANDROID_API__ < 26
|
26
|
+
throw std::runtime_error("Skia Videos are only support on API 26 and above");
|
27
|
+
#endif
|
28
|
+
}
|
29
|
+
|
30
|
+
RNSkAndroidVideo::~RNSkAndroidVideo() {}
|
31
|
+
|
32
|
+
sk_sp<SkImage> RNSkAndroidVideo::nextImage(double *timeStamp) {
|
33
|
+
#if __ANDROID_API__ >= 26
|
34
|
+
JNIEnv *env = facebook::jni::Environment::current();
|
35
|
+
// Get the Java class and method ID
|
36
|
+
jclass cls = env->GetObjectClass(_jniVideo.get());
|
37
|
+
jmethodID mid =
|
38
|
+
env->GetMethodID(cls, "nextImage", "()Landroid/hardware/HardwareBuffer;");
|
39
|
+
if (mid == nullptr) {
|
40
|
+
// Method not found, handle error
|
41
|
+
RNSkLogger::logToConsole("nextImage method not found");
|
42
|
+
return nullptr;
|
43
|
+
}
|
44
|
+
// Call the Java method
|
45
|
+
jobject jHardwareBuffer = env->CallObjectMethod(_jniVideo.get(), mid);
|
46
|
+
if (jHardwareBuffer == nullptr) {
|
47
|
+
RNSkLogger::logToConsole("Buffer not found");
|
48
|
+
// Null return, handle error
|
49
|
+
return nullptr;
|
50
|
+
}
|
51
|
+
// Convert jobject to AHardwareBuffer
|
52
|
+
AHardwareBuffer *buffer =
|
53
|
+
AHardwareBuffer_fromHardwareBuffer(env, jHardwareBuffer);
|
54
|
+
return SkiaOpenGLSurfaceFactory::makeImageFromHardwareBuffer(buffer);
|
55
|
+
#else
|
56
|
+
return nullptr;
|
57
|
+
#endif
|
58
|
+
}
|
59
|
+
|
60
|
+
double RNSkAndroidVideo::duration() {
|
61
|
+
JNIEnv *env = facebook::jni::Environment::current();
|
62
|
+
jclass cls = env->GetObjectClass(_jniVideo.get());
|
63
|
+
jmethodID mid = env->GetMethodID(cls, "getDuration", "()D");
|
64
|
+
if (!mid) {
|
65
|
+
RNSkLogger::logToConsole("getDuration method not found");
|
66
|
+
return 0.0;
|
67
|
+
}
|
68
|
+
return env->CallDoubleMethod(_jniVideo.get(), mid);
|
69
|
+
}
|
70
|
+
double RNSkAndroidVideo::framerate() {
|
71
|
+
JNIEnv *env = facebook::jni::Environment::current();
|
72
|
+
jclass cls = env->GetObjectClass(_jniVideo.get());
|
73
|
+
jmethodID mid = env->GetMethodID(cls, "getFrameRate", "()D");
|
74
|
+
if (!mid) {
|
75
|
+
RNSkLogger::logToConsole("getFrameRate method not found");
|
76
|
+
return 0.0;
|
77
|
+
}
|
78
|
+
return env->CallDoubleMethod(_jniVideo.get(), mid);
|
79
|
+
}
|
80
|
+
|
81
|
+
void RNSkAndroidVideo::seek(double timestamp) {
|
82
|
+
JNIEnv *env = facebook::jni::Environment::current();
|
83
|
+
jclass cls = env->GetObjectClass(_jniVideo.get());
|
84
|
+
jmethodID mid = env->GetMethodID(cls, "seek", "(J)V");
|
85
|
+
if (!mid) {
|
86
|
+
RNSkLogger::logToConsole("seek method not found");
|
87
|
+
return;
|
88
|
+
}
|
89
|
+
env->CallVoidMethod(_jniVideo.get(), mid, static_cast<jlong>(timestamp));
|
90
|
+
}
|
91
|
+
|
92
|
+
} // namespace RNSkia
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <string>
|
4
|
+
|
5
|
+
#include <fbjni/fbjni.h>
|
6
|
+
#include <jni.h>
|
7
|
+
#include <jsi/jsi.h>
|
8
|
+
|
9
|
+
#pragma clang diagnostic push
|
10
|
+
#pragma clang diagnostic ignored "-Wdocumentation"
|
11
|
+
|
12
|
+
#include "include/core/SkImage.h"
|
13
|
+
|
14
|
+
#pragma clang diagnostic pop
|
15
|
+
|
16
|
+
#include "RNSkVideo.h"
|
17
|
+
|
18
|
+
namespace RNSkia {
|
19
|
+
|
20
|
+
namespace jsi = facebook::jsi;
|
21
|
+
namespace jni = facebook::jni;
|
22
|
+
|
23
|
+
class RNSkAndroidVideo : public RNSkVideo {
|
24
|
+
private:
|
25
|
+
jni::global_ref<jobject> _jniVideo;
|
26
|
+
|
27
|
+
public:
|
28
|
+
explicit RNSkAndroidVideo(jni::global_ref<jobject> jniVideo);
|
29
|
+
~RNSkAndroidVideo();
|
30
|
+
sk_sp<SkImage> nextImage(double *timeStamp = nullptr) override;
|
31
|
+
double duration() override;
|
32
|
+
double framerate() override;
|
33
|
+
void seek(double timestamp) override;
|
34
|
+
};
|
35
|
+
|
36
|
+
} // namespace RNSkia
|
@@ -37,7 +37,6 @@ SkiaOpenGLSurfaceFactory::makeImageFromHardwareBuffer(void *buffer,
|
|
37
37
|
// TODO: find out if we can detect, which graphic buffers support
|
38
38
|
// GR_GL_TEXTURE_2D
|
39
39
|
case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
|
40
|
-
case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
|
41
40
|
format = GrBackendFormats::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_EXTERNAL);
|
42
41
|
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
|
43
42
|
format = GrBackendFormats::MakeGL(GR_GL_RGBA16F, GR_GL_TEXTURE_EXTERNAL);
|
@@ -64,9 +63,10 @@ SkiaOpenGLSurfaceFactory::makeImageFromHardwareBuffer(void *buffer,
|
|
64
63
|
const_cast<AHardwareBuffer *>(hardwareBuffer), description.width,
|
65
64
|
description.height, &deleteImageProc, &updateImageProc, &deleteImageCtx,
|
66
65
|
false, format, false);
|
67
|
-
if (!backendTex.isValid())
|
68
|
-
|
66
|
+
if (!backendTex.isValid()) {
|
67
|
+
RNSkLogger::logToConsole(
|
69
68
|
"Failed to convert HardwareBuffer to OpenGL Texture!");
|
69
|
+
return nullptr;
|
70
70
|
}
|
71
71
|
sk_sp<SkImage> image = SkImages::BorrowTextureFrom(
|
72
72
|
ThreadContextHolder::ThreadSkiaOpenGLContext.directContext.get(),
|
@@ -38,6 +38,11 @@ public class PlatformContext {
|
|
38
38
|
mHybridData = initHybrid(reactContext.getResources().getDisplayMetrics().density);
|
39
39
|
}
|
40
40
|
|
41
|
+
@DoNotStrip
|
42
|
+
public Object createVideo(String url) {
|
43
|
+
return new RNSkVideo(mContext, url);
|
44
|
+
}
|
45
|
+
|
41
46
|
private byte[] getStreamAsBytes(InputStream is) throws IOException {
|
42
47
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
43
48
|
int nRead;
|
@@ -0,0 +1,185 @@
|
|
1
|
+
package com.shopify.reactnative.skia;
|
2
|
+
|
3
|
+
import android.content.Context;
|
4
|
+
import android.graphics.ImageFormat;
|
5
|
+
import android.hardware.HardwareBuffer;
|
6
|
+
import android.media.Image;
|
7
|
+
import android.media.ImageReader;
|
8
|
+
import android.media.MediaCodec;
|
9
|
+
import android.media.MediaExtractor;
|
10
|
+
import android.media.MediaFormat;
|
11
|
+
import android.net.Uri;
|
12
|
+
import android.os.Build;
|
13
|
+
import android.view.Surface;
|
14
|
+
|
15
|
+
import androidx.annotation.RequiresApi;
|
16
|
+
|
17
|
+
import com.facebook.jni.annotations.DoNotStrip;
|
18
|
+
|
19
|
+
import java.io.IOException;
|
20
|
+
import java.nio.ByteBuffer;
|
21
|
+
|
22
|
+
public class RNSkVideo {
|
23
|
+
private final Uri uri;
|
24
|
+
private final Context context;
|
25
|
+
|
26
|
+
private MediaExtractor extractor;
|
27
|
+
private MediaCodec decoder;
|
28
|
+
private ImageReader imageReader;
|
29
|
+
private Surface outputSurface;
|
30
|
+
private double durationMs;
|
31
|
+
private double frameRate;
|
32
|
+
|
33
|
+
RNSkVideo(Context context, String localUri) {
|
34
|
+
this.uri = Uri.parse(localUri);
|
35
|
+
this.context = context;
|
36
|
+
this.initializeReader();
|
37
|
+
}
|
38
|
+
|
39
|
+
private void initializeReader() {
|
40
|
+
extractor = new MediaExtractor();
|
41
|
+
try {
|
42
|
+
extractor.setDataSource(context, this.uri, null);
|
43
|
+
int trackIndex = selectVideoTrack(extractor);
|
44
|
+
if (trackIndex < 0) {
|
45
|
+
throw new RuntimeException("No video track found in " + this.uri);
|
46
|
+
}
|
47
|
+
extractor.selectTrack(trackIndex);
|
48
|
+
MediaFormat format = extractor.getTrackFormat(trackIndex);
|
49
|
+
// Retrieve and store video properties
|
50
|
+
if (format.containsKey(MediaFormat.KEY_DURATION)) {
|
51
|
+
durationMs = format.getLong(MediaFormat.KEY_DURATION) / 1000; // Convert microseconds to milliseconds
|
52
|
+
}
|
53
|
+
if (format.containsKey(MediaFormat.KEY_FRAME_RATE)) {
|
54
|
+
frameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
|
55
|
+
}
|
56
|
+
int width = format.getInteger(MediaFormat.KEY_WIDTH);
|
57
|
+
int height = format.getInteger(MediaFormat.KEY_HEIGHT);
|
58
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
59
|
+
imageReader = ImageReader.newInstance(
|
60
|
+
width,
|
61
|
+
height,
|
62
|
+
ImageFormat.PRIVATE,
|
63
|
+
2,
|
64
|
+
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
|
65
|
+
);
|
66
|
+
} else {
|
67
|
+
imageReader = ImageReader.newInstance(width, height,
|
68
|
+
ImageFormat.PRIVATE, 2);
|
69
|
+
}
|
70
|
+
outputSurface = imageReader.getSurface();
|
71
|
+
|
72
|
+
// Create a decoder for the format
|
73
|
+
String mime = format.getString(MediaFormat.KEY_MIME);
|
74
|
+
decoder = MediaCodec.createDecoderByType(mime);
|
75
|
+
|
76
|
+
// Note: Use an output Surface for rendering if necessary, otherwise handle buffers
|
77
|
+
decoder.configure(format, outputSurface, null, 0);
|
78
|
+
decoder.start();
|
79
|
+
} catch (IOException e) {
|
80
|
+
throw new RuntimeException("Failed to initialize extractor or decoder", e);
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
@DoNotStrip
|
85
|
+
public double getDuration() {
|
86
|
+
return durationMs;
|
87
|
+
}
|
88
|
+
|
89
|
+
@DoNotStrip
|
90
|
+
|
91
|
+
public double getFrameRate() {
|
92
|
+
return frameRate;
|
93
|
+
}
|
94
|
+
|
95
|
+
@DoNotStrip
|
96
|
+
public HardwareBuffer nextImage() {
|
97
|
+
if (!decoderOutputAvailable()) {
|
98
|
+
decodeFrame();
|
99
|
+
}
|
100
|
+
|
101
|
+
Image image = imageReader.acquireLatestImage();
|
102
|
+
if (image != null) {
|
103
|
+
HardwareBuffer hardwareBuffer = image.getHardwareBuffer();
|
104
|
+
image.close(); // Make sure to close the Image to free up the buffer
|
105
|
+
return hardwareBuffer;
|
106
|
+
}
|
107
|
+
return null;
|
108
|
+
}
|
109
|
+
|
110
|
+
@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);
|
114
|
+
// Flush the codec to reset internal state and buffers
|
115
|
+
if (decoder != null) {
|
116
|
+
decoder.flush();
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
private int selectVideoTrack(MediaExtractor extractor) {
|
121
|
+
int numTracks = extractor.getTrackCount();
|
122
|
+
for (int i = 0; i < numTracks; i++) {
|
123
|
+
MediaFormat format = extractor.getTrackFormat(i);
|
124
|
+
String mime = format.getString(MediaFormat.KEY_MIME);
|
125
|
+
if (mime.startsWith("video/")) {
|
126
|
+
return i;
|
127
|
+
}
|
128
|
+
}
|
129
|
+
return -1;
|
130
|
+
}
|
131
|
+
|
132
|
+
private boolean decoderOutputAvailable() {
|
133
|
+
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
|
134
|
+
int outputBufferId = decoder.dequeueOutputBuffer(info, 0);
|
135
|
+
if (outputBufferId >= 0) {
|
136
|
+
// If a buffer is available, release it immediately back since we are just checking
|
137
|
+
decoder.releaseOutputBuffer(outputBufferId, true);
|
138
|
+
return true;
|
139
|
+
}
|
140
|
+
return false;
|
141
|
+
}
|
142
|
+
|
143
|
+
private void decodeFrame() {
|
144
|
+
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
|
145
|
+
long timeoutUs = 10000;
|
146
|
+
boolean isEOS = false;
|
147
|
+
|
148
|
+
int inputBufferId = decoder.dequeueInputBuffer(timeoutUs);
|
149
|
+
if (inputBufferId >= 0) {
|
150
|
+
ByteBuffer inputBuffer = decoder.getInputBuffer(inputBufferId);
|
151
|
+
int sampleSize = extractor.readSampleData(inputBuffer, 0);
|
152
|
+
if (sampleSize < 0) {
|
153
|
+
// End of stream, make sure to send this information to the decoder
|
154
|
+
decoder.queueInputBuffer(inputBufferId, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
|
155
|
+
isEOS = true;
|
156
|
+
} else {
|
157
|
+
long presentationTimeUs = extractor.getSampleTime();
|
158
|
+
decoder.queueInputBuffer(inputBufferId, 0, sampleSize, presentationTimeUs, 0);
|
159
|
+
extractor.advance();
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
int outputBufferId = decoder.dequeueOutputBuffer(info, timeoutUs);
|
164
|
+
if (outputBufferId >= 0) {
|
165
|
+
// If we have a valid buffer, release it to make it available to the ImageReader's surface
|
166
|
+
decoder.releaseOutputBuffer(outputBufferId, true);
|
167
|
+
|
168
|
+
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
|
169
|
+
isEOS = true;
|
170
|
+
}
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
174
|
+
public void release() {
|
175
|
+
if (decoder != null) {
|
176
|
+
decoder.stop();
|
177
|
+
decoder.release();
|
178
|
+
decoder = null;
|
179
|
+
}
|
180
|
+
if (extractor != null) {
|
181
|
+
extractor.release();
|
182
|
+
extractor = null;
|
183
|
+
}
|
184
|
+
}
|
185
|
+
}
|
package/cpp/api/JsiSkApi.h
CHANGED
@@ -50,6 +50,7 @@
|
|
50
50
|
#include "JsiSkTypefaceFactory.h"
|
51
51
|
#include "JsiSkTypefaceFontProviderFactory.h"
|
52
52
|
#include "JsiSkVertices.h"
|
53
|
+
#include "JsiVideo.h"
|
53
54
|
|
54
55
|
namespace RNSkia {
|
55
56
|
|
@@ -67,6 +68,7 @@ public:
|
|
67
68
|
// We create the system font manager eagerly since it has proven to be too
|
68
69
|
// slow to do it on demand
|
69
70
|
JsiSkFontMgrFactory::getFontMgr(getContext());
|
71
|
+
installFunction("Video", JsiVideo::createCtor(context));
|
70
72
|
installFunction("Font", JsiSkFont::createCtor(context));
|
71
73
|
installFunction("Paint", JsiSkPaint::createCtor(context));
|
72
74
|
installFunction("RSXform", JsiSkRSXform::createCtor(context));
|
@@ -0,0 +1,87 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <memory>
|
4
|
+
#include <numeric>
|
5
|
+
#include <utility>
|
6
|
+
#include <vector>
|
7
|
+
|
8
|
+
#include "JsiSkHostObjects.h"
|
9
|
+
#include "RNSkLog.h"
|
10
|
+
#include <jsi/jsi.h>
|
11
|
+
|
12
|
+
#include "JsiSkPaint.h"
|
13
|
+
#include "JsiSkPoint.h"
|
14
|
+
#include "JsiSkRect.h"
|
15
|
+
#include "JsiSkTypeface.h"
|
16
|
+
|
17
|
+
#include "RNSkVideo.h"
|
18
|
+
|
19
|
+
#pragma clang diagnostic push
|
20
|
+
#pragma clang diagnostic ignored "-Wdocumentation"
|
21
|
+
|
22
|
+
#include "include/core/SkFont.h"
|
23
|
+
#include "include/core/SkFontMetrics.h"
|
24
|
+
|
25
|
+
#pragma clang diagnostic pop
|
26
|
+
|
27
|
+
namespace RNSkia {
|
28
|
+
|
29
|
+
namespace jsi = facebook::jsi;
|
30
|
+
|
31
|
+
class JsiVideo : public JsiSkWrappingSharedPtrHostObject<RNSkVideo> {
|
32
|
+
public:
|
33
|
+
EXPORT_JSI_API_TYPENAME(JsiVideo, Video)
|
34
|
+
|
35
|
+
JSI_HOST_FUNCTION(nextImage) {
|
36
|
+
double timestamp = 0;
|
37
|
+
auto video = getObject();
|
38
|
+
auto image = video->nextImage(×tamp);
|
39
|
+
if (!image) {
|
40
|
+
return jsi::Value::null();
|
41
|
+
}
|
42
|
+
return jsi::Object::createFromHostObject(
|
43
|
+
runtime, std::make_shared<JsiSkImage>(getContext(), std::move(image)));
|
44
|
+
}
|
45
|
+
|
46
|
+
JSI_HOST_FUNCTION(duration) { return getObject()->duration(); }
|
47
|
+
|
48
|
+
JSI_HOST_FUNCTION(framerate) { return getObject()->framerate(); }
|
49
|
+
|
50
|
+
JSI_HOST_FUNCTION(seek) {
|
51
|
+
double timestamp = arguments[0].asNumber();
|
52
|
+
getObject()->seek(timestamp);
|
53
|
+
return jsi::Value::undefined();
|
54
|
+
}
|
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))
|
61
|
+
|
62
|
+
JsiVideo(std::shared_ptr<RNSkPlatformContext> context,
|
63
|
+
std::shared_ptr<RNSkVideo> video)
|
64
|
+
: JsiSkWrappingSharedPtrHostObject(std::move(context), std::move(video)) {
|
65
|
+
}
|
66
|
+
|
67
|
+
/**
|
68
|
+
* Creates the function for construction a new instance of the SkFont
|
69
|
+
* wrapper
|
70
|
+
* @param context Platform context
|
71
|
+
* @return A function for creating a new host object wrapper for the SkFont
|
72
|
+
* class
|
73
|
+
*/
|
74
|
+
static const jsi::HostFunctionType
|
75
|
+
createCtor(std::shared_ptr<RNSkPlatformContext> context) {
|
76
|
+
return JSI_HOST_FUNCTION_LAMBDA {
|
77
|
+
auto url = arguments[0].asString(runtime).utf8(runtime);
|
78
|
+
auto video = context->createVideo(url);
|
79
|
+
// Return the newly constructed object
|
80
|
+
return jsi::Object::createFromHostObject(
|
81
|
+
runtime,
|
82
|
+
std::make_shared<JsiVideo>(std::move(context), std::move(video)));
|
83
|
+
};
|
84
|
+
}
|
85
|
+
};
|
86
|
+
|
87
|
+
} // namespace RNSkia
|
@@ -10,6 +10,7 @@
|
|
10
10
|
#include <utility>
|
11
11
|
|
12
12
|
#include "RNSkDispatchQueue.h"
|
13
|
+
#include "RNSkVideo.h"
|
13
14
|
|
14
15
|
#pragma clang diagnostic push
|
15
16
|
#pragma clang diagnostic ignored "-Wdocumentation"
|
@@ -146,6 +147,8 @@ public:
|
|
146
147
|
|
147
148
|
virtual uint64_t makeNativeBuffer(sk_sp<SkImage> image) = 0;
|
148
149
|
|
150
|
+
virtual std::shared_ptr<RNSkVideo> createVideo(const std::string &url) = 0;
|
151
|
+
|
149
152
|
/**
|
150
153
|
* Return the Platform specific font manager
|
151
154
|
*/
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <string>
|
4
|
+
|
5
|
+
#pragma clang diagnostic push
|
6
|
+
#pragma clang diagnostic ignored "-Wdocumentation"
|
7
|
+
|
8
|
+
#include "include/core/SkImage.h"
|
9
|
+
|
10
|
+
#pragma clang diagnostic pop
|
11
|
+
|
12
|
+
namespace RNSkia {
|
13
|
+
|
14
|
+
class RNSkVideo {
|
15
|
+
public:
|
16
|
+
virtual ~RNSkVideo() = default;
|
17
|
+
virtual sk_sp<SkImage> nextImage(double *timeStamp = nullptr) = 0;
|
18
|
+
virtual double duration() = 0;
|
19
|
+
virtual double framerate() = 0;
|
20
|
+
virtual void seek(double timestamp) = 0;
|
21
|
+
};
|
22
|
+
|
23
|
+
} // namespace RNSkia
|
@@ -65,6 +65,8 @@ public:
|
|
65
65
|
|
66
66
|
void releaseNativeBuffer(uint64_t pointer) override;
|
67
67
|
|
68
|
+
std::shared_ptr<RNSkVideo> createVideo(const std::string &url) override;
|
69
|
+
|
68
70
|
virtual void performStreamOperation(
|
69
71
|
const std::string &sourceUri,
|
70
72
|
const std::function<void(std::unique_ptr<SkStreamAsset>)> &op) override;
|
@@ -5,6 +5,7 @@
|
|
5
5
|
#include <thread>
|
6
6
|
#include <utility>
|
7
7
|
|
8
|
+
#include "RNSkiOSVideo.h"
|
8
9
|
#import "SkiaCVPixelBufferUtils.h"
|
9
10
|
#import "SkiaMetalSurfaceFactory.h"
|
10
11
|
|
@@ -143,6 +144,11 @@ uint64_t RNSkiOSPlatformContext::makeNativeBuffer(sk_sp<SkImage> image) {
|
|
143
144
|
return reinterpret_cast<uint64_t>(pixelBuffer);
|
144
145
|
}
|
145
146
|
|
147
|
+
std::shared_ptr<RNSkVideo>
|
148
|
+
RNSkiOSPlatformContext::createVideo(const std::string &url) {
|
149
|
+
return std::make_shared<RNSkiOSVideo>(url, this);
|
150
|
+
}
|
151
|
+
|
146
152
|
void RNSkiOSPlatformContext::raiseError(const std::exception &err) {
|
147
153
|
RCTFatal(RCTErrorWithMessage([NSString stringWithUTF8String:err.what()]));
|
148
154
|
}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <string>
|
4
|
+
|
5
|
+
#include <AVFoundation/AVFoundation.h>
|
6
|
+
#include <CoreVideo/CoreVideo.h>
|
7
|
+
|
8
|
+
#pragma clang diagnostic push
|
9
|
+
#pragma clang diagnostic ignored "-Wdocumentation"
|
10
|
+
|
11
|
+
#include "include/core/SkImage.h"
|
12
|
+
|
13
|
+
#pragma clang diagnostic pop
|
14
|
+
|
15
|
+
#include "RNSkPlatformContext.h"
|
16
|
+
#include "RNSkVideo.h"
|
17
|
+
|
18
|
+
namespace RNSkia {
|
19
|
+
|
20
|
+
class RNSkiOSVideo : public RNSkVideo {
|
21
|
+
private:
|
22
|
+
std::string _url;
|
23
|
+
AVAssetReader *_reader = nullptr;
|
24
|
+
AVAssetReaderTrackOutput *_trackOutput = nullptr;
|
25
|
+
RNSkPlatformContext *_context;
|
26
|
+
double _duration = 0;
|
27
|
+
double _framerate = 0;
|
28
|
+
void setupReader(CMTimeRange timeRange);
|
29
|
+
NSDictionary *getOutputSettings();
|
30
|
+
|
31
|
+
public:
|
32
|
+
RNSkiOSVideo(std::string url, RNSkPlatformContext *context);
|
33
|
+
~RNSkiOSVideo();
|
34
|
+
sk_sp<SkImage> nextImage(double *timeStamp = nullptr) override;
|
35
|
+
double duration() override;
|
36
|
+
double framerate() override;
|
37
|
+
void seek(double timestamp) override;
|
38
|
+
};
|
39
|
+
|
40
|
+
} // namespace RNSkia
|