react-native-video-trim 8.1.2 → 8.1.4

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.
@@ -690,7 +690,9 @@ open class BaseVideoTrimModule internal constructor(
690
690
 
691
691
  if (!needsReEncode) {
692
692
  // Stream copy: no encoder is opened so the fallback chain doesn't apply.
693
+ // -y overwrites any pre-existing output file without prompting.
693
694
  val cmds = mutableListOf(
695
+ "-y",
694
696
  "-ss", "${startTime}ms",
695
697
  "-to", "${endTime}ms",
696
698
  "-i", url,
@@ -721,7 +723,11 @@ open class BaseVideoTrimModule internal constructor(
721
723
  } catch (_: Exception) {}
722
724
 
723
725
  val buildCommand: (List<String>) -> Array<String> = { encoderArgs ->
726
+ // -y overwrites the output file without prompting, so the encoder fallback
727
+ // chain's software retry can reuse the same output path left behind by the
728
+ // failed hardware attempt instead of aborting on FFmpeg's overwrite prompt.
724
729
  val cmds = mutableListOf(
730
+ "-y",
725
731
  "-ss", "${startTime}ms",
726
732
  "-to", "${endTime}ms",
727
733
  "-i", url,
@@ -297,7 +297,8 @@ object VideoTrimmerUtil {
297
297
  if (!needsReEncode) {
298
298
  // Stream copy: no re-encoding, extremely fast but only cuts at keyframes.
299
299
  // No encoder is opened so the fallback chain doesn't apply — single attempt.
300
- val cmds = mutableListOf("-ss", "${startMs}ms", "-to", "${endMs}ms", "-i", inputFile)
300
+ // -y overwrites any pre-existing output file without prompting.
301
+ val cmds = mutableListOf("-y", "-ss", "${startMs}ms", "-to", "${endMs}ms", "-i", inputFile)
301
302
  if (removeAudio) {
302
303
  cmds.addAll(listOf("-c:v", "copy", "-an"))
303
304
  } else {
@@ -354,7 +355,11 @@ object VideoTrimmerUtil {
354
355
  // Note: Android FFmpegKit auto-rotates by default, so no -noautorotate is needed.
355
356
  // The transpose filters above only handle user-initiated rotation, not source metadata.
356
357
  val buildCommand: (List<String>) -> Array<String> = { encoderArgs ->
357
- val cmds = mutableListOf("-ss", "${startMs}ms", "-to", "${endMs}ms", "-i", inputFile)
358
+ // -y overwrites the output file without prompting. This is critical for the
359
+ // encoder fallback chain: the first (hardware) attempt opens/creates the output
360
+ // file before MediaCodec fails, so the software retry reuses the same path and
361
+ // would otherwise hit FFmpeg's interactive "Overwrite? [y/N]" prompt and abort.
362
+ val cmds = mutableListOf("-y", "-ss", "${startMs}ms", "-to", "${endMs}ms", "-i", inputFile)
358
363
  // When enablePreciseTrimming is the only reason for re-encode (no transforms),
359
364
  // videoFilters is empty — skip -vf entirely to avoid FFmpeg error on empty filter.
360
365
  if (filterString.isNotEmpty()) {
@@ -359,7 +359,11 @@ public class VideoTrim: RCTEventEmitter, AssetLoaderDelegate, UIDocumentPickerDe
359
359
  root.present(progressAlert, animated: true, completion: nil)
360
360
  }
361
361
 
362
+ // -y overwrites any pre-existing output file without prompting, so FFmpeg never
363
+ // blocks on an interactive "Overwrite? [y/N]" prompt (hardening; also keeps the
364
+ // command symmetric with Android, where -y is required by the encoder fallback chain).
362
365
  var cmds = [
366
+ "-y",
363
367
  "-ss",
364
368
  "\(startTime * 1000)ms",
365
369
  "-to",
@@ -378,22 +382,13 @@ public class VideoTrim: RCTEventEmitter, AssetLoaderDelegate, UIDocumentPickerDe
378
382
  let needsReEncode = hasUserTransform || cropNorm != nil || enablePreciseTrimming || needsSpeed
379
383
 
380
384
  if needsReEncode, let vc = vc {
381
- // -noautorotate disables FFmpeg's automatic rotation, so we must manually
382
- // compensate for the source video's rotation metadata via transpose filters.
383
- if let asset = vc.asset,
384
- let videoTrack = asset.tracks(withMediaType: .video).first {
385
- let t = videoTrack.preferredTransform
386
- let sourceAngle = atan2(t.b, t.a)
387
- if abs(sourceAngle - .pi / 2) < 0.1 {
388
- videoFilters.append("transpose=1")
389
- } else if abs(sourceAngle + .pi / 2) < 0.1 {
390
- videoFilters.append("transpose=2")
391
- } else if abs(abs(sourceAngle) - .pi) < 0.1 {
392
- videoFilters.append("transpose=1")
393
- videoFilters.append("transpose=1")
394
- }
395
- }
396
-
385
+ // Let FFmpeg autorotate the source (note: NO -noautorotate below). Autorotate bakes
386
+ // the source rotation matrix into upright, display-orientation pixels AND strips the
387
+ // matrix from the output. The previous approach (-noautorotate + a manual source-
388
+ // compensation transpose) baked the pixels but left the source rotation matrix on the
389
+ // output, so on ffmpeg-kit 6 every rotation-tagged portrait clip came out
390
+ // double-rotated (sideways). User rotate/flip and crop below operate on the already-
391
+ // upright autorotated frame, so their math is unchanged.
397
392
  switch vc.rotationCount {
398
393
  case 1: videoFilters.append("transpose=2")
399
394
  case 2:
@@ -460,9 +455,9 @@ public class VideoTrim: RCTEventEmitter, AssetLoaderDelegate, UIDocumentPickerDe
460
455
  }
461
456
  }
462
457
 
463
- // -noautorotate: we handle rotation via explicit transpose filters above,
464
- // so FFmpeg must not auto-rotate or the output will be double-rotated.
465
- cmds.append("-noautorotate")
458
+ // NOTE: intentionally NO -noautorotate. FFmpeg autorotates the input so the source
459
+ // rotation is baked into the pixels and the output carries no stale rotation matrix
460
+ // (otherwise rotation-tagged portrait clips are double-rotated -> sideways on ffmpeg-kit 6).
466
461
  cmds.append(contentsOf: ["-i", inputFile.path])
467
462
  // When enablePreciseTrimming is the only reason for re-encode (no transforms),
468
463
  // videoFilters is empty — skip -vf entirely to avoid FFmpeg error on empty filter.
@@ -648,7 +643,9 @@ public class VideoTrim: RCTEventEmitter, AssetLoaderDelegate, UIDocumentPickerDe
648
643
 
649
644
  let startTime = config["startTime"] as? Double ?? 0
650
645
  let endTime = config["endTime"] as? Double ?? 0
646
+ // -y overwrites any pre-existing output file without prompting (hardening).
651
647
  var cmds = [
648
+ "-y",
652
649
  "-ss",
653
650
  "\(startTime)ms",
654
651
  "-to",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-video-trim",
3
- "version": "8.1.2",
3
+ "version": "8.1.4",
4
4
  "description": "Video trimmer for your React Native app",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",