• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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