react-native-video-trim 7.1.0 → 8.0.0
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/README.md +287 -6
- package/android/src/main/java/com/videotrim/BaseVideoTrimModule.kt +488 -34
- package/android/src/main/java/com/videotrim/utils/StorageUtil.kt +95 -36
- package/android/src/main/java/com/videotrim/utils/VideoTrimmerUtil.kt +39 -17
- package/android/src/main/java/com/videotrim/widgets/AudioWaveformView.kt +92 -0
- package/android/src/main/java/com/videotrim/widgets/VideoTrimmerView.kt +579 -8
- package/android/src/main/res/drawable/speaker_slash_fill.xml +19 -0
- package/android/src/main/res/drawable/speaker_wave_2_fill.xml +23 -0
- package/android/src/main/res/layout/video_trimmer_view.xml +22 -0
- package/android/src/newarch/VideoTrimModule.kt +33 -0
- package/android/src/oldarch/VideoTrimModule.kt +41 -0
- package/android/src/oldarch/VideoTrimSpec.kt +17 -0
- package/ios/AudioWaveformView.swift +75 -0
- package/ios/VideoTrim.mm +180 -1
- package/ios/VideoTrim.swift +632 -39
- package/ios/VideoTrimmer.swift +300 -0
- package/ios/VideoTrimmerViewController.swift +129 -4
- package/lib/module/NativeVideoTrim.js +52 -0
- package/lib/module/NativeVideoTrim.js.map +1 -1
- package/lib/module/index.js +155 -2
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/NativeVideoTrim.d.ts +158 -0
- package/lib/typescript/src/NativeVideoTrim.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +65 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/NativeVideoTrim.ts +171 -0
- package/src/index.tsx +211 -2
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
+
android:width="20.574dp"
|
|
3
|
+
android:height="21.997dp"
|
|
4
|
+
android:viewportWidth="20.574"
|
|
5
|
+
android:viewportHeight="21.997">
|
|
6
|
+
<path
|
|
7
|
+
android:fillColor="#FF000000"
|
|
8
|
+
android:pathData="M0,0h20.574v21.997h-20.574z"
|
|
9
|
+
android:strokeAlpha="0"
|
|
10
|
+
android:fillAlpha="0"/>
|
|
11
|
+
<path
|
|
12
|
+
android:pathData="M14.746,18.846C14.618,19.308 14.214,19.617 13.685,19.617C13.236,19.617 12.855,19.431 12.406,19.001L8.246,15.056C8.177,14.998 8.099,14.968 8.002,14.968L5.199,14.968C3.881,14.968 3.158,14.246 3.158,12.83L3.158,9.197C3.158,8.561 3.306,8.063 3.59,7.71ZM14.789,3.543L14.789,13.536L8.231,6.982C8.236,6.978 8.241,6.974 8.246,6.97L12.406,3.064C12.904,2.585 13.217,2.39 13.666,2.39C14.33,2.39 14.789,2.908 14.789,3.543Z"
|
|
13
|
+
android:fillColor="#ffffff"
|
|
14
|
+
android:fillAlpha="0.85"/>
|
|
15
|
+
<path
|
|
16
|
+
android:pathData="M18.158,20.642C18.451,20.935 18.929,20.935 19.222,20.642C19.506,20.339 19.515,19.871 19.222,19.578L2.494,2.859C2.201,2.566 1.713,2.566 1.42,2.859C1.136,3.142 1.136,3.64 1.42,3.923Z"
|
|
17
|
+
android:fillColor="#ffffff"
|
|
18
|
+
android:fillAlpha="0.85"/>
|
|
19
|
+
</vector>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
+
android:width="22.158dp"
|
|
3
|
+
android:height="17.236dp"
|
|
4
|
+
android:viewportWidth="22.158"
|
|
5
|
+
android:viewportHeight="17.236">
|
|
6
|
+
<path
|
|
7
|
+
android:fillColor="#FF000000"
|
|
8
|
+
android:pathData="M0,0h22.158v17.236h-22.158z"
|
|
9
|
+
android:strokeAlpha="0"
|
|
10
|
+
android:fillAlpha="0"/>
|
|
11
|
+
<path
|
|
12
|
+
android:pathData="M18.74,15.322C19.102,15.566 19.551,15.479 19.815,15.107C21.065,13.389 21.797,11.025 21.797,8.613C21.797,6.201 21.074,3.818 19.815,2.119C19.551,1.748 19.102,1.66 18.74,1.904C18.379,2.148 18.32,2.607 18.604,3.008C19.668,4.512 20.283,6.533 20.283,8.613C20.283,10.693 19.648,12.695 18.604,14.219C18.33,14.619 18.379,15.078 18.74,15.322Z"
|
|
13
|
+
android:fillColor="#ffffff"
|
|
14
|
+
android:fillAlpha="0.85"/>
|
|
15
|
+
<path
|
|
16
|
+
android:pathData="M15.127,12.773C15.449,12.998 15.908,12.93 16.172,12.549C16.924,11.563 17.373,10.107 17.373,8.613C17.373,7.119 16.924,5.674 16.172,4.678C15.908,4.297 15.449,4.219 15.127,4.453C14.727,4.727 14.668,5.215 14.971,5.615C15.537,6.396 15.859,7.48 15.859,8.613C15.859,9.746 15.527,10.82 14.971,11.611C14.678,12.021 14.727,12.49 15.127,12.773Z"
|
|
17
|
+
android:fillColor="#ffffff"
|
|
18
|
+
android:fillAlpha="0.85"/>
|
|
19
|
+
<path
|
|
20
|
+
android:pathData="M10.527,17.236C11.172,17.236 11.631,16.777 11.631,16.143L11.631,1.162C11.631,0.527 11.172,0.01 10.508,0.01C10.049,0.01 9.746,0.215 9.248,0.684L5.078,4.59C5.02,4.648 4.932,4.678 4.834,4.678L2.041,4.678C0.713,4.678 0,5.41 0,6.816L0,10.449C0,11.865 0.713,12.588 2.041,12.588L4.834,12.588C4.932,12.588 5.02,12.617 5.078,12.676L9.248,16.621C9.688,17.051 10.068,17.236 10.527,17.236Z"
|
|
21
|
+
android:fillColor="#ffffff"
|
|
22
|
+
android:fillAlpha="0.85"/>
|
|
23
|
+
</vector>
|
|
@@ -79,6 +79,28 @@
|
|
|
79
79
|
android:tint="#80FFFFFF"
|
|
80
80
|
android:scaleType="fitCenter"
|
|
81
81
|
android:contentDescription="Crop" />
|
|
82
|
+
|
|
83
|
+
<ImageView
|
|
84
|
+
android:id="@+id/muteBtn"
|
|
85
|
+
android:layout_width="22dp"
|
|
86
|
+
android:layout_height="22dp"
|
|
87
|
+
android:src="@drawable/speaker_wave_2_fill"
|
|
88
|
+
android:tint="@android:color/white"
|
|
89
|
+
android:scaleType="fitCenter"
|
|
90
|
+
android:layout_marginStart="12dp"
|
|
91
|
+
android:contentDescription="Mute" />
|
|
92
|
+
|
|
93
|
+
<TextView
|
|
94
|
+
android:id="@+id/speedBtn"
|
|
95
|
+
android:layout_width="wrap_content"
|
|
96
|
+
android:layout_height="22dp"
|
|
97
|
+
android:text="1x"
|
|
98
|
+
android:textColor="@android:color/white"
|
|
99
|
+
android:textSize="13sp"
|
|
100
|
+
android:textStyle="bold"
|
|
101
|
+
android:gravity="center"
|
|
102
|
+
android:layout_marginStart="12dp"
|
|
103
|
+
android:contentDescription="Speed" />
|
|
82
104
|
</LinearLayout>
|
|
83
105
|
|
|
84
106
|
<View
|
|
@@ -3,6 +3,7 @@ package com.videotrim
|
|
|
3
3
|
import android.util.Log
|
|
4
4
|
import com.facebook.react.bridge.Promise
|
|
5
5
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.bridge.ReadableArray
|
|
6
7
|
import com.facebook.react.bridge.ReadableMap
|
|
7
8
|
import com.facebook.react.bridge.WritableMap
|
|
8
9
|
|
|
@@ -69,6 +70,38 @@ class VideoTrimModule(
|
|
|
69
70
|
base.trim(url, options, promise)
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
override fun getFrameAt(url: String, options: ReadableMap, promise: Promise) {
|
|
74
|
+
base.getFrameAt(url, options, promise)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
override fun extractAudio(url: String, options: ReadableMap, promise: Promise) {
|
|
78
|
+
base.extractAudio(url, options, promise)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
override fun compress(url: String, options: ReadableMap, promise: Promise) {
|
|
82
|
+
base.compress(url, options, promise)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
override fun toGif(url: String, options: ReadableMap, promise: Promise) {
|
|
86
|
+
base.toGif(url, options, promise)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
override fun merge(urls: ReadableArray, options: ReadableMap, promise: Promise) {
|
|
90
|
+
base.merge(urls, options, promise)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
override fun saveToPhoto(filePath: String, promise: Promise) {
|
|
94
|
+
base.saveToPhoto(filePath, promise)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
override fun saveToDocuments(filePath: String, promise: Promise) {
|
|
98
|
+
base.saveToDocuments(filePath, promise)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
override fun share(filePath: String, promise: Promise) {
|
|
102
|
+
base.share(filePath, promise)
|
|
103
|
+
}
|
|
104
|
+
|
|
72
105
|
companion object {
|
|
73
106
|
const val NAME = "VideoTrim"
|
|
74
107
|
}
|
|
@@ -3,6 +3,7 @@ package com.videotrim
|
|
|
3
3
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
4
4
|
import com.facebook.react.bridge.Arguments
|
|
5
5
|
import com.facebook.react.bridge.WritableMap
|
|
6
|
+
import com.facebook.react.bridge.ReadableArray
|
|
6
7
|
|
|
7
8
|
import com.facebook.react.bridge.*
|
|
8
9
|
import com.facebook.react.module.annotations.ReactModule
|
|
@@ -69,6 +70,46 @@ class VideoTrimModule internal constructor(context: ReactApplicationContext) : V
|
|
|
69
70
|
base.trim(url, options, promise)
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
@ReactMethod
|
|
74
|
+
override fun getFrameAt(url: String, options: ReadableMap?, promise: Promise) {
|
|
75
|
+
base.getFrameAt(url, options, promise)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@ReactMethod
|
|
79
|
+
override fun extractAudio(url: String, options: ReadableMap?, promise: Promise) {
|
|
80
|
+
base.extractAudio(url, options, promise)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@ReactMethod
|
|
84
|
+
override fun compress(url: String, options: ReadableMap?, promise: Promise) {
|
|
85
|
+
base.compress(url, options, promise)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@ReactMethod
|
|
89
|
+
override fun toGif(url: String, options: ReadableMap?, promise: Promise) {
|
|
90
|
+
base.toGif(url, options, promise)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@ReactMethod
|
|
94
|
+
override fun merge(urls: ReadableArray, options: ReadableMap?, promise: Promise) {
|
|
95
|
+
base.merge(urls, options, promise)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@ReactMethod
|
|
99
|
+
override fun saveToPhoto(filePath: String, promise: Promise) {
|
|
100
|
+
base.saveToPhoto(filePath, promise)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@ReactMethod
|
|
104
|
+
override fun saveToDocuments(filePath: String, promise: Promise) {
|
|
105
|
+
base.saveToDocuments(filePath, promise)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@ReactMethod
|
|
109
|
+
override fun share(filePath: String, promise: Promise) {
|
|
110
|
+
base.share(filePath, promise)
|
|
111
|
+
}
|
|
112
|
+
|
|
72
113
|
companion object {
|
|
73
114
|
const val NAME = "VideoTrim"
|
|
74
115
|
}
|
|
@@ -3,6 +3,7 @@ package com.videotrim
|
|
|
3
3
|
import com.facebook.react.bridge.Promise
|
|
4
4
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
5
|
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
6
|
+
import com.facebook.react.bridge.ReadableArray
|
|
6
7
|
import com.facebook.react.bridge.ReadableMap
|
|
7
8
|
|
|
8
9
|
abstract class VideoTrimSpec internal constructor(context: ReactApplicationContext) :
|
|
@@ -21,4 +22,20 @@ abstract class VideoTrimSpec internal constructor(context: ReactApplicationConte
|
|
|
21
22
|
abstract fun isValidFile(url: String, promise: Promise)
|
|
22
23
|
|
|
23
24
|
abstract fun trim(url: String, options: ReadableMap?, promise: Promise)
|
|
25
|
+
|
|
26
|
+
abstract fun getFrameAt(url: String, options: ReadableMap?, promise: Promise)
|
|
27
|
+
|
|
28
|
+
abstract fun extractAudio(url: String, options: ReadableMap?, promise: Promise)
|
|
29
|
+
|
|
30
|
+
abstract fun compress(url: String, options: ReadableMap?, promise: Promise)
|
|
31
|
+
|
|
32
|
+
abstract fun toGif(url: String, options: ReadableMap?, promise: Promise)
|
|
33
|
+
|
|
34
|
+
abstract fun merge(urls: ReadableArray, options: ReadableMap?, promise: Promise)
|
|
35
|
+
|
|
36
|
+
abstract fun saveToPhoto(filePath: String, promise: Promise)
|
|
37
|
+
|
|
38
|
+
abstract fun saveToDocuments(filePath: String, promise: Promise)
|
|
39
|
+
|
|
40
|
+
abstract fun share(filePath: String, promise: Promise)
|
|
24
41
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
/// Custom UIView that draws an audio waveform as a row of vertical rounded-rect bars.
|
|
4
|
+
///
|
|
5
|
+
/// Each bar's height is driven by a normalized amplitude value in [0, 1].
|
|
6
|
+
/// The view recalculates bar count from its own width and maps the amplitudes
|
|
7
|
+
/// array proportionally, so it works correctly regardless of whether the
|
|
8
|
+
/// amplitudes array has more or fewer entries than the visible bar count.
|
|
9
|
+
///
|
|
10
|
+
/// The `backgroundColor` provides the waveform track color; bars are drawn
|
|
11
|
+
/// on top with `barColor`.
|
|
12
|
+
class AudioWaveformView: UIView {
|
|
13
|
+
var amplitudes: [CGFloat] = [] {
|
|
14
|
+
didSet { setNeedsDisplay() }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
var barColor: UIColor = .white {
|
|
18
|
+
didSet { setNeedsDisplay() }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
var barWidth: CGFloat = 3 {
|
|
22
|
+
didSet { setNeedsDisplay() }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
var barGap: CGFloat = 2 {
|
|
26
|
+
didSet { setNeedsDisplay() }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
var barCornerRadius: CGFloat = 1.5 {
|
|
30
|
+
didSet { setNeedsDisplay() }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
override init(frame: CGRect) {
|
|
34
|
+
super.init(frame: frame)
|
|
35
|
+
isOpaque = false
|
|
36
|
+
contentMode = .redraw
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
required init?(coder: NSCoder) {
|
|
40
|
+
super.init(coder: coder)
|
|
41
|
+
isOpaque = false
|
|
42
|
+
contentMode = .redraw
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override func draw(_ rect: CGRect) {
|
|
46
|
+
guard !amplitudes.isEmpty else { return }
|
|
47
|
+
guard let ctx = UIGraphicsGetCurrentContext() else { return }
|
|
48
|
+
|
|
49
|
+
let totalHeight = rect.height
|
|
50
|
+
let step = barWidth + barGap
|
|
51
|
+
let barCount = Int(floor(rect.width / step))
|
|
52
|
+
guard barCount > 0 else { return }
|
|
53
|
+
|
|
54
|
+
// Keep bars from touching the container edges
|
|
55
|
+
let verticalPadding = barWidth * 1.5
|
|
56
|
+
let drawableHeight = totalHeight - verticalPadding * 2
|
|
57
|
+
guard drawableHeight > 0 else { return }
|
|
58
|
+
let minBarHeight = barWidth
|
|
59
|
+
|
|
60
|
+
ctx.setFillColor(barColor.cgColor)
|
|
61
|
+
|
|
62
|
+
for i in 0..<barCount {
|
|
63
|
+
let ampIndex = i * amplitudes.count / barCount
|
|
64
|
+
let amp = amplitudes[min(ampIndex, amplitudes.count - 1)]
|
|
65
|
+
let barHeight = max(minBarHeight, amp * drawableHeight)
|
|
66
|
+
let x = CGFloat(i) * step
|
|
67
|
+
let y = verticalPadding + (drawableHeight - barHeight) / 2.0
|
|
68
|
+
let barRect = CGRect(x: x, y: y, width: barWidth, height: barHeight)
|
|
69
|
+
let path = UIBezierPath(roundedRect: barRect, cornerRadius: barCornerRadius)
|
|
70
|
+
ctx.addPath(path.cgPath)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
ctx.fillPath()
|
|
74
|
+
}
|
|
75
|
+
}
|
package/ios/VideoTrim.mm
CHANGED
|
@@ -73,8 +73,10 @@ RCT_EXPORT_MODULE()
|
|
|
73
73
|
dict[@"startTime"] = @(options.startTime());
|
|
74
74
|
dict[@"endTime"] = @(options.endTime());
|
|
75
75
|
dict[@"enablePreciseTrimming"] = @(options.enablePreciseTrimming());
|
|
76
|
+
dict[@"removeAudio"] = @(options.removeAudio());
|
|
77
|
+
dict[@"speed"] = @(options.speed());
|
|
76
78
|
|
|
77
|
-
[self->videoTrim
|
|
79
|
+
[self->videoTrim trimWithInputFile:url config:dict completion:^(NSDictionary<NSString *,id> * _Nonnull result) {
|
|
78
80
|
BOOL success = [result[@"success"] boolValue];
|
|
79
81
|
if (success) {
|
|
80
82
|
resolve(result);
|
|
@@ -143,6 +145,8 @@ RCT_EXPORT_MODULE()
|
|
|
143
145
|
dict[@"alertOnFailMessage"] = config.alertOnFailMessage();
|
|
144
146
|
dict[@"alertOnFailCloseText"] = config.alertOnFailCloseText();
|
|
145
147
|
dict[@"enablePreciseTrimming"] = @(config.enablePreciseTrimming());
|
|
148
|
+
dict[@"removeAudio"] = @(config.removeAudio());
|
|
149
|
+
dict[@"speed"] = @(config.speed());
|
|
146
150
|
|
|
147
151
|
// Handle optional color values
|
|
148
152
|
auto trimmerColorOpt = config.trimmerColor();
|
|
@@ -155,6 +159,31 @@ RCT_EXPORT_MODULE()
|
|
|
155
159
|
dict[@"handleIconColor"] = @(handleIconColorOpt.value());
|
|
156
160
|
}
|
|
157
161
|
|
|
162
|
+
auto waveformColorOpt = config.waveformColor();
|
|
163
|
+
if (waveformColorOpt.has_value()) {
|
|
164
|
+
dict[@"waveformColor"] = @(waveformColorOpt.value());
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
auto waveformBackgroundColorOpt = config.waveformBackgroundColor();
|
|
168
|
+
if (waveformBackgroundColorOpt.has_value()) {
|
|
169
|
+
dict[@"waveformBackgroundColor"] = @(waveformBackgroundColorOpt.value());
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
auto waveformBarWidthOpt = config.waveformBarWidth();
|
|
173
|
+
if (waveformBarWidthOpt.has_value()) {
|
|
174
|
+
dict[@"waveformBarWidth"] = @(waveformBarWidthOpt.value());
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
auto waveformBarGapOpt = config.waveformBarGap();
|
|
178
|
+
if (waveformBarGapOpt.has_value()) {
|
|
179
|
+
dict[@"waveformBarGap"] = @(waveformBarGapOpt.value());
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
auto waveformBarCornerRadiusOpt = config.waveformBarCornerRadius();
|
|
183
|
+
if (waveformBarCornerRadiusOpt.has_value()) {
|
|
184
|
+
dict[@"waveformBarCornerRadius"] = @(waveformBarCornerRadiusOpt.value());
|
|
185
|
+
}
|
|
186
|
+
|
|
158
187
|
auto zoomOnWaitingDurationOpt = config.zoomOnWaitingDuration();
|
|
159
188
|
if (zoomOnWaitingDurationOpt.has_value()) {
|
|
160
189
|
dict[@"zoomOnWaitingDuration"] = @(zoomOnWaitingDurationOpt.value());
|
|
@@ -168,6 +197,135 @@ RCT_EXPORT_MODULE()
|
|
|
168
197
|
[self->videoTrim showEditor:filePath withConfig:dict];
|
|
169
198
|
}
|
|
170
199
|
|
|
200
|
+
- (void)getFrameAt:(nonnull NSString *)url
|
|
201
|
+
options:(JS::NativeVideoTrim::FrameExtractionOptions &)options
|
|
202
|
+
resolve:(nonnull RCTPromiseResolveBlock)resolve
|
|
203
|
+
reject:(nonnull RCTPromiseRejectBlock)reject {
|
|
204
|
+
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
|
205
|
+
dict[@"time"] = @(options.time());
|
|
206
|
+
dict[@"format"] = options.format();
|
|
207
|
+
dict[@"quality"] = @(options.quality());
|
|
208
|
+
dict[@"maxWidth"] = @(options.maxWidth());
|
|
209
|
+
dict[@"maxHeight"] = @(options.maxHeight());
|
|
210
|
+
|
|
211
|
+
[VideoTrimSwift getFrameAt:url options:dict completion:^(NSDictionary<NSString *, id> * _Nonnull result) {
|
|
212
|
+
if (result[@"error"]) {
|
|
213
|
+
reject(@"ERR_FRAME_EXTRACTION", result[@"error"], [NSError errorWithDomain:@"" code:200 userInfo:nil]);
|
|
214
|
+
} else {
|
|
215
|
+
resolve(result);
|
|
216
|
+
}
|
|
217
|
+
}];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
- (void)extractAudio:(nonnull NSString *)url
|
|
221
|
+
options:(JS::NativeVideoTrim::ExtractAudioOptions &)options
|
|
222
|
+
resolve:(nonnull RCTPromiseResolveBlock)resolve
|
|
223
|
+
reject:(nonnull RCTPromiseRejectBlock)reject {
|
|
224
|
+
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
|
225
|
+
dict[@"outputExt"] = options.outputExt();
|
|
226
|
+
|
|
227
|
+
[VideoTrimSwift extractAudio:url options:dict completion:^(NSDictionary<NSString *, id> * _Nonnull result) {
|
|
228
|
+
if (result[@"error"]) {
|
|
229
|
+
reject(@"ERR_EXTRACT_AUDIO", result[@"error"], [NSError errorWithDomain:@"" code:200 userInfo:nil]);
|
|
230
|
+
} else {
|
|
231
|
+
resolve(result);
|
|
232
|
+
}
|
|
233
|
+
}];
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
- (void)compress:(nonnull NSString *)url
|
|
237
|
+
options:(JS::NativeVideoTrim::CompressOptions &)options
|
|
238
|
+
resolve:(nonnull RCTPromiseResolveBlock)resolve
|
|
239
|
+
reject:(nonnull RCTPromiseRejectBlock)reject {
|
|
240
|
+
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
|
241
|
+
dict[@"quality"] = options.quality();
|
|
242
|
+
dict[@"bitrate"] = @(options.bitrate());
|
|
243
|
+
dict[@"width"] = @(options.width());
|
|
244
|
+
dict[@"height"] = @(options.height());
|
|
245
|
+
dict[@"frameRate"] = @(options.frameRate());
|
|
246
|
+
dict[@"outputExt"] = options.outputExt();
|
|
247
|
+
dict[@"removeAudio"] = @(options.removeAudio());
|
|
248
|
+
|
|
249
|
+
[VideoTrimSwift compress:url options:dict completion:^(NSDictionary<NSString *, id> * _Nonnull result) {
|
|
250
|
+
if (result[@"error"]) {
|
|
251
|
+
reject(@"ERR_COMPRESS", result[@"error"], [NSError errorWithDomain:@"" code:200 userInfo:nil]);
|
|
252
|
+
} else {
|
|
253
|
+
resolve(result);
|
|
254
|
+
}
|
|
255
|
+
}];
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
- (void)toGif:(nonnull NSString *)url
|
|
259
|
+
options:(JS::NativeVideoTrim::GifOptions &)options
|
|
260
|
+
resolve:(nonnull RCTPromiseResolveBlock)resolve
|
|
261
|
+
reject:(nonnull RCTPromiseRejectBlock)reject {
|
|
262
|
+
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
|
263
|
+
dict[@"startTime"] = @(options.startTime());
|
|
264
|
+
dict[@"endTime"] = @(options.endTime());
|
|
265
|
+
dict[@"fps"] = @(options.fps());
|
|
266
|
+
dict[@"width"] = @(options.width());
|
|
267
|
+
|
|
268
|
+
[VideoTrimSwift toGif:url options:dict completion:^(NSDictionary<NSString *, id> * _Nonnull result) {
|
|
269
|
+
if (result[@"error"]) {
|
|
270
|
+
reject(@"ERR_GIF", result[@"error"], [NSError errorWithDomain:@"" code:200 userInfo:nil]);
|
|
271
|
+
} else {
|
|
272
|
+
resolve(result);
|
|
273
|
+
}
|
|
274
|
+
}];
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
- (void)merge:(nonnull NSArray<NSString *> *)urls
|
|
278
|
+
options:(JS::NativeVideoTrim::MergeOptions &)options
|
|
279
|
+
resolve:(nonnull RCTPromiseResolveBlock)resolve
|
|
280
|
+
reject:(nonnull RCTPromiseRejectBlock)reject {
|
|
281
|
+
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
|
282
|
+
dict[@"outputExt"] = options.outputExt();
|
|
283
|
+
|
|
284
|
+
[VideoTrimSwift merge:urls options:dict completion:^(NSDictionary<NSString *, id> * _Nonnull result) {
|
|
285
|
+
if (result[@"error"]) {
|
|
286
|
+
reject(@"ERR_MERGE", result[@"error"], [NSError errorWithDomain:@"" code:200 userInfo:nil]);
|
|
287
|
+
} else {
|
|
288
|
+
resolve(result);
|
|
289
|
+
}
|
|
290
|
+
}];
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
- (void)saveToPhoto:(nonnull NSString *)filePath
|
|
294
|
+
resolve:(nonnull RCTPromiseResolveBlock)resolve
|
|
295
|
+
reject:(nonnull RCTPromiseRejectBlock)reject {
|
|
296
|
+
[VideoTrimSwift saveToPhoto:filePath completion:^(NSDictionary<NSString *, id> * _Nonnull result) {
|
|
297
|
+
if (result[@"error"]) {
|
|
298
|
+
reject(@"ERR_SAVE_TO_PHOTO", result[@"error"], [NSError errorWithDomain:@"" code:200 userInfo:nil]);
|
|
299
|
+
} else {
|
|
300
|
+
resolve(result);
|
|
301
|
+
}
|
|
302
|
+
}];
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
- (void)saveToDocuments:(nonnull NSString *)filePath
|
|
306
|
+
resolve:(nonnull RCTPromiseResolveBlock)resolve
|
|
307
|
+
reject:(nonnull RCTPromiseRejectBlock)reject {
|
|
308
|
+
[VideoTrimSwift saveToDocuments:filePath completion:^(NSDictionary<NSString *, id> * _Nonnull result) {
|
|
309
|
+
if (result[@"error"]) {
|
|
310
|
+
reject(@"ERR_SAVE_TO_DOCUMENTS", result[@"error"], [NSError errorWithDomain:@"" code:200 userInfo:nil]);
|
|
311
|
+
} else {
|
|
312
|
+
resolve(result);
|
|
313
|
+
}
|
|
314
|
+
}];
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
- (void)share:(nonnull NSString *)filePath
|
|
318
|
+
resolve:(nonnull RCTPromiseResolveBlock)resolve
|
|
319
|
+
reject:(nonnull RCTPromiseRejectBlock)reject {
|
|
320
|
+
[VideoTrimSwift share:filePath completion:^(NSDictionary<NSString *, id> * _Nonnull result) {
|
|
321
|
+
if (result[@"error"]) {
|
|
322
|
+
reject(@"ERR_SHARE", result[@"error"], [NSError errorWithDomain:@"" code:200 userInfo:nil]);
|
|
323
|
+
} else {
|
|
324
|
+
resolve(result);
|
|
325
|
+
}
|
|
326
|
+
}];
|
|
327
|
+
}
|
|
328
|
+
|
|
171
329
|
- (void)closeEditor {
|
|
172
330
|
if (self->videoTrim) {
|
|
173
331
|
[self->videoTrim closeEditor:0];
|
|
@@ -228,6 +386,27 @@ RCT_EXTERN_METHOD(isValidFile:(NSString*)uri withResolver:(RCTPromiseResolveBloc
|
|
|
228
386
|
RCT_EXTERN_METHOD(trim:(NSString*)uri withConfig:(NSDictionary *)config
|
|
229
387
|
withResolver:(RCTPromiseResolveBlock)resolve
|
|
230
388
|
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
389
|
+
RCT_EXTERN_METHOD(getFrameAt:(NSString*)url withOptions:(NSDictionary *)options
|
|
390
|
+
withResolver:(RCTPromiseResolveBlock)resolve
|
|
391
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
392
|
+
RCT_EXTERN_METHOD(extractAudio:(NSString*)url withOptions:(NSDictionary *)options
|
|
393
|
+
withResolver:(RCTPromiseResolveBlock)resolve
|
|
394
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
395
|
+
RCT_EXTERN_METHOD(compress:(NSString*)url withOptions:(NSDictionary *)options
|
|
396
|
+
withResolver:(RCTPromiseResolveBlock)resolve
|
|
397
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
398
|
+
RCT_EXTERN_METHOD(toGif:(NSString*)url withOptions:(NSDictionary *)options
|
|
399
|
+
withResolver:(RCTPromiseResolveBlock)resolve
|
|
400
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
401
|
+
RCT_EXTERN_METHOD(merge:(NSArray *)urls withOptions:(NSDictionary *)options
|
|
402
|
+
withResolver:(RCTPromiseResolveBlock)resolve
|
|
403
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
404
|
+
RCT_EXTERN_METHOD(saveToPhoto:(NSString*)filePath withResolver:(RCTPromiseResolveBlock)resolve
|
|
405
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
406
|
+
RCT_EXTERN_METHOD(saveToDocuments:(NSString*)filePath withResolver:(RCTPromiseResolveBlock)resolve
|
|
407
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
408
|
+
RCT_EXTERN_METHOD(share:(NSString*)filePath withResolver:(RCTPromiseResolveBlock)resolve
|
|
409
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
231
410
|
@end
|
|
232
411
|
|
|
233
412
|
#endif
|