• 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;
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