-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexposure_manager.cpp
More file actions
144 lines (118 loc) · 4.47 KB
/
Copy pathexposure_manager.cpp
File metadata and controls
144 lines (118 loc) · 4.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include "exposure_manager.h"
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <cstring> // For memset and strerror
#include <algorithm> // For std::min and std::max
// --- 工具函数,源自 demo.cpp ---
// [修复] 移除了未被使用的 mapRange 函数以消除警告
// static double mapRange(int value, int in_min, int in_max, double out_min, double out_max) {
// return out_min + (double)(value - in_min) * (out_max - out_min) / (double)(in_max - in_min);
// }
static int mapRangeReverse(double value, double out_min, double out_max, int in_min, int in_max) {
return (int)(in_min + (value - out_min) * (in_max - in_min) / (out_max - out_min));
}
// --- 类实现 ---
ExposureManager::ExposureManager(std::string device_path)
: m_device_path(std::move(device_path)) {}
ExposureManager::~ExposureManager() {
stop();
}
void ExposureManager::start() {
m_stop_flag = false;
m_thread = std::thread(&ExposureManager::run, this);
}
void ExposureManager::stop() {
if (m_stop_flag.load()) return;
{
std::lock_guard<std::mutex> lock(m_mutex);
m_stop_flag = true;
}
m_cv.notify_one();
if (m_thread.joinable()) {
m_thread.join();
}
}
void ExposureManager::set_iso(int iso) {
std::lock_guard<std::mutex> lock(m_mutex);
m_iso_target = iso;
m_new_request = true;
m_cv.notify_one();
}
void ExposureManager::set_ev(double ev) {
std::lock_guard<std::mutex> lock(m_mutex);
m_ev_target = ev;
m_new_request = true;
m_cv.notify_one();
}
void ExposureManager::run() {
while (!m_stop_flag.load()) {
std::unique_lock<std::mutex> lock(m_mutex);
m_cv.wait(lock, [this] { return m_new_request || m_stop_flag.load(); });
if (m_stop_flag.load()) break;
if (m_new_request) {
apply_settings();
m_new_request = false; // 在锁内重置标志
}
}
}
void ExposureManager::apply_settings() {
// 这个函数在已持有锁的情况下被run()调用
int fd = open(m_device_path.c_str(), O_RDWR);
if (fd < 0) {
std::cerr << "[ExposureManager] 错误: 无法打开设备 " << m_device_path << ": " << strerror(errno) << std::endl;
// 重置请求,避免下次循环再次尝试
m_iso_target = -1;
m_ev_target = 999;
return;
}
struct v4l2_queryctrl qctrl;
struct v4l2_control ctrl;
int gain_min = 0, gain_max = 0;
int exp_min = 0, exp_max = 0;
// 查询增益(gain)控件
memset(&qctrl, 0, sizeof(qctrl));
qctrl.id = V4L2_CID_ANALOGUE_GAIN;
if (ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0) {
gain_min = qctrl.minimum;
gain_max = qctrl.maximum;
}
// 查询曝光(exposure)控件
memset(&qctrl, 0, sizeof(qctrl));
qctrl.id = V4L2_CID_EXPOSURE;
if (ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0) {
exp_min = qctrl.minimum;
exp_max = qctrl.maximum;
}
// 如果有ISO设置请求
if (m_iso_target != -1) {
int gain_target = mapRangeReverse(m_iso_target, 100.0, 1600.0, gain_min, gain_max);
gain_target = std::min(std::max(gain_target, gain_min), gain_max);
memset(&ctrl, 0, sizeof(ctrl));
ctrl.id = V4L2_CID_ANALOGUE_GAIN;
ctrl.value = gain_target;
if (ioctl(fd, VIDIOC_S_CTRL, &ctrl) == 0) {
std::cout << "[ExposureManager] 已设置 ISO=" << m_iso_target << " (对应 gain=" << gain_target << ")" << std::endl;
} else {
std::cerr << "[ExposureManager] 设置 ISO 失败: " << strerror(errno) << std::endl;
}
m_iso_target = -1; // 重置请求
}
// 如果有EV设置请求
if (m_ev_target != 999) {
int exp_target = mapRangeReverse(m_ev_target, -4.0, +4.0, exp_min, exp_max);
exp_target = std::min(std::max(exp_target, exp_min), exp_max);
memset(&ctrl, 0, sizeof(ctrl));
ctrl.id = V4L2_CID_EXPOSURE;
ctrl.value = exp_target;
if (ioctl(fd, VIDIOC_S_CTRL, &ctrl) == 0) {
std::cout << "[ExposureManager] 已设置 EV=" << m_ev_target << " (对应 exposure=" << exp_target << ")" << std::endl;
} else {
std::cerr << "[ExposureManager] 设置 EV 失败: " << strerror(errno) << std::endl;
}
m_ev_target = 999; // 重置请求
}
close(fd);
}