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