1 /*
2 * Copyright (C) 2021–2022 Beijing OSWare Technology Co., Ltd
3 * This file contains confidential and proprietary information of
4 * OSWare Technology Co., Ltd
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #include "v4l2_fileformat.h"
20 #include "securec.h"
21 #include "v4l2_dev.h"
22
23 namespace OHOS::Camera {
HosFileFormat()24 HosFileFormat::HosFileFormat() {}
~HosFileFormat()25 HosFileFormat::~HosFileFormat() {}
26
V4L2SearchFormat(int fd,std::vector<DeviceFormat> & fmtDesc)27 RetCode HosFileFormat::V4L2SearchFormat(int fd, std::vector<DeviceFormat>& fmtDesc)
28 {
29 int i, j, k;
30 struct v4l2_fmtdesc enumFmtDesc = {};
31 struct v4l2_frmsizeenum frmSize = {};
32 struct v4l2_frmivalenum fraMival = {};
33 constexpr uint32_t fmtMax = 50;
34
35 for (i = 0; i < fmtMax; ++i) {
36 enumFmtDesc.index = i;
37 enumFmtDesc.type = bufType_;
38 if (ioctl(fd, VIDIOC_ENUM_FMT, &enumFmtDesc) < 0) {
39 break;
40 }
41
42 CAMERA_LOGD("[%d]Supported format with description = %s\n\n", i, enumFmtDesc.description);
43
44 for (j = 0; j < fmtMax; ++j) {
45 frmSize.index = j;
46 frmSize.pixel_format = enumFmtDesc.pixelformat;
47 if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmSize) < 0) {
48 break;
49 }
50
51 if (frmSize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
52 CAMERA_LOGD("V4L2_FRMSIZE_TYPE_DISCRETE width %d x height %d\n\n",
53 frmSize.discrete.width, frmSize.discrete.height);
54 }
55
56 for (k = 0; k < fmtMax; ++k) {
57 fraMival.index = k;
58 fraMival.pixel_format = frmSize.pixel_format;
59 fraMival.width = frmSize.discrete.width;
60 fraMival.height = frmSize.discrete.height;
61 if (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &fraMival) < 0) {
62 break;
63 }
64
65 DeviceFormat currentFormat = {};
66 currentFormat.fmtdesc.description = std::string((char*)enumFmtDesc.description);
67 currentFormat.fmtdesc.pixelformat = enumFmtDesc.pixelformat;
68 currentFormat.fmtdesc.width = frmSize.discrete.width;
69 currentFormat.fmtdesc.height = frmSize.discrete.height;
70 currentFormat.fmtdesc.fps.numerator = fraMival.discrete.numerator;
71 currentFormat.fmtdesc.fps.denominator = fraMival.discrete.denominator;
72
73 fmtDesc.push_back(currentFormat);
74
75 CAMERA_LOGD("frame interval: %d, %d\n\n", fraMival.discrete.numerator, fraMival.discrete.denominator);
76 }
77 }
78 }
79
80 if (i == 0) {
81 CAMERA_LOGD("no valid supported formats\n");
82 return RC_ERROR;
83 }
84
85 return RC_OK;
86 }
87
V4L2GetFmtDescs(int fd,std::vector<DeviceFormat> & fmtDesc)88 RetCode HosFileFormat::V4L2GetFmtDescs(int fd, std::vector<DeviceFormat>& fmtDesc)
89 {
90 RetCode rc = RC_OK;
91
92 std::vector<DeviceFormat>().swap(fmtDesc);
93
94 if (fd < 0) {
95 CAMERA_LOGE("V4L2GetFmtDescs fd error\n");
96 return RC_ERROR;
97 }
98
99 V4L2SearchBufType(fd);
100 if (bufType_ == V4L2_BUF_TYPE_PRIVATE) {
101 CAMERA_LOGE("V4L2GetFmtDescs bufType_ == 0\n");
102 return RC_ERROR;
103 }
104
105 rc = V4L2SearchFormat(fd, fmtDesc);
106 if (rc != RC_OK) {
107 CAMERA_LOGE("V4L2SearchFormat error\n");
108 }
109
110 return rc;
111 }
112
V4L2GetCapability(int fd,const std::string & devName,std::string & cameraId)113 RetCode HosFileFormat::V4L2GetCapability(int fd, const std::string& devName, std::string& cameraId)
114 {
115 struct v4l2_capability cap = {};
116
117 int rc = ioctl(fd, VIDIOC_QUERYCAP, &cap);
118 if (rc < 0) {
119 return RC_ERROR;
120 }
121
122 if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
123 return RC_ERROR;
124 }
125
126 if (!((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) || (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))) {
127 return RC_ERROR;
128 }
129
130 if (cameraId != std::string((char*)cap.driver)) {
131 return RC_ERROR;
132 }
133
134 std::lock_guard<std::mutex> l(HosV4L2Dev::deviceFdLock_);
135 HosV4L2Dev::deviceMatch.insert(std::make_pair(std::string((char*)cap.driver), devName));
136
137 CAMERA_LOGD("v4l2 driver name = %{public}s\n", cap.driver);
138 CAMERA_LOGD("v4l2 capabilities = 0x%{public}x\n", cap.capabilities);
139 CAMERA_LOGD("v4l2 card: %{public}s\n", cap.card);
140 CAMERA_LOGD("v4l2 bus info: %{public}s\n", cap.bus_info);
141
142 return RC_OK;
143 }
144
V4L2GetFmt(int fd,DeviceFormat & format)145 RetCode HosFileFormat::V4L2GetFmt(int fd, DeviceFormat& format)
146 {
147 struct v4l2_format fmt = {};
148
149 if (bufType_ == 0) {
150 V4L2SearchBufType(fd);
151 if (bufType_ == V4L2_BUF_TYPE_PRIVATE) {
152 CAMERA_LOGE("V4L2GetFmt bufType_ == 0\n");
153 return RC_ERROR;
154 }
155 }
156
157 fmt.type = bufType_;
158 int rc = ioctl(fd, VIDIOC_G_FMT, &fmt);
159 if (rc < 0) {
160 CAMERA_LOGE("error: ioctl VIDIOC_G_FMT failed: %s\n", strerror(errno));
161 return RC_ERROR;
162 }
163
164 if (bufType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
165 format.fmtdesc.width = fmt.fmt.pix_mp.width;
166 format.fmtdesc.height = fmt.fmt.pix_mp.height;
167 format.fmtdesc.pixelformat = fmt.fmt.pix_mp.pixelformat;
168 format.fmtdesc.sizeimage = fmt.fmt.pix.sizeimage;
169 } else if (bufType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
170 format.fmtdesc.width = fmt.fmt.pix.width;
171 format.fmtdesc.height = fmt.fmt.pix.height;
172 format.fmtdesc.pixelformat = fmt.fmt.pix.pixelformat;
173 format.fmtdesc.sizeimage = fmt.fmt.pix.sizeimage;
174 }
175
176 return RC_OK;
177 }
178
V4L2SetFmt(int fd,DeviceFormat & format)179 RetCode HosFileFormat::V4L2SetFmt(int fd, DeviceFormat& format)
180 {
181 struct v4l2_format fmt = {};
182
183 if (bufType_ == 0) {
184 V4L2SearchBufType(fd);
185 if (bufType_ == V4L2_BUF_TYPE_PRIVATE) {
186 CAMERA_LOGE("V4L2GetFmt bufType_ == 0\n");
187 return RC_ERROR;
188 }
189 }
190 fmt.type = bufType_;
191
192 if (bufType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
193 fmt.fmt.pix_mp.pixelformat = format.fmtdesc.pixelformat;
194 fmt.fmt.pix_mp.width = format.fmtdesc.width;
195 fmt.fmt.pix_mp.height = format.fmtdesc.height;
196 fmt.fmt.pix_mp.field = V4L2_FIELD_INTERLACED;
197 fmt.fmt.pix_mp.num_planes = 1;
198 } else if (bufType_ == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
199 fmt.fmt.pix.pixelformat = format.fmtdesc.pixelformat;
200 fmt.fmt.pix.width = format.fmtdesc.width;
201 fmt.fmt.pix.height = format.fmtdesc.height;
202 }
203
204 int rc = ioctl(fd, VIDIOC_S_FMT, &fmt);
205 if (rc < 0) {
206 CAMERA_LOGE("error: ioctl VIDIOC_S_FMT failed: %s\n", strerror(errno));
207 return RC_ERROR;
208 }
209
210 return RC_OK;
211 }
212
V4L2GetCrop(int fd,DeviceFormat & format)213 RetCode HosFileFormat::V4L2GetCrop(int fd, DeviceFormat& format)
214 {
215 struct v4l2_crop crop = {};
216
217 if (bufType_ == 0) {
218 V4L2SearchBufType(fd);
219 if (bufType_ == V4L2_BUF_TYPE_PRIVATE) {
220 CAMERA_LOGE("V4L2GetFmt bufType_ == 0\n");
221 return RC_ERROR;
222 }
223 }
224 crop.type = bufType_;
225
226 int rc = ioctl(fd, VIDIOC_G_CROP, &crop);
227 if (rc < 0) {
228 CAMERA_LOGE("error: ioctl VIDIOC_G_CROP failed: %s\n", strerror(errno));
229 return RC_ERROR;
230 }
231
232 format.crop.left = crop.c.left;
233 format.crop.top = crop.c.top;
234 format.crop.width = crop.c.width;
235 format.crop.height = crop.c.height;
236
237 return RC_OK;
238 }
239
V4L2SetCrop(int fd,DeviceFormat & format)240 RetCode HosFileFormat::V4L2SetCrop(int fd, DeviceFormat& format)
241 {
242 struct v4l2_crop crop = {};
243
244 if (bufType_ == 0) {
245 V4L2SearchBufType(fd);
246 if (bufType_ == V4L2_BUF_TYPE_PRIVATE) {
247 CAMERA_LOGE("V4L2GetFmt bufType_ == 0\n");
248 return RC_ERROR;
249 }
250 }
251
252 crop.type = bufType_;
253 crop.c.left = format.crop.left;
254 crop.c.top = format.crop.top;
255 crop.c.width = format.crop.width;
256 crop.c.height = format.crop.height;
257
258 int rc = ioctl(fd, VIDIOC_S_CROP, &crop);
259 if (rc < 0) {
260 CAMERA_LOGE("error: ioctl VIDIOC_S_CROP failed: %s\n", strerror(errno));
261 return RC_ERROR;
262 }
263
264 return RC_OK;
265 }
266
V4L2GetCropCap(int fd,DeviceFormat & format)267 RetCode HosFileFormat::V4L2GetCropCap(int fd, DeviceFormat& format)
268 {
269 struct v4l2_cropcap cropcap = {};
270
271 if (bufType_ == 0) {
272 V4L2SearchBufType(fd);
273 if (bufType_ == V4L2_BUF_TYPE_PRIVATE) {
274 CAMERA_LOGE("V4L2GetFmt bufType_ == 0\n");
275 return RC_ERROR;
276 }
277 }
278 cropcap.type = bufType_;
279
280 int rc = ioctl(fd, VIDIOC_CROPCAP, &cropcap);
281 if (rc < 0) {
282 CAMERA_LOGE("error: ioctl VIDIOC_CROPCAP failed: %s\n", strerror(errno));
283 return RC_ERROR;
284 }
285
286 format.cropcap.bounds.height = cropcap.bounds.height;
287 format.cropcap.bounds.left = cropcap.bounds.left;
288 format.cropcap.bounds.top = cropcap.bounds.top;
289 format.cropcap.bounds.width = cropcap.bounds.width;
290
291 format.cropcap.defrect.height = cropcap.defrect.height;
292 format.cropcap.defrect.left = cropcap.defrect.left;
293 format.cropcap.defrect.top = cropcap.defrect.top;
294 format.cropcap.defrect.width = cropcap.defrect.width;
295
296 format.cropcap.pixelaspect.denominator = cropcap.pixelaspect.denominator;
297 format.cropcap.pixelaspect.numerator = cropcap.pixelaspect.numerator;
298
299 return RC_OK;
300 }
301
V4L2OpenDevice(const std::string & deviceName)302 int HosFileFormat::V4L2OpenDevice(const std::string& deviceName)
303 {
304 if (deviceName.length() == 0) {
305 CAMERA_LOGD("V4L2OpenDevice deviceName length is 0\n");
306 }
307
308 int rc = 0;
309 char* devName = nullptr;
310
311 devName = realpath(deviceName.c_str(), nullptr);
312 if (devName == nullptr) {
313 CAMERA_LOGE("V4L2OpenDevice realpath error\n");
314 return RCERRORFD;
315 }
316 rc = open(devName, O_RDWR | O_NONBLOCK, 0);
317
318 CAMERA_LOGD("V4L2OpenDevice %s\n", devName);
319 free(devName);
320
321 return rc;
322 }
323
V4L2CloseDevice(int fd)324 void HosFileFormat::V4L2CloseDevice(int fd)
325 {
326 close(fd);
327 }
328
V4L2MatchDevice(std::vector<std::string> & cameraIDs)329 void HosFileFormat::V4L2MatchDevice(std::vector<std::string>& cameraIDs)
330 {
331 struct stat st = {};
332 char devName[16] = {0};
333 std::string name = DEVICENAMEX;
334 int fd = 0;
335 int rc = 0;
336
337 for (auto &it : cameraIDs) {
338 for (int i = 0; i < MAXVIDEODEVICE; ++i) {
339 if ((sprintf_s(devName, sizeof(devName), "%s%d", name.c_str(), i)) < 0) {
340 CAMERA_LOGE("%s: sprintf devName failed", __func__);
341 }
342
343 if (stat(devName, &st) != 0) {
344 continue;
345 }
346
347 if (!S_ISCHR(st.st_mode)) {
348 continue;
349 }
350
351 fd = open(devName, O_RDWR | O_NONBLOCK, 0);
352 if (fd == -1) {
353 continue;
354 }
355
356 rc = V4L2GetCapability(fd, devName, it);
357 if (rc == RC_ERROR) {
358 close(fd);
359 continue;
360 }
361
362 close(fd);
363 break;
364 }
365 }
366 }
367
V4L2SearchBufType(int fd)368 int HosFileFormat::V4L2SearchBufType(int fd)
369 {
370 struct v4l2_capability cap = {};
371
372 int rc = ioctl(fd, VIDIOC_QUERYCAP, &cap);
373 if (rc < 0) {
374 CAMERA_LOGE("V4L2SearchBufType VIDIOC_QUERYCAP error\n");
375 return static_cast<int>(V4L2_BUF_TYPE_PRIVATE);
376 }
377
378 if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
379 CAMERA_LOGE("V4L2SearchBufType capabilities is not support V4L2_CAP_STREAMING\n");
380 return static_cast<int>(V4L2_BUF_TYPE_PRIVATE);
381 }
382
383 if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) {
384 bufType_ = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
385 } else if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) {
386 bufType_ = V4L2_BUF_TYPE_VIDEO_CAPTURE;
387 }
388
389 return static_cast<int>(bufType_);
390 }
391 } // namespace OHOS::Camera
392