tiagocoutinho / linuxpy

Human friendly interface to linux subsystems using python
https://tiagocoutinho.github.io/linuxpy/
GNU General Public License v3.0
28 stars 3 forks source link

v4l2 sub-device queries. #23

Closed notiska closed 1 month ago

notiska commented 1 month ago

The library doesn't seem to be able to query v4l2 sub-devices. When attempting to do so, I believe the wrong ioctl call is used (VIDIOC_QUERYCAP vs VIDIOC_SUBDEV_QUERYCAP).

The line in question is: https://github.com/tiagocoutinho/linuxpy/blob/master/linuxpy/video/device.py#L262 I've also included the full error:

In [9]: dev.open()
---------------------------------------------------------------------------
OSError                                   Traceback (most recent call last)
Cell In [9], line 1
----> 1 dev.open()

File ~/.local/lib/python3.11/site-packages/linuxpy/device.py:116, in BaseDevice.open(self)
    114 self.log.info("opening %s", self.filename)
    115 self._fobj = self.io.open(self.filename, self._read_write)
--> 116 self._on_open()
    117 self.log.info("opened %s", self.filename)

File ~/.local/lib/python3.11/site-packages/linuxpy/video/device.py:758, in Device._on_open(self)
    757 def _on_open(self):
--> 758     self.info = read_info(self.fileno())
    759     self.controls = Controls.from_device(self)

File ~/.local/lib/python3.11/site-packages/linuxpy/video/device.py:357, in read_info(fd)
    356 def read_info(fd):
--> 357     caps = read_capabilities(fd)
    358     version_tuple = (
    359         (caps.version & 0xFF0000) >> 16,
    360         (caps.version & 0x00FF00) >> 8,
    361         (caps.version & 0x0000FF),
    362     )
    363     version_str = ".".join(map(str, version_tuple))

File ~/.local/lib/python3.11/site-packages/linuxpy/video/device.py:262, in read_capabilities(fd)
    260 def read_capabilities(fd):
    261     caps = raw.v4l2_capability()
--> 262     ioctl(fd, IOC.QUERYCAP, caps)
    263     return caps

File ~/.local/lib/python3.11/site-packages/linuxpy/ioctl.py:67, in ioctl(fd, request, *args)
     65 def ioctl(fd, request, *args):
     66     log.debug("%s, request=%s, arg=%s", fd, request, args)
---> 67     fcntl.ioctl(fd, request, *args)
     68     return args and args[0] or None

OSError: [Errno 25] Inappropriate ioctl for device

P.S. Thanks for the great library, it's a real help :)

notiska commented 1 month ago

This issue looks fixed in #24.

Additionally, if I change the ioctl call to VIDIOC_SUBDEV_QUERYCAP, there seem to be control parsing issues, although I'm not sure if these are unrelated. I understand that changing this line is unintended functionality, but I've attached the error below in case it is also of any use:

In [3]: dev.open()
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In [3], line 1
----> 1 dev.open()

File ~/.local/lib/python3.11/site-packages/linuxpy/device.py:116, in BaseDevice.open(self)
    114 self.log.info("opening %s", self.filename)
    115 self._fobj = self.io.open(self.filename, self._read_write)
--> 116 self._on_open()
    117 self.log.info("opened %s", self.filename)

File ~/.local/lib/python3.11/site-packages/linuxpy/video/device.py:759, in Device._on_open(self)
    757 def _on_open(self):
    758     self.info = read_info(self.fileno())
--> 759     self.controls = Controls.from_device(self)

File ~/.local/lib/python3.11/site-packages/linuxpy/video/device.py:888, in Controls.from_device(cls, device)
    886     ctrl_type = ControlType(ctrl.type)
    887     ctrl_class = ctrl_type_map.get(ctrl_type, GenericControl)
--> 888     ctrl_dict[ctrl.id] = ctrl_class(device, ctrl)
    890 return cls(ctrl_dict)

File ~/.local/lib/python3.11/site-packages/linuxpy/video/device.py:1222, in MenuControl.__init__(self, device, info)
   1220     self.data = {item.index: item.name.decode() for item in iter_read_menu(self.device._fobj, self)}
   1221 elif self.type == ControlType.INTEGER_MENU:
-> 1222     self.data = {item.index: int(item.name) for item in iter_read_menu(self.device._fobj, self)}
   1223 else:
   1224     raise TypeError(f"MenuControl only supports control types MENU or INTEGER_MENU, but not {self.type.name}")

File ~/.local/lib/python3.11/site-packages/linuxpy/video/device.py:1222, in <dictcomp>(.0)
   1220     self.data = {item.index: item.name.decode() for item in iter_read_menu(self.device._fobj, self)}
   1221 elif self.type == ControlType.INTEGER_MENU:
-> 1222     self.data = {item.index: int(item.name) for item in iter_read_menu(self.device._fobj, self)}
   1223 else:
   1224     raise TypeError(f"MenuControl only supports control types MENU or INTEGER_MENU, but not {self.type.name}")

ValueError: invalid literal for int() with base 10: b''

I'm also happy to provide any further details that may be required, if these issues are within the scope of the project.

tiagocoutinho commented 1 month ago

Thanks for reporting. Indeed I never tested a device with sub-device capability.

I just checked with vivid in #24 but unfortunately it doesn't have sub-device support yet. (https://docs.kernel.org/admin-guide/media/vivid.html#some-future-improvements)

Please let me know if #24 fixes your problem

notiska commented 1 month ago

My bad, I should've been more clear with my phrasing. In this case I was referring to a second error that was raised after I had hard-coded the VIDIOC_SUBDEV_QUERYCAP ioctl call. I wasn't sure if it was related to sub-devices, or was a separate issue, so I mentioned it alongside.

I thought it may have been fixed by this commit: https://github.com/tiagocoutinho/linuxpy/pull/24/commits/5bd1412a19901028e11f9b1772b703b8c2c9c999 (in #24). Although, upon proper testing though, it doesn't appear to have been fixed.

Sorry for the confusion, I'm probably relating two separate issues in this case. I'll re-edit my original comment in case you need to see what I said.

tiagocoutinho commented 1 month ago

At this point the library doesn't support v4l2 sub-devices. Are you creating the device explicitly with something like Device("/dev/v4l-subdev0") ? Can you share the details about your hardware?

FYI, #24 was merged into master

notiska commented 1 month ago

Yes, I am creating the device explicitly with Device("/dev/v4l-subdev2").

In terms of hardware it's a Raspberry Pi 5 with a specific sensor. I don't think it'll help much unfortunately, but it's this one in particular: https://wiki.veye.cc/index.php/MV-MIPI-IMX287M_Index. /dev/v4l-subdev2 is used to configure settings for the camera, and /dev/video0 is used to retrieve the frames. (/dev/video0 works fine, BTW.) I'm not 100% sure why this is the case. As far as I've been told, it's due to the way media devices are handled on the Raspberry Pi 5.

I'm not sure if these will help, but I've attached the output of some commands too:

Regarding #24, the error is slightly different but I believe still fails in the same place:

File ~/Documents/linuxpy/linuxpy/video/device.py:1424, in <dictcomp>(.0)
   1422     self.data = {item.index: item.name.decode() for item in iter_read_menu(self.device._fobj, self)}
   1423 elif self.type == ControlType.INTEGER_MENU:
-> 1424     self.data = {item.index: ord(item.name) for item in iter_read_menu(self.device._fobj, self)}
   1425 else:
   1426     raise TypeError(f"MenuControl only supports control types MENU or INTEGER_MENU, but not {self.type.name}")

TypeError: ord() expected a character, but string of length 0 found

I will look more into the the int(item.name)/ord(item.name) error and see if I can get any more information about it.

notiska commented 1 month ago

So with the int(item.name)/ord(item.name) issue, the control in question is:

link_frequency 0x009f0901 (intmenu): min=0 max=0 default=0 value=0 (1500000000 0x59682f00)
        0: 1500000000 (0x59682f00)

Upon looking into this line: https://github.com/tiagocoutinho/linuxpy/blob/master/linuxpy/video/device.py#L1424 item.value seems to have the 1500000000 value reported by v4l2-ctl, and changing the line to:

self.data = {item.index: item.value for item in iter_read_menu(self.device._fobj, self)}

fixes the issue for me (python3 v4l2py-ctl.py --device /dev/v4l-subdev2: v4l2py-ctl-out.txt), though I'm not sure if this is a universal fix.

Also, I can put this under a separate issue if you want, as it doesn't seem to be related to querying sub-devices.

tiagocoutinho commented 1 month ago

yes, looks like the correct fix. I'm applying it on #27 Thanks for the feedback