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 {
|
struct _lmp_device_config {
|
||||||
char *path;
|
char *path;
|
||||||
char *make;
|
const char *make;
|
||||||
char *model;
|
const char *model;
|
||||||
int count;
|
int count;
|
||||||
|
int loaded_config;
|
||||||
|
int loaded_uvc;
|
||||||
libmegapixels_camera **cameras;
|
libmegapixels_camera **cameras;
|
||||||
};
|
};
|
||||||
typedef struct _lmp_device_config libmegapixels_devconfig;
|
typedef struct _lmp_device_config libmegapixels_devconfig;
|
||||||
|
|
||||||
|
EXPORT int
|
||||||
|
libmegapixels_init(libmegapixels_devconfig **config);
|
||||||
|
|
||||||
EXPORT int
|
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
|
EXPORT int
|
||||||
libmegapixels_open(libmegapixels_camera *camera);
|
libmegapixels_open(libmegapixels_camera *camera);
|
||||||
|
20
src/mode.c
20
src/mode.c
@@ -4,12 +4,6 @@
|
|||||||
#include "mode.h"
|
#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
|
// TODO: The 16 bit formats are imported from millipixels and seem broken
|
||||||
static struct libmegapixels_modename mode_lut[] = {
|
static struct libmegapixels_modename mode_lut[] = {
|
||||||
{
|
{
|
||||||
@@ -90,7 +84,7 @@ static struct libmegapixels_modename mode_lut[] = {
|
|||||||
{
|
{
|
||||||
.name = "GRBG16",
|
.name = "GRBG16",
|
||||||
.v4l_pixel_format = V4L2_PIX_FMT_SGRBG16,
|
.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",
|
.name = "RGGB16",
|
||||||
@@ -132,3 +126,15 @@ format_name_to_media_busfmt(const char *name)
|
|||||||
}
|
}
|
||||||
return 0;
|
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
|
#pragma once
|
||||||
|
|
||||||
|
struct libmegapixels_modename {
|
||||||
|
char *name;
|
||||||
|
uint32_t v4l_pixel_format;
|
||||||
|
uint32_t media_bus_format;
|
||||||
|
};
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
format_name_to_v4l_pixfmt(const char *name);
|
format_name_to_v4l_pixfmt(const char *name);
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
format_name_to_media_busfmt(const char *name);
|
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 <linux/media.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <linux/videodev2.h>
|
||||||
#include "libmegapixels.h"
|
#include "libmegapixels.h"
|
||||||
#include "mode.h"
|
#include "mode.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@@ -317,15 +318,20 @@ load_camera(libmegapixels_devconfig *config, config_t *cfg, const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
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_t cfg;
|
||||||
config_setting_t *setting, *member;
|
config_setting_t *setting, *member;
|
||||||
|
|
||||||
*config = malloc(sizeof(libmegapixels_devconfig));
|
config->path = strdup(file);
|
||||||
(*config)->path = strdup(file);
|
if (config->count == 0) {
|
||||||
(*config)->count = 0;
|
config->cameras = malloc(0);
|
||||||
(*config)->cameras = malloc(sizeof((*config)->cameras));
|
}
|
||||||
|
|
||||||
config_init(&cfg);
|
config_init(&cfg);
|
||||||
if (!config_read_file(&cfg, file)) {
|
if (!config_read_file(&cfg, file)) {
|
||||||
@@ -345,11 +351,11 @@ libmegapixels_load_file(libmegapixels_devconfig **config, const char *file)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config_lookup_string(&cfg, "Make", (const char **) &(*config)->make)) {
|
if (!config_lookup_string(&cfg, "Make", &config->make)) {
|
||||||
(*config)->make = strdup("Megapixels");
|
config->make = strdup("Megapixels");
|
||||||
}
|
}
|
||||||
if (!config_lookup_string(&cfg, "Model", (const char **) &(*config)->model)) {
|
if (!config_lookup_string(&cfg, "Model", &config->model)) {
|
||||||
(*config)->model = strdup("Camera");
|
config->model = strdup("Camera");
|
||||||
}
|
}
|
||||||
|
|
||||||
setting = config_root_setting(&cfg);
|
setting = config_root_setting(&cfg);
|
||||||
@@ -370,8 +376,127 @@ libmegapixels_load_file(libmegapixels_devconfig **config, const char *file)
|
|||||||
if (strcmp(member->name, "Model") == 0) {
|
if (strcmp(member->name, "Model") == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
load_camera(*config, &cfg, member->name);
|
load_camera(config, &cfg, member->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
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,16 +129,20 @@ libmegapixels_open(libmegapixels_camera *camera)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
camera->media_fd = open(camera->media_path, O_RDWR);
|
if (camera->media_path) {
|
||||||
if (camera->media_fd < 0) {
|
camera->media_fd = open(camera->media_path, O_RDWR);
|
||||||
log_error("Could not open %s: %s\n", camera->media_path, strerror(errno));
|
if (camera->media_fd < 0) {
|
||||||
return -1;
|
log_error("Could not open %s: %s\n", camera->media_path, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
camera->sensor_fd = open(camera->sensor_path, O_RDWR);
|
if (camera->sensor_path) {
|
||||||
if (camera->sensor_fd < 0) {
|
camera->sensor_fd = open(camera->sensor_path, O_RDWR);
|
||||||
log_error("Could not open %s: %s\n", camera->sensor_path, strerror(errno));
|
if (camera->sensor_fd < 0) {
|
||||||
return -1;
|
log_error("Could not open %s: %s\n", camera->sensor_path, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
camera->video_fd = open(camera->video_path, O_RDWR);
|
camera->video_fd = open(camera->video_path, O_RDWR);
|
||||||
@@ -147,9 +151,16 @@ libmegapixels_open(libmegapixels_camera *camera)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = load_entity_ids(camera);
|
// If this is an UVC camera the sensor _is_ the video device
|
||||||
if (ret < 0) {
|
if (camera->sensor_fd == 0) {
|
||||||
return ret;
|
camera->sensor_fd = camera->video_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (camera->media_fd > 0) {
|
||||||
|
int ret = load_entity_ids(camera);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -158,6 +169,11 @@ libmegapixels_open(libmegapixels_camera *camera)
|
|||||||
void
|
void
|
||||||
libmegapixels_close(libmegapixels_camera *camera)
|
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) {
|
if (camera->media_fd != 0) {
|
||||||
close(camera->media_fd);
|
close(camera->media_fd);
|
||||||
camera->media_fd = 0;
|
camera->media_fd = 0;
|
||||||
@@ -165,6 +181,9 @@ libmegapixels_close(libmegapixels_camera *camera)
|
|||||||
if (camera->sensor_fd != 0) {
|
if (camera->sensor_fd != 0) {
|
||||||
close(camera->sensor_fd);
|
close(camera->sensor_fd);
|
||||||
camera->sensor_fd = 0;
|
camera->sensor_fd = 0;
|
||||||
|
if (uvc) {
|
||||||
|
camera->video_fd = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (camera->video_fd != 0) {
|
if (camera->video_fd != 0) {
|
||||||
close(camera->video_fd);
|
close(camera->video_fd);
|
||||||
|
@@ -33,14 +33,19 @@ main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
libmegapixels_devconfig *config = {0};
|
libmegapixels_devconfig *config = {0};
|
||||||
|
libmegapixels_init(&config);
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
printf("No config found\n");
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
printf("Using config: %s\n", configpath);
|
|
||||||
|
|
||||||
if (!libmegapixels_load_file(&config, configpath)) {
|
libmegapixels_load_uvc(config);
|
||||||
|
if (config->count == 0) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,9 +54,13 @@ main(int argc, char *argv[])
|
|||||||
|
|
||||||
for (int i = 0; i < config->count; i++) {
|
for (int i = 0; i < config->count; i++) {
|
||||||
printf("\n----[ Camera %s (%d) ]----\n", config->cameras[i]->name, i);
|
printf("\n----[ Camera %s (%d) ]----\n", config->cameras[i]->name, i);
|
||||||
printf("Media : %s (%s)\n", config->cameras[i]->bridge_name, config->cameras[i]->media_path);
|
if (config->cameras[i]->bridge_name) {
|
||||||
printf("Sensor: %s (%s)\n", config->cameras[i]->sensor_name, config->cameras[i]->sensor_path);
|
printf("Media : %s (%s)\n", config->cameras[i]->bridge_name, config->cameras[i]->media_path);
|
||||||
printf("Bridge: %s\n", config->cameras[i]->video_path);
|
}
|
||||||
|
if (config->cameras[i]->sensor_name) {
|
||||||
|
printf("Sensor: %s (%s)\n", config->cameras[i]->sensor_name, config->cameras[i]->sensor_path);
|
||||||
|
}
|
||||||
|
printf("Video : %s\n", config->cameras[i]->video_path);
|
||||||
printf("Modes : ");
|
printf("Modes : ");
|
||||||
for (int j = 0; j < config->cameras[i]->num_modes; j++) {
|
for (int j = 0; j < config->cameras[i]->num_modes; j++) {
|
||||||
if (j > 0) {
|
if (j > 0) {
|
||||||
|
@@ -67,21 +67,24 @@ main(int argc, char *argv[])
|
|||||||
char configpath[PATH_MAX];
|
char configpath[PATH_MAX];
|
||||||
int ret = libmegapixels_find_config(configpath);
|
int ret = libmegapixels_find_config(configpath);
|
||||||
libmegapixels_devconfig *config = {0};
|
libmegapixels_devconfig *config = {0};
|
||||||
|
libmegapixels_init(&config);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printf("Using config: %s\n", configpath);
|
printf("Using config: %s\n", configpath);
|
||||||
libmegapixels_load_file(&config, configpath);
|
libmegapixels_load_file(config, configpath);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "No config found for this device\n");
|
fprintf(stderr, "No config found for this device\n");
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
libmegapixels_load_uvc(config);
|
||||||
|
|
||||||
if (config->count == 0) {
|
if (config->count == 0) {
|
||||||
fprintf(stderr, "No valid camera configuration\n");
|
fprintf(stderr, "No valid camera configuration\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (camera_id > config->count) {
|
if (camera_id > config->count - 1) {
|
||||||
fprintf(stderr, "Camera id %d does not exist\n", camera_id);
|
fprintf(stderr, "Camera id %d does not exist\n", camera_id);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
libmegapixels_camera *camera = config->cameras[camera_id];
|
libmegapixels_camera *camera = config->cameras[camera_id];
|
||||||
|
Reference in New Issue
Block a user