-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bunch of V4L2 features #9
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
import fcntl | ||
import os | ||
from enum import IntFlag | ||
from copy import copy | ||
|
||
import v4l2.uapi | ||
|
||
|
@@ -66,6 +67,8 @@ def __init__(self, dev_path: str) -> None: | |
except OSError: | ||
self.has_streams = False | ||
|
||
self.controls = self.enum_ext_ctrls() | ||
|
||
def get_formats(self, pad, stream=0, which=v4l2.uapi.V4L2_SUBDEV_FORMAT_ACTIVE): | ||
val = v4l2.uapi.v4l2_subdev_mbus_code_enum() | ||
val.pad = pad | ||
|
@@ -271,3 +274,53 @@ def set_control(self, ctrl_id: int, ctrl_val: int): | |
v4l2_ctrl.value = ctrl_val | ||
|
||
fcntl.ioctl(self.fd, v4l2.uapi.VIDIOC_S_CTRL, v4l2_ctrl, False) | ||
|
||
def enum_ext_ctrls(self): | ||
ctrl = v4l2.uapi.v4l2_queryctrl() | ||
ctrl.id = v4l2.uapi.V4L2_CTRL_FLAG_NEXT_CTRL | ||
ext_ctrls = {} | ||
while True: | ||
try: | ||
fcntl.ioctl(self.fd, v4l2.uapi.VIDIOC_QUERYCTRL, ctrl) | ||
except OSError: | ||
return ext_ctrls | ||
|
||
if ctrl.type != v4l2.uapi.V4L2_CTRL_TYPE_CTRL_CLASS: | ||
ext_ctrls[ctrl.id] = copy(ctrl) | ||
|
||
ctrl.id |= v4l2.uapi.V4L2_CTRL_FLAG_NEXT_CTRL | ||
|
||
def get_ext_ctrl(self, ctrl_id: int): | ||
ctrl = v4l2.uapi.v4l2_ext_control() | ||
ctrl.id = ctrl_id | ||
ext_ctrl = v4l2.uapi.v4l2_ext_controls() | ||
ext_ctrl.which = v4l2.uapi.V4L2_CTRL_WHICH_CUR_VAL | ||
ext_ctrl.count = 1 | ||
ext_ctrl.controls = ctypes.pointer(ctrl) | ||
fcntl.ioctl(self.fd, v4l2.uapi.VIDIOC_G_EXT_CTRLS, ext_ctrl) | ||
return ( | ||
ctrl.value64 | ||
if (self.controls[ctrl_id].type == v4l2.uapi.V4L2_CTRL_TYPE_INTEGER64) | ||
else ctrl.value | ||
) | ||
|
||
def set_ext_ctrl(self, ctrl_id, ctrl_val): | ||
# TODO: handle situation when control is dynamically grabbed | ||
if self.controls[ctrl_id].flags & v4l2.uapi.V4L2_CTRL_FLAG_READ_ONLY: | ||
print(f"Control id [{ctrl_id}] isn't writable") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should raise an exception. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes sure... I realized now the poor quality of this PR... Regarding ext ctrls, I made the choice to enumerate controls at SubDevice initialization : Would you mind giving me your opinion and I could propose an updated implementation. |
||
return | ||
if self.controls[ctrl_id].flags & v4l2.uapi.V4L2_CTRL_FLAG_GRABBED: | ||
print(f'Control id [{ctrl_id}] temporarily grabbed') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And this too. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same than above :-) |
||
return | ||
|
||
ctrl = v4l2.uapi.v4l2_ext_control() | ||
ctrl.id = ctrl_id | ||
if self.controls[ctrl_id].type == v4l2.uapi.V4L2_CTRL_TYPE_INTEGER64: | ||
ctrl.value64 = ctrl_val | ||
else: | ||
ctrl.value = ctrl_val | ||
ext_ctrl = v4l2.uapi.v4l2_ext_controls() | ||
ext_ctrl.which = v4l2.uapi.V4L2_CTRL_WHICH_CUR_VAL | ||
ext_ctrl.count = 1 | ||
ext_ctrl.controls = ctypes.pointer(ctrl) | ||
fcntl.ioctl(self.fd, v4l2.uapi.VIDIOC_S_EXT_CTRLS, ext_ctrl) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would help me to understand what you need if you would describe in the commit desc what you use this for (similarly for exporting CaptureStreamer). Looks like you just use it to set/get a single 32/64 bit value? I'm not super familiar with v4l2 controls as I haven't used them too much, but I think I'd really like to be able to expose a unified API for the users. No "ext" vs "non-ext" stuff, but just a way to get and set controls, regardless if the driver supports ext or not. So, we already have the "naive" set_control(), I'd like to see it extended so it just works, instead of adding set_ext_ctrl(), requiring the caller to know which one to use. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, As explained above, I have a WIP 'mediapipe' branch (https://github.com/sylpe/pyv4l2/tree/mediapipe). Please find below an example of how I use it :
This could help understand better the context. I would have like to use the existing set_control(), but for some of the controls (especially integer64) and flags, It was possible to go through the "legacy" control API. I'm totally aligned with you, better to improve the existing API. Depending of your thoughts I could proposed a better implementation fitting with pyv4l2 philosophy. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3613,6 +3613,7 @@ class struct_v4l2_ext_control(Structure): | |
'reserved2', | ||
'unnamed_1', | ||
] | ||
struct_v4l2_ext_control._pack_ = 1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This file is generated, you can't modify it as the modification will get overwritten. If this is really needed, then something needs to be done either in the generator script or init.py. Or maybe there's a bug in the ctypesgen, which needs to be fixed. It's also not clear to me why this is needed or how it helps... struct_v4l2_ext_control has u32 fields, and the last one is an union. How does it get packed without this change? Which field gets extra alignment without this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Honestly I didn't really understand why this was needed... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
struct_v4l2_ext_control._anonymous_ = [ | ||
'unnamed_1', | ||
] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've never seen this style used before. Maybe it's just me, but that's very unclear to me. How about just:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, its not you :-), just badly written... Will fix it.
It also raise questions about the type of controls to support (In a first step, I only needed INTEGER64).