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