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