mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-07-17 17:21:55 +00:00
refactoring
This commit is contained in:
@@ -108,23 +108,6 @@ static int _capture_open_queue_buffers(us_capture_s *cap);
|
||||
static int _capture_open_export_to_dma(us_capture_s *cap);
|
||||
static int _capture_apply_resolution(us_capture_s *cap, uint width, uint height, float hz);
|
||||
|
||||
static void _capture_apply_controls(const us_capture_s *cap);
|
||||
|
||||
static int _capture_query_control(
|
||||
const us_capture_s *cap,
|
||||
struct v4l2_queryctrl *query,
|
||||
const char *name,
|
||||
uint cid,
|
||||
bool quiet);
|
||||
|
||||
static void _capture_set_control(
|
||||
const us_capture_s *cap,
|
||||
const struct v4l2_queryctrl *query,
|
||||
const char *name,
|
||||
uint cid,
|
||||
int value,
|
||||
bool quiet);
|
||||
|
||||
static const char *_format_to_string_nullable(uint format);
|
||||
static const char *_format_to_string_supported(uint format);
|
||||
static const char *_standard_to_string(v4l2_std_id standard);
|
||||
@@ -160,11 +143,13 @@ us_capture_s *us_capture_init(void) {
|
||||
cap->n_bufs = us_get_cores_available() + 1;
|
||||
cap->min_frame_size = 128;
|
||||
cap->timeout = 1;
|
||||
cap->ctl = us_controls_init();
|
||||
cap->run = run;
|
||||
return cap;
|
||||
}
|
||||
|
||||
void us_capture_destroy(us_capture_s *cap) {
|
||||
us_controls_destroy(cap->ctl);
|
||||
free(cap->run);
|
||||
free(cap);
|
||||
}
|
||||
@@ -283,7 +268,7 @@ int us_capture_open(us_capture_s *cap) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
_capture_apply_controls(cap);
|
||||
us_controls_apply(cap->ctl, cap->run->fd);
|
||||
|
||||
enum v4l2_buf_type type = run->capture_type;
|
||||
if (us_xioctl(run->fd, VIDIOC_STREAMON, &type) < 0) {
|
||||
@@ -1361,111 +1346,6 @@ static int _capture_apply_resolution(us_capture_s *cap, uint width, uint height,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _capture_apply_controls(const us_capture_s *cap) {
|
||||
# define SET_CID_VALUE(x_cid, x_field, x_value, x_quiet) { \
|
||||
struct v4l2_queryctrl m_query; \
|
||||
if (_capture_query_control(cap, &m_query, #x_field, x_cid, x_quiet) == 0) { \
|
||||
_capture_set_control(cap, &m_query, #x_field, x_cid, x_value, x_quiet); \
|
||||
} \
|
||||
}
|
||||
|
||||
# define SET_CID_DEFAULT(x_cid, x_field, x_quiet) { \
|
||||
struct v4l2_queryctrl m_query; \
|
||||
if (_capture_query_control(cap, &m_query, #x_field, x_cid, x_quiet) == 0) { \
|
||||
_capture_set_control(cap, &m_query, #x_field, x_cid, m_query.default_value, x_quiet); \
|
||||
} \
|
||||
}
|
||||
|
||||
# define CONTROL_MANUAL_CID(x_cid, x_field) { \
|
||||
if (cap->ctl.x_field.mode == CTL_MODE_VALUE) { \
|
||||
SET_CID_VALUE(x_cid, x_field, cap->ctl.x_field.value, false); \
|
||||
} else if (cap->ctl.x_field.mode == CTL_MODE_DEFAULT) { \
|
||||
SET_CID_DEFAULT(x_cid, x_field, false); \
|
||||
} \
|
||||
}
|
||||
|
||||
# define CONTROL_AUTO_CID(x_cid_auto, x_cid_manual, x_field) { \
|
||||
if (cap->ctl.x_field.mode == CTL_MODE_VALUE) { \
|
||||
SET_CID_VALUE(x_cid_auto, x_field##_auto, 0, true); \
|
||||
SET_CID_VALUE(x_cid_manual, x_field, cap->ctl.x_field.value, false); \
|
||||
} else if (cap->ctl.x_field.mode == CTL_MODE_AUTO) { \
|
||||
SET_CID_VALUE(x_cid_auto, x_field##_auto, 1, false); \
|
||||
} else if (cap->ctl.x_field.mode == CTL_MODE_DEFAULT) { \
|
||||
SET_CID_VALUE(x_cid_auto, x_field##_auto, 0, true); /* Reset inactive flag */ \
|
||||
SET_CID_DEFAULT(x_cid_manual, x_field, false); \
|
||||
SET_CID_DEFAULT(x_cid_auto, x_field##_auto, false); \
|
||||
} \
|
||||
}
|
||||
|
||||
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);
|
||||
CONTROL_MANUAL_CID ( V4L2_CID_COLORFX, color_effect);
|
||||
CONTROL_MANUAL_CID ( V4L2_CID_ROTATE, rotate);
|
||||
CONTROL_MANUAL_CID ( V4L2_CID_VFLIP, flip_vertical);
|
||||
CONTROL_MANUAL_CID ( V4L2_CID_HFLIP, flip_horizontal);
|
||||
|
||||
# undef CONTROL_AUTO_CID
|
||||
# undef CONTROL_MANUAL_CID
|
||||
# undef SET_CID_DEFAULT
|
||||
# undef SET_CID_VALUE
|
||||
}
|
||||
|
||||
static int _capture_query_control(
|
||||
const us_capture_s *cap,
|
||||
struct v4l2_queryctrl *query,
|
||||
const char *name,
|
||||
uint cid,
|
||||
bool quiet
|
||||
) {
|
||||
// cppcheck-suppress redundantPointerOp
|
||||
US_MEMSET_ZERO(*query);
|
||||
query->id = cid;
|
||||
|
||||
if (us_xioctl(cap->run->fd, VIDIOC_QUERYCTRL, query) < 0 || query->flags & V4L2_CTRL_FLAG_DISABLED) {
|
||||
if (!quiet) {
|
||||
_LOG_ERROR("Changing control %s is unsupported", name);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _capture_set_control(
|
||||
const us_capture_s *cap,
|
||||
const struct v4l2_queryctrl *query,
|
||||
const char *name,
|
||||
uint cid,
|
||||
int value,
|
||||
bool quiet
|
||||
) {
|
||||
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;
|
||||
}
|
||||
|
||||
struct v4l2_control ctl = {
|
||||
.id = cid,
|
||||
.value = value,
|
||||
};
|
||||
if (us_xioctl(cap->run->fd, VIDIOC_S_CTRL, &ctl) < 0) {
|
||||
if (!quiet) {
|
||||
_LOG_PERROR("Can't set control %s", name);
|
||||
}
|
||||
} else if (!quiet) {
|
||||
_LOG_INFO("Applying control %s: %d", name, ctl.value);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *_format_to_string_nullable(uint format) {
|
||||
US_ARRAY_ITERATE(_FORMATS, 0, item, {
|
||||
if (item->format == format) {
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
#include "types.h"
|
||||
#include "frame.h"
|
||||
#include "media.h"
|
||||
#include "controls.h"
|
||||
|
||||
|
||||
#define US_VIDEO_MIN_WIDTH ((uint)160)
|
||||
@@ -51,11 +53,6 @@ typedef struct {
|
||||
atomic_int refs;
|
||||
} us_capture_hwbuf_s;
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
uint pad;
|
||||
} us_media_pad_s;
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
int dv_timings_fd;
|
||||
@@ -76,34 +73,6 @@ typedef struct {
|
||||
int open_error_once;
|
||||
} us_capture_runtime_s;
|
||||
|
||||
typedef enum {
|
||||
CTL_MODE_NONE = 0,
|
||||
CTL_MODE_VALUE,
|
||||
CTL_MODE_AUTO,
|
||||
CTL_MODE_DEFAULT,
|
||||
} us_control_mode_e;
|
||||
|
||||
typedef struct {
|
||||
us_control_mode_e mode;
|
||||
int value;
|
||||
} us_control_s;
|
||||
|
||||
typedef struct {
|
||||
us_control_s brightness;
|
||||
us_control_s contrast;
|
||||
us_control_s saturation;
|
||||
us_control_s hue;
|
||||
us_control_s gamma;
|
||||
us_control_s sharpness;
|
||||
us_control_s backlight_compensation;
|
||||
us_control_s white_balance;
|
||||
us_control_s gain;
|
||||
us_control_s color_effect;
|
||||
us_control_s rotate;
|
||||
us_control_s flip_vertical;
|
||||
us_control_s flip_horizontal;
|
||||
} us_controls_s;
|
||||
|
||||
typedef struct {
|
||||
char *path;
|
||||
uint input;
|
||||
@@ -125,7 +94,7 @@ typedef struct {
|
||||
bool allow_truncated_frames;
|
||||
bool persistent;
|
||||
uint timeout;
|
||||
us_controls_s ctl;
|
||||
us_controls_s *ctl;
|
||||
us_capture_runtime_s *run;
|
||||
} us_capture_s;
|
||||
|
||||
|
||||
173
src/libs/controls.c
Normal file
173
src/libs/controls.c
Normal file
@@ -0,0 +1,173 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "controls.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/v4l2-controls.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "tools.h"
|
||||
#include "logging.h"
|
||||
#include "xioctl.h"
|
||||
|
||||
|
||||
static int _query_control(
|
||||
int fd,
|
||||
struct v4l2_queryctrl *query,
|
||||
const char *name,
|
||||
uint cid,
|
||||
bool quiet);
|
||||
|
||||
static void _set_control(
|
||||
int fd,
|
||||
const struct v4l2_queryctrl *query,
|
||||
const char *name,
|
||||
uint cid,
|
||||
int value,
|
||||
bool quiet);
|
||||
|
||||
|
||||
#define _LOG_ERROR(x_msg, ...) US_LOG_ERROR("CAP: " x_msg, ##__VA_ARGS__)
|
||||
#define _LOG_PERROR(x_msg, ...) US_LOG_PERROR("CAP: " x_msg, ##__VA_ARGS__)
|
||||
#define _LOG_INFO(x_msg, ...) US_LOG_INFO("CAP: " x_msg, ##__VA_ARGS__)
|
||||
|
||||
|
||||
us_controls_s *us_controls_init(void) {
|
||||
us_controls_s *ctl;
|
||||
US_CALLOC(ctl, 1);
|
||||
return ctl;
|
||||
}
|
||||
|
||||
void us_controls_destroy(us_controls_s *ctl) {
|
||||
free(ctl);
|
||||
}
|
||||
|
||||
void us_controls_apply(const us_controls_s *ctl, int fd) {
|
||||
# define SET_CID_VALUE(x_cid, x_field, x_value, x_quiet) { \
|
||||
struct v4l2_queryctrl m_query; \
|
||||
if (_query_control(fd, &m_query, #x_field, x_cid, x_quiet) == 0) { \
|
||||
_set_control(fd, &m_query, #x_field, x_cid, x_value, x_quiet); \
|
||||
} \
|
||||
}
|
||||
|
||||
# define SET_CID_DEFAULT(x_cid, x_field, x_quiet) { \
|
||||
struct v4l2_queryctrl m_query; \
|
||||
if (_query_control(fd, &m_query, #x_field, x_cid, x_quiet) == 0) { \
|
||||
_set_control(fd, &m_query, #x_field, x_cid, m_query.default_value, x_quiet); \
|
||||
} \
|
||||
}
|
||||
|
||||
# define CONTROL_MANUAL_CID(x_cid, x_field) { \
|
||||
if (ctl->x_field.mode == US_CTL_MODE_VALUE) { \
|
||||
SET_CID_VALUE(x_cid, x_field, ctl->x_field.value, false); \
|
||||
} else if (ctl->x_field.mode == US_CTL_MODE_DEFAULT) { \
|
||||
SET_CID_DEFAULT(x_cid, x_field, false); \
|
||||
} \
|
||||
}
|
||||
|
||||
# define CONTROL_AUTO_CID(x_cid_auto, x_cid_manual, x_field) { \
|
||||
if (ctl->x_field.mode == US_CTL_MODE_VALUE) { \
|
||||
SET_CID_VALUE(x_cid_auto, x_field##_auto, 0, true); \
|
||||
SET_CID_VALUE(x_cid_manual, x_field, ctl->x_field.value, false); \
|
||||
} else if (ctl->x_field.mode == US_CTL_MODE_AUTO) { \
|
||||
SET_CID_VALUE(x_cid_auto, x_field##_auto, 1, false); \
|
||||
} else if (ctl->x_field.mode == US_CTL_MODE_DEFAULT) { \
|
||||
SET_CID_VALUE(x_cid_auto, x_field##_auto, 0, true); /* Reset inactive flag */ \
|
||||
SET_CID_DEFAULT(x_cid_manual, x_field, false); \
|
||||
SET_CID_DEFAULT(x_cid_auto, x_field##_auto, false); \
|
||||
} \
|
||||
}
|
||||
|
||||
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);
|
||||
CONTROL_MANUAL_CID ( V4L2_CID_COLORFX, color_effect);
|
||||
CONTROL_MANUAL_CID ( V4L2_CID_ROTATE, rotate);
|
||||
CONTROL_MANUAL_CID ( V4L2_CID_VFLIP, flip_vertical);
|
||||
CONTROL_MANUAL_CID ( V4L2_CID_HFLIP, flip_horizontal);
|
||||
|
||||
# undef CONTROL_AUTO_CID
|
||||
# undef CONTROL_MANUAL_CID
|
||||
# undef SET_CID_DEFAULT
|
||||
# undef SET_CID_VALUE
|
||||
}
|
||||
|
||||
static int _query_control(
|
||||
int fd,
|
||||
struct v4l2_queryctrl *query,
|
||||
const char *name,
|
||||
uint cid,
|
||||
bool quiet
|
||||
) {
|
||||
// cppcheck-suppress redundantPointerOp
|
||||
US_MEMSET_ZERO(*query);
|
||||
query->id = cid;
|
||||
|
||||
if (us_xioctl(fd, VIDIOC_QUERYCTRL, query) < 0 || query->flags & V4L2_CTRL_FLAG_DISABLED) {
|
||||
if (!quiet) {
|
||||
_LOG_ERROR("Changing control %s is unsupported", name);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _set_control(
|
||||
int fd,
|
||||
const struct v4l2_queryctrl *query,
|
||||
const char *name,
|
||||
uint cid,
|
||||
int value,
|
||||
bool quiet
|
||||
) {
|
||||
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;
|
||||
}
|
||||
|
||||
struct v4l2_control ctl = {
|
||||
.id = cid,
|
||||
.value = value,
|
||||
};
|
||||
if (us_xioctl(fd, VIDIOC_S_CTRL, &ctl) < 0) {
|
||||
if (!quiet) {
|
||||
_LOG_PERROR("Can't set control %s", name);
|
||||
}
|
||||
} else if (!quiet) {
|
||||
_LOG_INFO("Applying control %s: %d", name, ctl.value);
|
||||
}
|
||||
}
|
||||
60
src/libs/controls.h
Normal file
60
src/libs/controls.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*****************************************************************************
|
||||
# #
|
||||
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
|
||||
# #
|
||||
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
|
||||
typedef enum {
|
||||
US_CTL_MODE_NONE = 0,
|
||||
US_CTL_MODE_VALUE,
|
||||
US_CTL_MODE_AUTO,
|
||||
US_CTL_MODE_DEFAULT,
|
||||
} us_control_mode_e;
|
||||
|
||||
typedef struct {
|
||||
us_control_mode_e mode;
|
||||
int value;
|
||||
} us_control_s;
|
||||
|
||||
typedef struct {
|
||||
us_control_s brightness;
|
||||
us_control_s contrast;
|
||||
us_control_s saturation;
|
||||
us_control_s hue;
|
||||
us_control_s gamma;
|
||||
us_control_s sharpness;
|
||||
us_control_s backlight_compensation;
|
||||
us_control_s white_balance;
|
||||
us_control_s gain;
|
||||
us_control_s color_effect;
|
||||
us_control_s rotate;
|
||||
us_control_s flip_vertical;
|
||||
us_control_s flip_horizontal;
|
||||
} us_controls_s;
|
||||
|
||||
|
||||
us_controls_s *us_controls_init(void);
|
||||
void us_controls_destroy(us_controls_s *ctl);
|
||||
|
||||
void us_controls_apply(const us_controls_s *ctl, int fd);
|
||||
@@ -29,6 +29,12 @@
|
||||
#include "types.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
uint pad;
|
||||
} us_media_pad_s;
|
||||
|
||||
|
||||
int us_media_find_link(
|
||||
struct media_v2_topology *topology,
|
||||
u32 link_type,
|
||||
|
||||
@@ -379,15 +379,15 @@ int us_options_parse(
|
||||
}
|
||||
|
||||
# define OPT_CTL_DEFAULT_NOBREAK(x_dest) { \
|
||||
cap->ctl.x_dest.mode = CTL_MODE_DEFAULT; \
|
||||
cap->ctl->x_dest.mode = US_CTL_MODE_DEFAULT; \
|
||||
}
|
||||
|
||||
# define OPT_CTL_MANUAL(x_dest) { \
|
||||
if (!strcasecmp(optarg, "default")) { \
|
||||
OPT_CTL_DEFAULT_NOBREAK(x_dest); \
|
||||
} else { \
|
||||
cap->ctl.x_dest.mode = CTL_MODE_VALUE; \
|
||||
OPT_NUMBER("--"#x_dest, cap->ctl.x_dest.value, INT_MIN, INT_MAX, 0); \
|
||||
cap->ctl->x_dest.mode = US_CTL_MODE_VALUE; \
|
||||
OPT_NUMBER("--"#x_dest, cap->ctl->x_dest.value, INT_MIN, INT_MAX, 0); \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
@@ -396,10 +396,10 @@ int us_options_parse(
|
||||
if (!strcasecmp(optarg, "default")) { \
|
||||
OPT_CTL_DEFAULT_NOBREAK(x_dest); \
|
||||
} else if (!strcasecmp(optarg, "auto")) { \
|
||||
cap->ctl.x_dest.mode = CTL_MODE_AUTO; \
|
||||
cap->ctl->x_dest.mode = US_CTL_MODE_AUTO; \
|
||||
} else { \
|
||||
cap->ctl.x_dest.mode = CTL_MODE_VALUE; \
|
||||
OPT_NUMBER("--"#x_dest, cap->ctl.x_dest.value, INT_MIN, INT_MAX, 0); \
|
||||
cap->ctl->x_dest.mode = US_CTL_MODE_VALUE; \
|
||||
OPT_NUMBER("--"#x_dest, cap->ctl->x_dest.value, INT_MIN, INT_MAX, 0); \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user