big controls refactoring

This commit is contained in:
Devaev Maxim
2019-03-12 23:46:19 +03:00
parent 22be6443ef
commit 8a2a0474b2
3 changed files with 158 additions and 125 deletions

View File

@@ -69,7 +69,9 @@ static int _device_open_mmap(struct device_t *dev);
static int _device_open_queue_buffers(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 void _device_open_alloc_picbufs(struct device_t *dev);
static int _device_apply_resolution(struct device_t *dev, unsigned width, unsigned height); 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_fourcc(char *buf, size_t size, unsigned format);
static const char *_format_to_string_nullable(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 device_t *device_init() {
struct image_settings_t *img; struct controls_t *ctl;
struct device_runtime_t *run; struct device_runtime_t *run;
struct device_t *dev; struct device_t *dev;
A_CALLOC(img, 1); A_CALLOC(ctl, 1);
A_CALLOC(run, 1); A_CALLOC(run, 1);
run->fd = -1; run->fd = -1;
@@ -97,14 +99,14 @@ struct device_t *device_init() {
dev->n_workers = dev->n_buffers; dev->n_workers = dev->n_buffers;
dev->timeout = 1; dev->timeout = 1;
dev->error_delay = 1; dev->error_delay = 1;
dev->img = img; dev->ctl = ctl;
dev->run = run; dev->run = run;
return dev; return dev;
} }
void device_destroy(struct device_t *dev) { void device_destroy(struct device_t *dev) {
free(dev->run); free(dev->run);
free(dev->img); free(dev->ctl);
free(dev); free(dev);
} }
@@ -149,7 +151,7 @@ int device_open(struct device_t *dev) {
goto error; goto error;
} }
_device_open_alloc_picbufs(dev); _device_open_alloc_picbufs(dev);
_device_apply_image_settings(dev); _device_apply_controls(dev);
LOG_DEBUG("Device fd=%d initialized", dev->run->fd); LOG_DEBUG("Device fd=%d initialized", dev->run->fd);
return 0; return 0;
@@ -460,38 +462,23 @@ static int _device_apply_resolution(struct device_t *dev, unsigned width, unsign
return 0; return 0;
} }
static void _device_apply_image_settings(struct device_t *dev) { static void _device_apply_controls(struct device_t *dev) {
struct v4l2_queryctrl query; # define SET_CID(_cid, _dest, _value, _quiet) { \
struct v4l2_control ctl; if (_device_check_control(dev, #_dest, _cid, _value, _quiet) == 0) { \
_device_set_control(dev, #_dest, _cid, _value, _quiet); \
# 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); \
} \
} \
} \ } \
} }
# define SET_CID_MANUAL(_cid, _dest) { \ # 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) { \ # define SET_CID_AUTO(_cid_auto, _cid_manual, _dest) { \
if (dev->img->_dest##_set) { \ if (dev->ctl->_dest.value_set || dev->ctl->_dest.auto_set) { \
SET_CID(_cid_auto, _dest##_auto); \ SET_CID(_cid_auto, _dest##_auto, dev->ctl->_dest.auto_set, dev->ctl->_dest.value_set); \
if (!dev->img->_dest##_auto) { SET_CID(_cid_manual, _dest); } \ SET_CID_MANUAL(_cid_manual, _dest); \
} \ } \
} }
@@ -510,6 +497,44 @@ static void _device_apply_image_settings(struct device_t *dev) {
# undef SET_CID # 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) { static const char *_format_to_string_fourcc(char *buf, size_t size, unsigned format) {
assert(size >= 8); assert(size >= 8);
buf[0] = format & 0x7F; buf[0] = format & 0x7F;

View File

@@ -69,23 +69,23 @@ struct device_runtime_t {
bool capturing; bool capturing;
}; };
#define S_MANUAL(_dest) int _dest; bool _dest##_set; struct control_t {
#define S_AUTO(_dest) int _dest; bool _dest##_set; bool _dest##_auto; int value;
bool value_set;
struct image_settings_t { bool auto_set;
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);
}; };
#undef S_AUTO struct controls_t {
#undef S_MANUAL 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 { struct device_t {
char *path; char *path;
@@ -103,7 +103,7 @@ struct device_t {
unsigned timeout; unsigned timeout;
unsigned error_delay; unsigned error_delay;
struct image_settings_t *img; struct controls_t *ctl;
struct device_runtime_t *run; struct device_runtime_t *run;
sig_atomic_t volatile stop; sig_atomic_t volatile stop;

View File

@@ -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 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[] = { static const struct option _long_opts[] = {
{"device", required_argument, NULL, 'd'}, {"device", required_argument, NULL, 'd'},
{"input", required_argument, NULL, 'i'}, {"input", required_argument, NULL, 'i'},
{"width", required_argument, NULL, 'x'}, {"width", required_argument, NULL, 'x'},
{"height", required_argument, NULL, 'y'}, {"height", required_argument, NULL, 'y'},
{"format", required_argument, NULL, 'm'}, {"format", required_argument, NULL, 'm'},
{"tv-standard", required_argument, NULL, 'a'}, {"tv-standard", required_argument, NULL, 'a'},
{"desired-fps", required_argument, NULL, 'f'}, {"desired-fps", required_argument, NULL, 'f'},
{"min-frame-size", required_argument, NULL, 'z'}, {"min-frame-size", required_argument, NULL, 'z'},
{"dv-timings", no_argument, NULL, 't'}, {"dv-timings", no_argument, NULL, 't'},
{"buffers", required_argument, NULL, 'b'}, {"buffers", required_argument, NULL, 'b'},
{"workers", required_argument, NULL, 'w'}, {"workers", required_argument, NULL, 'w'},
{"quality", required_argument, NULL, 'q'}, {"quality", required_argument, NULL, 'q'},
{"encoder", required_argument, NULL, 'c'}, {"encoder", required_argument, NULL, 'c'},
{"device-timeout", required_argument, NULL, 1000}, {"device-timeout", required_argument, NULL, 1000},
{"device-persistent", no_argument, NULL, 1001}, {"device-persistent", no_argument, NULL, 1001},
{"device-error-delay", required_argument, NULL, 1002}, {"device-error-delay", required_argument, NULL, 1002},
{"image-brightness", required_argument, NULL, 2000}, {"brightness", required_argument, NULL, 2000},
{"image-brightness-auto", no_argument, NULL, 2001}, {"brightness-auto", no_argument, NULL, 2001},
{"image-contrast", required_argument, NULL, 2002}, {"contrast", required_argument, NULL, 2002},
{"image-saturation", required_argument, NULL, 2003}, {"saturation", required_argument, NULL, 2003},
{"image-hue", required_argument, NULL, 2004}, {"hue", required_argument, NULL, 2004},
{"image-hue-auto", no_argument, NULL, 2005}, {"hue-auto", no_argument, NULL, 2005},
{"image-gamma", required_argument, NULL, 2006}, {"gamma", required_argument, NULL, 2006},
{"image-sharpness", required_argument, NULL, 2007}, {"sharpness", required_argument, NULL, 2007},
{"image-backlight-compensation", required_argument, NULL, 2008}, {"backlight-compensation", required_argument, NULL, 2008},
{"image-white-balance", required_argument, NULL, 2009}, {"white-balance", required_argument, NULL, 2009},
{"image-white-balance-auto", no_argument, NULL, 2010}, {"white-balance-auto", no_argument, NULL, 2010},
{"image-gain", required_argument, NULL, 2011}, {"gain", required_argument, NULL, 2011},
{"image-gain-auto", no_argument, NULL, 2012}, {"gain-auto", no_argument, NULL, 2012},
{"host", required_argument, NULL, 's'}, {"host", required_argument, NULL, 's'},
{"port", required_argument, NULL, 'p'}, {"port", required_argument, NULL, 'p'},
{"unix", required_argument, NULL, 'u'}, {"unix", required_argument, NULL, 'u'},
{"unix-rm", no_argument, NULL, 'r'}, {"unix-rm", no_argument, NULL, 'r'},
{"unix-mode", required_argument, NULL, 'o'}, {"unix-mode", required_argument, NULL, 'o'},
{"drop-same-frames", required_argument, NULL, 'e'}, {"drop-same-frames", required_argument, NULL, 'e'},
{"fake-width", required_argument, NULL, 3001}, {"fake-width", required_argument, NULL, 3001},
{"fake-height", required_argument, NULL, 3002}, {"fake-height", required_argument, NULL, 3002},
{"server-timeout", required_argument, NULL, 3003}, {"server-timeout", required_argument, NULL, 3003},
{"perf", no_argument, NULL, 5000}, {"perf", no_argument, NULL, 5000},
{"verbose", no_argument, NULL, 5001}, {"verbose", no_argument, NULL, 5001},
{"debug", no_argument, NULL, 5002}, {"debug", no_argument, NULL, 5002},
{"log-level", required_argument, NULL, 5010}, {"log-level", required_argument, NULL, 5010},
{"help", no_argument, NULL, 'h'}, {"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 6000}, {"version", no_argument, NULL, 6000},
{NULL, 0, NULL, 0}, {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-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(" --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(" after a timeout. Default: %u\n\n", dev->error_delay);
printf("Image options:\n"); printf("Image control options:\n");
printf("---------------\n"); printf("---------------\n");
printf(" --image-brightness <N> -- Set brightness. Default: no change.\n\n"); printf(" --brightness <N> -- Set brightness. Default: no change.\n\n");
printf(" --image-brightness-auto -- Enable automatic brightness control. Default: no change.\n\n"); printf(" --brightness-auto -- Enable automatic brightness control. Default: no change.\n\n");
printf(" --image-contrast <N> -- Set contrast. Default: no change.\n\n"); printf(" --contrast <N> -- Set contrast. Default: no change.\n\n");
printf(" --image-saturation <N> -- Set saturation. Default: no change.\n\n"); printf(" --saturation <N> -- Set saturation. Default: no change.\n\n");
printf(" --image-hue <N> -- Set hue. Default: no change.\n\n"); printf(" --hue <N> -- Set hue. Default: no change.\n\n");
printf(" --image-hue-auto -- Enable automatic hue control. Default: no change.\n\n"); printf(" --hue-auto -- Enable automatic hue control. Default: no change.\n\n");
printf(" --image-gamma <N> -- Set gamma. Default: no change.\n\n"); printf(" --gamma <N> -- Set gamma. Default: no change.\n\n");
printf(" --image-sharpness <N> -- Set sharpness. Default: no change.\n\n"); printf(" --sharpness <N> -- Set sharpness. Default: no change.\n\n");
printf(" --image-backlight-compensation <N> -- Set backlight compensation. Default: no change.\n\n"); printf(" --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(" --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(" --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(" --gain <N> -- Set gain. Default: no change.\n\n");
printf(" --image-gain-auto -- Enable automatic gain control. Default: no change.\n\n"); printf(" --gain-auto -- Enable automatic gain control. Default: no change.\n\n");
printf("HTTP server options:\n"); printf("HTTP server options:\n");
printf("--------------------\n"); printf("--------------------\n");
printf(" -s|--host <address> -- Listen on Hostname or IP. Default: %s\n\n", server->host); 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; \ 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) \ # define OPT_CTL(_dest) { \
{ dev->img->_dest##_set = true; OPT_INT(dev->img->_dest, "--image-"#_dest, 10); break; } 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) \ # define OPT_CTL_AUTO(_dest) { \
{ dev->img->_dest##_set = true; dev->img->_dest##_auto = true; break; } dev->ctl->_dest.value_set = false; \
dev->ctl->_dest.auto_set = true; \
break; \
}
int index; int index;
int ch; 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 1001: OPT_SET(dev->persistent, true);
case 1002: OPT_UNSIGNED(dev->error_delay, "--device-error-delay", 1, 60); case 1002: OPT_UNSIGNED(dev->error_delay, "--device-error-delay", 1, 60);
case 2000: OPT_IMG(brightness); case 2000: OPT_CTL(brightness);
case 2001: OPT_IMG_AUTO(brightness); case 2001: OPT_CTL_AUTO(brightness);
case 2002: OPT_IMG(contrast); case 2002: OPT_CTL(contrast);
case 2003: OPT_IMG(saturation); case 2003: OPT_CTL(saturation);
case 2004: OPT_IMG(hue); case 2004: OPT_CTL(hue);
case 2005: OPT_IMG_AUTO(hue); case 2005: OPT_CTL_AUTO(hue);
case 2006: OPT_IMG(gamma); case 2006: OPT_CTL(gamma);
case 2007: OPT_IMG(sharpness); case 2007: OPT_CTL(sharpness);
case 2008: OPT_IMG(backlight_compensation); case 2008: OPT_CTL(backlight_compensation);
case 2009: OPT_IMG(white_balance); case 2009: OPT_CTL(white_balance);
case 2010: OPT_IMG_AUTO(white_balance); case 2010: OPT_CTL_AUTO(white_balance);
case 2011: OPT_IMG(gain); case 2011: OPT_CTL(gain);
case 2012: OPT_IMG_AUTO(gain); case 2012: OPT_CTL_AUTO(gain);
case 's': OPT_SET(server->host, optarg); case 's': OPT_SET(server->host, optarg);
case 'p': OPT_UNSIGNED(server->port, "--port", 1, 65535); 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_CTL_AUTO
# undef OPT_IMG # undef OPT_CTL
# undef OPT_CHMOD # undef OPT_CHMOD
# undef OPT_INT # undef OPT_INT
# undef OPT_PARSE # undef OPT_PARSE