From 09fc14d63d5d3eef0935bfc84a50b8ff967efe72 Mon Sep 17 00:00:00 2001 From: Devaev Maxim Date: Tue, 5 Mar 2019 09:54:15 +0300 Subject: [PATCH] First implementation of image settings --- src/device.c | 45 +++++++++++++++++++++++++++++ src/device.h | 17 +++++++++++ src/main.c | 81 ++++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 124 insertions(+), 19 deletions(-) diff --git a/src/device.c b/src/device.c index 697aa64..5ef620c 100644 --- a/src/device.c +++ b/src/device.c @@ -65,6 +65,7 @@ static int _device_open_check_cap(struct device_t *dev); static int _device_open_dv_timings(struct device_t *dev); static int _device_apply_dv_timings(struct device_t *dev); static int _device_open_format(struct device_t *dev); +static void _device_open_set_image_settings(struct device_t *dev); static void _device_open_alloc_picbufs(struct device_t *dev); static int _device_open_mmap(struct device_t *dev); static int _device_open_queue_buffers(struct device_t *dev); @@ -77,9 +78,12 @@ static const char *_standard_to_string(v4l2_std_id standard); struct device_t *device_init() { + struct image_settings_t *img; struct device_runtime_t *run; struct device_t *dev; + A_CALLOC(img, 1); + A_CALLOC(run, 1); run->fd = -1; @@ -93,12 +97,14 @@ struct device_t *device_init() { dev->n_workers = dev->n_buffers; dev->timeout = 1; dev->error_delay = 1; + dev->img = img; dev->run = run; return dev; } void device_destroy(struct device_t *dev) { free(dev->run); + free(dev->img); free(dev); } @@ -136,6 +142,7 @@ int device_open(struct device_t *dev) { if (_device_open_format(dev) < 0) { goto error; } + _device_open_set_image_settings(dev); if (_device_open_mmap(dev) < 0) { goto error; } @@ -350,6 +357,44 @@ static int _device_open_format(struct device_t *dev) { return 0; } +static void _device_open_set_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) { \ + LOG_INFO("Changing image " #_dest " is unsupported"); \ + } else { \ + MEMSET_ZERO(ctl); ctl.id = _cid; ctl.value = (int)dev->img->_dest; \ + if (xioctl(dev->run->fd, VIDIOC_S_CTRL, &ctl) < 0) { LOG_PERROR("Can't set image " #_dest); } \ + else { LOG_INFO("Using image " #_dest ": %d", ctl.value); } \ + } \ + } + +# define SET_CID_MANUAL(_cid, _dest) { \ + if (dev->img->_dest##_set) { SET_CID(_cid, _dest); } \ + } + +# 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); } \ + } \ + } + + SET_CID_AUTO (V4L2_CID_AUTOBRIGHTNESS, V4L2_CID_BRIGHTNESS, brightness); + SET_CID_MANUAL ( V4L2_CID_CONTRAST, contrast); + SET_CID_MANUAL ( V4L2_CID_SATURATION, saturation); + SET_CID_AUTO (V4L2_CID_HUE_AUTO, V4L2_CID_HUE, hue); + SET_CID_MANUAL ( V4L2_CID_GAMMA, gamma); + SET_CID_MANUAL ( V4L2_CID_SHARPNESS, sharpness); + +# undef SET_CID_AUTO +# undef SET_CID_MANUAL +# undef SET_CID +} + static int _device_open_mmap(struct device_t *dev) { struct v4l2_requestbuffers req; diff --git a/src/device.h b/src/device.h index a04fb91..cc6e007 100644 --- a/src/device.h +++ b/src/device.h @@ -69,6 +69,21 @@ 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); +}; + +#undef S_AUTO +#undef S_MANUAL + struct device_t { char *path; unsigned input; @@ -85,6 +100,8 @@ struct device_t { unsigned timeout; unsigned error_delay; + struct image_settings_t *img; + struct device_runtime_t *run; sig_atomic_t volatile stop; }; diff --git a/src/main.c b/src/main.c index 2b0df9b..718ab7d 100644 --- a/src/main.c +++ b/src/main.c @@ -60,15 +60,24 @@ static const struct option _long_opts[] = { {"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}, + {"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, 2001}, - {"fake-height", required_argument, NULL, 2002}, - {"server-timeout", required_argument, NULL, 2003}, + {"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}, @@ -122,6 +131,16 @@ 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 -- 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("---------------\n"); + printf(" --image-brightness -- Set brightness. Default: no change.\n\n"); + printf(" --image-brightness-auto -- Enable automatic brightness control. Default: no change.\n\n"); + printf(" --image-contrast -- Set contrast. Default: no change.\n\n"); + printf(" --image-saturation -- Set saturation. Default: no change.\n\n"); + printf(" --image-hue -- Set hue. Default: no change.\n\n"); + printf(" --image-hue-auto -- Enable automatic hue control. Default: no change.\n\n"); + printf(" --image-gamma -- Set gamma. Default: no change.\n\n"); + printf(" --image-sharpness -- Set sharpness. Default: no change.\n\n"); printf("HTTP server options:\n"); printf("--------------------\n"); printf(" -s|--host
-- Listen on Hostname or IP. Default: %s\n\n", server->host); @@ -152,22 +171,34 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct e # define OPT_SET(_dest, _value) \ { _dest = _value; break; } -# define OPT_UNSIGNED(_dest, _name, _min, _max) \ - { errno = 0; char *_end = NULL; int _tmp = strtol(optarg, &_end, 0); \ - if (errno || *_end || _tmp < _min || _tmp > _max) \ - { printf("Invalid value for '%s=%s'; min=%u; max=%u\n", _name, optarg, _min, _max); return -1; } \ - _dest = _tmp; break; } +# define OPT_UNSIGNED(_dest, _name, _min, _max) { \ + errno = 0; char *_end = NULL; int _tmp = strtol(optarg, &_end, 0); \ + if (errno || *_end || _tmp < _min || _tmp > _max) { \ + printf("Invalid value for '%s=%s'; min=%u; max=%u\n", _name, optarg, _min, _max); \ + return -1; \ + } _dest = _tmp; break; } -# define OPT_PARSE(_dest, _func, _invalid, _name) \ - { if ((_dest = _func(optarg)) == _invalid) \ - { printf("Unknown " _name ": %s\n", optarg); return -1; } \ - break; } +# define OPT_PARSE(_dest, _func, _invalid, _name) { \ + if ((_dest = _func(optarg)) == _invalid) { \ + printf("Unknown " _name ": %s\n", optarg); \ + return -1; \ + } break; } + +# define OPT_INT(_dest, _name, _base) { \ + errno = 0; char *_end = NULL; int _tmp = strtol(optarg, &_end, _base); \ + if (errno || *_end) { \ + printf("Invalid value for '%s=%s'\n", _name, optarg); \ + return -1; \ + } _dest = _tmp; break; } # define OPT_CHMOD(_dest, _name) \ - { errno = 0; char *_end = NULL; int _tmp = strtol(optarg, &_end, 8); \ - if (errno || *_end) \ - { printf("Invalid value for '%s=%s'\n", _name, optarg); return -1; } \ - _dest = _tmp; break; } + 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_IMG_AUTO(_dest) \ + { dev->img->_dest##_set = true; dev->img->_dest##_auto = true; break; } int index; int ch; @@ -195,15 +226,24 @@ 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 's': OPT_SET(server->host, optarg); case 'p': OPT_UNSIGNED(server->port, "--port", 1, 65535); case 'u': OPT_SET(server->unix_path, optarg); case 'r': OPT_SET(server->unix_rm, true); case 'o': OPT_CHMOD(server->unix_mode, "--unix-mode"); case 'e': OPT_UNSIGNED(server->drop_same_frames, "--drop-same-frames", 0, 30); - case 2001: OPT_UNSIGNED(server->fake_width, "--fake-width", 0, 1920); - case 2002: OPT_UNSIGNED(server->fake_height, "--fake-height", 0, 1200); - case 2003: OPT_UNSIGNED(server->timeout, "--server-timeout", 1, 60); + case 3001: OPT_UNSIGNED(server->fake_width, "--fake-width", 0, 1920); + case 3002: OPT_UNSIGNED(server->fake_height, "--fake-height", 0, 1200); + case 3003: OPT_UNSIGNED(server->timeout, "--server-timeout", 1, 60); case 5000: OPT_SET(log_level, LOG_LEVEL_PERF); case 5001: OPT_SET(log_level, LOG_LEVEL_VERBOSE); @@ -216,7 +256,10 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct e } } +# undef OPT_IMG_AUTO +# undef OPT_IMG # undef OPT_CHMOD +# undef OPT_INT # undef OPT_PARSE # undef OPT_UNSIGNED # undef OPT_SET