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