react-native-video-trim 7.1.1 → 8.1.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 +257 -1
- 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 +38 -16
- package/android/src/main/java/com/videotrim/widgets/VideoTrimmerView.kt +92 -5
- 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 +25 -3
- 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/VideoTrim.mm +160 -1
- package/ios/VideoTrim.swift +632 -39
- package/ios/VideoTrimmerViewController.swift +129 -28
- package/lib/module/NativeVideoTrim.js +52 -0
- package/lib/module/NativeVideoTrim.js.map +1 -1
- package/lib/module/index.js +143 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/NativeVideoTrim.d.ts +161 -0
- package/lib/typescript/src/NativeVideoTrim.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +62 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/NativeVideoTrim.ts +183 -0
- package/src/index.tsx +186 -0
package/README.md
CHANGED
|
@@ -5,6 +5,12 @@
|
|
|
5
5
|
- [API Reference](#api-reference)
|
|
6
6
|
* [showEditor()](#showeditor)
|
|
7
7
|
* [trim()](#trim)
|
|
8
|
+
* [getFrameAt()](#getframeat)
|
|
9
|
+
* [extractAudio()](#extractaudio)
|
|
10
|
+
* [compress()](#compress)
|
|
11
|
+
* [toGif()](#togif)
|
|
12
|
+
* [merge()](#merge)
|
|
13
|
+
* [Utility Functions](#utility-functions)
|
|
8
14
|
* [File Management](#file-management)
|
|
9
15
|
- [Configuration Options](#configuration-options)
|
|
10
16
|
* [Basic Options](#basic-options)
|
|
@@ -12,6 +18,8 @@
|
|
|
12
18
|
* [Behavior Options](#behavior-options)
|
|
13
19
|
- [Platform Setup](#platform-setup)
|
|
14
20
|
- [Advanced Features](#advanced-features)
|
|
21
|
+
* [Mute Audio / Remove Audio](#mute-audio--remove-audio)
|
|
22
|
+
* [Speed Adjustment](#speed-adjustment)
|
|
15
23
|
* [Theming](#theming)
|
|
16
24
|
* [Audio Trimming](#audio-trimming)
|
|
17
25
|
* [Remote Files (HTTPS)](#remote-files-https)
|
|
@@ -43,6 +51,13 @@ A powerful, easy-to-use video and audio trimming library for React Native applic
|
|
|
43
51
|
- **📹 Video & Audio Support** - Trim both video and audio files with waveform visualization
|
|
44
52
|
- **🔄 Flip, Rotate & Crop** - Built-in video transforms with undo/redo support
|
|
45
53
|
- **🎯 Precise Trimming** - Optional frame-accurate cuts via hardware-accelerated re-encoding
|
|
54
|
+
- **🔇 Mute / Remove Audio** - Strip audio track via editor toggle or headless option
|
|
55
|
+
- **⏩ Speed Adjustment** - Change playback speed (0.25x–4x) in editor or headless
|
|
56
|
+
- **🗜️ Video Compression** - Reduce file size with quality presets or custom bitrate/resolution
|
|
57
|
+
- **🖼️ Frame Extraction** - Extract a single frame as JPEG/PNG at any timestamp
|
|
58
|
+
- **🎵 Extract Audio** - Pull the audio track out of a video file
|
|
59
|
+
- **🎞️ GIF Conversion** - Convert a video segment to an animated GIF
|
|
60
|
+
- **🔗 Video Merge** - Concatenate multiple clips into a single file (headless)
|
|
46
61
|
- **🌐 Local & Remote Files** - Support for local storage and HTTPS URLs
|
|
47
62
|
- **💾 Multiple Save Options** - Photos, Documents, or Share to other apps
|
|
48
63
|
- **✅ File Validation** - Built-in validation for media files
|
|
@@ -57,6 +72,13 @@ A powerful, easy-to-use video and audio trimming library for React Native applic
|
|
|
57
72
|
| **Trimming** | Video/audio trimming with visual timeline controls and audio waveform |
|
|
58
73
|
| **Transforms** | Horizontal flip, 90° rotation, and freeform crop with undo/redo |
|
|
59
74
|
| **Precise Trimming** | Frame-accurate cuts using hardware re-encoding (opt-in) |
|
|
75
|
+
| **Mute Audio** | Strip audio track from output — editor toggle + headless option |
|
|
76
|
+
| **Speed Control** | 0.25x–4x playback speed — editor selector + headless option |
|
|
77
|
+
| **Compression** | Reduce file size via quality presets or custom bitrate/resolution |
|
|
78
|
+
| **Frame Extraction** | Extract a single frame as JPEG/PNG at a given timestamp |
|
|
79
|
+
| **Audio Extraction** | Extract the audio track from a video into a separate file |
|
|
80
|
+
| **GIF Conversion** | Convert a video segment to an animated GIF with palette optimization |
|
|
81
|
+
| **Video Merge** | Concatenate multiple clips into one file (headless API) |
|
|
60
82
|
| **Validation** | Check if files are valid video/audio before processing |
|
|
61
83
|
| **Save Options** | Photos, Documents, Share sheet integration |
|
|
62
84
|
| **File Management** | Complete file lifecycle management |
|
|
@@ -125,6 +147,7 @@ Create `android/app/src/main/res/xml/file_paths.xml`:
|
|
|
125
147
|
<?xml version="1.0" encoding="utf-8"?>
|
|
126
148
|
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
|
127
149
|
<files-path name="internal_files" path="." />
|
|
150
|
+
<cache-path name="cache_files" path="." />
|
|
128
151
|
<external-path name="external_files" path="." />
|
|
129
152
|
</paths>
|
|
130
153
|
```
|
|
@@ -227,6 +250,184 @@ const outputPath = await trim('/path/to/video.mp4', {
|
|
|
227
250
|
});
|
|
228
251
|
```
|
|
229
252
|
|
|
253
|
+
### getFrameAt()
|
|
254
|
+
|
|
255
|
+
Extract a single video frame as a JPEG or PNG image.
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
getFrameAt(url: string, options?: Partial<FrameExtractionOptions>): Promise<FrameResult>
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**Options:**
|
|
262
|
+
|
|
263
|
+
| Option | Type | Default | Description |
|
|
264
|
+
|--------|------|---------|-------------|
|
|
265
|
+
| `time` | `number` | `0` | Timestamp in milliseconds |
|
|
266
|
+
| `format` | `string` | `"jpeg"` | Output format: `"jpeg"` or `"png"` |
|
|
267
|
+
| `quality` | `number` | `80` | JPEG quality (0–100). Ignored for PNG |
|
|
268
|
+
| `maxWidth` | `number` | `-1` | Max width in pixels (`-1` for original) |
|
|
269
|
+
| `maxHeight` | `number` | `-1` | Max height in pixels (`-1` for original) |
|
|
270
|
+
|
|
271
|
+
**Example:**
|
|
272
|
+
```javascript
|
|
273
|
+
import { getFrameAt } from 'react-native-video-trim';
|
|
274
|
+
|
|
275
|
+
const { outputPath } = await getFrameAt('/path/to/video.mp4', {
|
|
276
|
+
time: 5000, // 5 seconds
|
|
277
|
+
format: 'jpeg',
|
|
278
|
+
quality: 90,
|
|
279
|
+
maxWidth: 640,
|
|
280
|
+
});
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### extractAudio()
|
|
284
|
+
|
|
285
|
+
Extract the audio track from a video file into a separate audio file.
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
extractAudio(url: string, options?: Partial<ExtractAudioOptions>): Promise<ExtractAudioResult>
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
**Options:**
|
|
292
|
+
|
|
293
|
+
| Option | Type | Default | Description |
|
|
294
|
+
|--------|------|---------|-------------|
|
|
295
|
+
| `outputExt` | `string` | `"m4a"` | Output format: `"m4a"`, `"wav"`, `"mp3"` (requires FFmpegKit with libmp3lame), etc. |
|
|
296
|
+
|
|
297
|
+
**Returns:** `{ outputPath: string, duration: number }` (duration in milliseconds)
|
|
298
|
+
|
|
299
|
+
**Example:**
|
|
300
|
+
```javascript
|
|
301
|
+
import { extractAudio } from 'react-native-video-trim';
|
|
302
|
+
|
|
303
|
+
const { outputPath, duration } = await extractAudio('/path/to/video.mp4', {
|
|
304
|
+
outputExt: 'm4a',
|
|
305
|
+
});
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### compress()
|
|
309
|
+
|
|
310
|
+
Compress a video file to reduce its size.
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
compress(url: string, options?: Partial<CompressOptions>): Promise<CompressResult>
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
**Options:**
|
|
317
|
+
|
|
318
|
+
| Option | Type | Default | Description |
|
|
319
|
+
|--------|------|---------|-------------|
|
|
320
|
+
| `quality` | `string` | `"medium"` | Preset: `"low"`, `"medium"`, or `"high"` |
|
|
321
|
+
| `bitrate` | `number` | `-1` | Explicit bitrate in bps. Overrides `quality` when set |
|
|
322
|
+
| `width` | `number` | `-1` | Target width (`-1` to keep original) |
|
|
323
|
+
| `height` | `number` | `-1` | Target height (`-1` to keep original) |
|
|
324
|
+
| `frameRate` | `number` | `-1` | Target frame rate (`-1` to keep original) |
|
|
325
|
+
| `outputExt` | `string` | `"mp4"` | Output file extension |
|
|
326
|
+
| `removeAudio` | `boolean` | `false` | Strip audio from the output |
|
|
327
|
+
|
|
328
|
+
**Example:**
|
|
329
|
+
```javascript
|
|
330
|
+
import { compress } from 'react-native-video-trim';
|
|
331
|
+
|
|
332
|
+
// Quality preset
|
|
333
|
+
const { outputPath } = await compress('/path/to/video.mp4', {
|
|
334
|
+
quality: 'medium',
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// Custom settings
|
|
338
|
+
const { outputPath } = await compress('/path/to/video.mp4', {
|
|
339
|
+
width: 720,
|
|
340
|
+
bitrate: 2_000_000,
|
|
341
|
+
removeAudio: true,
|
|
342
|
+
});
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### toGif()
|
|
346
|
+
|
|
347
|
+
Convert a video segment to an animated GIF using FFmpeg's palette-based encoding for good quality.
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
toGif(url: string, options?: Partial<GifOptions>): Promise<GifResult>
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
**Options:**
|
|
354
|
+
|
|
355
|
+
| Option | Type | Default | Description |
|
|
356
|
+
|--------|------|---------|-------------|
|
|
357
|
+
| `startTime` | `number` | `0` | Start time in milliseconds |
|
|
358
|
+
| `endTime` | `number` | `-1` | End time in milliseconds (`-1` for end of video) |
|
|
359
|
+
| `fps` | `number` | `10` | Frame rate of the GIF |
|
|
360
|
+
| `width` | `number` | `-1` | Width in pixels (`-1` for original). Height auto-scales |
|
|
361
|
+
|
|
362
|
+
**Example:**
|
|
363
|
+
```javascript
|
|
364
|
+
import { toGif } from 'react-native-video-trim';
|
|
365
|
+
|
|
366
|
+
const { outputPath } = await toGif('/path/to/video.mp4', {
|
|
367
|
+
startTime: 2000,
|
|
368
|
+
endTime: 7000,
|
|
369
|
+
fps: 15,
|
|
370
|
+
width: 320,
|
|
371
|
+
});
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### merge()
|
|
375
|
+
|
|
376
|
+
Concatenate multiple media files into a single file. Headless only (no editor UI).
|
|
377
|
+
|
|
378
|
+
```typescript
|
|
379
|
+
merge(urls: string[], options?: Partial<MergeOptions>): Promise<MergeResult>
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**Options:**
|
|
383
|
+
|
|
384
|
+
| Option | Type | Default | Description |
|
|
385
|
+
|--------|------|---------|-------------|
|
|
386
|
+
| `outputExt` | `string` | `"mp4"` | Output file extension |
|
|
387
|
+
|
|
388
|
+
**Returns:** `{ outputPath: string, duration: number }` (duration in milliseconds)
|
|
389
|
+
|
|
390
|
+
> **Note:** Merge uses FFmpeg's concat filter with hardware-accelerated re-encoding (h264_videotoolbox on iOS, h264_mediacodec on Android). Input clips can have different codecs, resolutions, or frame rates — each input is automatically scaled, padded (letterboxed/pillarboxed), and frame-rate-normalized to match the first clip's dimensions and fps (capped at 30 fps). The output bitrate matches the highest-quality input to preserve quality.
|
|
391
|
+
>
|
|
392
|
+
> **Limitation:** Only **local file paths** are supported. Remote URLs are not supported because the default FFmpegKit build does not include OpenSSL.
|
|
393
|
+
|
|
394
|
+
**Example:**
|
|
395
|
+
```javascript
|
|
396
|
+
import { merge } from 'react-native-video-trim';
|
|
397
|
+
|
|
398
|
+
const { outputPath, duration } = await merge([
|
|
399
|
+
'/path/to/clip1.mp4',
|
|
400
|
+
'/path/to/clip2.mp4',
|
|
401
|
+
'/path/to/clip3.mp4',
|
|
402
|
+
]);
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### Utility Functions
|
|
406
|
+
|
|
407
|
+
Standalone functions for saving, sharing, or exporting any output file. These work with output from any API (`compress`, `toGif`, `merge`, `trim`, etc.).
|
|
408
|
+
|
|
409
|
+
| Method | Description | Returns |
|
|
410
|
+
|--------|-------------|---------|
|
|
411
|
+
| `saveToPhoto(filePath)` | Save a file to the device's photo library (requires permission) | `Promise<SaveToPhotoResult>` |
|
|
412
|
+
| `saveToDocuments(filePath)` | Open the system document picker to save a file | `Promise<SaveToDocumentsResult>` |
|
|
413
|
+
| `share(filePath)` | Open the system share sheet for a file | `Promise<ShareResult>` |
|
|
414
|
+
|
|
415
|
+
**Examples:**
|
|
416
|
+
```javascript
|
|
417
|
+
import { compress, saveToPhoto, share, deleteFile } from 'react-native-video-trim';
|
|
418
|
+
|
|
419
|
+
// Compress then save to photo library
|
|
420
|
+
const { outputPath } = await compress('/path/to/video.mp4', { quality: 'medium' });
|
|
421
|
+
await saveToPhoto(outputPath);
|
|
422
|
+
await deleteFile(outputPath);
|
|
423
|
+
|
|
424
|
+
// Merge then share
|
|
425
|
+
const { outputPath: merged } = await merge(['/clip1.mp4', '/clip2.mp4']);
|
|
426
|
+
await share(merged);
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
> **Note:** Headless API outputs (`getFrameAt`, `extractAudio`, `compress`, `toGif`, `merge`) are written to the **cache directory**, which the OS may purge under storage pressure when your app is not running. Files from `showEditor` and `trim` are written to the persistent documents directory. For all outputs, call `deleteFile(outputPath)` when you are done with the file, or use `cleanFiles()` periodically to free space.
|
|
430
|
+
|
|
230
431
|
### File Management
|
|
231
432
|
|
|
232
433
|
| Method | Description | Returns |
|
|
@@ -265,6 +466,8 @@ All configuration options are optional. Here are the most commonly used ones:
|
|
|
265
466
|
| `minDuration` | `number` | `1000` | Minimum duration in milliseconds |
|
|
266
467
|
| `autoplay` | `boolean` | `false` | Auto-play media on load |
|
|
267
468
|
| `jumpToPositionOnLoad` | `number` | - | Initial position in milliseconds |
|
|
469
|
+
| `removeAudio` | `boolean` | `false` | Strip the audio track from the output (see [Mute Audio](#mute-audio--remove-audio)) |
|
|
470
|
+
| `speed` | `number` | `1.0` | Playback speed multiplier (0.25–4.0). Forces re-encoding when ≠ 1.0 (see [Speed Adjustment](#speed-adjustment)) |
|
|
268
471
|
|
|
269
472
|
### Save & Share Options
|
|
270
473
|
|
|
@@ -285,6 +488,7 @@ All configuration options are optional. Here are the most commonly used ones:
|
|
|
285
488
|
| Option | Type | Default | Description |
|
|
286
489
|
|--------|------|---------|-------------|
|
|
287
490
|
| `theme` | `'dark' \| 'light'` | `'dark'` | Editor color theme (see [Theming](#theming)) |
|
|
491
|
+
| `durationFormat` | `'mm:ss' \| 'mm:ss.SS' \| 'mm:ss.SSS' \| 'hh:mm:ss' \| 'hh:mm:ss.SSS'` | `'mm:ss.SSS'` | Format of the start / current / end time labels in the editor. Use `'mm:ss'` to hide milliseconds. Unknown values fall back to the default. Only affects on-screen labels; event payloads still report raw milliseconds. |
|
|
288
492
|
| `cancelButtonText` | `string` | `"Cancel"` | Cancel button text |
|
|
289
493
|
| `saveButtonText` | `string` | `"Save"` | Save button text |
|
|
290
494
|
| `trimmingText` | `string` | `"Trimming video..."` | Progress dialog text |
|
|
@@ -381,6 +585,10 @@ showEditor(videoPath, {
|
|
|
381
585
|
openShareSheetOnFinish: true,
|
|
382
586
|
removeAfterSavedToPhoto: true,
|
|
383
587
|
|
|
588
|
+
// Audio & speed
|
|
589
|
+
removeAudio: false,
|
|
590
|
+
speed: 1.0,
|
|
591
|
+
|
|
384
592
|
// UI customization
|
|
385
593
|
theme: 'light',
|
|
386
594
|
headerText: "Trim Your Video",
|
|
@@ -414,6 +622,52 @@ buildscript {
|
|
|
414
622
|
|
|
415
623
|
## Advanced Features
|
|
416
624
|
|
|
625
|
+
### Mute Audio / Remove Audio
|
|
626
|
+
|
|
627
|
+
Strip the audio track from the output. Available in both the editor UI and headless APIs.
|
|
628
|
+
|
|
629
|
+
**Editor UI:** A mute toggle button appears in the toolbar (speaker icon). Tap to toggle audio on/off. The mute state carries over to the exported file.
|
|
630
|
+
|
|
631
|
+
**Headless / Config:** Set `removeAudio: true` on `showEditor()`, `trim()`, or `compress()`.
|
|
632
|
+
|
|
633
|
+
```javascript
|
|
634
|
+
// Editor with audio muted by default
|
|
635
|
+
showEditor(videoUrl, {
|
|
636
|
+
removeAudio: true,
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
// Headless trim without audio
|
|
640
|
+
const result = await trim(videoUrl, {
|
|
641
|
+
startTime: 0,
|
|
642
|
+
endTime: 10000,
|
|
643
|
+
removeAudio: true,
|
|
644
|
+
});
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
### Speed Adjustment
|
|
648
|
+
|
|
649
|
+
Change the playback speed of the output (0.25x to 4x). Available in both the editor UI and headless APIs.
|
|
650
|
+
|
|
651
|
+
**Editor UI:** A speed button appears in the toolbar showing the current speed (e.g. "1x"). Tap to open a native speed menu — `UIMenu` on iOS 14+ (with `UIAlertController` fallback on older versions), `PopupMenu` on Android. Choose from: 0.25x, 0.5x, 1x, 1.5x, 2x, 3x, 4x. The preview updates in real time, and the selected speed is applied during export.
|
|
652
|
+
|
|
653
|
+
**Headless / Config:** Set the `speed` option. When speed ≠ 1.0, re-encoding is automatically forced (video via `setpts` filter, audio via `atempo` chain).
|
|
654
|
+
|
|
655
|
+
```javascript
|
|
656
|
+
// Editor starting at 2x speed
|
|
657
|
+
showEditor(videoUrl, {
|
|
658
|
+
speed: 2.0,
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
// Headless trim at half speed
|
|
662
|
+
const result = await trim(videoUrl, {
|
|
663
|
+
startTime: 0,
|
|
664
|
+
endTime: 30000,
|
|
665
|
+
speed: 0.5,
|
|
666
|
+
});
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
> **Note:** Speed adjustment forces re-encoding regardless of the `enablePreciseTrimming` flag, since FFmpeg filters are required to alter the tempo.
|
|
670
|
+
|
|
417
671
|
### Theming
|
|
418
672
|
|
|
419
673
|
The editor supports dark and light themes. Set the `theme` option to switch between them:
|
|
@@ -704,7 +958,9 @@ export default function VideoTrimmer() {
|
|
|
704
958
|
|
|
705
959
|
- Use `trim()` for batch processing without UI
|
|
706
960
|
- Clean up generated files regularly with `cleanFiles()`
|
|
707
|
-
-
|
|
961
|
+
- Use `compress()` to reduce large videos before upload
|
|
962
|
+
- `merge()` always re-encodes via the concat filter — expect longer processing for large files or many clips
|
|
963
|
+
- Speed adjustment, compression, and merge force re-encoding — expect longer processing for large files
|
|
708
964
|
|
|
709
965
|
## Credits
|
|
710
966
|
|