1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "v4l2_control.h"
17
18 namespace OHOS::Camera {
HosV4L2Control()19 HosV4L2Control::HosV4L2Control() {}
~HosV4L2Control()20 HosV4L2Control::~HosV4L2Control() {}
21
V4L2SetCtrls(int fd,std::vector<DeviceControl> & control,const int numControls)22 RetCode HosV4L2Control::V4L2SetCtrls (int fd, std::vector<DeviceControl>& control, const int numControls)
23 {
24 int ret;
25 int count = 0;
26
27 if (numControls != control.size()) {
28 CAMERA_LOGE("HosV4L2Control::V4L2SetCtrls numControls != control.size()\n");
29 return RC_ERROR;
30 }
31
32 struct v4l2_ext_control cList[numControls];
33 for (auto itr = control.begin(); itr != control.end(); itr++) {
34 if (itr->flags & V4L2_CTRL_FLAG_READ_ONLY) {
35 continue;
36 }
37
38 if (count < numControls) {
39 cList[count].value = itr->value;
40 count++;
41 }
42 auto itrNext = itr + 1;
43 if (itrNext == control.end() || itr->ctrl_class != itrNext->ctrl_class) {
44 struct v4l2_ext_controls ctrls = {};
45 ctrls.ctrl_class = itr->ctrl_class;
46 ctrls.count = count;
47 ctrls.controls = cList;
48 ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls);
49 if (ret) {
50 CAMERA_LOGE("HosV4L2Control::VIDIOC_S_EXT_CTRLS set failed try to VIDIOC_S_CTRL\n");
51 struct v4l2_control ctrl;
52
53 for (int i = 0; count > 0; i++, count--) {
54 ctrl.id = cList[i].id;
55 ctrl.value = cList[i].value;
56 ret = ioctl(fd, VIDIOC_S_CTRL, &ctrl);
57 if (ret) {
58 CAMERA_LOGE("HosV4L2Control::V4L2SetCtrls VIDIOC_S_CTRL error i = %d\n", i);
59 continue;
60 }
61 }
62 }
63
64 count = 0;
65 }
66 }
67
68 return RC_OK;
69 }
70
V4L2GetCtrls(int fd,std::vector<DeviceControl> & control,const int numControls)71 RetCode HosV4L2Control::V4L2GetCtrls (int fd, std::vector<DeviceControl>& control, const int numControls)
72 {
73 int ret;
74 int count = 0;
75 auto iter = control.begin();
76
77 if (numControls != control.size()) {
78 CAMERA_LOGE("HosV4L2Control::V4L2GetCtrls numControls != control.size()\n");
79 return RC_ERROR;
80 }
81
82 struct v4l2_ext_control cList[numControls];
83 for (auto itr = control.begin(); itr != control.end(); itr++) {
84 if (itr->flags & V4L2_CTRL_FLAG_WRITE_ONLY) {
85 continue;
86 }
87 if (count < numControls) {
88 cList[count].id = itr->id;
89 count++;
90 }
91
92 auto itrNext = itr + 1;
93 if (itrNext == control.end() || itr->ctrl_class != itrNext->ctrl_class) {
94 struct v4l2_ext_controls ctrls = {};
95 ctrls.ctrl_class = itr->ctrl_class;
96 ctrls.count = count;
97 ctrls.controls = cList;
98 ret = ioctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls);
99 if (ret) {
100 CAMERA_LOGE("HosV4L2Control::VIDIOC_G_EXT_CTRLS set failed try to VIDIOC_S_CTRL\n");
101 struct v4l2_control ctrl;
102 for (int i = 0; count > 0; i++, count--) {
103 ctrl.id = cList[i].id;
104 ret = ioctl(fd, VIDIOC_G_CTRL, &ctrl);
105 if (ret) {
106 continue;
107 }
108
109 iter->value = ctrl.value;
110 iter++;
111 }
112 } else {
113 for (int i = 0; count > 0; i++, count--) {
114 iter->value = cList[i].value;
115 iter++;
116 }
117 }
118
119 count = 0;
120 }
121 }
122
123 return RC_OK;
124 }
125
V4L2GetCtrl(int fd,unsigned int id,int & value)126 RetCode HosV4L2Control::V4L2GetCtrl(int fd, unsigned int id, int& value)
127 {
128 int rc = 0;
129 struct v4l2_control ctrl;
130
131 ctrl.id = id;
132
133 rc = ioctl(fd, VIDIOC_G_CTRL, &ctrl);
134 if (rc < 0) {
135 CAMERA_LOGE("HosV4L2Control::V4L2GetCtrl error rc = %d", rc);
136 return RC_ERROR;
137 }
138
139 value = ctrl.value;
140
141 return RC_OK;
142 }
143
V4L2SetCtrl(int fd,unsigned int id,int value)144 RetCode HosV4L2Control::V4L2SetCtrl(int fd, unsigned int id, int value)
145 {
146 struct v4l2_control ctrl;
147 int rc;
148
149 CAMERA_LOGD("HosV4L2Control::V4L2SetCtrl value = %d\n", value);
150
151 ctrl.id = id;
152 ctrl.value = value;
153
154 rc = ioctl(fd, VIDIOC_S_CTRL, &ctrl);
155 if (rc < 0) {
156 CAMERA_LOGE("HosV4L2Control::V4L2SetCtrl error rc = %d", rc);
157 return RC_ERROR;
158 }
159
160 return RC_OK;
161 }
162
ExtControl(int fd,struct v4l2_queryctrl * ctrl)163 int HosV4L2Control::ExtControl(int fd, struct v4l2_queryctrl *ctrl)
164 {
165 int ret = 0;
166
167 if (ctrl == nullptr) {
168 CAMERA_LOGE("HosV4L2Control::ExtControl ctrl == nullptr");
169 return -1;
170 }
171
172 ctrl->id |= V4L2_CTRL_FLAG_NEXT_CTRL;
173 ret = ioctl(fd, VIDIOC_QUERYCTRL, ctrl);
174
175 return ret;
176 }
177
V4L2SetValue(int fd,std::vector<DeviceControl> & control,DeviceControl & ctrl,v4l2_queryctrl & qCtrl)178 void HosV4L2Control::V4L2SetValue(int fd, std::vector<DeviceControl>& control,
179 DeviceControl& ctrl, v4l2_queryctrl& qCtrl)
180 {
181 int value;
182 int rc;
183
184 ctrl.id = qCtrl.id;
185 ctrl.ctrl_class = V4L2_CTRL_ID2CLASS(qCtrl.id);
186 ctrl.type = qCtrl.type;
187 ctrl.minimum = qCtrl.minimum;
188 ctrl.maximum = qCtrl.maximum;
189 ctrl.step = qCtrl.step;
190 ctrl.default_value = qCtrl.default_value;
191 ctrl.flags = qCtrl.flags;
192 ctrl.name = std::string(reinterpret_cast<char*>(qCtrl.name));
193
194 if (qCtrl.type == V4L2_CTRL_TYPE_CTRL_CLASS) {
195 CAMERA_LOGD("%-14s\n", qCtrl.name);
196 control.push_back(ctrl);
197 return;
198 }
199
200 rc = V4L2GetCtrl(fd, qCtrl.id, value);
201 if (rc != RC_ERROR) {
202 ctrl.value = value;
203 CAMERA_LOGD("%-14s : id=%08x, type=%d, minimum=%d, maximum=%d\n"
204 "\t\t value = %d, step=%d, default_value=%d\n",
205 qCtrl.name, qCtrl.id, qCtrl.type, qCtrl.minimum, qCtrl.maximum,
206 value, qCtrl.step, qCtrl.default_value);
207 }
208 }
209
V4L2EnumExtControls(int fd,std::vector<DeviceControl> & control)210 void HosV4L2Control::V4L2EnumExtControls(int fd, std::vector<DeviceControl>& control)
211 {
212 struct v4l2_queryctrl qCtrl = {};
213 DeviceControl ctrl = {};
214 int rc;
215
216 qCtrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
217 while (!ExtControl(fd, &qCtrl)) {
218 if (qCtrl.flags & V4L2_CTRL_FLAG_DISABLED) {
219 CAMERA_LOGD("V4L2ENUMExtControls flags V4L2_CTRL_FLAG_DISABLED\n");
220 continue;
221 }
222
223 V4L2SetValue(fd, control, ctrl, qCtrl);
224
225 if (qCtrl.type == V4L2_CTRL_TYPE_MENU) {
226 struct v4l2_querymenu menu = {};
227 V4l2Menu menuTemp = {};
228
229 for (menu.index = qCtrl.minimum;
230 menu.index <= qCtrl.maximum;
231 menu.index++) {
232 menu.id = qCtrl.id;
233 rc = ioctl(fd, VIDIOC_QUERYMENU, &menu);
234 if (rc < 0) {
235 continue;
236 }
237 CAMERA_LOGD("\t %d : %s\n", menu.index, menu.name);
238 menuTemp.index = menu.index;
239 menuTemp.id = menu.id;
240 menuTemp.value = menu.value;
241 menuTemp.name = std::string(reinterpret_cast<char*>(menu.name));
242 ctrl.menu.push_back(menuTemp);
243 }
244 }
245
246 control.push_back(ctrl);
247 }
248 }
249
V4L2GetControl(int fd,std::vector<DeviceControl> & control,unsigned int id)250 int HosV4L2Control::V4L2GetControl(int fd, std::vector<DeviceControl>& control, unsigned int id)
251 {
252 struct v4l2_queryctrl queryCtrl = {};
253 DeviceControl ctrl = {};
254 int rc;
255
256 queryCtrl.id = id;
257 rc = ioctl(fd, VIDIOC_QUERYCTRL, &queryCtrl);
258 if (rc < 0) {
259 CAMERA_LOGE("V4L2GetControl ioctl error rc %d\n", rc);
260 return RC_ERROR;
261 }
262
263 if (queryCtrl.flags & V4L2_CTRL_FLAG_DISABLED) {
264 CAMERA_LOGD("V4L2ENUMExtControls flags V4L2_CTRL_FLAG_DISABLED\n");
265 return RC_OK;
266 }
267
268 V4L2SetValue(fd, control, ctrl, queryCtrl);
269
270 if (queryCtrl.type == V4L2_CTRL_TYPE_MENU) {
271 struct v4l2_querymenu menu = {};
272 V4l2Menu mTemp = {};
273
274 for (menu.index = queryCtrl.minimum;
275 menu.index <= queryCtrl.maximum;
276 menu.index++) {
277 menu.id = queryCtrl.id;
278 rc = ioctl(fd, VIDIOC_QUERYMENU, &menu);
279 if (rc < 0) {
280 continue;
281 }
282 CAMERA_LOGD("\t %d : %s\n", menu.index, menu.name);
283 mTemp.index = menu.index;
284 mTemp.id = menu.id;
285 mTemp.value = menu.value;
286 mTemp.name = std::string(reinterpret_cast<char*>(menu.name));
287 ctrl.menu.push_back(mTemp);
288 }
289 }
290
291 control.push_back(ctrl);
292
293 return RC_OK;
294 }
295
V4L2EnumControls(int fd,std::vector<DeviceControl> & control)296 void HosV4L2Control::V4L2EnumControls(int fd, std::vector<DeviceControl>& control)
297 {
298 int rc;
299 constexpr uint32_t max = V4L2_CID_PRIVATE_BASE + 100;
300
301 for (unsigned int id = V4L2_CID_BASE; id < V4L2_CID_LASTP1; id++) {
302 rc = V4L2GetControl(fd, control, id);
303 if (rc == RC_ERROR)
304 break;
305 }
306
307 for (unsigned int id = V4L2_CID_PRIVATE_BASE; id < max; id++) {
308 rc = V4L2GetControl(fd, control, id);
309 if (rc == RC_ERROR)
310 break;
311 }
312 }
313
V4L2GetControls(int fd,std::vector<DeviceControl> & control)314 RetCode HosV4L2Control::V4L2GetControls(int fd, std::vector<DeviceControl>& control)
315 {
316 int rc;
317 struct v4l2_queryctrl qCtrl = {};
318
319 std::vector<DeviceControl>().swap(control);
320
321 if (fd < 0) {
322 CAMERA_LOGE("V4L2EnumExtControls fd error\n");
323 return RC_ERROR;
324 }
325
326 qCtrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
327 rc = ExtControl(fd, &qCtrl);
328 if (rc < 0) {
329 CAMERA_LOGD("V4L2GetControls no support V4L2_CTRL_FLAG_NEXT_CTRL\n");
330 V4L2EnumControls(fd, control);
331 } else {
332 CAMERA_LOGD("V4L2GetControls support V4L2_CTRL_FLAG_NEXT_CTRL\n");
333 V4L2EnumExtControls(fd, control);
334 }
335
336 return RC_OK;
337 }
338 } // namespace OHOS::Camera
339