Skip to content

Instantly share code, notes, and snippets.

@d0rc
Created October 2, 2025 11:56
Show Gist options
  • Select an option

  • Save d0rc/8c9f48f7bb768b95b9e130e825ba66cc to your computer and use it in GitHub Desktop.

Select an option

Save d0rc/8c9f48f7bb768b95b9e130e825ba66cc to your computer and use it in GitHub Desktop.

To capture a video stream from a Logitech C270 HD Webcam using libusb, you'll need to interface with the webcam's USB Video Class (UVC) interface, as the C270 is a UVC-compliant device. Below is a step-by-step guide to achieve this. Note that this process requires familiarity with C/C++ programming, USB protocols, and handling video data (e.g., MJPEG or YUYV formats). The approach assumes you're working on a Linux system, as libusb is commonly used there, but it can be adapted for other platforms.Prerequisites

  1. Install libusb: Ensure libusb-1.0 is installed (sudo apt install libusb-1.0-0-dev on Debian/Ubuntu or equivalent).
  2. Development Environment: Set up a C/C++ environment with a compiler (e.g., gcc) and necessary headers.
  3. Permissions: Ensure you have permissions to access the webcam (e.g., add your user to the video group or run as root, though root is not recommended).
  4. Dependencies: Optionally, install v4l2loopback to create a virtual video device for testing or piping the stream to other applications.

Steps to Capture Video Stream

  1. Initialize libusb:
    • Initialize a libusb context using libusb_init(NULL).
    • Set the debug level for troubleshooting: libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_DEBUG).
  2. Find the Logitech C270:
    • Use libusb_get_device_list() to enumerate USB devices.
    • Identify the C270 by its vendor ID (0x046d) and product ID (0x0825). Iterate through devices and check libusb_get_device_descriptor() for these IDs.
    • Open the device with libusb_open().
  3. Claim the UVC Interface:
    • Retrieve the device configuration using libusb_get_config_descriptor().
    • The C270 typically exposes multiple interfaces (e.g., video control and video streaming). The video streaming interface (usually interface 1) is what you need.
    • Detach the kernel driver if active (Linux only): libusb_detach_kernel_driver(handle, interface_number).
    • Claim the interface with libusb_claim_interface(handle, interface_number).
  4. Configure the Video Stream:
    • The C270 supports MJPEG and YUYV formats via UVC. Use libusb_control_transfer() to send UVC control requests (e.g., SET_CUR) to select the format, resolution (e.g., 1280x720), and frame rate (e.g., 30 fps).
    • UVC control requests involve:
      • bmRequestType: 0x21 (host-to-device, class, interface).
      • bRequest: SET_CUR (0x01).
      • wValue: VS_PROBE_CONTROL or VS_COMMIT_CONTROL (0x0200 or 0x0300).
      • wIndex: Interface number.
      • Data: A buffer specifying format, frame index, and frame interval (refer to UVC 1.5 specs for structure).
    • Query supported formats using GET_CUR/GET_MIN/GET_MAX requests to the video streaming interface.
  5. Set Up Isochronous Transfers:
    • The C270 uses isochronous transfers for video data. Configure an isochronous endpoint (typically endpoint 0x81 or 0x82, check with libusb_get_config_descriptor()).
    • Allocate transfer buffers with libusb_alloc_transfer(num_iso_packets).
    • Set up the transfer with libusb_fill_iso_transfer(), specifying the endpoint, buffer, and callback function.
    • Submit the transfer using libusb_submit_transfer().
  6. Handle Video Data:
    • In the callback function, process the received isochronous packets. The C270 typically sends MJPEG frames, which are JPEG-compressed images.
    • Parse the UVC payload header (first 12 bytes of each frame) to identify frame boundaries (check the SCR and PTS fields).
    • Save or process the MJPEG data (e.g., write to a file or decode to RGB for display).
  7. Event Handling:
    • Continuously call libusb_handle_events() in a loop to process USB events and trigger callbacks.
    • Use multiple transfers (e.g., 3–5) to ensure smooth streaming by submitting new transfers as others complete.
  8. Clean Up:
    • Free transfers with libusb_free_transfer().
    • Release the interface with libusb_release_interface().
    • Close the device with libusb_close() and clean up the context with libusb_exit().

Example Code (Simplified)Below is a basic example in C to initialize and start capturing. This is a starting point and needs error handling and format negotiation for production use.

c

#include <libusb-1.0/libusb.h>
#include <stdio.h>
#include <stdlib.h>

void transfer_callback(struct libusb_transfer *transfer) {
    if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
        printf("Received %d bytes\n", transfer->actual_length);
        // Process MJPEG data here
        libusb_submit_transfer(transfer); // Resubmit for continuous streaming
    } else {
        fprintf(stderr, "Transfer error: %d\n", transfer->status);
    }
}

int main() {
    libusb_context *ctx = NULL;
    libusb_device_handle *handle = NULL;
    libusb_init(&ctx);

    // Find C270 (vendor: 0x046d, product: 0x0825)
    handle = libusb_open_device_with_vid_pid(ctx, 0x046d, 0x0825);
    if (!handle) {
        fprintf(stderr, "Failed to open device\n");
        libusb_exit(ctx);
        return 1;
    }

    // Claim interface (assuming interface 1 for streaming)
    libusb_detach_kernel_driver(handle, 1);
    libusb_claim_interface(handle, 1);

    // Configure format (simplified, use control transfers for real setup)
    unsigned char buf[256];
    struct libusb_transfer *transfer = libusb_alloc_transfer(8);
    unsigned char *data = malloc(1024 * 1024); // Buffer for video data
    libusb_fill_iso_transfer(transfer, handle, 0x81, data, 1024 * 1024, 8, transfer_callback, NULL, 0);
    libusb_submit_transfer(transfer);

    // Event loop
    while (1) {
        libusb_handle_events(ctx);
    }

    // Cleanup
    libusb_free_transfer(transfer);
    free(data);
    libusb_release_interface(handle, 1);
    libusb_close(handle);
    libusb_exit(ctx);
    return 0;
}

Key Considerations

  • UVC Protocol Details: Refer to the USB Video Class 1.5 specification for control and streaming formats. The C270 supports MJPEG (preferred for lower bandwidth) and YUYV.
  • Performance: Isochronous transfers require careful buffer management to avoid dropped frames. Use large enough buffers and multiple transfers.
  • Decoding: MJPEG frames can be decoded using libraries like OpenCV or FFmpeg for display or further processing.
  • Permissions: On Linux, ensure /dev/bus/usb/ permissions allow access, or use udev rules.
  • Debugging: Use tools like v4l2-ctl --list-formats-ext to verify supported formats and wireshark with USB capture to debug transfers.

Alternative ApproachFor simpler video capture, consider using libuvc (a user-space UVC library built on libusb) or Video4Linux2 (V4L2) instead of raw libusb. These abstract much of the USB complexity:

  • libuvc: Provides a higher-level API for UVC devices (install via libuvc-dev).
  • V4L2: Use /dev/videoX with V4L2 APIs for a more mature, kernel-supported approach.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment