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