Skip to content

Instantly share code, notes, and snippets.

@ab2005
Last active April 15, 2023 09:40
Show Gist options
  • Select an option

  • Save ab2005/f1061a0814952807b32db204f90c65b3 to your computer and use it in GitHub Desktop.

Select an option

Save ab2005/f1061a0814952807b32db204f90c65b3 to your computer and use it in GitHub Desktop.
Simple uvc camera capture using libuvc

Run:

  1. brew install libuvc
  2. gcc uvccam.c -luvc -o exx
  3. To get device info run: ./exx 1>/dev/null
  4. To save YUV422 to file: ./exx 2>/dev/null 1>video.yuv

Some ffmpeg experiments:

Record raw YUV422 from camera:

ffmpeg -f rawvideo -s:v 640x480 -pix_fmt yuyv422 -r 30 -i yuv30 /Volumes/SP\ PHD\ U3/480p.mp4

Record MP4 video from raw YUV422:

ffmpeg -f rawvideo -s:v 640x480 -pix_fmt yuyv422 -r 30 -i yuv out.mp4

Record MP4 video from camera:

( ./exx 2>/dev/null) | (ffmpeg -f rawvideo -s:v 640x480 -pix_fmt yuyv422 -r 30 -i pipe:0 _out.mp4)

List connected uvc cameras:

ffmpeg -f avfoundation -list_devices true -i “”

Stream realtime video from uvc camera:

ffmpeg -f avfoundation -r 30 -i "0:0" -deinterlace -vcodec libx264 -pix_fmt yuv420p -preset medium -g 60 -b:v 2500k -acodec libmp3lame -ar 44100 -threads 6 -qscale 3 -b:a 712000 -bufsize 512k -f mpegts udp://10.0.0.157:1234

/*
* Created by alexB, 2/18/2108
*/
#include "libuvc/libuvc.h"
#include <stdio.h>
#include <unistd.h>
/* This callback function runs once per frame. Use it to perform any
* quick processing you need, or have it put the frame into your application's
* input queue. If this function takes too long, you'll start losing frames.
*/
void cb(uvc_frame_t *frame, void *ptr) {
uvc_frame_t *bgr;
uvc_error_t ret;
write(1, frame->data, frame->data_bytes);
}
int main(int argc, char **argv) {
uvc_context_t *ctx;
uvc_device_t *dev;
uvc_device_handle_t *devh;
uvc_stream_ctrl_t ctrl;
uvc_error_t res;
counter = 0;
/* Initialize a UVC service context. Libuvc will set up its own libusb
* context. Replace NULL with a libusb_context pointer to run libuvc
* from an existing libusb context. */
res = uvc_init(&ctx, NULL);
if (res < 0) {
uvc_perror(res, "uvc_init");
return res;
}
fprintf(stderr, "UVC initialized\n");
/* Locates the first attached UVC device, stores in dev */
res = uvc_find_device(ctx, &dev,
0, 0, NULL); /* filter devices: vendor_id, product_id, "serial_num" */
if (res < 0) {
uvc_perror(res, "uvc_find_device"); /* no devices found */
} else {
fprintf(stderr, "Device found\n");
/* Try to open the device: requires exclusive access */
res = uvc_open(dev, &devh);
if (res < 0) {
uvc_perror(res, "uvc_open"); /* unable to open device */
} else {
fprintf(stderr, "Device opened\n");
/* Print out a message containing all the information that libuvc
* knows about the device */
uvc_print_diag(devh, stderr);
int fmt = UVC_FRAME_FORMAT_YUYV;
/* Try to negotiate a 640x480 30 fps YUYV stream profile */
res = uvc_get_stream_ctrl_format_size(
devh, &ctrl, /* result stored in ctrl */
fmt, /* YUV 422, aka YUV 4:2:2. try _COMPRESSED */
640, 480, 30 /* width, height, fps */
);
if (res < 0) {
uvc_perror(res, "get_mode"); /* device doesn't provide a matching stream */
} else {
/* Print out the result */
fprintf(stderr, "uvc_print_stream_ctrl:\n");
uvc_print_stream_ctrl(&ctrl, stderr);
/* Start the video stream. The library will call user function cb:
* cb(frame, (void*) 12345) */
res = uvc_start_streaming(devh, &ctrl, cb, (void*)12345, 0);
if (res < 0) {
uvc_perror(res, "start_streaming"); /* unable to start stream */
} else {
fprintf(stderr, "Streaming...\n");
uvc_set_ae_mode(devh, 1); /* e.g., turn on auto exposure */
sleep(100);
/* End the stream. Blocks until last callback is serviced */
uvc_stop_streaming(devh);
sleep(3); /* sleep 3 sec */
fprintf(stderr, "Done streaming\n");
}
}
/* Release our handle on the device */
uvc_close(devh);
fprintf(stderr, "Device closed\n");
fclose(1);
}
/* Release the device descriptor */
uvc_unref_device(dev);
}
/* Close the UVC context. This closes and cleans up any existing device handles,
* and it closes the libusb context if one was not provided. */
fprintf(stderr, "Device unrefed\n");
uvc_exit(ctx);
fprintf(stderr, "UVC exited");
return 0;
}
@nautomm
Copy link

nautomm commented Feb 21, 2018

Great, I like this code.
It is working the same way as the code for SensorBoard - it will be easy to integrate it.
We already have a database/storage so we need just to store 1h recordings from the camera.

@UdayanMallik
Copy link

UdayanMallik commented May 29, 2021

What is meant by /* Try to open the device: requires exclusive access */ Specially the Requires exclusive access part. How do I make sure my camera is giving exclusive access to the UVClib driver. I am in the Linux environment. Ubuntu 21.04.

@criminact
Copy link

criminact commented Apr 15, 2023

@UdayanMallik There are 2 solutions to providing exclusive access to the device on Unix based systems-

  1. One is by adding the VID PID of the device in udev (Try searching for udev device access on Google)
  2. Second is to check which usb dev node is created when you're plugging in your camera. You need to change chmod +777 on that particular dev node. (Usually the dev nodes for USB are under -> /dev/bus/usb). Try plugging your camera out and check the nodes. Plug it in now and check which nodes are newly created. Give them read write access.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment