npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

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-camera

2. Add UVCCamera native library

This module requires the UVCCamera library.

Option A: Copy the library module

  1. Clone or copy the libuvccamera folder from UVCCamera repo into your android/ directory
  2. 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 UVCCamera

Then 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.xml is in place
  • Check logcat for errors: adb logcat | grep UVCCamera

"Camera is not connected" error

  • Make sure you called requestPermission() first
  • Wait for the onCameraConnected event before calling takePhoto()

App crashes on start

  • Ensure libuvccamera is properly included in your project
  • Check that all native dependencies are linked
  • Run ./gradlew clean in 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