Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qv4l2camera.cpp
Go to the documentation of this file.
1
// Copyright (C) 2021 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4
#
include
"qv4l2camera_p.h"
5
6
#
include
<
QtMultimedia
/
private
/
qcameradevice_p
.
h
>
7
#
include
<
QtMultimedia
/
private
/
qmemoryvideobuffer_p
.
h
>
8
#
include
<
QtMultimedia
/
private
/
qmultimediautils_p
.
h
>
9
#
include
<
QtMultimedia
/
private
/
qv4l2filedescriptor_p
.
h
>
10
#
include
<
QtMultimedia
/
private
/
qv4l2memorytransfer_p
.
h
>
11
#
include
<
QtMultimedia
/
private
/
qvideoframe_p
.
h
>
12
#
include
<
QtCore
/
qloggingcategory
.
h
>
13
#
include
<
QtCore
/
qsocketnotifier
.
h
>
14
#
include
<
QtCore
/
private
/
qcore_unix_p
.
h
>
15
16
QT_BEGIN_NAMESPACE
17
18
namespace
QtV4L2
{
19
20
Q_STATIC_LOGGING_CATEGORY
(
qLcV4L2Camera
,
"qt.multimedia.v4l2.camera"
);
21
22
static
const
struct
23
{
24
QVideoFrameFormat
::
PixelFormat
fmt
;
25
uint32_t
v4l2Format
;
26
} formatMap[] = {
27
// ### How do we handle V4L2_PIX_FMT_H264 and V4L2_PIX_FMT_MPEG4?
28
{
QVideoFrameFormat
::
Format_YUV420P
,
V4L2_PIX_FMT_YUV420
},
29
{
QVideoFrameFormat
::
Format_YUV422P
,
V4L2_PIX_FMT_YUV422P
},
30
{
QVideoFrameFormat
::
Format_YUYV
,
V4L2_PIX_FMT_YUYV
},
31
{
QVideoFrameFormat
::
Format_UYVY
,
V4L2_PIX_FMT_UYVY
},
32
{
QVideoFrameFormat
::
Format_XBGR8888
,
V4L2_PIX_FMT_XBGR32
},
33
{
QVideoFrameFormat
::
Format_XRGB8888
,
V4L2_PIX_FMT_XRGB32
},
34
{
QVideoFrameFormat
::
Format_ABGR8888
,
V4L2_PIX_FMT_ABGR32
},
35
{
QVideoFrameFormat
::
Format_ARGB8888
,
V4L2_PIX_FMT_ARGB32
},
36
{
QVideoFrameFormat
::
Format_BGRX8888
,
V4L2_PIX_FMT_BGR32
},
37
{
QVideoFrameFormat
::
Format_RGBX8888
,
V4L2_PIX_FMT_RGB32
},
38
{
QVideoFrameFormat
::
Format_BGRA8888
,
V4L2_PIX_FMT_BGRA32
},
39
{
QVideoFrameFormat
::
Format_RGBA8888
,
V4L2_PIX_FMT_RGBA32
},
40
{
QVideoFrameFormat
::
Format_Y8
,
V4L2_PIX_FMT_GREY
},
41
{
QVideoFrameFormat
::
Format_Y16
,
V4L2_PIX_FMT_Y16
},
42
{
QVideoFrameFormat
::
Format_NV12
,
V4L2_PIX_FMT_NV12
},
43
{
QVideoFrameFormat
::
Format_NV21
,
V4L2_PIX_FMT_NV21
},
44
{
QVideoFrameFormat
::
Format_Jpeg
,
V4L2_PIX_FMT_MJPEG
},
45
{
QVideoFrameFormat
::
Format_Jpeg
,
V4L2_PIX_FMT_JPEG
},
46
{
QVideoFrameFormat
::
Format_Invalid
, 0 },
47
};
48
49
QVideoFrameFormat
::
PixelFormat
formatForV4L2Format
(uint32_t v4l2Format)
50
{
51
auto
*f = formatMap;
52
while
(f->v4l2Format) {
53
if
(f->v4l2Format == v4l2Format)
54
return
f->fmt;
55
++f;
56
}
57
return
QVideoFrameFormat::Format_Invalid;
58
}
59
60
uint32_t
v4l2FormatForPixelFormat
(QVideoFrameFormat::PixelFormat format)
61
{
62
auto
*f = formatMap;
63
while
(f->v4l2Format) {
64
if
(f->fmt == format)
65
return
f->v4l2Format;
66
++f;
67
}
68
return
0;
69
}
70
71
QV4L2Camera
::
QV4L2Camera
(
QCamera
*
camera
) :
QPlatformCamera
(
camera
) { }
72
73
QV4L2Camera
::~
QV4L2Camera
()
74
{
75
stopCapturing
();
76
closeV4L2Fd
();
77
}
78
79
bool
QV4L2Camera
::
isActive
()
const
80
{
81
return
m_active
;
82
}
83
84
void
QV4L2Camera
::
setActive
(
bool
active
)
85
{
86
if
(
m_active
==
active
)
87
return
;
88
if
(
m_cameraDevice
.
isNull
() &&
active
)
89
return
;
90
91
if
(
m_cameraFormat
.
isNull
())
92
resolveCameraFormat
({});
93
94
m_active
=
active
;
95
if
(
m_active
)
96
startCapturing
();
97
else
98
stopCapturing
();
99
100
Q_EMIT
newVideoFrame
({});
101
102
Q_EMIT
activeChanged
(
active
);
103
}
104
105
void
QV4L2Camera
::
setCamera
(
const
QCameraDevice
&
camera
)
106
{
107
if
(
m_cameraDevice
==
camera
)
108
return
;
109
110
stopCapturing
();
111
closeV4L2Fd
();
112
113
m_cameraDevice
=
camera
;
114
resolveCameraFormat
({});
115
116
initV4L2Controls
();
117
118
if
(
m_active
)
119
startCapturing
();
120
}
121
122
bool
QV4L2Camera
::
setCameraFormat
(
const
QCameraFormat
&
format
)
123
{
124
if
(!
format
.
isNull
() && !
m_cameraDevice
.
videoFormats
().
contains
(
format
))
125
return
false
;
126
127
if
(!
resolveCameraFormat
(
format
))
128
return
true
;
129
130
if
(
m_active
) {
131
stopCapturing
();
132
closeV4L2Fd
();
133
134
initV4L2Controls
();
135
startCapturing
();
136
}
137
138
return
true
;
139
}
140
141
bool
QV4L2Camera
::
resolveCameraFormat
(
const
QCameraFormat
&
format
)
142
{
143
auto
fmt
=
format
;
144
if
(
fmt
.
isNull
())
145
fmt
=
findBestCameraFormat
(
m_cameraDevice
);
146
147
if
(
fmt
==
m_cameraFormat
)
148
return
false
;
149
150
m_cameraFormat
=
fmt
;
151
return
true
;
152
}
153
154
void
QV4L2Camera
::
setFocusMode
(
QCamera
::
FocusMode
mode
)
155
{
156
if
(
mode
==
focusMode
())
157
return
;
158
159
bool
focusDist
=
supportedFeatures
() &
QCamera
::
Feature
::
FocusDistance
;
160
if
(!
focusDist
&& !
m_v4l2Info
.
rangedFocus
)
161
return
;
162
163
switch
(
mode
) {
164
default
:
165
case
QCamera
::
FocusModeAuto
:
166
setV4L2Parameter
(
V4L2_CID_FOCUS_AUTO
, 1);
167
if
(
m_v4l2Info
.
rangedFocus
)
168
setV4L2Parameter
(
V4L2_CID_AUTO_FOCUS_RANGE
,
V4L2_AUTO_FOCUS_RANGE_AUTO
);
169
break
;
170
case
QCamera
::
FocusModeAutoNear
:
171
setV4L2Parameter
(
V4L2_CID_FOCUS_AUTO
, 1);
172
if
(
m_v4l2Info
.
rangedFocus
)
173
setV4L2Parameter
(
V4L2_CID_AUTO_FOCUS_RANGE
,
V4L2_AUTO_FOCUS_RANGE_MACRO
);
174
else
if
(
focusDist
)
175
setV4L2Parameter
(
V4L2_CID_FOCUS_ABSOLUTE
,
m_v4l2Info
.
minFocus
);
176
break
;
177
case
QCamera
::
FocusModeAutoFar
:
178
setV4L2Parameter
(
V4L2_CID_FOCUS_AUTO
, 1);
179
if
(
m_v4l2Info
.
rangedFocus
)
180
setV4L2Parameter
(
V4L2_CID_AUTO_FOCUS_RANGE
,
V4L2_AUTO_FOCUS_RANGE_INFINITY
);
181
break
;
182
case
QCamera
::
FocusModeInfinity
:
183
setV4L2Parameter
(
V4L2_CID_FOCUS_AUTO
, 0);
184
setV4L2Parameter
(
V4L2_CID_FOCUS_ABSOLUTE
,
m_v4l2Info
.
maxFocus
);
185
break
;
186
case
QCamera
::
FocusModeManual
:
187
setV4L2Parameter
(
V4L2_CID_FOCUS_AUTO
, 0);
188
setFocusDistance
(
focusDistance
());
189
break
;
190
}
191
focusModeChanged
(
mode
);
192
}
193
194
void
QV4L2Camera
::
setFocusDistance
(
float
d
)
195
{
196
int
distance
=
m_v4l2Info
.
minFocus
+
int
((
m_v4l2Info
.
maxFocus
-
m_v4l2Info
.
minFocus
) *
d
);
197
setV4L2Parameter
(
V4L2_CID_FOCUS_ABSOLUTE
,
distance
);
198
focusDistanceChanged
(
d
);
199
}
200
201
void
QV4L2Camera
::
zoomTo
(
float
factor
,
float
)
202
{
203
if
(
m_v4l2Info
.
maxZoom
==
m_v4l2Info
.
minZoom
)
204
return
;
205
factor
=
qBound
(1.,
factor
, 2.);
206
int
zoom
=
m_v4l2Info
.
minZoom
+ (
factor
- 1.) * (
m_v4l2Info
.
maxZoom
-
m_v4l2Info
.
minZoom
);
207
setV4L2Parameter
(
V4L2_CID_ZOOM_ABSOLUTE
,
zoom
);
208
zoomFactorChanged
(
factor
);
209
}
210
211
bool
QV4L2Camera
::
isFocusModeSupported
(
QCamera
::
FocusMode
mode
)
const
212
{
213
if
(
supportedFeatures
() &
QCamera
::
Feature
::
FocusDistance
214
&& (
mode
==
QCamera
::
FocusModeManual
||
mode
==
QCamera
::
FocusModeAutoNear
215
||
mode
==
QCamera
::
FocusModeInfinity
))
216
return
true
;
217
218
return
mode
==
QCamera
::
FocusModeAuto
;
219
}
220
221
void
QV4L2Camera
::
setFlashMode
(
QCamera
::
FlashMode
mode
)
222
{
223
if
(!
m_v4l2Info
.
flashSupported
||
mode
==
QCamera
::
FlashOn
)
224
return
;
225
setV4L2Parameter
(
V4L2_CID_FLASH_LED_MODE
,
226
mode
==
QCamera
::
FlashAuto
?
V4L2_FLASH_LED_MODE_FLASH
227
:
V4L2_FLASH_LED_MODE_NONE
);
228
flashModeChanged
(
mode
);
229
}
230
231
bool
QV4L2Camera
::
isFlashModeSupported
(
QCamera
::
FlashMode
mode
)
const
232
{
233
if
(
m_v4l2Info
.
flashSupported
&&
mode
==
QCamera
::
FlashAuto
)
234
return
true
;
235
return
mode
==
QCamera
::
FlashOff
;
236
}
237
238
bool
QV4L2Camera
::
isFlashReady
()
const
239
{
240
struct
v4l2_queryctrl
queryControl
;
241
::
memset
(&
queryControl
, 0,
sizeof
(
queryControl
));
242
queryControl
.
id
=
V4L2_CID_AUTO_WHITE_BALANCE
;
243
244
return
m_v4l2FileDescriptor
&&
m_v4l2FileDescriptor
->
call
(
VIDIOC_QUERYCTRL
, &
queryControl
);
245
}
246
247
void
QV4L2Camera
::
setTorchMode
(
QCamera
::
TorchMode
mode
)
248
{
249
if
(!
m_v4l2Info
.
torchSupported
||
mode
==
QCamera
::
TorchOn
)
250
return
;
251
setV4L2Parameter
(
V4L2_CID_FLASH_LED_MODE
,
252
mode
==
QCamera
::
TorchOn
?
V4L2_FLASH_LED_MODE_TORCH
253
:
V4L2_FLASH_LED_MODE_NONE
);
254
torchModeChanged
(
mode
);
255
}
256
257
bool
QV4L2Camera
::
isTorchModeSupported
(
QCamera
::
TorchMode
mode
)
const
258
{
259
if
(
mode
==
QCamera
::
TorchOn
)
260
return
m_v4l2Info
.
torchSupported
;
261
return
mode
==
QCamera
::
TorchOff
;
262
}
263
264
void
QV4L2Camera
::
setExposureMode
(
QCamera
::
ExposureMode
mode
)
265
{
266
if
(
m_v4l2Info
.
autoExposureSupported
&&
m_v4l2Info
.
manualExposureSupported
) {
267
if
(
mode
!=
QCamera
::
ExposureAuto
&&
mode
!=
QCamera
::
ExposureManual
)
268
return
;
269
int
value
=
QCamera
::
ExposureAuto
?
V4L2_EXPOSURE_AUTO
:
V4L2_EXPOSURE_MANUAL
;
270
setV4L2Parameter
(
V4L2_CID_EXPOSURE_AUTO
,
value
);
271
exposureModeChanged
(
mode
);
272
return
;
273
}
274
}
275
276
bool
QV4L2Camera
::
isExposureModeSupported
(
QCamera
::
ExposureMode
mode
)
const
277
{
278
if
(
mode
==
QCamera
::
ExposureAuto
)
279
return
true
;
280
if
(
m_v4l2Info
.
manualExposureSupported
&&
m_v4l2Info
.
autoExposureSupported
)
281
return
mode
==
QCamera
::
ExposureManual
;
282
return
false
;
283
}
284
285
void
QV4L2Camera
::
setExposureCompensation
(
float
compensation
)
286
{
287
if
((
m_v4l2Info
.
minExposureAdjustment
!= 0 ||
m_v4l2Info
.
maxExposureAdjustment
!= 0)) {
288
int
value
=
qBound
(
m_v4l2Info
.
minExposureAdjustment
, (
int
)(
compensation
* 1000),
289
m_v4l2Info
.
maxExposureAdjustment
);
290
setV4L2Parameter
(
V4L2_CID_AUTO_EXPOSURE_BIAS
,
value
);
291
exposureCompensationChanged
(
value
/ 1000.);
292
return
;
293
}
294
}
295
296
void
QV4L2Camera
::
setManualIsoSensitivity
(
int
iso
)
297
{
298
if
(!(
supportedFeatures
() &
QCamera
::
Feature
::
IsoSensitivity
))
299
return
;
300
setV4L2Parameter
(
V4L2_CID_ISO_SENSITIVITY_AUTO
,
301
iso
<= 0 ?
V4L2_ISO_SENSITIVITY_AUTO
:
V4L2_ISO_SENSITIVITY_MANUAL
);
302
if
(
iso
> 0) {
303
iso
=
qBound
(
minIso
(),
iso
,
maxIso
());
304
setV4L2Parameter
(
V4L2_CID_ISO_SENSITIVITY
,
iso
);
305
}
306
}
307
308
int
QV4L2Camera
::
isoSensitivity
()
const
309
{
310
if
(!(
supportedFeatures
() &
QCamera
::
Feature
::
IsoSensitivity
))
311
return
-1;
312
return
getV4L2Parameter
(
V4L2_CID_ISO_SENSITIVITY
);
313
}
314
315
void
QV4L2Camera
::
setManualExposureTime
(
float
secs
)
316
{
317
if
(
m_v4l2Info
.
manualExposureSupported
&&
m_v4l2Info
.
autoExposureSupported
) {
318
int
exposure
=
319
qBound
(
m_v4l2Info
.
minExposure
,
qRound
(
secs
* 10000.),
m_v4l2Info
.
maxExposure
);
320
setV4L2Parameter
(
V4L2_CID_EXPOSURE_ABSOLUTE
,
exposure
);
321
exposureTimeChanged
(
exposure
/ 10000.);
322
return
;
323
}
324
}
325
326
float
QV4L2Camera
::
exposureTime
()
const
327
{
328
return
getV4L2Parameter
(
V4L2_CID_EXPOSURE_ABSOLUTE
) / 10000.;
329
}
330
331
bool
QV4L2Camera
::
isWhiteBalanceModeSupported
(
QCamera
::
WhiteBalanceMode
mode
)
const
332
{
333
if
(
m_v4l2Info
.
autoWhiteBalanceSupported
&&
m_v4l2Info
.
colorTemperatureSupported
)
334
return
true
;
335
336
return
mode
==
QCamera
::
WhiteBalanceAuto
;
337
}
338
339
void
QV4L2Camera
::
setWhiteBalanceMode
(
QCamera
::
WhiteBalanceMode
mode
)
340
{
341
Q_ASSERT
(
isWhiteBalanceModeSupported
(
mode
));
342
343
int
temperature
=
colorTemperatureForWhiteBalance
(
mode
);
344
int
t
=
setV4L2ColorTemperature
(
temperature
);
345
if
(
t
== 0)
346
mode
=
QCamera
::
WhiteBalanceAuto
;
347
whiteBalanceModeChanged
(
mode
);
348
}
349
350
void
QV4L2Camera
::
setColorTemperature
(
int
temperature
)
351
{
352
if
(
temperature
== 0) {
353
setWhiteBalanceMode
(
QCamera
::
WhiteBalanceAuto
);
354
return
;
355
}
356
357
Q_ASSERT
(
isWhiteBalanceModeSupported
(
QCamera
::
WhiteBalanceManual
));
358
359
int
t
=
setV4L2ColorTemperature
(
temperature
);
360
if
(
t
)
361
colorTemperatureChanged
(
t
);
362
}
363
364
void
QV4L2Camera
::
readFrame
()
365
{
366
Q_ASSERT
(
m_memoryTransfer
);
367
368
auto
buffer
=
m_memoryTransfer
->
dequeueBuffer
();
369
if
(!
buffer
) {
370
qCWarning
(
qLcV4L2Camera
) <<
"Cannot take buffer"
;
371
372
if
(
errno
==
ENODEV
) {
373
// camera got removed while being active
374
stopCapturing
();
375
closeV4L2Fd
();
376
}
377
378
return
;
379
}
380
381
auto
videoBuffer
=
std
::
make_unique
<
QMemoryVideoBuffer
>(
buffer
->
data
,
m_bytesPerLine
);
382
QVideoFrame
frame
=
QVideoFramePrivate
::
createFrame
(
std
::
move
(
videoBuffer
),
frameFormat
());
383
384
auto
&
v4l2Buffer
=
buffer
->
v4l2Buffer
;
385
386
if
(
m_firstFrameTime
.
tv_sec
== -1)
387
m_firstFrameTime
=
v4l2Buffer
.
timestamp
;
388
qint64
secs
=
v4l2Buffer
.
timestamp
.
tv_sec
-
m_firstFrameTime
.
tv_sec
;
389
qint64
usecs
=
v4l2Buffer
.
timestamp
.
tv_usec
-
m_firstFrameTime
.
tv_usec
;
390
frame
.
setStartTime
(
secs
* 1000000 +
usecs
);
391
frame
.
setEndTime
(
frame
.
startTime
() +
m_frameDuration
);
392
393
Q_EMIT
newVideoFrame
(
frame
);
394
395
if
(!
m_memoryTransfer
->
enqueueBuffer
(
v4l2Buffer
.
index
))
396
qCWarning
(
qLcV4L2Camera
) <<
"Cannot add buffer"
;
397
}
398
399
void
QV4L2Camera
::
setCameraBusy
()
400
{
401
m_cameraBusy
=
true
;
402
updateError
(
QCamera
::
CameraError
,
QLatin1String
(
"Camera is in use"
));
403
}
404
405
void
QV4L2Camera
::
initV4L2Controls
()
406
{
407
m_v4l2Info
= {};
408
QCamera
::
Features
features
;
409
410
const
QByteArray
deviceName
=
m_cameraDevice
.
id
();
411
Q_ASSERT
(!
deviceName
.
isEmpty
());
412
413
closeV4L2Fd
();
414
415
const
int
descriptor
=
qt_safe_open
(
deviceName
.
constData
(),
O_RDWR
);
416
if
(
descriptor
== -1) {
417
qCWarning
(
qLcV4L2Camera
) <<
"Unable to open the camera"
<<
deviceName
418
<<
"for read to query the parameter info:"
419
<<
qt_error_string
(
errno
);
420
updateError
(
QCamera
::
CameraError
,
QLatin1String
(
"Cannot open camera"
));
421
return
;
422
}
423
424
m_v4l2FileDescriptor
=
425
std
::
make_shared
<
QV4L2FileDescriptor
>(
QUniqueFileDescriptorHandle
{
descriptor
});
426
427
qCDebug
(
qLcV4L2Camera
) <<
"FD="
<<
descriptor
;
428
429
struct
v4l2_queryctrl
queryControl
;
430
::
memset
(&
queryControl
, 0,
sizeof
(
queryControl
));
431
queryControl
.
id
=
V4L2_CID_AUTO_WHITE_BALANCE
;
432
433
if
(
m_v4l2FileDescriptor
->
call
(
VIDIOC_QUERYCTRL
, &
queryControl
)) {
434
m_v4l2Info
.
autoWhiteBalanceSupported
=
true
;
435
setV4L2Parameter
(
V4L2_CID_AUTO_WHITE_BALANCE
,
true
);
436
}
437
438
::
memset
(&
queryControl
, 0,
sizeof
(
queryControl
));
439
queryControl
.
id
=
V4L2_CID_WHITE_BALANCE_TEMPERATURE
;
440
if
(
m_v4l2FileDescriptor
->
call
(
VIDIOC_QUERYCTRL
, &
queryControl
)) {
441
m_v4l2Info
.
minColorTemp
=
queryControl
.
minimum
;
442
m_v4l2Info
.
maxColorTemp
=
queryControl
.
maximum
;
443
m_v4l2Info
.
colorTemperatureSupported
=
true
;
444
features
|=
QCamera
::
Feature
::
ColorTemperature
;
445
}
446
447
::
memset
(&
queryControl
, 0,
sizeof
(
queryControl
));
448
queryControl
.
id
=
V4L2_CID_EXPOSURE_AUTO
;
449
if
(
m_v4l2FileDescriptor
->
call
(
VIDIOC_QUERYCTRL
, &
queryControl
)) {
450
m_v4l2Info
.
autoExposureSupported
=
true
;
451
}
452
453
::
memset
(&
queryControl
, 0,
sizeof
(
queryControl
));
454
queryControl
.
id
=
V4L2_CID_EXPOSURE_ABSOLUTE
;
455
if
(
m_v4l2FileDescriptor
->
call
(
VIDIOC_QUERYCTRL
, &
queryControl
)) {
456
m_v4l2Info
.
manualExposureSupported
=
true
;
457
m_v4l2Info
.
minExposure
=
queryControl
.
minimum
;
458
m_v4l2Info
.
maxExposure
=
queryControl
.
maximum
;
459
features
|=
QCamera
::
Feature
::
ManualExposureTime
;
460
}
461
462
::
memset
(&
queryControl
, 0,
sizeof
(
queryControl
));
463
queryControl
.
id
=
V4L2_CID_AUTO_EXPOSURE_BIAS
;
464
if
(
m_v4l2FileDescriptor
->
call
(
VIDIOC_QUERYCTRL
, &
queryControl
)) {
465
m_v4l2Info
.
minExposureAdjustment
=
queryControl
.
minimum
;
466
m_v4l2Info
.
maxExposureAdjustment
=
queryControl
.
maximum
;
467
features
|=
QCamera
::
Feature
::
ExposureCompensation
;
468
}
469
470
::
memset
(&
queryControl
, 0,
sizeof
(
queryControl
));
471
queryControl
.
id
=
V4L2_CID_ISO_SENSITIVITY_AUTO
;
472
if
(
m_v4l2FileDescriptor
->
call
(
VIDIOC_QUERYCTRL
, &
queryControl
)) {
473
queryControl
.
id
=
V4L2_CID_ISO_SENSITIVITY
;
474
if
(
m_v4l2FileDescriptor
->
call
(
VIDIOC_QUERYCTRL
, &
queryControl
)) {
475
features
|=
QCamera
::
Feature
::
IsoSensitivity
;
476
minIsoChanged
(
queryControl
.
minimum
);
477
maxIsoChanged
(
queryControl
.
minimum
);
478
}
479
}
480
481
::
memset
(&
queryControl
, 0,
sizeof
(
queryControl
));
482
queryControl
.
id
=
V4L2_CID_FOCUS_ABSOLUTE
;
483
if
(
m_v4l2FileDescriptor
->
call
(
VIDIOC_QUERYCTRL
, &
queryControl
)) {
484
m_v4l2Info
.
minExposureAdjustment
=
queryControl
.
minimum
;
485
m_v4l2Info
.
maxExposureAdjustment
=
queryControl
.
maximum
;
486
features
|=
QCamera
::
Feature
::
FocusDistance
;
487
}
488
489
::
memset
(&
queryControl
, 0,
sizeof
(
queryControl
));
490
queryControl
.
id
=
V4L2_CID_AUTO_FOCUS_RANGE
;
491
if
(
m_v4l2FileDescriptor
->
call
(
VIDIOC_QUERYCTRL
, &
queryControl
)) {
492
m_v4l2Info
.
rangedFocus
=
true
;
493
}
494
495
::
memset
(&
queryControl
, 0,
sizeof
(
queryControl
));
496
queryControl
.
id
=
V4L2_CID_FLASH_LED_MODE
;
497
if
(
m_v4l2FileDescriptor
->
call
(
VIDIOC_QUERYCTRL
, &
queryControl
)) {
498
m_v4l2Info
.
flashSupported
=
queryControl
.
minimum
<=
V4L2_FLASH_LED_MODE_FLASH
499
&&
queryControl
.
maximum
>=
V4L2_FLASH_LED_MODE_FLASH
;
500
m_v4l2Info
.
torchSupported
=
queryControl
.
minimum
<=
V4L2_FLASH_LED_MODE_TORCH
501
&&
queryControl
.
maximum
>=
V4L2_FLASH_LED_MODE_TORCH
;
502
}
503
504
::
memset
(&
queryControl
, 0,
sizeof
(
queryControl
));
505
queryControl
.
id
=
V4L2_CID_ZOOM_ABSOLUTE
;
506
if
(
m_v4l2FileDescriptor
->
call
(
VIDIOC_QUERYCTRL
, &
queryControl
)) {
507
m_v4l2Info
.
minZoom
=
queryControl
.
minimum
;
508
m_v4l2Info
.
maxZoom
=
queryControl
.
maximum
;
509
}
510
// zoom factors are in arbitrary units, so we simply normalize them to go from 1 to 2
511
// if they are different
512
minimumZoomFactorChanged
(1);
513
maximumZoomFactorChanged
(
m_v4l2Info
.
minZoom
!=
m_v4l2Info
.
maxZoom
? 2 : 1);
514
515
supportedFeaturesChanged
(
features
);
516
}
517
518
void
QV4L2Camera
::
closeV4L2Fd
()
519
{
520
Q_ASSERT
(!
m_memoryTransfer
);
521
522
m_v4l2Info
= {};
523
m_cameraBusy
=
false
;
524
m_v4l2FileDescriptor
=
nullptr
;
525
}
526
527
int
QV4L2Camera
::
setV4L2ColorTemperature
(
int
temperature
)
528
{
529
struct
v4l2_control
control
;
530
::
memset
(&
control
, 0,
sizeof
(
control
));
531
532
if
(
m_v4l2Info
.
autoWhiteBalanceSupported
) {
533
setV4L2Parameter
(
V4L2_CID_AUTO_WHITE_BALANCE
,
temperature
== 0 ?
true
:
false
);
534
}
else
if
(
temperature
== 0) {
535
temperature
= 5600;
536
}
537
538
if
(
temperature
!= 0 &&
m_v4l2Info
.
colorTemperatureSupported
) {
539
temperature
=
qBound
(
m_v4l2Info
.
minColorTemp
,
temperature
,
m_v4l2Info
.
maxColorTemp
);
540
if
(!
setV4L2Parameter
(
541
V4L2_CID_WHITE_BALANCE_TEMPERATURE
,
542
qBound
(
m_v4l2Info
.
minColorTemp
,
temperature
,
m_v4l2Info
.
maxColorTemp
)))
543
temperature
= 0;
544
}
else
{
545
temperature
= 0;
546
}
547
548
return
temperature
;
549
}
550
551
bool
QV4L2Camera
::
setV4L2Parameter
(
quint32
id
,
qint32
value
)
552
{
553
v4l2_control
control
{
id
,
value
};
554
if
(!
m_v4l2FileDescriptor
->
call
(
VIDIOC_S_CTRL
, &
control
)) {
555
qWarning
() <<
"Unable to set the V4L2 Parameter"
<<
Qt
::
hex
<<
id
<<
"to"
<<
value
556
<<
qt_error_string
(
errno
);
557
return
false
;
558
}
559
return
true
;
560
}
561
562
int
QV4L2Camera
::
getV4L2Parameter
(
quint32
id
)
const
563
{
564
struct
v4l2_control
control
{
id
, 0 };
565
if
(!
m_v4l2FileDescriptor
->
call
(
VIDIOC_G_CTRL
, &
control
)) {
566
qWarning
() <<
"Unable to get the V4L2 Parameter"
<<
Qt
::
hex
<<
id
<<
qt_error_string
(
errno
);
567
return
0;
568
}
569
return
control
.
value
;
570
}
571
572
void
QV4L2Camera
::
setV4L2CameraFormat
()
573
{
574
if
(
m_v4l2Info
.
formatInitialized
|| !
m_v4l2FileDescriptor
)
575
return
;
576
577
Q_ASSERT
(!
m_cameraFormat
.
isNull
());
578
qCDebug
(
qLcV4L2Camera
) <<
"XXXXX"
<<
this
<<
m_cameraDevice
.
id
() <<
m_cameraFormat
.
pixelFormat
()
579
<<
m_cameraFormat
.
resolution
();
580
581
v4l2_format
fmt
= {};
582
fmt
.
type
=
V4L2_BUF_TYPE_VIDEO_CAPTURE
;
583
584
auto
size
=
m_cameraFormat
.
resolution
();
585
fmt
.
fmt
.
pix
.
width
=
size
.
width
();
586
fmt
.
fmt
.
pix
.
height
=
size
.
height
();
587
fmt
.
fmt
.
pix
.
pixelformat
=
v4l2FormatForPixelFormat
(
m_cameraFormat
.
pixelFormat
());
588
fmt
.
fmt
.
pix
.
field
=
V4L2_FIELD_ANY
;
589
590
qCDebug
(
qLcV4L2Camera
) <<
"setting camera format to"
<<
size
<<
fmt
.
fmt
.
pix
.
pixelformat
;
591
592
if
(!
m_v4l2FileDescriptor
->
call
(
VIDIOC_S_FMT
, &
fmt
)) {
593
if
(
errno
==
EBUSY
) {
594
setCameraBusy
();
595
return
;
596
}
597
qWarning
() <<
"Couldn't set video format on v4l2 camera"
<<
qt_error_string
(
errno
);
598
}
599
600
m_v4l2Info
.
formatInitialized
=
true
;
601
m_cameraBusy
=
false
;
602
603
m_bytesPerLine
=
fmt
.
fmt
.
pix
.
bytesperline
;
604
m_imageSize
=
std
::
max
(
fmt
.
fmt
.
pix
.
sizeimage
,
m_bytesPerLine
*
fmt
.
fmt
.
pix
.
height
);
605
606
switch
(
v4l2_colorspace
(
fmt
.
fmt
.
pix
.
colorspace
)) {
607
default
:
608
case
V4L2_COLORSPACE_DCI_P3
:
609
m_colorSpace
=
QVideoFrameFormat
::
ColorSpace_Undefined
;
610
break
;
611
case
V4L2_COLORSPACE_REC709
:
612
m_colorSpace
=
QVideoFrameFormat
::
ColorSpace_BT709
;
613
break
;
614
case
V4L2_COLORSPACE_JPEG
:
615
m_colorSpace
=
QVideoFrameFormat
::
ColorSpace_AdobeRgb
;
616
break
;
617
case
V4L2_COLORSPACE_SRGB
:
618
// ##### is this correct???
619
m_colorSpace
=
QVideoFrameFormat
::
ColorSpace_BT601
;
620
break
;
621
case
V4L2_COLORSPACE_BT2020
:
622
m_colorSpace
=
QVideoFrameFormat
::
ColorSpace_BT2020
;
623
break
;
624
}
625
626
v4l2_streamparm
streamParam
= {};
627
streamParam
.
type
=
V4L2_BUF_TYPE_VIDEO_CAPTURE
;
628
629
streamParam
.
parm
.
capture
.
capability
=
V4L2_CAP_TIMEPERFRAME
;
630
auto
[
num
,
den
] =
qRealToFraction
(1. /
m_cameraFormat
.
maxFrameRate
());
631
streamParam
.
parm
.
capture
.
timeperframe
= { (
uint
)
num
, (
uint
)
den
};
632
m_v4l2FileDescriptor
->
call
(
VIDIOC_S_PARM
, &
streamParam
);
633
634
m_frameDuration
= 1000000 *
streamParam
.
parm
.
capture
.
timeperframe
.
numerator
635
/
streamParam
.
parm
.
capture
.
timeperframe
.
denominator
;
636
}
637
638
void
QV4L2Camera
::
initV4L2MemoryTransfer
()
639
{
640
if
(
m_cameraBusy
)
641
return
;
642
643
Q_ASSERT
(!
m_memoryTransfer
);
644
645
m_memoryTransfer
=
makeUserPtrMemoryTransfer
(
m_v4l2FileDescriptor
,
m_imageSize
);
646
647
if
(
m_memoryTransfer
)
648
return
;
649
650
if
(
errno
==
EBUSY
) {
651
setCameraBusy
();
652
return
;
653
}
654
655
qCDebug
(
qLcV4L2Camera
) <<
"Cannot init V4L2_MEMORY_USERPTR; trying V4L2_MEMORY_MMAP"
;
656
657
m_memoryTransfer
=
makeMMapMemoryTransfer
(
m_v4l2FileDescriptor
);
658
659
if
(!
m_memoryTransfer
) {
660
qCWarning
(
qLcV4L2Camera
) <<
"Cannot init v4l2 memory transfer,"
<<
qt_error_string
(
errno
);
661
updateError
(
QCamera
::
CameraError
,
QLatin1String
(
"Cannot init V4L2 memory transfer"
));
662
}
663
}
664
665
void
QV4L2Camera
::
stopCapturing
()
666
{
667
if
(!
m_memoryTransfer
|| !
m_v4l2FileDescriptor
)
668
return
;
669
670
m_notifier
=
nullptr
;
671
672
if
(!
m_v4l2FileDescriptor
->
stopStream
()) {
673
// TODO: handle the case carefully to avoid possible memory corruption
674
if
(
errno
!=
ENODEV
)
675
qWarning
() <<
"failed to stop capture"
;
676
}
677
678
m_memoryTransfer
=
nullptr
;
679
m_cameraBusy
=
false
;
680
}
681
682
void
QV4L2Camera
::
startCapturing
()
683
{
684
if
(!
m_v4l2FileDescriptor
)
685
return
;
686
687
setV4L2CameraFormat
();
688
initV4L2MemoryTransfer
();
689
690
if
(
m_cameraBusy
|| !
m_memoryTransfer
)
691
return
;
692
693
if
(!
m_v4l2FileDescriptor
->
startStream
()) {
694
qWarning
() <<
"Couldn't start v4l2 camera stream"
;
695
return
;
696
}
697
698
m_notifier
=
699
std
::
make_unique
<
QSocketNotifier
>(
m_v4l2FileDescriptor
->
get
(),
QSocketNotifier
::
Read
);
700
connect
(
m_notifier
.
get
(), &
QSocketNotifier
::
activated
,
this
, &
QV4L2Camera
::
readFrame
);
701
702
m_firstFrameTime
= { -1, -1 };
703
}
704
705
QVideoFrameFormat
QV4L2Camera
::
frameFormat
()
const
706
{
707
auto
result
=
QPlatformCamera
::
frameFormat
();
708
result
.
setColorSpace
(
m_colorSpace
);
709
return
result
;
710
}
711
712
}
// namespace QtV4L2
713
714
QT_END_NAMESPACE
715
716
#
include
"moc_qv4l2camera_p.cpp"
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
QtV4L2
Definition
qv4l2camera.cpp:18
QtV4L2::v4l2FormatForPixelFormat
uint32_t v4l2FormatForPixelFormat(QVideoFrameFormat::PixelFormat format)
Definition
qv4l2camera.cpp:60
QtV4L2::fmt
QVideoFrameFormat::PixelFormat fmt
Definition
qv4l2camera.cpp:24
QtV4L2::formatForV4L2Format
QVideoFrameFormat::PixelFormat formatForV4L2Format(uint32_t v4l2Format)
Definition
qv4l2camera.cpp:49
QtV4L2::Q_STATIC_LOGGING_CATEGORY
Q_STATIC_LOGGING_CATEGORY(qLcV4L2Camera, "qt.multimedia.v4l2.camera")
QtV4L2::v4l2Format
uint32_t v4l2Format
Definition
qv4l2camera.cpp:25
qtmultimedia
src
multimedia
v4l2
qv4l2camera.cpp
Generated on
for Qt by
1.16.1