1 /*
2 * Copyright (c) 2023 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
V4L2VidiocSCtrl(int fd,int ret,struct v4l2_ext_control * cList,int count)22 void HosV4L2Control::V4L2VidiocSCtrl (int fd, int ret, struct v4l2_ext_control* cList, int count)
23 {
24 if (ret) {
25 CAMERA_LOGE("HosV4L2Control::VIDIOC_S_EXT_CTRLS set failed try to VIDIOC_S_CTRL\n");
26 struct v4l2_control ctrl;
27 for (int i = 0; count > 0; i++, count--) {
28 ctrl.id = cList[i].id;
29 ctrl.value = cList[i].value;
30 ret = ioctl(fd, VIDIOC_S_CTRL, &ctrl);
31 if (ret) {
32 CAMERA_LOGE("HosV4L2Control::V4L2SetCtrls VIDIOC_S_CTRL error i = %{public}d\n", i);
33 continue;
34 }
35 }
36 }
37 }
38
V4L2SetCtrls(int fd,std::vector<DeviceControl> & control,const int numControls)39 RetCode HosV4L2Control::V4L2SetCtrls (int fd, std::vector<DeviceControl>& control, const int numControls)
40 {
41 int ret;
42 int count = 0;
43 CAMERA_LOGI("HosV4L2Control::V4L2SetCtrls in fd %{public}d\n", fd);
44 if (numControls != static_cast<int>(control.size())) {
45 CAMERA_LOGE("HosV4L2Control::V4L2SetCtrls numControls != control.size()\n");
46 return RC_ERROR;
47 }
48
49 struct v4l2_ext_control cList[numControls];
50 for (auto itr = control.begin(); itr != control.end(); itr++) {
51 if (itr->flags & V4L2_CTRL_FLAG_READ_ONLY) {
52 continue;
53 }
54
55 if (count < numControls) {
56 cList[count].value = itr->value;
57 count++;
58 }
59 auto itrNext = itr + 1;
60 if (itrNext == control.end() || itr->ctrl_class != itrNext->ctrl_class) {
61 struct v4l2_ext_controls ctrls = {};
62 ctrls.ctrl_class = itr->ctrl_class;
63 ctrls.count = count;
64 ctrls.controls = cList;
65 ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls);
66
67 V4L2VidiocSCtrl(fd, ret, cList, count);
68 count = 0;
69 }
70 }
71 CAMERA_LOGI("HosV4L2Control::V4L2SetCtrls out fd %{public}d\n", fd);
72 return RC_OK;
73 }
74
V4L2VidiocGExtCtrls(int fd,int ret,int & count,v4l2_ext_control * cList,std::vector<DeviceControl> & control)75 void HosV4L2Control::V4L2VidiocGExtCtrls (int fd, int ret, int &count,
76 v4l2_ext_control *cList, std::vector<DeviceControl>& control)
77 {
78 auto iter = control.begin();
79 if (ret) {
80 CAMERA_LOGE("HosV4L2Control::VIDIOC_G_EXT_CTRLS set failed try to VIDIOC_S_CTRL\n");
81 struct v4l2_control ctrl;
82 for (int i = 0; count > 0; i++, count--) {
83 ctrl.id = cList[i].id;
84 ret = ioctl(fd, VIDIOC_G_CTRL, &ctrl);
85 if (ret) {
86 continue;
87 }
88
89 iter->value = ctrl.value;
90 iter++;
91 }
92 } else {
93 for (int i = 0; count > 0; i++, count--) {
94 iter->value = cList[i].value;
95 iter++;
96 }
97 }
98 }
99
V4L2GetCtrls(int fd,std::vector<DeviceControl> & control,const int numControls)100 RetCode HosV4L2Control::V4L2GetCtrls (int fd, std::vector<DeviceControl>& control, const int numControls)
101 {
102 int ret;
103 int count = 0;
104 CAMERA_LOGI("HosV4L2Control::V4L2GetCtrls in fd %{public}d\n", fd);
105 if (numControls != static_cast<int>(control.size())) {
106 CAMERA_LOGE("HosV4L2Control::V4L2GetCtrls numControls != control.size()\n");
107 return RC_ERROR;
108 }
109
110 struct v4l2_ext_control cList[numControls];
111 for (auto itr = control.begin(); itr != control.end(); itr++) {
112 if (itr->flags & V4L2_CTRL_FLAG_WRITE_ONLY) {
113 continue;
114 }
115 if (count < numControls) {
116 cList[count].id = itr->id;
117 count++;
118 }
119
120 auto itrNext = itr + 1;
121 if (itrNext == control.end() || itr->ctrl_class != itrNext->ctrl_class) {
122 struct v4l2_ext_controls ctrls = {};
123 ctrls.ctrl_class = itr->ctrl_class;
124 ctrls.count = count;
125 ctrls.controls = cList;
126 ret = ioctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls);
127 V4L2VidiocGExtCtrls(fd, ret, count, cList, control);
128
129 count = 0;
130 }
131 }
132 CAMERA_LOGI("HosV4L2Control::V4L2GetCtrls out fd %{public}d\n", fd);
133 return RC_OK;
134 }
135
V4L2GetCtrl(int fd,unsigned int id,int & value)136 RetCode HosV4L2Control::V4L2GetCtrl(int fd, unsigned int id, int& value)
137 {
138 CAMERA_LOGD("HosV4L2Control::V4L2GetCtrl in fd %{public}d\n", fd);
139 int rc = 0;
140 struct v4l2_control ctrl;
141
142 ctrl.id = id;
143
144 rc = ioctl(fd, VIDIOC_G_CTRL, &ctrl);
145 if (rc < 0) {
146 CAMERA_LOGE("HosV4L2Control::V4L2GetCtrl error rc = %{public}d", rc);
147 return RC_ERROR;
148 }
149
150 value = ctrl.value;
151 CAMERA_LOGD("HosV4L2Control::V4L2GetCtrl out fd %{public}d\n", fd);
152 return RC_OK;
153 }
154
V4L2SetCtrl(int fd,unsigned int id,int value)155 RetCode HosV4L2Control::V4L2SetCtrl(int fd, unsigned int id, int value)
156 {
157 struct v4l2_control ctrl;
158 int rc;
159
160 CAMERA_LOGI("V4L2SetCtrl in fd = %{public}d, id = %{public}d, value = %{public}d\n", fd, id, value);
161
162 ctrl.id = id;
163 ctrl.value = value;
164
165 rc = ioctl(fd, VIDIOC_S_CTRL, &ctrl);
166 if (rc < 0) {
167 CAMERA_LOGE("HosV4L2Control::V4L2SetCtrl error rc = %{public}d", rc);
168 return RC_ERROR;
169 }
170 CAMERA_LOGI("V4L2SetCtrl out fd = %{public}d, id = %{public}d, value = %{public}d\n", fd, id, value);
171 return RC_OK;
172 }
173
ExtControl(int fd,struct v4l2_queryctrl * ctrl)174 int HosV4L2Control::ExtControl(int fd, struct v4l2_queryctrl *ctrl)
175 {
176 int ret = 0;
177 CAMERA_LOGD("ExtControl in fd = %{public}d\n", fd);
178 if (ctrl == nullptr) {
179 CAMERA_LOGE("HosV4L2Control::ExtControl ctrl == nullptr");
180 return -1;
181 }
182
183 ctrl->id |= V4L2_CTRL_FLAG_NEXT_CTRL;
184 ret = ioctl(fd, VIDIOC_QUERYCTRL, ctrl);
185 if (ret < 0) {
186 CAMERA_LOGI("ExtControl out fd = %{public}d, ret = %{public}d\n", fd, ret);
187 }
188 return ret;
189 }
190
V4L2SetValue(int fd,std::vector<DeviceControl> & control,DeviceControl & ctrl,v4l2_queryctrl & qCtrl)191 void HosV4L2Control::V4L2SetValue(int fd, std::vector<DeviceControl>& control,
192 DeviceControl& ctrl, v4l2_queryctrl& qCtrl)
193 {
194 CAMERA_LOGD("V4L2SetValue in fd = %{public}d\n", fd);
195 int value, rc;
196
197 ctrl.id = qCtrl.id;
198 ctrl.ctrl_class = V4L2_CTRL_ID2CLASS(qCtrl.id);
199 ctrl.type = qCtrl.type;
200 ctrl.minimum = qCtrl.minimum;
201 ctrl.maximum = qCtrl.maximum;
202 ctrl.step = qCtrl.step;
203 ctrl.default_value = qCtrl.default_value;
204 ctrl.flags = qCtrl.flags;
205 ctrl.name = std::string(reinterpret_cast<char*>(qCtrl.name));
206
207 if (qCtrl.type == V4L2_CTRL_TYPE_CTRL_CLASS) {
208 CAMERA_LOGD("%{public}s-14s\n", qCtrl.name);
209 control.push_back(ctrl);
210 return;
211 }
212
213 rc = V4L2GetCtrl(fd, qCtrl.id, value);
214 if (rc != RC_ERROR) {
215 ctrl.value = value;
216 CAMERA_LOGD("%{public}s-14s : id=%{public}x-08x, type=%{public}d, minimum=%{public}d, maximum=%{public}d\n"
217 "\t\t value = %{public}d, step=%{public}d, default_value=%{public}d\n",
218 qCtrl.name, qCtrl.id, qCtrl.type, qCtrl.minimum, qCtrl.maximum,
219 value, qCtrl.step, qCtrl.default_value);
220 }
221 CAMERA_LOGD("V4L2SetValue out fd = %{public}d\n", fd);
222 }
223
V4L2EnumExtControl(int fd,v4l2_queryctrl & qCtrl,DeviceControl & ctrl)224 void HosV4L2Control::V4L2EnumExtControl(int fd, v4l2_queryctrl &qCtrl, DeviceControl &ctrl)
225 {
226 int rc;
227 if (qCtrl.type == V4L2_CTRL_TYPE_MENU) {
228 struct v4l2_querymenu menu = {};
229 V4l2Menu menuTemp = {};
230 for (menu.index = static_cast<uint32_t>(qCtrl.minimum);
231 menu.index <= static_cast<uint32_t>(qCtrl.maximum);
232 menu.index++) {
233 menu.id = qCtrl.id;
234 rc = ioctl(fd, VIDIOC_QUERYMENU, &menu);
235 if (rc < 0) {
236 continue;
237 }
238 CAMERA_LOGD("\t V4L2EnumExtControls %{public}d : %{public}s\n", menu.index, menu.name);
239 menuTemp.index = menu.index;
240 menuTemp.id = menu.id;
241 menuTemp.value = menu.value;
242 menuTemp.name = std::string(reinterpret_cast<char*>(menu.name));
243 ctrl.menu.push_back(menuTemp);
244 }
245 }
246 }
247
V4L2EnumExtControls(int fd,std::vector<DeviceControl> & control)248 void HosV4L2Control::V4L2EnumExtControls(int fd, std::vector<DeviceControl>& control)
249 {
250 CAMERA_LOGI("V4L2EnumExtControls in fd = %{public}d\n", fd);
251 struct v4l2_queryctrl qCtrl = {};
252 DeviceControl ctrl = {};
253
254 qCtrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
255 while (!ExtControl(fd, &qCtrl)) {
256 if (qCtrl.flags & V4L2_CTRL_FLAG_DISABLED) {
257 CAMERA_LOGI("V4L2ENUMExtControls flags V4L2_CTRL_FLAG_DISABLED\n");
258 continue;
259 }
260
261 V4L2SetValue(fd, control, ctrl, qCtrl);
262
263 V4L2EnumExtControl(fd, qCtrl, ctrl);
264 // Need fix: ctrl menu will keep old menu. Need clear ctrl every convert
265 control.push_back(ctrl);
266 }
267 CAMERA_LOGI("V4L2EnumExtControls out fd = %{public}d\n", fd);
268 }
269
V4L2GetControl(int fd,std::vector<DeviceControl> & control,unsigned int id)270 int HosV4L2Control::V4L2GetControl(int fd, std::vector<DeviceControl>& control, unsigned int id)
271 {
272 CAMERA_LOGI("V4L2GetControl in fd = %{public}d\n", fd);
273 struct v4l2_queryctrl queryCtrl = {};
274 DeviceControl ctrl = {};
275 int rc;
276
277 queryCtrl.id = id;
278 rc = ioctl(fd, VIDIOC_QUERYCTRL, &queryCtrl);
279 if (rc < 0) {
280 CAMERA_LOGE("V4L2GetControl ioctl error rc %{public}d\n", rc);
281 return RC_ERROR;
282 }
283
284 if (queryCtrl.flags & V4L2_CTRL_FLAG_DISABLED) {
285 CAMERA_LOGI("V4L2ENUMExtControls flags V4L2_CTRL_FLAG_DISABLED\n");
286 return RC_OK;
287 }
288
289 V4L2SetValue(fd, control, ctrl, queryCtrl);
290
291 if (queryCtrl.type == V4L2_CTRL_TYPE_MENU) {
292 struct v4l2_querymenu menu = {};
293 V4l2Menu mTemp = {};
294
295 for (menu.index = static_cast<uint32_t>(queryCtrl.minimum);
296 menu.index <= static_cast<uint32_t>(queryCtrl.maximum);
297 menu.index++) {
298 menu.id = queryCtrl.id;
299 rc = ioctl(fd, VIDIOC_QUERYMENU, &menu);
300 if (rc < 0) {
301 continue;
302 }
303 CAMERA_LOGD("\t %d : %s\n", menu.index, menu.name);
304 mTemp.index = menu.index;
305 mTemp.id = menu.id;
306 mTemp.value = menu.value;
307 mTemp.name = std::string(reinterpret_cast<char*>(menu.name));
308 ctrl.menu.push_back(mTemp);
309 }
310 }
311
312 control.push_back(ctrl);
313 CAMERA_LOGI("V4L2GetControl out fd = %{public}d\n", fd);
314 return RC_OK;
315 }
316
V4L2EnumControls(int fd,std::vector<DeviceControl> & control)317 void HosV4L2Control::V4L2EnumControls(int fd, std::vector<DeviceControl>& control)
318 {
319 CAMERA_LOGI("V4L2EnumControls in fd = %{public}d\n", fd);
320 int rc;
321 constexpr uint32_t max = V4L2_CID_PRIVATE_BASE + 100;
322
323 for (unsigned int id = V4L2_CID_BASE; id < V4L2_CID_LASTP1; id++) {
324 rc = V4L2GetControl(fd, control, id);
325 if (rc == RC_ERROR)
326 break;
327 }
328
329 for (unsigned int id = V4L2_CID_PRIVATE_BASE; id < max; id++) {
330 rc = V4L2GetControl(fd, control, id);
331 if (rc == RC_ERROR)
332 break;
333 }
334 CAMERA_LOGI("V4L2EnumControls out fd = %{public}d\n", fd);
335 }
336
V4L2GetControls(int fd,std::vector<DeviceControl> & control)337 RetCode HosV4L2Control::V4L2GetControls(int fd, std::vector<DeviceControl>& control)
338 {
339 CAMERA_LOGI("V4L2GetControls out fd = %{public}d\n", fd);
340 int rc;
341 struct v4l2_queryctrl qCtrl = {};
342
343 std::vector<DeviceControl>().swap(control);
344
345 if (fd < 0) {
346 CAMERA_LOGE("V4L2EnumExtControls fd error\n");
347 return RC_ERROR;
348 }
349
350 qCtrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
351 rc = ExtControl(fd, &qCtrl);
352 if (rc < 0) {
353 CAMERA_LOGE("V4L2GetControls no support V4L2_CTRL_FLAG_NEXT_CTRL\n");
354 V4L2EnumControls(fd, control);
355 } else {
356 CAMERA_LOGE("V4L2GetControls support V4L2_CTRL_FLAG_NEXT_CTRL\n");
357 V4L2EnumExtControls(fd, control);
358 }
359 CAMERA_LOGI("V4L2GetControls in fd = %{public}d\n", fd);
360 return RC_OK;
361 }
362 } // namespace OHOS::Camera
363