react-native-turbo-uvc-camera
v0.0.0
Published
React Native module for USB Video Class (UVC) cameras on Android
Readme
react-native-uvc-camera
React Native Turbo Module for USB Video Class (UVC) cameras on Android. Capture photos from external USB cameras connected via USB OTG.
✨ Features
- ✅ Android USB Host API support
- ✅ Auto USB device detection
- ✅ Photo capture from UVC cameras
- ✅ YUV to RGB conversion (supports both MJPEG and raw YUV formats)
- ✅ Event-based connection/disconnection notifications
- ✅ Turbo Module architecture (New Architecture ready)
- ✅ TypeScript definitions included
📦 Installation
1. Install the package
npm install react-native-uvc-camera
# or
yarn add react-native-uvc-camera2. Add UVCCamera native library
This module requires the UVCCamera library.
Option A: Copy the library module
- Clone or copy the
libuvccamerafolder from UVCCamera repo into yourandroid/directory - Add to your
android/settings.gradle:
include ':libuvccamera'
project(':libuvccamera').projectDir = new File(rootProject.projectDir, 'libuvccamera')Option B: Use git submodule (recommended)
cd android
git submodule add https://github.com/saki4510t/UVCCamera.git UVCCameraThen in android/settings.gradle:
include ':libuvccamera'
project(':libuvccamera').projectDir = new File(rootProject.projectDir, 'UVCCamera/libuvccamera')3. Update AndroidManifest.xml
Add USB permissions and features to your android/app/src/main/AndroidManifest.xml:
<manifest>
<!-- USB Host feature -->
<uses-feature android:name="android.hardware.usb.host" android:required="false" />
<application>
<activity android:name=".MainActivity">
<!-- ... existing intent filters ... -->
<!-- USB device attached intent filter -->
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
</application>
</manifest>4. Create device filter
Create android/app/src/main/res/xml/device_filter.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- UVC Camera (USB Video Class) -->
<usb-device class="14" />
</resources>🚀 Usage
import UVCCamera, { type PhotoResult } from 'react-native-uvc-camera';
import { useEffect, useState } from 'react';
function CameraScreen() {
const [isConnected, setIsConnected] = useState(false);
const [photo, setPhoto] = useState<PhotoResult | null>(null);
useEffect(() => {
// Initialize USB monitor
UVCCamera.initialize();
// Listen for camera events
const connectedListener = UVCCamera.addListener('onCameraConnected', (data) => {
console.log('Camera connected:', data.deviceName);
setIsConnected(true);
});
const disconnectedListener = UVCCamera.addListener('onCameraDisconnected', (data) => {
console.log('Camera disconnected:', data.deviceName);
setIsConnected(false);
});
const errorListener = UVCCamera.addListener('onCameraError', (data) => {
console.error('Camera error:', data.error);
});
// Cleanup
return () => {
connectedListener.remove();
disconnectedListener.remove();
errorListener.remove();
UVCCamera.destroy();
};
}, []);
const handleRequestPermission = async () => {
try {
await UVCCamera.requestPermission();
// Permission dialog will be shown to user
} catch (error) {
console.error('Permission error:', error);
}
};
const handleTakePhoto = async () => {
try {
const result = await UVCCamera.takePhoto();
console.log('Photo captured:', result);
setPhoto(result);
// result.path: File path
// result.uri: File URI (file://...)
// result.width: Image width
// result.height: Image height
} catch (error) {
console.error('Capture error:', error);
}
};
return (
<View>
<Text>{isConnected ? 'Camera Connected' : 'No Camera'}</Text>
<Button title="Request USB Permission" onPress={handleRequestPermission} />
<Button
title="Take Photo"
onPress={handleTakePhoto}
disabled={!isConnected}
/>
{photo && <Image source={{ uri: photo.uri }} />}
</View>
);
}📚 API
Methods
initialize(): Promise<boolean>
Initialize the USB monitor. Call this once when your app starts.
requestPermission(): Promise<boolean>
Request permission to access the USB camera. Android will show a permission dialog.
takePhoto(): Promise<PhotoResult>
Capture a photo from the connected UVC camera.
Returns:
{
path: string; // Absolute file path
uri: string; // File URI (file://...)
width: number; // Image width in pixels
height: number; // Image height in pixels
}stopPreview(): Promise<boolean>
Stop the camera preview.
destroy(): Promise<boolean>
Cleanup and release camera resources.
Events
onUsbDeviceAttached
Fired when a USB device is physically attached.
UVCCamera.addListener('onUsbDeviceAttached', (data: { deviceName: string }) => {
console.log('Device attached:', data.deviceName);
});onCameraConnected
Fired when the camera is successfully connected and ready to use.
UVCCamera.addListener('onCameraConnected', (data: { deviceName: string; success: boolean }) => {
console.log('Camera ready:', data.deviceName);
});onCameraDisconnected
Fired when the camera is disconnected.
UVCCamera.addListener('onCameraDisconnected', (data: { deviceName: string }) => {
console.log('Camera disconnected:', data.deviceName);
});onUsbDeviceDetached
Fired when a USB device is physically removed.
UVCCamera.addListener('onUsbDeviceDetached', (data: { deviceName: string }) => {
console.log('Device detached:', data.deviceName);
});onPermissionCancelled
Fired when the user cancels the USB permission dialog.
UVCCamera.addListener('onPermissionCancelled', (data: { deviceName: string }) => {
console.log('Permission cancelled:', data.deviceName);
});onCameraError
Fired when an error occurs.
UVCCamera.addListener('onCameraError', (data: { error: string }) => {
console.error('Camera error:', data.error);
});⚙️ Technical Details
- Supported Formats: MJPEG, YUV (YUYV)
- Auto Format Detection: Tries MJPEG decode first, falls back to YUV conversion
- Default Resolution: 640x480 (configurable in native code)
- Photo Format: JPEG (90% quality)
- Storage: App's external files directory (
Pictures/) - Architecture: Turbo Module (supports both old and new RN architecture)
🔧 Troubleshooting
Camera not detected
- Ensure your device supports USB Host mode (USB OTG)
- Check that the camera is UVC compliant
- Verify
device_filter.xmlis in place - Check logcat for errors:
adb logcat | grep UVCCamera
"Camera is not connected" error
- Make sure you called
requestPermission()first - Wait for the
onCameraConnectedevent before callingtakePhoto()
App crashes on start
- Ensure
libuvccamerais properly included in your project - Check that all native dependencies are linked
- Run
./gradlew cleanin the android folder
"Failed to decode image"
- Your camera might be sending raw YUV instead of MJPEG
- The module automatically handles YUV→RGB conversion
- If issues persist, check the frame format logs in logcat
📄 License
MIT
👏 Credits
Built on top of saki4510t/UVCCamera
