diff --git a/src/device.c b/src/device.c index e3d896e..364f1eb 100644 --- a/src/device.c +++ b/src/device.c @@ -77,9 +77,10 @@ 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_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 int _device_query_control(struct device_t *dev, struct v4l2_queryctrl *query, const char *name, unsigned cid, bool quiet); +static void _device_set_control(struct device_t *dev, struct v4l2_queryctrl *query, 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); @@ -610,65 +611,81 @@ static int _device_apply_resolution(struct device_t *dev, unsigned width, unsign } 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_VALUE(_cid, _field, _value, _quiet) { \ + struct v4l2_queryctrl query; \ + if (_device_query_control(dev, &query, #_field, _cid, _quiet) == 0) { \ + _device_set_control(dev, &query, #_field, _cid, _value, _quiet); \ } \ } -# define SET_CID_MANUAL(_cid, _dest) { \ - if (dev->ctl._dest.value_set) { \ - SET_CID(_cid, _dest, dev->ctl._dest.value, false); \ +# define SET_CID_DEFAULT(_cid, _field, _quiet) { \ + struct v4l2_queryctrl query; \ + if (_device_query_control(dev, &query, #_field, _cid, _quiet) == 0) { \ + _device_set_control(dev, &query, #_field, _cid, query.default_value, _quiet); \ } \ } -# define SET_CID_AUTO(_cid_auto, _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); \ +# define CONTROL_MANUAL_CID(_cid, _field) { \ + if (dev->ctl._field.value_set) { \ + SET_CID_VALUE(_cid, _field, dev->ctl._field.value, false); \ + } else if (dev->ctl._field.default_set) { \ + SET_CID_DEFAULT(_cid, _field, false); \ } \ } - 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); - SET_CID_MANUAL ( V4L2_CID_BACKLIGHT_COMPENSATION, backlight_compensation); - SET_CID_AUTO (V4L2_CID_AUTO_WHITE_BALANCE, V4L2_CID_WHITE_BALANCE_TEMPERATURE, white_balance); - SET_CID_AUTO (V4L2_CID_AUTOGAIN, V4L2_CID_GAIN, gain); +# define CONTROL_AUTO_CID(_cid_auto, _cid_manual, _field) { \ + if (dev->ctl._field.value_set) { \ + SET_CID_VALUE(_cid_auto, _field##_auto, 0, true); \ + SET_CID_VALUE(_cid_manual, _field, dev->ctl._field.value, false); \ + } else if (dev->ctl._field.auto_set) { \ + SET_CID_VALUE(_cid_auto, _field##_auto, 1, false); \ + } else if (dev->ctl._field.default_set) { \ + SET_CID_VALUE(_cid_auto, _field##_auto, 0, true); /* Reset inactive flag */ \ + SET_CID_DEFAULT(_cid_manual, _field, false); \ + SET_CID_DEFAULT(_cid_auto, _field##_auto, false); \ + } \ + } -# undef SET_CID_AUTO -# undef SET_CID_MANUAL -# undef SET_CID + CONTROL_AUTO_CID (V4L2_CID_AUTOBRIGHTNESS, V4L2_CID_BRIGHTNESS, brightness); + CONTROL_MANUAL_CID ( V4L2_CID_CONTRAST, contrast); + CONTROL_MANUAL_CID ( V4L2_CID_SATURATION, saturation); + CONTROL_AUTO_CID (V4L2_CID_HUE_AUTO, V4L2_CID_HUE, hue); + CONTROL_MANUAL_CID ( V4L2_CID_GAMMA, gamma); + CONTROL_MANUAL_CID ( V4L2_CID_SHARPNESS, sharpness); + CONTROL_MANUAL_CID ( V4L2_CID_BACKLIGHT_COMPENSATION, backlight_compensation); + CONTROL_AUTO_CID (V4L2_CID_AUTO_WHITE_BALANCE, V4L2_CID_WHITE_BALANCE_TEMPERATURE, white_balance); + CONTROL_AUTO_CID (V4L2_CID_AUTOGAIN, V4L2_CID_GAIN, gain); + +# undef CONTROL_AUTO_CID +# undef CONTROL_MANUAL_CID +# undef SET_CID_DEFAULT +# undef SET_CID_VALUE } -static int _device_check_control(struct device_t *dev, const char *name, unsigned cid, int value, bool quiet) { - struct v4l2_queryctrl query; +static int _device_query_control(struct device_t *dev, struct v4l2_queryctrl *query, const char *name, unsigned cid, bool quiet) { + MEMSET_ZERO(*query); + query->id = cid; - MEMSET_ZERO(query); - query.id = cid; - - if (xioctl(dev->run->fd, VIDIOC_QUERYCTRL, &query) < 0 || query.flags & V4L2_CTRL_FLAG_DISABLED) { + 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) { +static void _device_set_control(struct device_t *dev, struct v4l2_queryctrl *query, const char *name, unsigned cid, int value, bool quiet) { struct v4l2_control ctl; + 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; + } + MEMSET_ZERO(ctl); ctl.id = cid; ctl.value = value; @@ -678,7 +695,7 @@ static void _device_set_control(struct device_t *dev, const char *name, unsigned LOG_PERROR("Can't set control %s", name); } } else if (!quiet) { - LOG_INFO("Using control %s: %d", name, ctl.value); + LOG_INFO("Applying control %s: %d", name, ctl.value); } } diff --git a/src/device.h b/src/device.h index 6a6b2db..0b04ccc 100644 --- a/src/device.h +++ b/src/device.h @@ -68,6 +68,7 @@ struct control_t { int value; bool value_set; bool auto_set; + bool default_set; }; struct controls_t { diff --git a/src/options.c b/src/options.c index 714f3b2..80b5573 100644 --- a/src/options.c +++ b/src/options.c @@ -80,19 +80,29 @@ enum _OPT_VALUES { _O_DEVICE_TIMEOUT = 10000, _O_DEVICE_ERROR_DELAY, + _O_IMAGE_DEFAULT, _O_BRIGHTNESS, _O_BRIGHTNESS_AUTO, + _O_BRIGHTNESS_DEFAULT, _O_CONTRAST, + _O_CONTRAST_DEFAULT, _O_SATURATION, + _O_SATURATION_DEFAULT, _O_HUE, _O_HUE_AUTO, + _O_HUE_DEFAULT, _O_GAMMA, + _O_GAMMA_DEFAULT, _O_SHARPNESS, + _O_SHARPNESS_DEFAULT, _O_BACKLIGHT_COMPENSATION, + _O_BACKLIGHT_COMPENSATION_DEFAULT, _O_WHITE_BALANCE, _O_WHITE_BALANCE_AUTO, + _O_WHITE_BALANCE_DEFAULT, _O_GAIN, _O_GAIN_AUTO, + _O_GAIN_DEFAULT, _O_USER, _O_PASSWD, @@ -143,19 +153,29 @@ static const struct option _LONG_OPTS[] = { {"device-timeout", required_argument, NULL, _O_DEVICE_TIMEOUT}, {"device-error-delay", required_argument, NULL, _O_DEVICE_ERROR_DELAY}, + {"image-default", no_argument, NULL, _O_IMAGE_DEFAULT}, {"brightness", required_argument, NULL, _O_BRIGHTNESS}, {"brightness-auto", no_argument, NULL, _O_BRIGHTNESS_AUTO}, + {"brightness-default", no_argument, NULL, _O_BRIGHTNESS_DEFAULT}, {"contrast", required_argument, NULL, _O_CONTRAST}, + {"contrast-default", no_argument, NULL, _O_CONTRAST_DEFAULT}, {"saturation", required_argument, NULL, _O_SATURATION}, + {"saturation-default", no_argument, NULL, _O_SATURATION_DEFAULT}, {"hue", required_argument, NULL, _O_HUE}, {"hue-auto", no_argument, NULL, _O_HUE_AUTO}, + {"hue-default", no_argument, NULL, _O_HUE_DEFAULT}, {"gamma", required_argument, NULL, _O_GAMMA}, + {"gamma-default", no_argument, NULL, _O_GAMMA_DEFAULT}, {"sharpness", required_argument, NULL, _O_SHARPNESS}, + {"sharpness-default", no_argument, NULL, _O_SHARPNESS_DEFAULT}, {"backlight-compensation", required_argument, NULL, _O_BACKLIGHT_COMPENSATION}, + {"backlight-compensation-default", no_argument, NULL, _O_BACKLIGHT_COMPENSATION_DEFAULT}, {"white-balance", required_argument, NULL, _O_WHITE_BALANCE}, {"white-balance-auto", no_argument, NULL, _O_WHITE_BALANCE_AUTO}, + {"white-balance-default", no_argument, NULL, _O_WHITE_BALANCE_DEFAULT}, {"gain", required_argument, NULL, _O_GAIN}, {"gain-auto", no_argument, NULL, _O_GAIN_AUTO}, + {"gain-default", no_argument, NULL, _O_GAIN_DEFAULT}, {"host", required_argument, NULL, _O_HOST}, {"port", required_argument, NULL, _O_PORT}, @@ -278,6 +298,7 @@ int options_parse(struct options_t *options, struct device_t *dev, struct encode # define OPT_CTL(_dest) { \ dev->ctl._dest.value_set = true; \ dev->ctl._dest.auto_set = false; \ + dev->ctl._dest.default_set = false; \ OPT_NUMBER("--"#_dest, dev->ctl._dest.value, INT_MIN, INT_MAX, 0); \ break; \ } @@ -285,6 +306,18 @@ int options_parse(struct options_t *options, struct device_t *dev, struct encode # define OPT_CTL_AUTO(_dest) { \ dev->ctl._dest.value_set = false; \ dev->ctl._dest.auto_set = true; \ + dev->ctl._dest.default_set = false; \ + break; \ + } + +# define OPT_CTL_DEFAULT_NOBREAK(_dest) { \ + dev->ctl._dest.value_set = false; \ + dev->ctl._dest.auto_set = false; \ + dev->ctl._dest.default_set = true; \ + } + +# define OPT_CTL_DEFAULT(_dest) { \ + OPT_CTL_DEFAULT_NOBREAK(_dest); \ break; \ } @@ -335,19 +368,39 @@ int options_parse(struct options_t *options, struct device_t *dev, struct encode case _O_DEVICE_TIMEOUT: OPT_NUMBER("--device-timeout", dev->timeout, 1, 60, 0); case _O_DEVICE_ERROR_DELAY: OPT_NUMBER("--device-error-delay", dev->error_delay, 1, 60, 0); + case _O_IMAGE_DEFAULT: + OPT_CTL_DEFAULT_NOBREAK(brightness); + OPT_CTL_DEFAULT_NOBREAK(contrast); + OPT_CTL_DEFAULT_NOBREAK(saturation); + OPT_CTL_DEFAULT_NOBREAK(hue); + OPT_CTL_DEFAULT_NOBREAK(gamma); + OPT_CTL_DEFAULT_NOBREAK(sharpness); + OPT_CTL_DEFAULT_NOBREAK(backlight_compensation); + OPT_CTL_DEFAULT_NOBREAK(white_balance); + OPT_CTL_DEFAULT_NOBREAK(gain); + break; case _O_BRIGHTNESS: OPT_CTL(brightness); case _O_BRIGHTNESS_AUTO: OPT_CTL_AUTO(brightness); + case _O_BRIGHTNESS_DEFAULT: OPT_CTL_DEFAULT(brightness); case _O_CONTRAST: OPT_CTL(contrast); + case _O_CONTRAST_DEFAULT: OPT_CTL_DEFAULT(contrast); case _O_SATURATION: OPT_CTL(saturation); + case _O_SATURATION_DEFAULT: OPT_CTL_DEFAULT(saturation); case _O_HUE: OPT_CTL(hue); case _O_HUE_AUTO: OPT_CTL_AUTO(hue); + case _O_HUE_DEFAULT: OPT_CTL_DEFAULT(hue); case _O_GAMMA: OPT_CTL(gamma); + case _O_GAMMA_DEFAULT: OPT_CTL_DEFAULT(gamma); case _O_SHARPNESS: OPT_CTL(sharpness); + case _O_SHARPNESS_DEFAULT: OPT_CTL_DEFAULT(sharpness); case _O_BACKLIGHT_COMPENSATION: OPT_CTL(backlight_compensation); + case _O_BACKLIGHT_COMPENSATION_DEFAULT: OPT_CTL_DEFAULT(backlight_compensation); case _O_WHITE_BALANCE: OPT_CTL(white_balance); case _O_WHITE_BALANCE_AUTO: OPT_CTL_AUTO(white_balance); + case _O_WHITE_BALANCE_DEFAULT: OPT_CTL_DEFAULT(white_balance); case _O_GAIN: OPT_CTL(gain); case _O_GAIN_AUTO: OPT_CTL_AUTO(gain); + case _O_GAIN_DEFAULT: OPT_CTL_DEFAULT(gain); case _O_HOST: OPT_SET(server->host, optarg); case _O_PORT: OPT_NUMBER("--port", server->port, 1, 65535, 0); @@ -404,6 +457,8 @@ int options_parse(struct options_t *options, struct device_t *dev, struct encode } # endif +# undef OPT_CTL_DEFAULT +# undef OPT_CTL_DEFAULT_NOBREAK # undef OPT_CTL_AUTO # undef OPT_CTL # undef OPT_PARSE @@ -562,19 +617,29 @@ static void _help(struct device_t *dev, struct encoder_t *encoder, struct http_s printf(" after an error (timeout for example). Default: %u.\n\n", dev->error_delay); printf("Image control options:\n"); printf("══════════════════════\n"); - printf(" --brightness ───────────── Set brightness. Default: no change.\n\n"); - printf(" --brightness-auto ──────────── Enable automatic brightness control. Default: no change.\n\n"); - printf(" --contrast ─────────────── Set contrast. Default: no change.\n\n"); - printf(" --saturation ───────────── Set saturation. Default: no change.\n\n"); - printf(" --hue ──────────────────── Set hue. Default: no change.\n\n"); - printf(" --hue-auto ─────────────────── Enable automatic hue control. Default: no change.\n\n"); - printf(" --gamma ────────────────── Set gamma. Default: no change.\n\n"); - printf(" --sharpness ────────────── Set sharpness. Default: no change.\n\n"); - printf(" --backlight-compensation ─ Set backlight compensation. Default: no change.\n\n"); - printf(" --white-balance ────────── Set white balance. Default: no change.\n\n"); - printf(" --white-balance-auto ───────── Enable automatic white balance control. Default: no change.\n\n"); - printf(" --gain ─────────────────── Set gain. Default: no change.\n\n"); - printf(" --gain-auto ────────────────── Enable automatic gain control. Default: no change.\n\n"); + printf(" --image-default ────────────────── Reset all image settings bellow to default. Default: no change.\n\n"); + printf(" --brightness ───────────────── Set brightness. Default: no change.\n"); + printf(" --brightness-auto ──────────────── Enable automatic brightness control. Default: no change.\n"); + printf(" --brightness-default ───────────── Set default brightness. Default: no change.\n\n"); + printf(" --contrast ─────────────────── Set contrast. Default: no change.\n"); + printf(" --contrast-default ─────────────── Set default contrast. Default: no change.\n\n"); + printf(" --saturation ───────────────── Set saturation. Default: no change.\n"); + printf(" --saturation-default ───────────── Set default saturation. Default: no change.\n\n"); + printf(" --hue ──────────────────────── Set hue. Default: no change.\n"); + printf(" --hue-auto ─────────────────────── Enable automatic hue control. Default: no change.\n"); + printf(" --hue-default ──────────────────── Set default hue. Default: no change.\n\n"); + printf(" --gamma ────────────────────── Set gamma. Default: no change.\n"); + printf(" --gamma-default ────────────────── Set default gamma. Default: no change.\n\n"); + printf(" --sharpness ────────────────── Set sharpness. Default: no change.\n"); + printf(" --sharpness-default ────────────── Set default sharpness. Default: no change.\n\n"); + printf(" --backlight-compensation ───── Set backlight compensation. Default: no change.\n"); + printf(" --backlight-compensation-default ─ Set default backlight compensation. Default: no change.\n\n"); + printf(" --white-balance ────────────── Set white balance. Default: no change.\n"); + printf(" --white-balance-auto ───────────── Enable automatic white balance control. Default: no change.\n"); + printf(" --white-balance-default ────────── Set default white balance. Default: no change.\n\n"); + printf(" --gain ─────────────────────── Set gain. Default: no change.\n"); + printf(" --gain-auto ────────────────────── Enable automatic gain control. Default: no change.\n\n"); + printf(" --gain-default ─────────────────── Set default gain. 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);