rn-av-binder
v1.0.1
Published
On-device image + audio → MP4 composition for React Native. AVFoundation (iOS) and MediaCodec/MediaMuxer (Android). New Architecture compatible.
Downloads
292
Maintainers
Readme
rn-av-binder
On-device image + audio → MP4 composition for React Native — no FFmpeg, no third-party media libraries. Uses AVFoundation on iOS and MediaCodec / MediaMuxer / MediaExtractor on Android. Built as an Expo Module for the New Architecture (Fabric + JSI).
Motivation
ffmpeg-kit was retired in April 2025, leaving React Native apps without a maintained, fully
on-device way to turn a still image plus an audio track into a playable video. rn-av-binder
is the pure-native replacement for the common "audiogram" use case: it encodes a single static
image as a 2-frame H.264 video and muxes the original audio in unmodified (passthrough, no
re-encode), so the output duration matches the source audio and the operation is fast and
lossless on the audio side.
Installation
yarn add rn-av-binder
npx expo run:ios # or eas buildAdd the plugin to your app.json, then rebuild the native project:
{
"expo": {
"plugins": ["rn-av-binder"]
}
}Native linking itself is automatic via Expo Modules autolinking; the plugin entry exists so the package is registered in your config and to allow future native config tweaks.
API
import { createVideo } from "rn-av-binder";
createVideo(options, onProgress?): Promise<CreateVideoResult>;CreateVideoOptions
| Field | Type | Required | Description |
| ----------- | -------- | -------- | ------------------------------------------------------------------ |
| imageUri | string | yes | file:// URI to a JPEG or PNG image |
| audioUri | string | yes | file:// URI to an AAC, MP3, or M4A audio file |
| outputUri | string | no | file:// URI for the MP4. Defaults to <cacheDir>/image_audio_<timestamp>.mp4 |
CreateVideoResult
| Field | Type | Description |
| ------------ | -------- | -------------------------------------- |
| uri | string | file:// URI of the created MP4 |
| durationMs | number | Duration of the output video, in ms |
ProgressEvent
| Field | Type | Description |
| ---------- | -------- | ------------------------------------ |
| progress | number | Encoding progress from 0.0 to 1.0 |
The optional onProgress callback receives { progress } and fires at 0.0, 0.5, and 1.0.
Usage
import * as ImagePicker from "expo-image-picker";
import * as DocumentPicker from "expo-document-picker";
import { createVideo } from "rn-av-binder";
async function makeVideo() {
const image = await ImagePicker.launchImageLibraryAsync({ mediaTypes: "Images" });
const audio = await DocumentPicker.getDocumentAsync({ type: "audio/*" });
if (image.canceled || audio.canceled) return;
const result = await createVideo(
{ imageUri: image.assets[0].uri, audioUri: audio.assets[0].uri },
({ progress }) => console.log(`${Math.round(progress * 100)}%`),
);
console.log(result.uri, `${(result.durationMs / 1000).toFixed(1)}s`);
}Platform requirements
- iOS 15.0+
- Android API 26+ (minSdkVersion 26)
- Expo SDK 52+
- React Native 0.76+
- New Architecture required (
newArchEnabled: true)
Running the example app
The repo includes a standalone example under example/ that installs the package via
"rn-av-binder": "file:.." — exactly what a consumer does after yarn add.
# from the package root
yarn install
yarn build
cd example
yarn install
npx expo run:ios # requires Xcode + iOS 15 simulator/device
npx expo run:android # requires Android Studio + API 26 emulator/devicePick an image and an audio file, tap Create Video, watch the progress bar, and the encoded MP4 plays inline on completion.
Publishing checklist
yarn buildcompletes with no TypeScript errors;build/index.jsandbuild/index.d.tsexist.npm pack --dry-runincludesbuild/,ios/,android/,expo-module.config.json,rn-av-binder.podspec,app.plugin.js— and excludesexample/.npm login(authenticate).npm publish(runsprepare→yarn buildautomatically).
Known limitations
- Single static image only — no slideshow, no transitions.
- No video-to-video processing; input must be one image + one audio file.
- Audio is passed through unchanged; the container must support the source audio codec (MP4 supports AAC/M4A; some exotic codecs may need transcoding, which this library does not do).
- On the iOS Simulator, camera-roll access can be limited — a physical device may be required for picking images.
