npm package: @louiscapelle/react-native-video-editing
Description: A React Native module for mixing audio with video, perfect for adding background music to videos while preserving original audio. Works on iOS and Android. Built with Expo modules.
Author: Louis CAPELLE
Latest version: 1.0.2

# react-native-video-editing

A powerful React Native module for mixing audio with video. Perfect for adding background music to videos while preserving the original audio track. Built with Expo modules for seamless integration.

## Features

- 🎵 **Mix audio with video** - Add background music while keeping original audio
- 📥 **Remote audio download** - Automatically downloads audio from URLs
- ⏱️ **Smart audio trimming** - Automatically trims audio to match video duration
- 🎬 **High-quality output** - Exports mixed videos in MP4 format
- 🧹 **Auto cleanup** - Automatically removes temporary files
- 🔄 **Cross-platform** - Currently supports iOS (Android coming soon)
- 📦 **Expo compatible** - Built with Expo modules for easy autolinking

## Installation

### For Expo managed projects

```bash
npx expo install @louiscapelle/react-native-video-editing
```

### For bare React Native projects

```bash
npm install @louiscapelle/react-native-video-editing
# or
yarn add @louiscapelle/react-native-video-editing
```

Then run:

```bash
npx pod-install
```

## Usage

```typescript
import ReactNativeVideoEditing from '@louiscapelle/react-native-video-editing';
import * as ImagePicker from 'expo-image-picker';

// Pick a video
const pickVideo = async () => {
  const result = await ImagePicker.launchImageLibraryAsync({
    mediaTypes: ['videos'],
    allowsEditing: false,
    quality: 1,
  });

  if (!result.canceled && result.assets[0]) {
    return result.assets[0].uri;
  }
};

// Mix video with audio
const mixVideo = async () => {
  try {
    const videoUri = await pickVideo();
    const audioUri = 'https://example.com/audio.mp3';

    const result = await ReactNativeVideoEditing.mixVideoWithAudio(
      videoUri,
      audioUri,
      'my-mixed-video.mp4' // optional custom filename
    );

    console.log('Success!', result.outputPath);
    // Output: /path/to/documents/my-mixed-video.mp4
  } catch (error) {
    console.error('Failed to mix video:', error);
  }
};
```

## API Reference

### `mixVideoWithAudio(videoUri, audioUri, outputFileName?)`

Mixes audio with a video file while preserving the original video audio.

**Parameters:**

- `videoUri` (string, required): Local file URI of the video (e.g., `file:///path/to/video.mp4`)
- `audioUri` (string, required): URL or local file URI of the audio (supports remote URLs like `https://example.com/audio.mp3`)
- `outputFileName` (string, optional): Custom filename for the output video (defaults to `mixed_video_[timestamp].mp4`)

**Returns:**

Promise that resolves to:

```typescript
{
  success: boolean;
  outputPath: string; // Absolute path to the mixed video file
}
```

**Behavior:**

- Downloads remote audio files automatically
- Mixes the new audio with the original video audio (both tracks are audible)
- Trims audio to match video duration if audio is longer
- Exports as MP4 format with highest quality settings
- Automatically cleans up downloaded audio files
- Saves output to the device's documents directory

**Example:**

```typescript
const result = await ReactNativeVideoEditing.mixVideoWithAudio(
  'file:///var/mobile/Containers/Data/Application/.../video.mov',
  'https://example.com/background-music.mp3',
  'final-video'
);

console.log(result);
// {
//   success: true,
//   outputPath: '/var/mobile/Containers/Data/Application/.../Documents/final-video.mp4'
// }
```

## Error Handling

The module throws errors with descriptive messages. Always wrap calls in try-catch blocks:

```typescript
try {
  const result = await ReactNativeVideoEditing.mixVideoWithAudio(
    videoUri,
    audioUri
  );
} catch (error) {
  if (error.message.includes('VIDEO_MIXING_ERROR')) {
    // Handle mixing errors
    console.error('Failed to mix video:', error.message);
  }
}
```

**Common error codes:**

- `Invalid audio URL` - The audio URL is malformed
- `Failed to download audio file` - Network error or invalid remote audio URL
- `Remote video URLs are not supported` - Video must be a local file
- `Video file has no video track` - Invalid or corrupted video file
- `Audio file has no audio track` - Invalid or corrupted audio file
- `Export failed` - Video export process failed

## Platform Support

| Platform | Status |
|----------|--------|
| iOS      | ✅ Fully Supported |
| Android  | ✅ Fully Supported |
| Web      | ❌ Not supported |

## Requirements

- **iOS**: iOS 13.0 or later
- **Android**: API level 24 (Android 7.0) or later
- **React Native**: 0.70.0 or later
- **Expo SDK**: 47 or later

## Permissions

### iOS

The module requires access to the photo library to read videos. Add the following to your `Info.plist`:

```xml
<key>NSPhotoLibraryUsageDescription</key>
<string>We need access to your photo library to select videos for editing</string>
```

Or if using Expo, add to your `app.json`:

```json
{
  "expo": {
    "ios": {
      "infoPlist": {
        "NSPhotoLibraryUsageDescription": "We need access to your photo library to select videos for editing"
      }
    }
  }
}
```

### Android

The module requires READ_EXTERNAL_STORAGE permission to access videos. Add to your `AndroidManifest.xml`:

```xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
```

For Android 13+ (API 33+), also add:

```xml
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
```

Or if using Expo, add to your `app.json`:

```json
{
  "expo": {
    "android": {
      "permissions": [
        "READ_EXTERNAL_STORAGE",
        "READ_MEDIA_VIDEO",
        "READ_MEDIA_AUDIO",
        "INTERNET"
      ]
    }
  }
}
```

**Note:** The module automatically requests runtime permissions when using expo-image-picker.

## Example App

Check out the `/example` folder in this repository for a complete working example with:

- Video picker using expo-image-picker
- Audio URL input
- Loading states
- Error handling
- Output path display

To run the example:

```bash
cd example
npm install

# For iOS
npx expo run:ios

# For Android
npx expo run:android
```

## Publishing to NPM

If you want to publish your own fork:

1. Update `package.json` with your details
2. Build the module:
   ```bash
   npm run build
   ```
3. Login to NPM:
   ```bash
   npm login
   ```
4. Publish:
   ```bash
   npm publish
   ```

## How Autolinking Works

This module uses **Expo autolinking**, which means:

- ✅ No manual linking required
- ✅ Automatically builds native code when running `expo prebuild`
- ✅ Works seamlessly with `expo run:ios` and `expo run:android`
- ✅ Compatible with EAS Build
- ✅ Native modules automatically discovered and linked

When you add this package to your project:

```bash
npx expo install @louiscapelle/react-native-video-editing
```

Then run your app:

```bash
npx expo run:ios  # Automatically compiles the Swift native module
```

No additional configuration needed!

## Technical Details

### iOS Implementation

The iOS implementation uses:

- **AVFoundation** framework for video/audio processing
- **AVMutableComposition** for combining video and audio tracks
- **AVAssetExportSession** for high-quality MP4 export
- **URLSession** for downloading remote audio files
- **Expo Modules API** for seamless React Native integration

### Android Implementation

The Android implementation uses:

- **MediaExtractor** for extracting video and audio tracks
- **MediaCodec** for encoding/decoding audio streams
- **MediaMuxer** for combining video and audio into MP4
- **URLConnection** for downloading remote audio files
- **Expo Modules API** for seamless React Native integration

Both platforms preserve the original video audio and add the new audio track, creating a true mix rather than a replacement.

**Note:** The Android implementation uses a simplified audio mixing approach. For production apps requiring advanced audio mixing (volume control, effects, etc.), consider using FFmpeg-based solutions.

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## License

MIT

## Author

Louis CAPELLE - [@LouisCapelle](https://github.com/LouisCapelle)

## Support

For issues and questions, please open an issue on [GitHub](https://github.com/LouisCapelle/react-native-video-editing/issues).