react-native-video-trim 7.1.0 → 7.1.1
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 +31 -5
- package/android/src/main/java/com/videotrim/utils/VideoTrimmerUtil.kt +1 -1
- package/android/src/main/java/com/videotrim/widgets/AudioWaveformView.kt +92 -0
- package/android/src/main/java/com/videotrim/widgets/VideoTrimmerView.kt +502 -8
- package/ios/AudioWaveformView.swift +75 -0
- package/ios/VideoTrim.mm +25 -0
- package/ios/VideoTrimmer.swift +300 -0
- package/ios/VideoTrimmerViewController.swift +33 -1
- package/lib/module/NativeVideoTrim.js.map +1 -1
- package/lib/module/index.js +13 -2
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/NativeVideoTrim.d.ts +10 -0
- package/lib/typescript/src/NativeVideoTrim.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +3 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/NativeVideoTrim.ts +10 -0
- package/src/index.tsx +28 -2
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ A powerful, easy-to-use video and audio trimming library for React Native applic
|
|
|
40
40
|
|
|
41
41
|
### ✨ Key Features
|
|
42
42
|
|
|
43
|
-
- **📹 Video & Audio Support** - Trim both video and audio files
|
|
43
|
+
- **📹 Video & Audio Support** - Trim both video and audio files with waveform visualization
|
|
44
44
|
- **🔄 Flip, Rotate & Crop** - Built-in video transforms with undo/redo support
|
|
45
45
|
- **🎯 Precise Trimming** - Optional frame-accurate cuts via hardware-accelerated re-encoding
|
|
46
46
|
- **🌐 Local & Remote Files** - Support for local storage and HTTPS URLs
|
|
@@ -54,7 +54,7 @@ A powerful, easy-to-use video and audio trimming library for React Native applic
|
|
|
54
54
|
|
|
55
55
|
| Feature | Description |
|
|
56
56
|
|---------|-------------|
|
|
57
|
-
| **Trimming** | Video/audio trimming with visual timeline controls |
|
|
57
|
+
| **Trimming** | Video/audio trimming with visual timeline controls and audio waveform |
|
|
58
58
|
| **Transforms** | Horizontal flip, 90° rotation, and freeform crop with undo/redo |
|
|
59
59
|
| **Precise Trimming** | Frame-accurate cuts using hardware re-encoding (opt-in) |
|
|
60
60
|
| **Validation** | Check if files are valid video/audio before processing |
|
|
@@ -295,6 +295,18 @@ All configuration options are optional. Here are the most commonly used ones:
|
|
|
295
295
|
| `handleIconColor` | `string` | - | Trimmer left/right handles color (defaults to black in light theme, white in dark theme) |
|
|
296
296
|
| `fullScreenModalIOS` | `boolean` | `false` | Use fullscreen modal on iOS |
|
|
297
297
|
|
|
298
|
+
### Audio Waveform Options
|
|
299
|
+
|
|
300
|
+
These options only apply when `type: 'audio'`. The waveform replaces the thumbnail track with a bar visualization of the audio amplitude.
|
|
301
|
+
|
|
302
|
+
| Option | Type | Default | Description |
|
|
303
|
+
|--------|------|---------|-------------|
|
|
304
|
+
| `waveformColor` | `string` | `"white"` | Fill color of the waveform bars |
|
|
305
|
+
| `waveformBackgroundColor` | `string` | `"#3478F6"` | Background color behind the bars |
|
|
306
|
+
| `waveformBarWidth` | `number` | `3` | Width of each bar in dp/pt |
|
|
307
|
+
| `waveformBarGap` | `number` | `2` | Gap between bars in dp/pt |
|
|
308
|
+
| `waveformBarCornerRadius` | `number` | `1.5` | Corner radius of each bar in dp/pt |
|
|
309
|
+
|
|
298
310
|
### Dialog Options
|
|
299
311
|
|
|
300
312
|
<details>
|
|
@@ -433,11 +445,11 @@ The `headerTextColor` and `handleIconColor` options automatically adapt to the a
|
|
|
433
445
|
### Audio Trimming
|
|
434
446
|
|
|
435
447
|
<div align="center">
|
|
436
|
-
<img src="images/audio_android.
|
|
437
|
-
<img src="images/audio_ios.
|
|
448
|
+
<img src="images/audio_android.png" width="200" />
|
|
449
|
+
<img src="images/audio_ios.png" width="200" />
|
|
438
450
|
</div>
|
|
439
451
|
|
|
440
|
-
For audio-only trimming, specify the media type and output format
|
|
452
|
+
For audio-only trimming, specify the media type and output format. The editor automatically displays an audio waveform visualization in place of the thumbnail track. The waveform updates on zoom for higher resolution.
|
|
441
453
|
|
|
442
454
|
```javascript
|
|
443
455
|
showEditor(audioUrl, {
|
|
@@ -447,6 +459,20 @@ showEditor(audioUrl, {
|
|
|
447
459
|
});
|
|
448
460
|
```
|
|
449
461
|
|
|
462
|
+
Customize the waveform appearance:
|
|
463
|
+
|
|
464
|
+
```javascript
|
|
465
|
+
showEditor(audioUrl, {
|
|
466
|
+
type: 'audio',
|
|
467
|
+
outputExt: 'mp3',
|
|
468
|
+
waveformColor: '#FFFFFF',
|
|
469
|
+
waveformBackgroundColor: '#3478F6',
|
|
470
|
+
waveformBarWidth: 3,
|
|
471
|
+
waveformBarGap: 2,
|
|
472
|
+
waveformBarCornerRadius: 1.5,
|
|
473
|
+
});
|
|
474
|
+
```
|
|
475
|
+
|
|
450
476
|
### Remote Files (HTTPS)
|
|
451
477
|
|
|
452
478
|
To trim remote files, you need the HTTPS-enabled version of FFmpeg:
|
|
@@ -204,7 +204,7 @@ object VideoTrimmerUtil {
|
|
|
204
204
|
endPosition: Long,
|
|
205
205
|
callback: SingleCallback<Bitmap, Int>
|
|
206
206
|
) {
|
|
207
|
-
BackgroundExecutor.execute(object : BackgroundExecutor.Task("", 0L, "") {
|
|
207
|
+
BackgroundExecutor.execute(object : BackgroundExecutor.Task("initial_thumbs", 0L, "") {
|
|
208
208
|
override fun execute() {
|
|
209
209
|
try {
|
|
210
210
|
val interval = (endPosition - startPosition) / (totalThumbsCount - 1)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
package com.videotrim.widgets
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.graphics.Canvas
|
|
5
|
+
import android.graphics.Color
|
|
6
|
+
import android.graphics.Paint
|
|
7
|
+
import android.graphics.RectF
|
|
8
|
+
import android.util.AttributeSet
|
|
9
|
+
import android.view.View
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Custom View that draws an audio waveform as a row of vertical rounded-rect bars.
|
|
13
|
+
*
|
|
14
|
+
* Each bar's height is driven by a normalized amplitude value in [0, 1].
|
|
15
|
+
* The view recalculates bar count from its own width and maps the amplitudes
|
|
16
|
+
* array proportionally, so it works correctly regardless of whether the
|
|
17
|
+
* amplitudes array has more or fewer entries than the visible bar count.
|
|
18
|
+
*
|
|
19
|
+
* The background color (set via [View.setBackgroundColor]) provides the
|
|
20
|
+
* waveform track color; the bars are drawn on top with [barColor].
|
|
21
|
+
*/
|
|
22
|
+
class AudioWaveformView @JvmOverloads constructor(
|
|
23
|
+
context: Context,
|
|
24
|
+
attrs: AttributeSet? = null,
|
|
25
|
+
defStyleAttr: Int = 0
|
|
26
|
+
) : View(context, attrs, defStyleAttr) {
|
|
27
|
+
|
|
28
|
+
var amplitudes: FloatArray = FloatArray(0)
|
|
29
|
+
private set
|
|
30
|
+
private val barPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
|
31
|
+
color = Color.WHITE
|
|
32
|
+
style = Paint.Style.FILL
|
|
33
|
+
}
|
|
34
|
+
private val barRect = RectF()
|
|
35
|
+
|
|
36
|
+
var barColor: Int
|
|
37
|
+
get() = barPaint.color
|
|
38
|
+
set(value) {
|
|
39
|
+
barPaint.color = value
|
|
40
|
+
invalidate()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
var barWidthPx: Float = 0f
|
|
44
|
+
set(value) {
|
|
45
|
+
field = value
|
|
46
|
+
invalidate()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
var barGapPx: Float = 0f
|
|
50
|
+
set(value) {
|
|
51
|
+
field = value
|
|
52
|
+
invalidate()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
var barCornerRadiusPx: Float = 0f
|
|
56
|
+
set(value) {
|
|
57
|
+
field = value
|
|
58
|
+
invalidate()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
fun setAmplitudes(data: FloatArray) {
|
|
62
|
+
amplitudes = data
|
|
63
|
+
invalidate()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
override fun onDraw(canvas: Canvas) {
|
|
67
|
+
super.onDraw(canvas)
|
|
68
|
+
if (amplitudes.isEmpty()) return
|
|
69
|
+
|
|
70
|
+
val totalHeight = height.toFloat()
|
|
71
|
+
val step = barWidthPx + barGapPx
|
|
72
|
+
if (step <= 0f) return
|
|
73
|
+
val barCount = (width.toFloat() / step).toInt()
|
|
74
|
+
if (barCount <= 0) return
|
|
75
|
+
|
|
76
|
+
// Keep bars from touching the container edges
|
|
77
|
+
val verticalPadding = barWidthPx * 1.5f
|
|
78
|
+
val drawableHeight = totalHeight - verticalPadding * 2f
|
|
79
|
+
if (drawableHeight <= 0f) return
|
|
80
|
+
val minBarHeight = barWidthPx
|
|
81
|
+
|
|
82
|
+
for (i in 0 until barCount) {
|
|
83
|
+
val ampIndex = (i * amplitudes.size / barCount).coerceIn(0, amplitudes.size - 1)
|
|
84
|
+
val amp = amplitudes[ampIndex]
|
|
85
|
+
val barHeight = (amp * drawableHeight).coerceAtLeast(minBarHeight)
|
|
86
|
+
val x = i * step
|
|
87
|
+
val y = verticalPadding + (drawableHeight - barHeight) / 2f
|
|
88
|
+
barRect.set(x, y, x + barWidthPx, y + barHeight)
|
|
89
|
+
canvas.drawRoundRect(barRect, barCornerRadiusPx, barCornerRadiusPx, barPaint)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|