Support UVC cameras somewhat
This commit is contained in:
@@ -1,31 +0,0 @@
|
||||
Version = 1;
|
||||
Make: "UVC";
|
||||
Model: "UVC";
|
||||
|
||||
Rear: {
|
||||
SensorDriver: "ov5640";
|
||||
BridgeDriver: "uvcvideo";
|
||||
FlashPath: "/sys/class/leds/white:flash";
|
||||
IsoMin: 100;
|
||||
IsoMax: 64000;
|
||||
|
||||
Modes: (
|
||||
{
|
||||
Width: 2592;
|
||||
Height: 1944;
|
||||
Rate: 15;
|
||||
Format: "BGGR8";
|
||||
Rotate: 270;
|
||||
FocalLength: 3.33;
|
||||
FNumber: 3.0;
|
||||
},
|
||||
{
|
||||
Width: 1280;
|
||||
Height: 720;
|
||||
Rate: 30;
|
||||
Format: "BGGR8";
|
||||
FocalLength: 3.33;
|
||||
FNumber: 3.0;
|
||||
}
|
||||
);
|
||||
};
|
@@ -75,17 +75,23 @@ typedef struct _lmp_camera libmegapixels_camera;
|
||||
|
||||
struct _lmp_device_config {
|
||||
char *path;
|
||||
char *make;
|
||||
char *model;
|
||||
const char *make;
|
||||
const char *model;
|
||||
int count;
|
||||
int loaded_config;
|
||||
int loaded_uvc;
|
||||
libmegapixels_camera **cameras;
|
||||
};
|
||||
typedef struct _lmp_device_config libmegapixels_devconfig;
|
||||
|
||||
EXPORT int
|
||||
libmegapixels_init(libmegapixels_devconfig **config);
|
||||
|
||||
EXPORT int
|
||||
libmegapixels_load_file(libmegapixels_devconfig **config, const char *file);
|
||||
libmegapixels_load_file(libmegapixels_devconfig *config, const char *file);
|
||||
|
||||
EXPORT int
|
||||
libmegapixels_load_uvc(libmegapixels_devconfig *config);
|
||||
|
||||
EXPORT int
|
||||
libmegapixels_open(libmegapixels_camera *camera);
|
||||
|
20
src/mode.c
20
src/mode.c
@@ -4,12 +4,6 @@
|
||||
#include "mode.h"
|
||||
|
||||
|
||||
struct libmegapixels_modename {
|
||||
char *name;
|
||||
uint32_t v4l_pixel_format;
|
||||
uint32_t media_bus_format;
|
||||
};
|
||||
|
||||
// TODO: The 16 bit formats are imported from millipixels and seem broken
|
||||
static struct libmegapixels_modename mode_lut[] = {
|
||||
{
|
||||
@@ -90,7 +84,7 @@ static struct libmegapixels_modename mode_lut[] = {
|
||||
{
|
||||
.name = "GRBG16",
|
||||
.v4l_pixel_format = V4L2_PIX_FMT_SGRBG16,
|
||||
.media_bus_format =MEDIA_BUS_FMT_SGRBG10_1X10 ,
|
||||
.media_bus_format =MEDIA_BUS_FMT_SGRBG10_1X10,
|
||||
},
|
||||
{
|
||||
.name = "RGGB16",
|
||||
@@ -132,3 +126,15 @@ format_name_to_media_busfmt(const char *name)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct libmegapixels_modename *
|
||||
v4l_pixfmt_to_mode(uint32_t pixfmt)
|
||||
{
|
||||
int count = sizeof(mode_lut) / sizeof(mode_lut[0]);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (mode_lut[i].v4l_pixel_format == pixfmt) {
|
||||
return &mode_lut[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
10
src/mode.h
10
src/mode.h
@@ -1,7 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
struct libmegapixels_modename {
|
||||
char *name;
|
||||
uint32_t v4l_pixel_format;
|
||||
uint32_t media_bus_format;
|
||||
};
|
||||
|
||||
uint32_t
|
||||
format_name_to_v4l_pixfmt(const char *name);
|
||||
|
||||
uint32_t
|
||||
format_name_to_media_busfmt(const char *name);
|
||||
|
||||
|
||||
struct libmegapixels_modename *
|
||||
v4l_pixfmt_to_mode(uint32_t pixfmt);
|
||||
|
145
src/parse.c
145
src/parse.c
@@ -10,6 +10,7 @@
|
||||
#include <linux/media.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include "libmegapixels.h"
|
||||
#include "mode.h"
|
||||
#include "util.h"
|
||||
@@ -317,15 +318,20 @@ load_camera(libmegapixels_devconfig *config, config_t *cfg, const char *name)
|
||||
}
|
||||
|
||||
int
|
||||
libmegapixels_load_file(libmegapixels_devconfig **config, const char *file)
|
||||
libmegapixels_load_file(libmegapixels_devconfig *config, const char *file)
|
||||
{
|
||||
if (config->loaded_config) {
|
||||
log_error("Config already loaded\n");
|
||||
return 0;
|
||||
}
|
||||
config->loaded_config = 1;
|
||||
config_t cfg;
|
||||
config_setting_t *setting, *member;
|
||||
|
||||
*config = malloc(sizeof(libmegapixels_devconfig));
|
||||
(*config)->path = strdup(file);
|
||||
(*config)->count = 0;
|
||||
(*config)->cameras = malloc(sizeof((*config)->cameras));
|
||||
config->path = strdup(file);
|
||||
if (config->count == 0) {
|
||||
config->cameras = malloc(0);
|
||||
}
|
||||
|
||||
config_init(&cfg);
|
||||
if (!config_read_file(&cfg, file)) {
|
||||
@@ -345,11 +351,11 @@ libmegapixels_load_file(libmegapixels_devconfig **config, const char *file)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!config_lookup_string(&cfg, "Make", (const char **) &(*config)->make)) {
|
||||
(*config)->make = strdup("Megapixels");
|
||||
if (!config_lookup_string(&cfg, "Make", &config->make)) {
|
||||
config->make = strdup("Megapixels");
|
||||
}
|
||||
if (!config_lookup_string(&cfg, "Model", (const char **) &(*config)->model)) {
|
||||
(*config)->model = strdup("Camera");
|
||||
if (!config_lookup_string(&cfg, "Model", &config->model)) {
|
||||
config->model = strdup("Camera");
|
||||
}
|
||||
|
||||
setting = config_root_setting(&cfg);
|
||||
@@ -370,8 +376,127 @@ libmegapixels_load_file(libmegapixels_devconfig **config, const char *file)
|
||||
if (strcmp(member->name, "Model") == 0) {
|
||||
continue;
|
||||
}
|
||||
load_camera(*config, &cfg, member->name);
|
||||
load_camera(config, &cfg, member->name);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
uvc_create_modes(libmegapixels_camera *camera, int fd)
|
||||
{
|
||||
struct v4l2_fmtdesc fmtdesc = {0};
|
||||
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
while (xioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) {
|
||||
fmtdesc.index++;
|
||||
struct libmegapixels_modename *mn = v4l_pixfmt_to_mode(fmtdesc.pixelformat);
|
||||
if (mn == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct v4l2_frmsizeenum framesize = {0};
|
||||
framesize.pixel_format = fmtdesc.pixelformat;
|
||||
|
||||
while (xioctl(fd, VIDIOC_ENUM_FRAMESIZES, &framesize) == 0) {
|
||||
if (framesize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
|
||||
|
||||
struct v4l2_frmivalenum frameinterval = {0};
|
||||
frameinterval.pixel_format = framesize.pixel_format;
|
||||
frameinterval.width = framesize.discrete.width;
|
||||
frameinterval.height = framesize.discrete.height;
|
||||
|
||||
while (xioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frameinterval) == 0) {
|
||||
frameinterval.index++;
|
||||
if (frameinterval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
|
||||
libmegapixels_mode *mode = calloc(1, sizeof(libmegapixels_mode));
|
||||
mode->v4l_pixfmt = fmtdesc.pixelformat;
|
||||
mode->width = (int) framesize.discrete.width;
|
||||
mode->height = (int) framesize.discrete.height;
|
||||
mode->media_busfmt = mn->media_bus_format;
|
||||
mode->rotation = 0;
|
||||
mode->rate = (int) ((double) frameinterval.discrete.denominator /
|
||||
(double) frameinterval.discrete.numerator);
|
||||
|
||||
camera->modes = realloc(camera->modes, (camera->num_modes + 1) * sizeof(camera->modes));
|
||||
if (camera->modes == NULL) {
|
||||
return;
|
||||
}
|
||||
camera->modes[camera->num_modes++] = mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
framesize.index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
libmegapixels_load_uvc(libmegapixels_devconfig *config)
|
||||
{
|
||||
if (config->loaded_uvc) {
|
||||
log_error("libmegapixels_load_uvc was already called\n");
|
||||
return 0;
|
||||
}
|
||||
config->loaded_uvc = 1;
|
||||
|
||||
struct dirent *dir;
|
||||
DIR *d = opendir("/dev");
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
if (strncmp(dir->d_name, "video", 5) == 0) {
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, PATH_MAX, "/dev/%s", dir->d_name);
|
||||
int fd = open(path, O_RDWR);
|
||||
if (fd < 0) {
|
||||
continue;
|
||||
}
|
||||
struct v4l2_capability vid_cap = {0};
|
||||
if (xioctl(fd, VIDIOC_QUERYCAP, &vid_cap) == -1) {
|
||||
perror("QUERYCAP");
|
||||
continue;
|
||||
}
|
||||
if (strcmp(vid_cap.driver, "uvcvideo") != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(vid_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(vid_cap.capabilities & V4L2_CAP_STREAMING)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct v4l2_fmtdesc fmtdesc = {0};
|
||||
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (xioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
libmegapixels_camera *camera;
|
||||
camera = calloc(1, sizeof(libmegapixels_camera));
|
||||
camera->name = strdup((const char *) vid_cap.card);
|
||||
camera->video_path = strdup(path);
|
||||
|
||||
uvc_create_modes(camera, fd);
|
||||
|
||||
close(fd);
|
||||
|
||||
config->cameras = realloc(config->cameras, (config->count + 1) * sizeof(config->cameras));
|
||||
if (config->cameras == NULL) {
|
||||
return -1;
|
||||
}
|
||||
config->cameras[config->count++] = camera;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
libmegapixels_init(libmegapixels_devconfig **config)
|
||||
{
|
||||
*config = calloc(1, sizeof(libmegapixels_devconfig));
|
||||
return 1;
|
||||
}
|
@@ -129,17 +129,21 @@ libmegapixels_open(libmegapixels_camera *camera)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (camera->media_path) {
|
||||
camera->media_fd = open(camera->media_path, O_RDWR);
|
||||
if (camera->media_fd < 0) {
|
||||
log_error("Could not open %s: %s\n", camera->media_path, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (camera->sensor_path) {
|
||||
camera->sensor_fd = open(camera->sensor_path, O_RDWR);
|
||||
if (camera->sensor_fd < 0) {
|
||||
log_error("Could not open %s: %s\n", camera->sensor_path, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
camera->video_fd = open(camera->video_path, O_RDWR);
|
||||
if (camera->video_fd < 0) {
|
||||
@@ -147,10 +151,17 @@ libmegapixels_open(libmegapixels_camera *camera)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If this is an UVC camera the sensor _is_ the video device
|
||||
if (camera->sensor_fd == 0) {
|
||||
camera->sensor_fd = camera->video_fd;
|
||||
}
|
||||
|
||||
if (camera->media_fd > 0) {
|
||||
int ret = load_entity_ids(camera);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -158,6 +169,11 @@ libmegapixels_open(libmegapixels_camera *camera)
|
||||
void
|
||||
libmegapixels_close(libmegapixels_camera *camera)
|
||||
{
|
||||
int uvc = 0;
|
||||
if (camera->sensor_fd != 0 && camera->sensor_fd == camera->video_fd) {
|
||||
uvc = 1;
|
||||
}
|
||||
|
||||
if (camera->media_fd != 0) {
|
||||
close(camera->media_fd);
|
||||
camera->media_fd = 0;
|
||||
@@ -165,6 +181,9 @@ libmegapixels_close(libmegapixels_camera *camera)
|
||||
if (camera->sensor_fd != 0) {
|
||||
close(camera->sensor_fd);
|
||||
camera->sensor_fd = 0;
|
||||
if (uvc) {
|
||||
camera->video_fd = 0;
|
||||
}
|
||||
}
|
||||
if (camera->video_fd != 0) {
|
||||
close(camera->video_fd);
|
||||
|
@@ -33,14 +33,19 @@ main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
libmegapixels_devconfig *config = {0};
|
||||
libmegapixels_init(&config);
|
||||
|
||||
if (!ret) {
|
||||
printf("No config found\n");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
printf("Using config: %s\n", configpath);
|
||||
if (!libmegapixels_load_file(config, configpath)) {
|
||||
printf("Could not load config\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!libmegapixels_load_file(&config, configpath)) {
|
||||
libmegapixels_load_uvc(config);
|
||||
if (config->count == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -49,9 +54,13 @@ main(int argc, char *argv[])
|
||||
|
||||
for (int i = 0; i < config->count; i++) {
|
||||
printf("\n----[ Camera %s (%d) ]----\n", config->cameras[i]->name, i);
|
||||
if (config->cameras[i]->bridge_name) {
|
||||
printf("Media : %s (%s)\n", config->cameras[i]->bridge_name, config->cameras[i]->media_path);
|
||||
}
|
||||
if (config->cameras[i]->sensor_name) {
|
||||
printf("Sensor: %s (%s)\n", config->cameras[i]->sensor_name, config->cameras[i]->sensor_path);
|
||||
printf("Bridge: %s\n", config->cameras[i]->video_path);
|
||||
}
|
||||
printf("Video : %s\n", config->cameras[i]->video_path);
|
||||
printf("Modes : ");
|
||||
for (int j = 0; j < config->cameras[i]->num_modes; j++) {
|
||||
if (j > 0) {
|
||||
|
@@ -67,21 +67,24 @@ main(int argc, char *argv[])
|
||||
char configpath[PATH_MAX];
|
||||
int ret = libmegapixels_find_config(configpath);
|
||||
libmegapixels_devconfig *config = {0};
|
||||
libmegapixels_init(&config);
|
||||
|
||||
if (ret) {
|
||||
printf("Using config: %s\n", configpath);
|
||||
libmegapixels_load_file(&config, configpath);
|
||||
libmegapixels_load_file(config, configpath);
|
||||
} else {
|
||||
fprintf(stderr, "No config found for this device\n");
|
||||
return 1;
|
||||
}
|
||||
libmegapixels_load_uvc(config);
|
||||
|
||||
if (config->count == 0) {
|
||||
fprintf(stderr, "No valid camera configuration\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (camera_id > config->count) {
|
||||
if (camera_id > config->count - 1) {
|
||||
fprintf(stderr, "Camera id %d does not exist\n", camera_id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
libmegapixels_camera *camera = config->cameras[camera_id];
|
||||
|
Reference in New Issue
Block a user