mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-03-01 21:26:33 +00:00
big controls refactoring
This commit is contained in:
87
src/device.c
87
src/device.c
@@ -69,7 +69,9 @@ static int _device_open_mmap(struct device_t *dev);
|
||||
static int _device_open_queue_buffers(struct device_t *dev);
|
||||
static void _device_open_alloc_picbufs(struct device_t *dev);
|
||||
static int _device_apply_resolution(struct device_t *dev, unsigned width, unsigned height);
|
||||
static void _device_apply_image_settings(struct device_t *dev);
|
||||
static void _device_apply_controls(struct device_t *dev);
|
||||
static int _device_check_control(struct device_t *dev, const char *name, unsigned cid, int value, bool quiet);
|
||||
static void _device_set_control(struct device_t *dev, const char *name, unsigned cid, int value, bool quiet);
|
||||
|
||||
static const char *_format_to_string_fourcc(char *buf, size_t size, unsigned format);
|
||||
static const char *_format_to_string_nullable(unsigned format);
|
||||
@@ -78,11 +80,11 @@ static const char *_standard_to_string(v4l2_std_id standard);
|
||||
|
||||
|
||||
struct device_t *device_init() {
|
||||
struct image_settings_t *img;
|
||||
struct controls_t *ctl;
|
||||
struct device_runtime_t *run;
|
||||
struct device_t *dev;
|
||||
|
||||
A_CALLOC(img, 1);
|
||||
A_CALLOC(ctl, 1);
|
||||
|
||||
A_CALLOC(run, 1);
|
||||
run->fd = -1;
|
||||
@@ -97,14 +99,14 @@ struct device_t *device_init() {
|
||||
dev->n_workers = dev->n_buffers;
|
||||
dev->timeout = 1;
|
||||
dev->error_delay = 1;
|
||||
dev->img = img;
|
||||
dev->ctl = ctl;
|
||||
dev->run = run;
|
||||
return dev;
|
||||
}
|
||||
|
||||
void device_destroy(struct device_t *dev) {
|
||||
free(dev->run);
|
||||
free(dev->img);
|
||||
free(dev->ctl);
|
||||
free(dev);
|
||||
}
|
||||
|
||||
@@ -149,7 +151,7 @@ int device_open(struct device_t *dev) {
|
||||
goto error;
|
||||
}
|
||||
_device_open_alloc_picbufs(dev);
|
||||
_device_apply_image_settings(dev);
|
||||
_device_apply_controls(dev);
|
||||
|
||||
LOG_DEBUG("Device fd=%d initialized", dev->run->fd);
|
||||
return 0;
|
||||
@@ -460,38 +462,23 @@ static int _device_apply_resolution(struct device_t *dev, unsigned width, unsign
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _device_apply_image_settings(struct device_t *dev) {
|
||||
struct v4l2_queryctrl query;
|
||||
struct v4l2_control ctl;
|
||||
|
||||
# define SET_CID(_cid, _dest) { \
|
||||
MEMSET_ZERO(query); query.id = _cid; \
|
||||
if (xioctl(dev->run->fd, VIDIOC_QUERYCTRL, &query) < 0 || query.flags & V4L2_CTRL_FLAG_DISABLED) { \
|
||||
LOG_INFO("Changing image " #_dest " is unsupported"); \
|
||||
} else { \
|
||||
MEMSET_ZERO(ctl); ctl.id = _cid; ctl.value = (int)dev->img->_dest; \
|
||||
if (ctl.value < query.minimum || ctl.value > query.maximum || ctl.value % query.step != 0) { \
|
||||
LOG_ERROR("Invalid value %d for image " #_dest ": min=%d, max=%d, default=%d, step=%u", \
|
||||
ctl.value, query.minimum, query.maximum, query.default_value, query.step); \
|
||||
} else { \
|
||||
if (xioctl(dev->run->fd, VIDIOC_S_CTRL, &ctl) < 0) { \
|
||||
LOG_PERROR("Can't set image " #_dest); \
|
||||
} else { \
|
||||
LOG_INFO("Using image " #_dest ": %d (min=%d, max=%d, default=%d, step=%u)", \
|
||||
ctl.value, query.minimum, query.maximum, query.default_value, query.step); \
|
||||
} \
|
||||
} \
|
||||
static void _device_apply_controls(struct device_t *dev) {
|
||||
# define SET_CID(_cid, _dest, _value, _quiet) { \
|
||||
if (_device_check_control(dev, #_dest, _cid, _value, _quiet) == 0) { \
|
||||
_device_set_control(dev, #_dest, _cid, _value, _quiet); \
|
||||
} \
|
||||
}
|
||||
|
||||
# define SET_CID_MANUAL(_cid, _dest) { \
|
||||
if (dev->img->_dest##_set) { SET_CID(_cid, _dest); } \
|
||||
if (dev->ctl->_dest.value_set) { \
|
||||
SET_CID(_cid, _dest, dev->ctl->_dest.value, false); \
|
||||
} \
|
||||
}
|
||||
|
||||
# define SET_CID_AUTO(_cid_auto, _cid_manual, _dest) { \
|
||||
if (dev->img->_dest##_set) { \
|
||||
SET_CID(_cid_auto, _dest##_auto); \
|
||||
if (!dev->img->_dest##_auto) { SET_CID(_cid_manual, _dest); } \
|
||||
if (dev->ctl->_dest.value_set || dev->ctl->_dest.auto_set) { \
|
||||
SET_CID(_cid_auto, _dest##_auto, dev->ctl->_dest.auto_set, dev->ctl->_dest.value_set); \
|
||||
SET_CID_MANUAL(_cid_manual, _dest); \
|
||||
} \
|
||||
}
|
||||
|
||||
@@ -510,6 +497,44 @@ static void _device_apply_image_settings(struct device_t *dev) {
|
||||
# undef SET_CID
|
||||
}
|
||||
|
||||
static int _device_check_control(struct device_t *dev, const char *name, unsigned cid, int value, bool quiet) {
|
||||
struct v4l2_queryctrl query;
|
||||
|
||||
MEMSET_ZERO(query);
|
||||
query.id = cid;
|
||||
|
||||
if (xioctl(dev->run->fd, VIDIOC_QUERYCTRL, &query) < 0 || query.flags & V4L2_CTRL_FLAG_DISABLED) {
|
||||
if (!quiet) {
|
||||
LOG_ERROR("Changing control %s is unsupported", name);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (value < query.minimum || value > query.maximum || value % query.step != 0) {
|
||||
if (!quiet) {
|
||||
LOG_ERROR("Invalid value %d of control %s: min=%d, max=%d, default=%d, step=%u",
|
||||
value, name, query.minimum, query.maximum, query.default_value, query.step);
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _device_set_control(struct device_t *dev, const char *name, unsigned cid, int value, bool quiet) {
|
||||
struct v4l2_control ctl;
|
||||
|
||||
MEMSET_ZERO(ctl);
|
||||
ctl.id = cid;
|
||||
ctl.value = value;
|
||||
|
||||
if (xioctl(dev->run->fd, VIDIOC_S_CTRL, &ctl) < 0) {
|
||||
if (!quiet) {
|
||||
LOG_PERROR("Can't set control %s", name);
|
||||
}
|
||||
} else if (!quiet) {
|
||||
LOG_INFO("Using control %s: %d", name, ctl.value);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *_format_to_string_fourcc(char *buf, size_t size, unsigned format) {
|
||||
assert(size >= 8);
|
||||
buf[0] = format & 0x7F;
|
||||
|
||||
32
src/device.h
32
src/device.h
@@ -69,23 +69,23 @@ struct device_runtime_t {
|
||||
bool capturing;
|
||||
};
|
||||
|
||||
#define S_MANUAL(_dest) int _dest; bool _dest##_set;
|
||||
#define S_AUTO(_dest) int _dest; bool _dest##_set; bool _dest##_auto;
|
||||
|
||||
struct image_settings_t {
|
||||
S_AUTO (brightness);
|
||||
S_MANUAL (contrast);
|
||||
S_MANUAL (saturation);
|
||||
S_AUTO (hue);
|
||||
S_MANUAL (gamma);
|
||||
S_MANUAL (sharpness);
|
||||
S_MANUAL (backlight_compensation);
|
||||
S_AUTO (white_balance);
|
||||
S_AUTO (gain);
|
||||
struct control_t {
|
||||
int value;
|
||||
bool value_set;
|
||||
bool auto_set;
|
||||
};
|
||||
|
||||
#undef S_AUTO
|
||||
#undef S_MANUAL
|
||||
struct controls_t {
|
||||
struct control_t brightness;
|
||||
struct control_t contrast;
|
||||
struct control_t saturation;
|
||||
struct control_t hue;
|
||||
struct control_t gamma;
|
||||
struct control_t sharpness;
|
||||
struct control_t backlight_compensation;
|
||||
struct control_t white_balance;
|
||||
struct control_t gain;
|
||||
};
|
||||
|
||||
struct device_t {
|
||||
char *path;
|
||||
@@ -103,7 +103,7 @@ struct device_t {
|
||||
unsigned timeout;
|
||||
unsigned error_delay;
|
||||
|
||||
struct image_settings_t *img;
|
||||
struct controls_t *ctl;
|
||||
|
||||
struct device_runtime_t *run;
|
||||
sig_atomic_t volatile stop;
|
||||
|
||||
164
src/main.c
164
src/main.c
@@ -43,53 +43,53 @@
|
||||
|
||||
static const char _short_opts[] = "d:i:x:y:m:a:f:z:tb:w:q:c:s:p:u:ro:e:h";
|
||||
static const struct option _long_opts[] = {
|
||||
{"device", required_argument, NULL, 'd'},
|
||||
{"input", required_argument, NULL, 'i'},
|
||||
{"width", required_argument, NULL, 'x'},
|
||||
{"height", required_argument, NULL, 'y'},
|
||||
{"format", required_argument, NULL, 'm'},
|
||||
{"tv-standard", required_argument, NULL, 'a'},
|
||||
{"desired-fps", required_argument, NULL, 'f'},
|
||||
{"min-frame-size", required_argument, NULL, 'z'},
|
||||
{"dv-timings", no_argument, NULL, 't'},
|
||||
{"buffers", required_argument, NULL, 'b'},
|
||||
{"workers", required_argument, NULL, 'w'},
|
||||
{"quality", required_argument, NULL, 'q'},
|
||||
{"encoder", required_argument, NULL, 'c'},
|
||||
{"device-timeout", required_argument, NULL, 1000},
|
||||
{"device-persistent", no_argument, NULL, 1001},
|
||||
{"device-error-delay", required_argument, NULL, 1002},
|
||||
{"device", required_argument, NULL, 'd'},
|
||||
{"input", required_argument, NULL, 'i'},
|
||||
{"width", required_argument, NULL, 'x'},
|
||||
{"height", required_argument, NULL, 'y'},
|
||||
{"format", required_argument, NULL, 'm'},
|
||||
{"tv-standard", required_argument, NULL, 'a'},
|
||||
{"desired-fps", required_argument, NULL, 'f'},
|
||||
{"min-frame-size", required_argument, NULL, 'z'},
|
||||
{"dv-timings", no_argument, NULL, 't'},
|
||||
{"buffers", required_argument, NULL, 'b'},
|
||||
{"workers", required_argument, NULL, 'w'},
|
||||
{"quality", required_argument, NULL, 'q'},
|
||||
{"encoder", required_argument, NULL, 'c'},
|
||||
{"device-timeout", required_argument, NULL, 1000},
|
||||
{"device-persistent", no_argument, NULL, 1001},
|
||||
{"device-error-delay", required_argument, NULL, 1002},
|
||||
|
||||
{"image-brightness", required_argument, NULL, 2000},
|
||||
{"image-brightness-auto", no_argument, NULL, 2001},
|
||||
{"image-contrast", required_argument, NULL, 2002},
|
||||
{"image-saturation", required_argument, NULL, 2003},
|
||||
{"image-hue", required_argument, NULL, 2004},
|
||||
{"image-hue-auto", no_argument, NULL, 2005},
|
||||
{"image-gamma", required_argument, NULL, 2006},
|
||||
{"image-sharpness", required_argument, NULL, 2007},
|
||||
{"image-backlight-compensation", required_argument, NULL, 2008},
|
||||
{"image-white-balance", required_argument, NULL, 2009},
|
||||
{"image-white-balance-auto", no_argument, NULL, 2010},
|
||||
{"image-gain", required_argument, NULL, 2011},
|
||||
{"image-gain-auto", no_argument, NULL, 2012},
|
||||
{"brightness", required_argument, NULL, 2000},
|
||||
{"brightness-auto", no_argument, NULL, 2001},
|
||||
{"contrast", required_argument, NULL, 2002},
|
||||
{"saturation", required_argument, NULL, 2003},
|
||||
{"hue", required_argument, NULL, 2004},
|
||||
{"hue-auto", no_argument, NULL, 2005},
|
||||
{"gamma", required_argument, NULL, 2006},
|
||||
{"sharpness", required_argument, NULL, 2007},
|
||||
{"backlight-compensation", required_argument, NULL, 2008},
|
||||
{"white-balance", required_argument, NULL, 2009},
|
||||
{"white-balance-auto", no_argument, NULL, 2010},
|
||||
{"gain", required_argument, NULL, 2011},
|
||||
{"gain-auto", no_argument, NULL, 2012},
|
||||
|
||||
{"host", required_argument, NULL, 's'},
|
||||
{"port", required_argument, NULL, 'p'},
|
||||
{"unix", required_argument, NULL, 'u'},
|
||||
{"unix-rm", no_argument, NULL, 'r'},
|
||||
{"unix-mode", required_argument, NULL, 'o'},
|
||||
{"drop-same-frames", required_argument, NULL, 'e'},
|
||||
{"fake-width", required_argument, NULL, 3001},
|
||||
{"fake-height", required_argument, NULL, 3002},
|
||||
{"server-timeout", required_argument, NULL, 3003},
|
||||
{"host", required_argument, NULL, 's'},
|
||||
{"port", required_argument, NULL, 'p'},
|
||||
{"unix", required_argument, NULL, 'u'},
|
||||
{"unix-rm", no_argument, NULL, 'r'},
|
||||
{"unix-mode", required_argument, NULL, 'o'},
|
||||
{"drop-same-frames", required_argument, NULL, 'e'},
|
||||
{"fake-width", required_argument, NULL, 3001},
|
||||
{"fake-height", required_argument, NULL, 3002},
|
||||
{"server-timeout", required_argument, NULL, 3003},
|
||||
|
||||
{"perf", no_argument, NULL, 5000},
|
||||
{"verbose", no_argument, NULL, 5001},
|
||||
{"debug", no_argument, NULL, 5002},
|
||||
{"log-level", required_argument, NULL, 5010},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"version", no_argument, NULL, 6000},
|
||||
{"perf", no_argument, NULL, 5000},
|
||||
{"verbose", no_argument, NULL, 5001},
|
||||
{"debug", no_argument, NULL, 5002},
|
||||
{"log-level", required_argument, NULL, 5010},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"version", no_argument, NULL, 6000},
|
||||
{NULL, 0, NULL, 0},
|
||||
};
|
||||
|
||||
@@ -136,21 +136,21 @@ static void _help(struct device_t *dev, struct encoder_t *encoder, struct http_s
|
||||
printf(" --device-persistent -- Don't re-initialize device on timeout. Default: disabled.\n\n");
|
||||
printf(" --device-error-delay <seconds> -- Delay before trying to connect to the device again\n");
|
||||
printf(" after a timeout. Default: %u\n\n", dev->error_delay);
|
||||
printf("Image options:\n");
|
||||
printf("Image control options:\n");
|
||||
printf("---------------\n");
|
||||
printf(" --image-brightness <N> -- Set brightness. Default: no change.\n\n");
|
||||
printf(" --image-brightness-auto -- Enable automatic brightness control. Default: no change.\n\n");
|
||||
printf(" --image-contrast <N> -- Set contrast. Default: no change.\n\n");
|
||||
printf(" --image-saturation <N> -- Set saturation. Default: no change.\n\n");
|
||||
printf(" --image-hue <N> -- Set hue. Default: no change.\n\n");
|
||||
printf(" --image-hue-auto -- Enable automatic hue control. Default: no change.\n\n");
|
||||
printf(" --image-gamma <N> -- Set gamma. Default: no change.\n\n");
|
||||
printf(" --image-sharpness <N> -- Set sharpness. Default: no change.\n\n");
|
||||
printf(" --image-backlight-compensation <N> -- Set backlight compensation. Default: no change.\n\n");
|
||||
printf(" --image-white-balance <N> -- Set white balance. Default: no change.\n\n");
|
||||
printf(" --image-white-balance-auto -- Enable automatic white balance control. Default: no change.\n\n");
|
||||
printf(" --image-gain <N> -- Set gain. Default: no change.\n\n");
|
||||
printf(" --image-gain-auto -- Enable automatic gain control. Default: no change.\n\n");
|
||||
printf(" --brightness <N> -- Set brightness. Default: no change.\n\n");
|
||||
printf(" --brightness-auto -- Enable automatic brightness control. Default: no change.\n\n");
|
||||
printf(" --contrast <N> -- Set contrast. Default: no change.\n\n");
|
||||
printf(" --saturation <N> -- Set saturation. Default: no change.\n\n");
|
||||
printf(" --hue <N> -- Set hue. Default: no change.\n\n");
|
||||
printf(" --hue-auto -- Enable automatic hue control. Default: no change.\n\n");
|
||||
printf(" --gamma <N> -- Set gamma. Default: no change.\n\n");
|
||||
printf(" --sharpness <N> -- Set sharpness. Default: no change.\n\n");
|
||||
printf(" --backlight-compensation <N> -- Set backlight compensation. Default: no change.\n\n");
|
||||
printf(" --white-balance <N> -- Set white balance. Default: no change.\n\n");
|
||||
printf(" --white-balance-auto -- Enable automatic white balance control. Default: no change.\n\n");
|
||||
printf(" --gain <N> -- Set gain. Default: no change.\n\n");
|
||||
printf(" --gain-auto -- Enable automatic gain control. Default: no change.\n\n");
|
||||
printf("HTTP server options:\n");
|
||||
printf("--------------------\n");
|
||||
printf(" -s|--host <address> -- Listen on Hostname or IP. Default: %s\n\n", server->host);
|
||||
@@ -209,13 +209,21 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct e
|
||||
break; \
|
||||
}
|
||||
|
||||
# define OPT_CHMOD(_dest, _name) OPT_INT(_dest, _name, 8)
|
||||
# define OPT_CHMOD(_dest, _name) \
|
||||
OPT_INT(_dest, _name, 8)
|
||||
|
||||
# define OPT_IMG(_dest) \
|
||||
{ dev->img->_dest##_set = true; OPT_INT(dev->img->_dest, "--image-"#_dest, 10); break; }
|
||||
# define OPT_CTL(_dest) { \
|
||||
dev->ctl->_dest.value_set = true; \
|
||||
dev->ctl->_dest.auto_set = false; \
|
||||
OPT_INT(dev->ctl->_dest.value, "--"#_dest, 10); \
|
||||
break; \
|
||||
}
|
||||
|
||||
# define OPT_IMG_AUTO(_dest) \
|
||||
{ dev->img->_dest##_set = true; dev->img->_dest##_auto = true; break; }
|
||||
# define OPT_CTL_AUTO(_dest) { \
|
||||
dev->ctl->_dest.value_set = false; \
|
||||
dev->ctl->_dest.auto_set = true; \
|
||||
break; \
|
||||
}
|
||||
|
||||
int index;
|
||||
int ch;
|
||||
@@ -243,19 +251,19 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct e
|
||||
case 1001: OPT_SET(dev->persistent, true);
|
||||
case 1002: OPT_UNSIGNED(dev->error_delay, "--device-error-delay", 1, 60);
|
||||
|
||||
case 2000: OPT_IMG(brightness);
|
||||
case 2001: OPT_IMG_AUTO(brightness);
|
||||
case 2002: OPT_IMG(contrast);
|
||||
case 2003: OPT_IMG(saturation);
|
||||
case 2004: OPT_IMG(hue);
|
||||
case 2005: OPT_IMG_AUTO(hue);
|
||||
case 2006: OPT_IMG(gamma);
|
||||
case 2007: OPT_IMG(sharpness);
|
||||
case 2008: OPT_IMG(backlight_compensation);
|
||||
case 2009: OPT_IMG(white_balance);
|
||||
case 2010: OPT_IMG_AUTO(white_balance);
|
||||
case 2011: OPT_IMG(gain);
|
||||
case 2012: OPT_IMG_AUTO(gain);
|
||||
case 2000: OPT_CTL(brightness);
|
||||
case 2001: OPT_CTL_AUTO(brightness);
|
||||
case 2002: OPT_CTL(contrast);
|
||||
case 2003: OPT_CTL(saturation);
|
||||
case 2004: OPT_CTL(hue);
|
||||
case 2005: OPT_CTL_AUTO(hue);
|
||||
case 2006: OPT_CTL(gamma);
|
||||
case 2007: OPT_CTL(sharpness);
|
||||
case 2008: OPT_CTL(backlight_compensation);
|
||||
case 2009: OPT_CTL(white_balance);
|
||||
case 2010: OPT_CTL_AUTO(white_balance);
|
||||
case 2011: OPT_CTL(gain);
|
||||
case 2012: OPT_CTL_AUTO(gain);
|
||||
|
||||
case 's': OPT_SET(server->host, optarg);
|
||||
case 'p': OPT_UNSIGNED(server->port, "--port", 1, 65535);
|
||||
@@ -278,8 +286,8 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct e
|
||||
}
|
||||
}
|
||||
|
||||
# undef OPT_IMG_AUTO
|
||||
# undef OPT_IMG
|
||||
# undef OPT_CTL_AUTO
|
||||
# undef OPT_CTL
|
||||
# undef OPT_CHMOD
|
||||
# undef OPT_INT
|
||||
# undef OPT_PARSE
|
||||
|
||||
Reference in New Issue
Block a user