react-native-video-trim 1.0.22 → 1.0.24

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.
@@ -164,6 +164,11 @@ public class VideoTrimModule extends ReactContextBaseJavaModule implements Video
164
164
  }
165
165
 
166
166
  @Override public void onTrimmingProgress(int percentage) {
167
+ // prevent onTrimmingProgress is called after onFinishTrim (some rare cases)
168
+ if (mProgressBar == null) {
169
+ return;
170
+ }
171
+
167
172
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
168
173
  mProgressBar.setProgress(percentage, true);
169
174
  } else {
@@ -172,10 +177,13 @@ public class VideoTrimModule extends ReactContextBaseJavaModule implements Video
172
177
  }
173
178
 
174
179
 
175
- @Override public void onFinishTrim(String in) {
180
+ @Override public void onFinishTrim(String in, long startTime, long endTime, int duration) {
176
181
  runOnUiThread(() -> {
177
182
  WritableMap map = Arguments.createMap();
178
183
  map.putString("outputPath", in);
184
+ map.putInt("duration", duration);
185
+ map.putDouble("startTime", (double) startTime);
186
+ map.putDouble("endTime", (double) endTime);
179
187
  sendEvent(getReactApplicationContext(), "onFinishTrimming", map);
180
188
  showEditorPromise.resolve(in);
181
189
  });
@@ -3,7 +3,7 @@ package com.videotrim.interfaces;
3
3
  public interface VideoTrimListener {
4
4
  void onStartTrim();
5
5
  void onTrimmingProgress(int percentage);
6
- void onFinishTrim(String url);
6
+ void onFinishTrim(String url, long startMs, long endMs, int videoDuration);
7
7
  void onError(String errorMessage);
8
8
  void onCancel();
9
9
  void onSave();
@@ -48,15 +48,29 @@ public class VideoTrimmerUtil {
48
48
  // Format the current date and time
49
49
  String formattedDateTime = dateFormat.format(currentDate);
50
50
 
51
- String cmd = "-ss " + startMs + "ms" + " -to " + endMs + "ms -i " + inputFile + " -c copy -metadata creation_time=" + formattedDateTime + " " + outputFile;
52
51
  callback.onStartTrim();
53
- FFmpegKit.executeAsync(cmd, session -> {
52
+
53
+ String[] cmds = {
54
+ "-ss",
55
+ startMs + "ms",
56
+ "-to",
57
+ endMs + "ms",
58
+ "-i",
59
+ inputFile,
60
+ "-c",
61
+ "copy",
62
+ "-metadata",
63
+ "creation_time=" + formattedDateTime,
64
+ outputFile
65
+ };
66
+
67
+ FFmpegKit.executeWithArgumentsAsync(cmds, session -> {
54
68
  SessionState state = session.getState();
55
69
  ReturnCode returnCode = session.getReturnCode();
56
70
 
57
71
  if (ReturnCode.isSuccess(returnCode)) {
58
72
  // SUCCESS
59
- callback.onFinishTrim(outputFile);
73
+ callback.onFinishTrim(outputFile, startMs, endMs, videoDuration);
60
74
  }
61
75
  else {
62
76
  // CANCEL + FAILURE
@@ -64,7 +78,7 @@ public class VideoTrimmerUtil {
64
78
  callback.onError(errorMessage);
65
79
  }
66
80
  }, log -> {
67
-
81
+ System.out.println("FFmpeg process started with log " + log.getMessage());
68
82
  }, statistics -> {
69
83
  int timeInMilliseconds = (int) statistics.getTime();
70
84
  if (timeInMilliseconds > 0) {
@@ -281,8 +281,6 @@ class VideoTrim: RCTEventEmitter {
281
281
  formatter.timeZone = TimeZone(identifier: "UTC")
282
282
  let dateTime = formatter.string(from: Date())
283
283
 
284
- let cmd = "-ss \(startTime * 1000)ms -to \(endTime * 1000)ms -i \(inputFile) -c copy -metadata creation_time=\(dateTime) \(outputFile)";
285
-
286
284
  self.emitEventToJS("onStartTrimming", eventData: nil)
287
285
 
288
286
  // Create Alert
@@ -304,14 +302,28 @@ class VideoTrim: RCTEventEmitter {
304
302
  })
305
303
  }
306
304
 
307
- FFmpegKit.executeAsync(cmd, withCompleteCallback: { session in
305
+ let cmds = [
306
+ "-ss",
307
+ "\(startTime * 1000)ms",
308
+ "-to",
309
+ "\(endTime * 1000)ms",
310
+ "-i",
311
+ "\(inputFile)",
312
+ "-c",
313
+ "copy",
314
+ "-metadata",
315
+ "creation_time=\(dateTime)",
316
+ outputFile
317
+ ]
318
+
319
+ FFmpegKit.execute(withArgumentsAsync: cmds, withCompleteCallback: { session in
308
320
  let _ = self.deleteFile(url: inputFile) // remove the file we just copied to document directory
309
321
 
310
322
  let state = session?.getState()
311
323
  let returnCode = session?.getReturnCode()
312
324
 
313
325
  if ReturnCode.isSuccess(returnCode) {
314
- let eventPayload: [String: Any] = ["outputPath": outputFile]
326
+ let eventPayload: [String: Any] = ["outputPath": outputFile, "startTime": startTime, "endTime": endTime, "duration": videoDuration]
315
327
  self.emitEventToJS("onFinishTrimming", eventData: eventPayload)
316
328
 
317
329
  if (self.saveToPhoto) {
@@ -356,7 +368,7 @@ class VideoTrim: RCTEventEmitter {
356
368
  })
357
369
  }
358
370
  }, withLogCallback: { log in
359
-
371
+ print("FFmpeg process started with log " + (log?.getMessage() ?? ""));
360
372
  }, withStatisticsCallback: { statistics in
361
373
  let timeInMilliseconds = statistics?.getTime() ?? 0;
362
374
  if timeInMilliseconds > 0 {
@@ -48,7 +48,6 @@ class VideoTrimmerViewController: UIViewController {
48
48
  var isSeekInProgress: Bool = false // Marker
49
49
  private var chaseTime = CMTime.zero
50
50
  private var preferredFrameRate: Float = 23.98
51
-
52
51
 
53
52
  // MARK: - Input
54
53
  @objc private func didBeginTrimmingFromStart(_ sender: VideoTrimmer) {
@@ -133,6 +132,9 @@ class VideoTrimmerViewController: UIViewController {
133
132
  player.removeTimeObserver(token)
134
133
  timeObserverToken = nil
135
134
  }
135
+ // Remove observer
136
+ NotificationCenter.default.removeObserver(self, name: .AVPlayerItemDidPlayToEndTime, object: player.currentItem)
137
+
136
138
  playerController.player = nil
137
139
  playerController.dismiss(animated: false, completion: nil)
138
140
  }
@@ -259,6 +261,15 @@ class VideoTrimmerViewController: UIViewController {
259
261
  playerController.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
260
262
  playerController.view.bottomAnchor.constraint(equalTo: trimmer.topAnchor, constant: -16)
261
263
  ])
264
+
265
+ // Add observer for the end of playback
266
+ NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying), name: .AVPlayerItemDidPlayToEndTime, object: player.currentItem)
267
+ }
268
+
269
+ @objc private func playerDidFinishPlaying(note: NSNotification) {
270
+ // Directly set the play icon
271
+ // the reason in at this time player.timeControlStatus == .playing still returns true
272
+ playBtn.setImage(self.playIcon, for: .normal)
262
273
  }
263
274
 
264
275
  private func setupTimeObserver() {
@@ -292,29 +303,29 @@ class VideoTrimmerViewController: UIViewController {
292
303
  public func seek(to time: CMTime) {
293
304
  seekSmoothlyToTime(newChaseTime: time)
294
305
  }
295
-
306
+
296
307
  private func seekSmoothlyToTime(newChaseTime: CMTime) {
297
308
  if CMTimeCompare(newChaseTime, chaseTime) != 0 {
298
309
  chaseTime = newChaseTime
299
-
310
+
300
311
  if !isSeekInProgress {
301
312
  trySeekToChaseTime()
302
313
  }
303
314
  }
304
315
  }
305
-
316
+
306
317
  private func trySeekToChaseTime() {
307
318
  guard player?.status == .readyToPlay else { return }
308
319
  actuallySeekToTime()
309
320
  }
310
-
321
+
311
322
  private func actuallySeekToTime() {
312
323
  isSeekInProgress = true
313
324
  let seekTimeInProgress = chaseTime
314
-
325
+
315
326
  player?.seek(to: seekTimeInProgress, toleranceBefore: .zero, toleranceAfter: .zero) { [weak self] _ in
316
327
  guard let `self` = self else { return }
317
-
328
+
318
329
  if CMTimeCompare(seekTimeInProgress, self.chaseTime) == 0 {
319
330
  self.isSeekInProgress = false
320
331
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-video-trim",
3
- "version": "1.0.22",
3
+ "version": "1.0.24",
4
4
  "description": "Video trimmer for your React Native app",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",