react-native-nitro-video-editor
v0.1.1
Published
Fast native photo and video editing for React Native powered by Nitro Modules
Downloads
253
Maintainers
Readme
react-native-nitro-video-editor
Fast native photo and video editing for React Native, powered by Nitro Modules.
The library is designed for social posting flows: pick from the native gallery, preview quickly, trim or style media, prepare the output only when needed, and stream uploads from native storage without copying large files through JavaScript.
Features
- Native photo and video pickers
- Cached native gallery flow for fast video selection
- Timeline thumbnail generation for trim UIs
- Video trim, playback speed, mute, external audio, filters, and upload preparation
- Image crop, filters, drawing strokes, text/emoji overlays, and export
- Native streaming upload with progress and cancellation
- Source reuse for unchanged videos
- Hardware-assisted native rendering for edits that require encoding
- Typed Nitro HybridObject API
Why use this instead of a heavy editor SDK
This package focuses on the media pipeline rather than forcing a complete editor product into your app. Your React Native UI can match your app, while native code handles the expensive media work.
- No large media buffers in the JS heap
- No mandatory "export screen" before post
- Apps can combine preparation and upload behind one Post button
- Native sessions keep trim/filter/crop state close to the platform media APIs
- The same low-level primitives can power custom Instagram-style, feed, story, or profile media flows
Platform support
| Platform | Status | | --- | --- | | iOS 15.1+ | PhotoKit gallery, AVFoundation editing, Core Image filters, native upload | | Android 6.0+ | Native picker, Media3 Transformer pipeline, native upload |
Installation
npm install react-native-nitro-video-editor react-native-nitro-modules
cd ios && pod installThis package requires react-native-nitro-modules because all native entry points are Nitro HybridObjects.
Pick a video
import { MediaEditor } from 'react-native-nitro-video-editor'
const asset = await MediaEditor.pickVideo({
presentation: 'native-gallery',
preferCurrentRepresentation: true,
})
if (asset === undefined) {
return
}
console.log(asset.uri, asset.durationMs, asset.width, asset.height)preferCurrentRepresentation asks the platform for the current Photos representation when possible. On iOS, this avoids an unnecessary picker-side transcode for compatible assets.
Build a timeline
const thumbnails = await asset.createThumbnails({
startMs: 0,
endMs: asset.durationMs,
count: 12,
maxDimensionPx: 180,
})Thumbnails are generated natively and returned as temporary local file URIs.
Prepare a video for upload
const edit = asset.createEditSession()
edit.setTrimRange({ startMs: 1_500, endMs: 8_000 })
edit.setFilter('none')
edit.setAudio({
muteSourceAudio: false,
externalAudioVolume: 0.85,
loopExternalAudio: true,
})
const task = edit.prepareForUpload({
preset: 'original',
fileType: 'mp4',
optimizeForNetworkUse: true,
playbackSpeed: 1,
})
const subscription = task.addOnProgressListener(progress => {
console.log(Math.round(progress * 100))
})
try {
const result = await task.start()
console.log(result.uri, result.byteSize, result.outputStrategy)
} finally {
subscription.remove()
}playbackSpeed accepts values from 0.5 through 2. A value of 1 preserves the source speed. When the selected video is unchanged, the task can return the source file immediately. Trim-only or mute-only paths can avoid full video encoding when the platform can safely do so. Speed changes, filters, and resolution changes require rendering.
Edit an image
const image = await MediaEditor.pickImage()
if (image === undefined) {
return
}
const edit = image.createEditSession()
edit.setCrop({ x: 0.1, y: 0, width: 0.8, height: 1 })
edit.setFilter('chrome')
edit.setOverlays([
{
id: 'caption-1',
kind: 'text',
content: 'TownCup',
x: 0.5,
y: 0.12,
scale: 1,
rotationDeg: 0,
color: '#FFFFFF',
fontSize: 32,
},
])
const [full, thumbnail] = await Promise.all([
edit.exportImage({ format: 'jpeg', quality: 0.9, maxDimensionPx: 2560 }),
edit.exportImage({ format: 'jpeg', quality: 0.82, maxDimensionPx: 1200 }),
])
console.log(full.uri, thumbnail.uri)Crop coordinates and overlay positions are normalized, so your UI can render at any screen size and export at native resolution.
Upload a prepared file
const upload = MediaEditor.createFileUpload(full.uri, {
url: presignedUrl,
method: 'put',
headers: {
'Content-Type': 'image/jpeg',
},
})
const subscription = upload.addOnProgressListener(progress => {
console.log(Math.round(progress * 100))
})
try {
const result = await upload.start()
console.log(result.statusCode, result.byteSize)
} finally {
subscription.remove()
}The upload task streams directly from native storage. This keeps memory stable for large videos and high-resolution images.
API architecture
MediaEditoris the autolinked root HybridObject.ImageAssetandVideoAssetown native media references.ImageEditSessionowns crop, filter, drawing, and overlay state.VideoEditSessionowns trim, filter, mute, and external audio state.VideoExportTaskandFileUploadTaskmodel progress, cancellation, and disposal.- Options and results are small typed structs.
Development
npm install
npm run specs
npm run typecheck
npm run example:typecheckFor the full implementation notes, see the repository docs:
docs/ARCHITECTURE.mddocs/UPLOAD_PIPELINE.mddocs/NITRO_IMPLEMENTATION_GUIDE.mddocs/ROADMAP.md
License
MIT
