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