react-native-video-trim 4.1.0 → 5.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/LICENSE +1 -1
- package/README.md +89 -76
- package/VideoTrim.podspec +3 -3
- package/android/build.gradle +6 -53
- package/android/gradle.properties +1 -1
- package/android/src/main/AndroidManifest.xml +1 -1
- package/android/src/main/java/com/{margelo/nitro/videotrim/VideoTrim.kt → videotrim/VideoTrimModule.kt} +246 -232
- package/android/src/main/java/com/videotrim/VideoTrimPackage.kt +33 -0
- package/android/src/main/java/com/{margelo/nitro/videotrim → videotrim}/enums/ErrorCode.java +1 -1
- package/android/src/main/java/com/{margelo/nitro/videotrim → videotrim}/interfaces/IVideoTrimmerView.java +1 -1
- package/android/src/main/java/com/{margelo/nitro/videotrim → videotrim}/interfaces/VideoTrimListener.java +5 -4
- package/android/src/main/java/com/{margelo/nitro/videotrim → videotrim}/utils/MediaMetadataUtil.java +1 -1
- package/android/src/main/java/com/{margelo/nitro/videotrim → videotrim}/utils/StorageUtil.java +1 -1
- package/android/src/main/java/com/{margelo/nitro/videotrim → videotrim}/utils/VideoTrimmerUtil.java +20 -18
- package/android/src/main/java/com/{margelo/nitro/videotrim → videotrim}/widgets/VideoTrimmerView.java +44 -45
- package/ios/AssetLoader.h +19 -0
- package/ios/AssetLoader.mm +87 -0
- package/ios/ErrorCode.h +9 -0
- package/ios/ProgressAlertController.h +15 -0
- package/ios/ProgressAlertController.mm +78 -0
- package/ios/VideoTrim.h +31 -0
- package/ios/VideoTrim.mm +663 -0
- package/ios/VideoTrimmer.h +67 -0
- package/ios/VideoTrimmer.mm +863 -0
- package/ios/VideoTrimmerThumb.h +23 -0
- package/ios/VideoTrimmerThumb.mm +175 -0
- package/ios/VideoTrimmerViewController.h +52 -0
- package/ios/VideoTrimmerViewController.mm +533 -0
- package/lib/module/NativeVideoTrim.js +5 -0
- package/lib/module/NativeVideoTrim.js.map +1 -0
- package/lib/module/index.js +22 -24
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/NativeVideoTrim.d.ts +107 -0
- package/lib/typescript/src/NativeVideoTrim.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +13 -10
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +15 -18
- package/src/NativeVideoTrim.ts +113 -0
- package/src/index.tsx +26 -31
- package/android/CMakeLists.txt +0 -24
- package/android/src/main/cpp/cpp-adapter.cpp +0 -6
- package/android/src/main/java/com/margelo/nitro/videotrim/VideoTrimPackage.kt +0 -22
- package/ios/AssetLoader.swift +0 -99
- package/ios/ErrorCode.swift +0 -17
- package/ios/ProgressAlertController.swift +0 -100
- package/ios/VideoTrim.swift +0 -67
- package/ios/VideoTrimImpl.swift +0 -957
- package/ios/VideoTrimmer.swift +0 -872
- package/ios/VideoTrimmerThumb.swift +0 -175
- package/ios/VideoTrimmerViewController.swift +0 -557
- package/lib/module/VideoTrim.nitro.js +0 -4
- package/lib/module/VideoTrim.nitro.js.map +0 -1
- package/lib/typescript/src/VideoTrim.nitro.d.ts +0 -257
- package/lib/typescript/src/VideoTrim.nitro.d.ts.map +0 -1
- package/nitrogen/generated/android/c++/JEditorConfig.hpp +0 -237
- package/nitrogen/generated/android/c++/JFileValidationResult.hpp +0 -61
- package/nitrogen/generated/android/c++/JFunc_void.hpp +0 -74
- package/nitrogen/generated/android/c++/JFunc_void_std__string_std__unordered_map_std__string__std__string_.hpp +0 -89
- package/nitrogen/generated/android/c++/JHybridVideoTrimSpec.cpp +0 -151
- package/nitrogen/generated/android/c++/JHybridVideoTrimSpec.hpp +0 -68
- package/nitrogen/generated/android/c++/JTrimOptions.hpp +0 -109
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/videotrim/EditorConfig.kt +0 -72
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/videotrim/FileValidationResult.kt +0 -28
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/videotrim/Func_void.kt +0 -80
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/videotrim/Func_void_std__string_std__unordered_map_std__string__std__string_.kt +0 -80
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/videotrim/HybridVideoTrimSpec.kt +0 -86
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/videotrim/TrimOptions.kt +0 -40
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/videotrim/videotrimOnLoad.kt +0 -35
- package/nitrogen/generated/android/videotrim+autolinking.cmake +0 -78
- package/nitrogen/generated/android/videotrim+autolinking.gradle +0 -27
- package/nitrogen/generated/android/videotrimOnLoad.cpp +0 -50
- package/nitrogen/generated/android/videotrimOnLoad.hpp +0 -25
- package/nitrogen/generated/ios/VideoTrim+autolinking.rb +0 -60
- package/nitrogen/generated/ios/VideoTrim-Swift-Cxx-Bridge.cpp +0 -96
- package/nitrogen/generated/ios/VideoTrim-Swift-Cxx-Bridge.hpp +0 -374
- package/nitrogen/generated/ios/VideoTrim-Swift-Cxx-Umbrella.hpp +0 -56
- package/nitrogen/generated/ios/VideoTrimAutolinking.mm +0 -33
- package/nitrogen/generated/ios/VideoTrimAutolinking.swift +0 -25
- package/nitrogen/generated/ios/c++/HybridVideoTrimSpecSwift.cpp +0 -11
- package/nitrogen/generated/ios/c++/HybridVideoTrimSpecSwift.hpp +0 -127
- package/nitrogen/generated/ios/swift/EditorConfig.swift +0 -541
- package/nitrogen/generated/ios/swift/FileValidationResult.swift +0 -57
- package/nitrogen/generated/ios/swift/Func_void.swift +0 -46
- package/nitrogen/generated/ios/swift/Func_void_FileValidationResult.swift +0 -46
- package/nitrogen/generated/ios/swift/Func_void_bool.swift +0 -46
- package/nitrogen/generated/ios/swift/Func_void_double.swift +0 -46
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +0 -46
- package/nitrogen/generated/ios/swift/Func_void_std__string.swift +0 -46
- package/nitrogen/generated/ios/swift/Func_void_std__string_std__unordered_map_std__string__std__string_.swift +0 -54
- package/nitrogen/generated/ios/swift/Func_void_std__vector_std__string_.swift +0 -46
- package/nitrogen/generated/ios/swift/HybridVideoTrimSpec.swift +0 -54
- package/nitrogen/generated/ios/swift/HybridVideoTrimSpec_cxx.swift +0 -241
- package/nitrogen/generated/ios/swift/TrimOptions.swift +0 -189
- package/nitrogen/generated/shared/c++/EditorConfig.hpp +0 -253
- package/nitrogen/generated/shared/c++/FileValidationResult.hpp +0 -77
- package/nitrogen/generated/shared/c++/HybridVideoTrimSpec.cpp +0 -27
- package/nitrogen/generated/shared/c++/HybridVideoTrimSpec.hpp +0 -80
- package/nitrogen/generated/shared/c++/TrimOptions.hpp +0 -125
- package/src/VideoTrim.nitro.ts +0 -263
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
package com.videotrim
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.BaseReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.module.model.ReactModuleInfo
|
|
7
|
+
import com.facebook.react.module.model.ReactModuleInfoProvider
|
|
8
|
+
import java.util.HashMap
|
|
9
|
+
|
|
10
|
+
class VideoTrimPackage : BaseReactPackage() {
|
|
11
|
+
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
|
|
12
|
+
return if (name == VideoTrimModule.NAME) {
|
|
13
|
+
VideoTrimModule(reactContext)
|
|
14
|
+
} else {
|
|
15
|
+
null
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
|
|
20
|
+
return ReactModuleInfoProvider {
|
|
21
|
+
val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
|
|
22
|
+
moduleInfos[VideoTrimModule.NAME] = ReactModuleInfo(
|
|
23
|
+
VideoTrimModule.NAME,
|
|
24
|
+
VideoTrimModule.NAME,
|
|
25
|
+
false, // canOverrideExistingModule
|
|
26
|
+
false, // needsEagerInit
|
|
27
|
+
false, // isCxxModule
|
|
28
|
+
true // isTurboModule
|
|
29
|
+
)
|
|
30
|
+
moduleInfos
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
package com.
|
|
1
|
+
package com.videotrim.interfaces;
|
|
2
2
|
|
|
3
|
-
import com.
|
|
3
|
+
import com.facebook.react.bridge.ReadableMap;
|
|
4
|
+
import com.videotrim.enums.ErrorCode;
|
|
4
5
|
|
|
5
6
|
import java.util.Map;
|
|
6
7
|
|
|
@@ -12,6 +13,6 @@ public interface VideoTrimListener {
|
|
|
12
13
|
void onError(String errorMessage, ErrorCode errorCode);
|
|
13
14
|
void onCancel();
|
|
14
15
|
void onSave();
|
|
15
|
-
void onLog(
|
|
16
|
-
void onStatistics(
|
|
16
|
+
void onLog(ReadableMap log);
|
|
17
|
+
void onStatistics(ReadableMap statistics);
|
|
17
18
|
}
|
package/android/src/main/java/com/{margelo/nitro/videotrim → videotrim}/utils/VideoTrimmerUtil.java
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
package com.
|
|
1
|
+
package com.videotrim.utils;
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint;
|
|
4
4
|
import android.graphics.Bitmap;
|
|
@@ -9,8 +9,10 @@ import com.arthenica.ffmpegkit.FFmpegKit;
|
|
|
9
9
|
import com.arthenica.ffmpegkit.FFmpegSession;
|
|
10
10
|
import com.arthenica.ffmpegkit.ReturnCode;
|
|
11
11
|
import com.arthenica.ffmpegkit.SessionState;
|
|
12
|
-
import com.
|
|
13
|
-
import com.
|
|
12
|
+
import com.facebook.react.bridge.Arguments;
|
|
13
|
+
import com.facebook.react.bridge.WritableMap;
|
|
14
|
+
import com.videotrim.enums.ErrorCode;
|
|
15
|
+
import com.videotrim.interfaces.VideoTrimListener;
|
|
14
16
|
|
|
15
17
|
import java.text.SimpleDateFormat;
|
|
16
18
|
import java.util.ArrayList;
|
|
@@ -99,11 +101,11 @@ public class VideoTrimmerUtil {
|
|
|
99
101
|
}, log -> {
|
|
100
102
|
Log.d(TAG, "FFmpeg process started with log " + log.getMessage());
|
|
101
103
|
|
|
102
|
-
|
|
103
|
-
map.
|
|
104
|
-
map.
|
|
105
|
-
map.
|
|
106
|
-
map.
|
|
104
|
+
WritableMap map = Arguments.createMap();
|
|
105
|
+
map.putInt("level", log.getLevel().getValue());
|
|
106
|
+
map.putString("message", log.getMessage());
|
|
107
|
+
map.putDouble("sessionId", log.getSessionId());
|
|
108
|
+
map.putString("logStr", log.toString());
|
|
107
109
|
|
|
108
110
|
callback.onLog(map);
|
|
109
111
|
}, statistics -> {
|
|
@@ -114,16 +116,16 @@ public class VideoTrimmerUtil {
|
|
|
114
116
|
callback.onTrimmingProgress(Math.min(Math.max(completePercentage, 0), 100));
|
|
115
117
|
}
|
|
116
118
|
|
|
117
|
-
|
|
118
|
-
map.
|
|
119
|
-
map.
|
|
120
|
-
map.
|
|
121
|
-
map.
|
|
122
|
-
map.
|
|
123
|
-
map.
|
|
124
|
-
map.
|
|
125
|
-
map.
|
|
126
|
-
map.
|
|
119
|
+
WritableMap map = Arguments.createMap();
|
|
120
|
+
map.putDouble("sessionId", statistics.getSessionId());
|
|
121
|
+
map.putInt("videoFrameNumber", statistics.getVideoFrameNumber());
|
|
122
|
+
map.putDouble("videoFps", statistics.getVideoFps());
|
|
123
|
+
map.putDouble("videoQuality", statistics.getVideoQuality());
|
|
124
|
+
map.putDouble("size", statistics.getSize());
|
|
125
|
+
map.putDouble("time", statistics.getTime());
|
|
126
|
+
map.putDouble("bitrate", statistics.getBitrate());
|
|
127
|
+
map.putDouble("speed", statistics.getSpeed());
|
|
128
|
+
map.putString("statisticsStr", statistics.toString());
|
|
127
129
|
callback.onStatistics(map);
|
|
128
130
|
});
|
|
129
131
|
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
package com.
|
|
1
|
+
package com.videotrim.widgets;
|
|
2
2
|
|
|
3
3
|
import static com.facebook.react.bridge.UiThreadUtil.runOnUiThread;
|
|
4
|
-
import static com.
|
|
5
|
-
import static com.
|
|
4
|
+
import static com.videotrim.utils.VideoTrimmerUtil.RECYCLER_VIEW_PADDING;
|
|
5
|
+
import static com.videotrim.utils.VideoTrimmerUtil.VIDEO_FRAMES_WIDTH;
|
|
6
6
|
|
|
7
7
|
import android.content.Context;
|
|
8
8
|
import android.content.pm.ActivityInfo;
|
|
9
9
|
import android.content.res.Configuration;
|
|
10
10
|
import android.graphics.Bitmap;
|
|
11
|
+
import android.graphics.Color;
|
|
11
12
|
import android.graphics.drawable.GradientDrawable;
|
|
12
13
|
import android.media.MediaMetadataRetriever;
|
|
13
14
|
import android.media.MediaPlayer;
|
|
@@ -34,17 +35,18 @@ import androidx.appcompat.app.AlertDialog;
|
|
|
34
35
|
|
|
35
36
|
import com.arthenica.ffmpegkit.FFmpegSession;
|
|
36
37
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
37
|
-
import com.
|
|
38
|
-
import com.
|
|
39
|
-
import com.
|
|
40
|
-
import com.
|
|
41
|
-
import com.
|
|
42
|
-
import com.
|
|
43
|
-
import com.
|
|
44
|
-
import com.
|
|
38
|
+
import com.facebook.react.bridge.ReadableMap;
|
|
39
|
+
import com.videotrim.R;
|
|
40
|
+
import com.videotrim.enums.ErrorCode;
|
|
41
|
+
import com.videotrim.interfaces.IVideoTrimmerView;
|
|
42
|
+
import com.videotrim.interfaces.VideoTrimListener;
|
|
43
|
+
import com.videotrim.utils.MediaMetadataUtil;
|
|
44
|
+
import com.videotrim.utils.StorageUtil;
|
|
45
|
+
import com.videotrim.utils.VideoTrimmerUtil;
|
|
45
46
|
|
|
46
47
|
import java.io.IOException;
|
|
47
48
|
import java.util.Locale;
|
|
49
|
+
import java.util.Objects;
|
|
48
50
|
|
|
49
51
|
import iknow.android.utils.DeviceUtil;
|
|
50
52
|
import iknow.android.utils.thread.BackgroundExecutor;
|
|
@@ -119,16 +121,16 @@ public class VideoTrimmerView extends FrameLayout implements IVideoTrimmerView {
|
|
|
119
121
|
private String alertOnFailCloseText = "Close";
|
|
120
122
|
private View currentSelectedhandle;
|
|
121
123
|
|
|
122
|
-
public VideoTrimmerView(ReactApplicationContext context,
|
|
124
|
+
public VideoTrimmerView(ReactApplicationContext context, ReadableMap config, AttributeSet attrs) {
|
|
123
125
|
this(context, attrs, 0, config);
|
|
124
126
|
}
|
|
125
127
|
|
|
126
|
-
public VideoTrimmerView(ReactApplicationContext context, AttributeSet attrs, int defStyleAttr,
|
|
128
|
+
public VideoTrimmerView(ReactApplicationContext context, AttributeSet attrs, int defStyleAttr, ReadableMap config) {
|
|
127
129
|
super(context, attrs, defStyleAttr);
|
|
128
130
|
init(context, config);
|
|
129
131
|
}
|
|
130
132
|
|
|
131
|
-
private void init(ReactApplicationContext context,
|
|
133
|
+
private void init(ReactApplicationContext context, ReadableMap config) {
|
|
132
134
|
this.mContext = context;
|
|
133
135
|
|
|
134
136
|
context.getCurrentActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
|
@@ -450,50 +452,47 @@ public class VideoTrimmerView extends FrameLayout implements IVideoTrimmerView {
|
|
|
450
452
|
return screenWidth;
|
|
451
453
|
}
|
|
452
454
|
|
|
453
|
-
private void configure(
|
|
454
|
-
if (config.
|
|
455
|
-
mMaxDuration = (long) Math.max(0, config.
|
|
455
|
+
private void configure(ReadableMap config) {
|
|
456
|
+
if (config.hasKey("maxDuration") && config.getDouble("maxDuration") > 0) {
|
|
457
|
+
mMaxDuration = (long) Math.max(0, config.getDouble("maxDuration") * 1000L);
|
|
456
458
|
}
|
|
457
459
|
|
|
458
|
-
if (config.
|
|
459
|
-
mMinDuration = (long) Math.max(1000L, config.
|
|
460
|
+
if (config.hasKey("minDuration") && config.getDouble("minDuration") > 0) {
|
|
461
|
+
mMinDuration = (long) Math.max(1000L, config.getDouble("minDuration") * 1000L);
|
|
460
462
|
}
|
|
461
463
|
|
|
462
|
-
cancelBtn.setText(config.
|
|
464
|
+
cancelBtn.setText(config.getString("cancelButtonText"));
|
|
465
|
+
saveBtn.setText(config.getString("saveButtonText"));
|
|
466
|
+
isVideoType = config.hasKey("type") && Objects.equals(config.getString("type"), "video");
|
|
467
|
+
System.out.println("1111 isVideoType: " + isVideoType);
|
|
463
468
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
isVideoType = config.getType().equals("video");
|
|
467
|
-
|
|
468
|
-
mOutputExt = config.getOutputExt();
|
|
469
|
+
mOutputExt = config.hasKey("outputExt") ? config.getString("outputExt") : "mp4";
|
|
469
470
|
if (!isVideoType) {
|
|
470
471
|
mOutputExt = "wav";
|
|
471
472
|
}
|
|
473
|
+
enableHapticFeedback = config.hasKey("enableHapticFeedback") && config.getBoolean("enableHapticFeedback");
|
|
474
|
+
autoplay = config.hasKey("autoplay") && config.getBoolean("autoplay");
|
|
472
475
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
if (config.getJumpToPositionOnLoad() > 0) {
|
|
477
|
-
jumpToPositionOnLoad = (long) config.getJumpToPositionOnLoad();
|
|
476
|
+
if (config.hasKey("jumpToPositionOnLoad") && config.getDouble("jumpToPositionOnLoad") > 0) {
|
|
477
|
+
jumpToPositionOnLoad = (long) Math.max(0, config.getDouble("jumpToPositionOnLoad") * 1000L);
|
|
478
478
|
}
|
|
479
|
+
headerText.setText(config.hasKey("headerText") ? config.getString("headerText") : "");
|
|
479
480
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
textSize = 16;
|
|
485
|
-
}
|
|
486
|
-
headerText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize);
|
|
487
|
-
headerText.setTextColor((int) config.getHeaderTextColor());
|
|
481
|
+
int textSize = config.hasKey("headerTextSize") ? config.getInt("headerTextSize") : 16;
|
|
482
|
+
if (textSize < 0) {
|
|
483
|
+
textSize = 16;
|
|
484
|
+
}
|
|
488
485
|
|
|
489
|
-
|
|
486
|
+
headerText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize);
|
|
487
|
+
headerText.setTextColor(config.hasKey("headerTextColor") ? config.getInt("headerTextColor") : Color.BLACK);
|
|
490
488
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
489
|
+
headerView.setVisibility(View.VISIBLE);
|
|
490
|
+
alertOnFailToLoad = config.hasKey("alertOnFailToLoad") && config.getBoolean("alertOnFailToLoad");
|
|
491
|
+
alertOnFailTitle = config.hasKey("alertOnFailTitle") ? config.getString("alertOnFailTitle") : "Error";
|
|
492
|
+
alertOnFailMessage = config.hasKey("alertOnFailMessage") ? config.getString("alertOnFailMessage") : "Fail to load media. Possibly invalid file or no network connection";
|
|
493
|
+
alertOnFailCloseText = config.hasKey("alertOnFailCloseText") ? config.getString("alertOnFailCloseText") : "Close";
|
|
494
|
+
enableRotation = config.hasKey("enableRotation") && config.getBoolean("enableRotation");
|
|
495
|
+
rotationAngle = config.hasKey("rotationAngle") ? config.getDouble("rotationAngle") : 0.0;
|
|
497
496
|
}
|
|
498
497
|
|
|
499
498
|
private void startTimingRunnable() {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
#import <AVFoundation/AVFoundation.h>
|
|
3
|
+
|
|
4
|
+
@class AssetLoader;
|
|
5
|
+
|
|
6
|
+
@protocol AssetLoaderDelegate <NSObject>
|
|
7
|
+
@optional
|
|
8
|
+
- (void)assetLoaderDidSucceed:(AssetLoader *)assetLoader;
|
|
9
|
+
- (void)assetLoader:(AssetLoader *)assetLoader didFailWithError:(NSError *)error forKey:(NSString *)key;
|
|
10
|
+
@end
|
|
11
|
+
|
|
12
|
+
@interface AssetLoader : NSObject
|
|
13
|
+
|
|
14
|
+
@property (nonatomic, weak) id<AssetLoaderDelegate> delegate;
|
|
15
|
+
@property (nonatomic, strong, readonly) AVURLAsset *asset;
|
|
16
|
+
|
|
17
|
+
- (void)loadAssetWithURL:(NSURL *)url isVideoType:(BOOL)isVideoType;
|
|
18
|
+
|
|
19
|
+
@end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#import "AssetLoader.h"
|
|
2
|
+
|
|
3
|
+
@interface AssetLoader ()
|
|
4
|
+
@property (nonatomic, strong) AVURLAsset *asset;
|
|
5
|
+
@end
|
|
6
|
+
|
|
7
|
+
@implementation AssetLoader
|
|
8
|
+
|
|
9
|
+
- (void)loadAssetWithURL:(NSURL *)url isVideoType:(BOOL)isVideoType {
|
|
10
|
+
NSDictionary *options = @{ AVURLAssetPreferPreciseDurationAndTimingKey: @YES };
|
|
11
|
+
self.asset = [AVURLAsset URLAssetWithURL:url options:options];
|
|
12
|
+
NSArray *keys = @[ @"duration", @"tracks" ];
|
|
13
|
+
[self.asset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
|
|
14
|
+
[self assetLoaded:isVideoType];
|
|
15
|
+
}];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
- (void)assetLoaded:(BOOL)isVideoType {
|
|
19
|
+
NSArray *keys = @[ @"duration", @"tracks" ];
|
|
20
|
+
for (NSString *key in keys) {
|
|
21
|
+
NSError *error = nil;
|
|
22
|
+
AVKeyValueStatus status = [self.asset statusOfValueForKey:key error:&error];
|
|
23
|
+
if (status == AVKeyValueStatusFailed) {
|
|
24
|
+
if ([self.delegate respondsToSelector:@selector(assetLoader:didFailWithError:forKey:)]) {
|
|
25
|
+
[self.delegate assetLoader:self didFailWithError:error forKey:key];
|
|
26
|
+
}
|
|
27
|
+
return;
|
|
28
|
+
} else if (status == AVKeyValueStatusCancelled) {
|
|
29
|
+
NSError *cancelError = [NSError errorWithDomain:@"AssetLoader" code:-1 userInfo:@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"%@ loading was cancelled", key] }];
|
|
30
|
+
if ([self.delegate respondsToSelector:@selector(assetLoader:didFailWithError:forKey:)]) {
|
|
31
|
+
[self.delegate assetLoader:self didFailWithError:cancelError forKey:key];
|
|
32
|
+
}
|
|
33
|
+
return;
|
|
34
|
+
} else if (status != AVKeyValueStatusLoaded) {
|
|
35
|
+
NSError *unknownError = [NSError errorWithDomain:@"AssetLoader" code:-1 userInfo:@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"%@ is in an unknown state", key] }];
|
|
36
|
+
if ([self.delegate respondsToSelector:@selector(assetLoader:didFailWithError:forKey:)]) {
|
|
37
|
+
[self.delegate assetLoader:self didFailWithError:unknownError forKey:key];
|
|
38
|
+
}
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (isVideoType) {
|
|
43
|
+
[self processAssetTracks];
|
|
44
|
+
} else {
|
|
45
|
+
if ([self.delegate respondsToSelector:@selector(assetLoaderDidSucceed:)]) {
|
|
46
|
+
[self.delegate assetLoaderDidSucceed:self];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
- (void)processAssetTracks {
|
|
52
|
+
NSArray *videoTracks = [self.asset tracksWithMediaType:AVMediaTypeVideo];
|
|
53
|
+
AVAssetTrack *videoTrack = videoTracks.firstObject;
|
|
54
|
+
if (!videoTrack) {
|
|
55
|
+
NSError *error = [NSError errorWithDomain:@"AssetLoader" code:-1 userInfo:@{ NSLocalizedDescriptionKey: @"No video tracks found" }];
|
|
56
|
+
if ([self.delegate respondsToSelector:@selector(assetLoader:didFailWithError:forKey:)]) {
|
|
57
|
+
[self.delegate assetLoader:self didFailWithError:error forKey:@"tracks"];
|
|
58
|
+
}
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
NSArray *trackKeys = @[ @"naturalSize", @"preferredTransform" ];
|
|
62
|
+
[videoTrack loadValuesAsynchronouslyForKeys:trackKeys completionHandler:^{
|
|
63
|
+
[self trackPropertiesLoaded:videoTrack];
|
|
64
|
+
}];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
- (void)trackPropertiesLoaded:(AVAssetTrack *)track {
|
|
68
|
+
NSError *error = nil;
|
|
69
|
+
AVKeyValueStatus naturalSizeStatus = [track statusOfValueForKey:@"naturalSize" error:&error];
|
|
70
|
+
AVKeyValueStatus preferredTransformStatus = [track statusOfValueForKey:@"preferredTransform" error:&error];
|
|
71
|
+
if (naturalSizeStatus == AVKeyValueStatusLoaded && preferredTransformStatus == AVKeyValueStatusLoaded) {
|
|
72
|
+
CGSize naturalSize = track.naturalSize;
|
|
73
|
+
CGAffineTransform preferredTransform = track.preferredTransform;
|
|
74
|
+
NSLog(@"Natural size: %@", NSStringFromCGSize(naturalSize));
|
|
75
|
+
NSLog(@"Preferred transform: %@", NSStringFromCGAffineTransform(preferredTransform));
|
|
76
|
+
if ([self.delegate respondsToSelector:@selector(assetLoaderDidSucceed:)]) {
|
|
77
|
+
[self.delegate assetLoaderDidSucceed:self];
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
if ([self.delegate respondsToSelector:@selector(assetLoader:didFailWithError:forKey:)]) {
|
|
81
|
+
NSString *failedKey = (naturalSizeStatus != AVKeyValueStatusLoaded) ? @"naturalSize" : @"preferredTransform";
|
|
82
|
+
[self.delegate assetLoader:self didFailWithError:error forKey:failedKey];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@end
|
package/ios/ErrorCode.h
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#import <UIKit/UIKit.h>
|
|
2
|
+
|
|
3
|
+
@interface ProgressAlertController : UIViewController
|
|
4
|
+
|
|
5
|
+
@property (nonatomic, copy) void (^onDismiss)(void);
|
|
6
|
+
@property (nonatomic, strong) UILabel *titleLabel;
|
|
7
|
+
@property (nonatomic, strong) UIProgressView *progressBar;
|
|
8
|
+
@property (nonatomic, strong) UIButton *actionButton;
|
|
9
|
+
|
|
10
|
+
- (void)setTitle:(NSString *)title;
|
|
11
|
+
- (void)setCancelTitle:(NSString *)title;
|
|
12
|
+
- (void)setProgress:(float)progress;
|
|
13
|
+
- (void)showCancelBtn;
|
|
14
|
+
|
|
15
|
+
@end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#import "ProgressAlertController.h"
|
|
2
|
+
|
|
3
|
+
@implementation ProgressAlertController
|
|
4
|
+
|
|
5
|
+
- (void)viewDidLoad {
|
|
6
|
+
[super viewDidLoad];
|
|
7
|
+
[self setupBackground];
|
|
8
|
+
[self setupAlertView];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
- (void)setupBackground {
|
|
12
|
+
self.view.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
- (void)setupAlertView {
|
|
16
|
+
UIView *alertView = [[UIView alloc] init];
|
|
17
|
+
alertView.backgroundColor = [UIColor colorWithRed:28/255.0 green:28/255.0 blue:30/255.0 alpha:1.0];
|
|
18
|
+
alertView.layer.cornerRadius = 12;
|
|
19
|
+
alertView.translatesAutoresizingMaskIntoConstraints = NO;
|
|
20
|
+
[self.view addSubview:alertView];
|
|
21
|
+
[NSLayoutConstraint activateConstraints:@[
|
|
22
|
+
[alertView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
|
|
23
|
+
[alertView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor],
|
|
24
|
+
[alertView.widthAnchor constraintEqualToConstant:270]
|
|
25
|
+
]];
|
|
26
|
+
self.titleLabel = [[UILabel alloc] init];
|
|
27
|
+
self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
|
|
28
|
+
self.titleLabel.textAlignment = NSTextAlignmentCenter;
|
|
29
|
+
self.titleLabel.font = [UIFont systemFontOfSize:18];
|
|
30
|
+
self.titleLabel.numberOfLines = 0;
|
|
31
|
+
self.titleLabel.textColor = [UIColor whiteColor];
|
|
32
|
+
[alertView addSubview:self.titleLabel];
|
|
33
|
+
self.progressBar = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
|
|
34
|
+
self.progressBar.translatesAutoresizingMaskIntoConstraints = NO;
|
|
35
|
+
[alertView addSubview:self.progressBar];
|
|
36
|
+
self.actionButton = [UIButton buttonWithType:UIButtonTypeSystem];
|
|
37
|
+
[self.actionButton setTitle:@"Cancel" forState:UIControlStateNormal];
|
|
38
|
+
[self.actionButton setTitleColor:[UIColor systemPinkColor] forState:UIControlStateNormal];
|
|
39
|
+
self.actionButton.titleLabel.font = [UIFont systemFontOfSize:16];
|
|
40
|
+
[self.actionButton addTarget:self action:@selector(dismissAlert) forControlEvents:UIControlEventTouchUpInside];
|
|
41
|
+
self.actionButton.translatesAutoresizingMaskIntoConstraints = NO;
|
|
42
|
+
self.actionButton.hidden = YES;
|
|
43
|
+
[alertView addSubview:self.actionButton];
|
|
44
|
+
[NSLayoutConstraint activateConstraints:@[
|
|
45
|
+
[self.titleLabel.topAnchor constraintEqualToAnchor:alertView.topAnchor constant:16],
|
|
46
|
+
[self.titleLabel.leadingAnchor constraintEqualToAnchor:alertView.leadingAnchor constant:16],
|
|
47
|
+
[self.titleLabel.trailingAnchor constraintEqualToAnchor:alertView.trailingAnchor constant:-16],
|
|
48
|
+
[self.progressBar.topAnchor constraintEqualToAnchor:self.titleLabel.bottomAnchor constant:16],
|
|
49
|
+
[self.progressBar.leadingAnchor constraintEqualToAnchor:alertView.leadingAnchor constant:16],
|
|
50
|
+
[self.progressBar.trailingAnchor constraintEqualToAnchor:alertView.trailingAnchor constant:-16],
|
|
51
|
+
[self.actionButton.topAnchor constraintEqualToAnchor:self.progressBar.bottomAnchor constant:16],
|
|
52
|
+
[self.actionButton.bottomAnchor constraintEqualToAnchor:alertView.bottomAnchor constant:-16],
|
|
53
|
+
[self.actionButton.centerXAnchor constraintEqualToAnchor:alertView.centerXAnchor]
|
|
54
|
+
]];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
- (void)dismissAlert {
|
|
58
|
+
if (self.onDismiss) self.onDismiss();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
- (void)setTitle:(NSString *)text {
|
|
62
|
+
self.titleLabel.text = text;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
- (void)setCancelTitle:(NSString *)text {
|
|
66
|
+
[self.actionButton setTitle:text forState:UIControlStateNormal];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
- (void)setProgress:(float)progress {
|
|
70
|
+
[self.progressBar setProgress:progress animated:YES];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
- (void)showCancelBtn {
|
|
74
|
+
[self.view layoutIfNeeded];
|
|
75
|
+
self.actionButton.hidden = NO;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@end
|
package/ios/VideoTrim.h
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#import <VideoTrimSpec/VideoTrimSpec.h>
|
|
2
|
+
#import <AVFoundation/AVFoundation.h>
|
|
3
|
+
#import <UIKit/UIKit.h>
|
|
4
|
+
#import "AssetLoader.h"
|
|
5
|
+
|
|
6
|
+
@class VideoTrimmerViewController;
|
|
7
|
+
@class ProgressAlertController;
|
|
8
|
+
|
|
9
|
+
@interface VideoTrim : NativeVideoTrimSpecBase <NativeVideoTrimSpec, AssetLoaderDelegate, UIDocumentPickerDelegate>
|
|
10
|
+
|
|
11
|
+
@property (nonatomic, strong) NSString *FILE_PREFIX;
|
|
12
|
+
@property (nonatomic, strong) NSString *BEFORE_TRIM_PREFIX;
|
|
13
|
+
@property (nonatomic, assign) BOOL isShowing;
|
|
14
|
+
@property (nonatomic, strong) VideoTrimmerViewController *vc;
|
|
15
|
+
@property (nonatomic, strong) NSURL *outputFile;
|
|
16
|
+
@property (nonatomic, assign) BOOL isVideoType;
|
|
17
|
+
//@property (nonatomic, assign) JS::NativeVideoTrim::EditorConfig editorConfig;
|
|
18
|
+
|
|
19
|
+
// Helper methods
|
|
20
|
+
- (NSURL *)renameFileAtURL:(NSURL *)url newName:(NSString *)newName;
|
|
21
|
+
- (void)trimWithViewController:(VideoTrimmerViewController *)viewController
|
|
22
|
+
inputFile:(NSURL *)inputFile
|
|
23
|
+
videoDuration:(double)videoDuration
|
|
24
|
+
startTime:(double)startTime
|
|
25
|
+
endTime:(double)endTime;
|
|
26
|
+
- (void)saveFileToFilesApp:(NSURL *)fileURL;
|
|
27
|
+
- (void)shareFile:(NSURL *)fileURL;
|
|
28
|
+
- (int)deleteFileAtURL:(NSURL *)url;
|
|
29
|
+
- (void)onError:(NSString *)message code:(NSString *)code;
|
|
30
|
+
|
|
31
|
+
@end
|