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