-
Notifications
You must be signed in to change notification settings - Fork 7
/
v4l2ctrls.py
156 lines (139 loc) · 6.26 KB
/
v4l2ctrls.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import logging
from fcntl import ioctl
import v4l2
class V4L2Ctrls:
def __init__(self, device, fd):
self.device = device
self.fd = fd
self.get_device_cap()
self.get_device_controls()
def setup_v4l2_ctrls(self, params):
for k, v in params.items():
if k in ['width', 'height', 'fps', 'auto_sleep', 'rotation',
'capture_format', 'capture_memory',
'decoder', 'decoder_input_format', 'decoder_memory',
'encoder', 'encoder_input_format', 'encoder_memory',
] or k.startswith('uvcx_'):
continue
ctrl = find_by_name(self.ctrls, k)
if ctrl == None:
logging.warning(f'Can\'t find {k} v4l2 control')
continue
intvalue = 0
if ctrl.type == v4l2.V4L2_CTRL_TYPE_INTEGER:
intvalue = int(v)
elif ctrl.type == v4l2.V4L2_CTRL_TYPE_BOOLEAN:
intvalue = int(bool(v))
elif ctrl.type == v4l2.V4L2_CTRL_TYPE_MENU:
menu = find_by_name(ctrl.menus, v)
if menu == None:
logging.warning(f'Can\'t find {v} in {[str(c.name, "utf-8") for c in ctrl.menus]}')
continue
intvalue = menu.index
elif ctrl.type == v4l2.V4L2_CTRL_TYPE_INTEGER_MENU:
menu = find_by_value(ctrl.menus, int(v))
if menu == None:
logging.warning(f'Can\'t find {v} in {[c.value for c in ctrl.menus]}')
continue
intvalue = menu.index
else:
logging.warning(f'Can\'t set {k} to {v} (Unsupported control type {ctrl.type})')
continue
try:
new_ctrl = v4l2.v4l2_control(ctrl.id, intvalue)
ioctl(self.fd, v4l2.VIDIOC_S_CTRL, new_ctrl)
if new_ctrl.value != intvalue:
logging.warning(f'Can\'t set {k} to {v} using {new_ctrl.value} instead of {intvalue}')
continue
ctrl.value = intvalue
except Exception as e:
logging.warning(f'Can\'t set {k} to {v} ({e})')
def get_device_cap(self):
cap = v4l2.v4l2_capability()
try:
ioctl(self.fd, v4l2.VIDIOC_QUERYCAP, cap)
except Exception as e:
logging.warning(f'v4l2ctrls: VIDIOC_QUERYCAP failed: ({e})')
self.card = str(cap.card, 'utf-8')
self.driver = str(cap.driver, 'utf-8')
def get_device_controls(self):
ctrls = []
strtrans = bytes.maketrans(b' -', b'__')
next_fl = v4l2.V4L2_CTRL_FLAG_NEXT_CTRL | v4l2.V4L2_CTRL_FLAG_NEXT_COMPOUND
qctrl = v4l2.v4l2_queryctrl(next_fl)
while True:
try:
ioctl(self.fd, v4l2.VIDIOC_QUERYCTRL, qctrl)
except:
break
if qctrl.type in [v4l2.V4L2_CTRL_TYPE_INTEGER, v4l2.V4L2_CTRL_TYPE_BOOLEAN,
v4l2.V4L2_CTRL_TYPE_MENU,v4l2.V4L2_CTRL_TYPE_INTEGER_MENU]:
try:
ctrl = v4l2.v4l2_control(qctrl.id)
ioctl(self.fd, v4l2.VIDIOC_G_CTRL, ctrl)
qctrl.value = ctrl.value
except:
logging.warning(f'Can\'t get ctrl {qctrl.name} value')
qctrl.name = qctrl.name.lower().translate(strtrans, delete = b',&(.)').replace(b'__', b'_')
if qctrl.type in [v4l2.V4L2_CTRL_TYPE_MENU, v4l2.V4L2_CTRL_TYPE_INTEGER_MENU]:
qctrl.menus = []
for i in range(qctrl.minimum, qctrl.maximum + 1):
try:
qmenu = v4l2.v4l2_querymenu(qctrl.id, i)
ioctl(self.fd, v4l2.VIDIOC_QUERYMENU, qmenu)
except:
continue
qctrl.menus.append(qmenu)
ctrls.append(qctrl)
qctrl = v4l2.v4l2_queryctrl(qctrl.id | next_fl)
self.ctrls = ctrls
def print_ctrls(self):
print(f'Device: {self.device}')
print(f'Name: {self.card}')
print(f'Driver: {self.driver}')
print(f'\nControls')
for c in self.ctrls:
if c.type == v4l2.V4L2_CTRL_TYPE_CTRL_CLASS:
print('\n' + str(c.name, 'utf-8')+'\n')
else:
print(str(c.name, 'utf-8'), end = ' = ')
if c.type in [v4l2.V4L2_CTRL_TYPE_MENU, v4l2.V4L2_CTRL_TYPE_INTEGER_MENU]:
defmenu = None
valmenu = None
for m in c.menus:
if m.index == c.value:
valmenu = m
if m.index == c.default:
defmenu = m
if valmenu:
print(f'{str(valmenu.name, "utf-8") if c.type == v4l2.V4L2_CTRL_TYPE_MENU else valmenu.value}\t(', end = ' ')
if defmenu:
print(f'default: {str(defmenu.name, "utf-8") if c.type == v4l2.V4L2_CTRL_TYPE_MENU else defmenu.value}', end = ' ')
print('values:', end = ' ')
for m in c.menus:
print('%a' % (str(m.name, 'utf-8') if c.type == v4l2.V4L2_CTRL_TYPE_MENU else m.value),
end = ' ')
print(')')
elif c.type in [v4l2.V4L2_CTRL_TYPE_INTEGER, v4l2.V4L2_CTRL_TYPE_BOOLEAN]:
print('%a\t(' % c.value, 'default:', c.default, 'min:', c.minimum, 'max:', c.maximum, end = '')
if c.step != 1:
print(' step:', c.step, end = '')
print(')')
else:
print()
def request_key_frame(self):
try:
ctrl = v4l2.v4l2_control(v4l2.V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, 0)
ioctl(self.fd, v4l2.VIDIOC_S_CTRL, ctrl)
except:
logging.warning(f'{self.device} can\'t request keyframe')
def find_by_name(ctrls, name):
for c in ctrls:
if name == str(c.name, 'utf-8'):
return c
return None
def find_by_value(menus, value):
for m in menus:
if value == m.value:
return m
return None