Skip to content
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

devices: imx708: Add a new IMX708 helper class #1093

Merged
merged 2 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions picamera2/devices/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .imx708 import IMX708
1 change: 1 addition & 0 deletions picamera2/devices/imx708/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .imx708 import IMX708
67 changes: 67 additions & 0 deletions picamera2/devices/imx708/imx708.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import fcntl
import os

from v4l2 import VIDIOC_S_CTRL, v4l2_control

from picamera2 import Picamera2

HDR_CTRL_ID = 0x009a0915


class IMX708:
def __init__(self, camera_num=None):
self.device_fd = None

camera_info = Picamera2.global_camera_info()
if camera_num is None:
camera_id = next((c['Id'] for c in camera_info if c['Model'] == 'imx708'), None)
else:
camera_id = next((c['Id'] for c in camera_info if c['Num'] == camera_num), None)

if camera_id is None:
raise RuntimeError('IMX708: Requested IMX708 camera device not be found')

for i in range(16):
test_dir = f'/sys/class/video4linux/v4l-subdev{i}/device'
module_dir = f'{test_dir}/driver/module'
id_dir = f'{test_dir}/of_node'
if os.path.exists(module_dir) and os.path.islink(module_dir) and 'imx708' in os.readlink(module_dir):
if os.path.islink(id_dir) and camera_id in os.readlink(id_dir):
self.device_fd = open(f'/dev/v4l-subdev{i}', 'rb+', buffering=0)
break

if self.device_fd is None:
raise RuntimeError('IMX708: Requested camera v4l2 device node not found')

def __del__(self):
self.close()

def close(self):
if self.device_fd:
self.device_fd.close()
naushir marked this conversation as resolved.
Show resolved Hide resolved
self.device_fd = None

def __enter__(self):
return self

def __exit__(self, exc_type, exc_value, tb):
self.close()

def set_sensor_hdr_mode(self, enable: bool):
"""
Set the sensor HDR mode (True/False) on the IMX708 device.

Note that after changing the HDR mode, you must
re-initialise the Picamera2 object to cache the updated sensor modes.
"""
ctrl = v4l2_control()
ctrl.id = HDR_CTRL_ID
ctrl.value = int(enable)

try:
fcntl.ioctl(self.device_fd, VIDIOC_S_CTRL, ctrl)
except OSError as err:
print(f'IMX708: Unable to set HDR control in the device node: {err}')

# Must reset the camera manager so that cached sensor modes can be refreshed.
Picamera2._cm.reset()
5 changes: 5 additions & 0 deletions picamera2/picamera2.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ def cms(self):
self._cms = libcamera.CameraManager.singleton()
return self._cms

def reset(self):
with self._lock:
self._cms = None
self._cms = libcamera.CameraManager.singleton()

def add(self, index, camera):
with self._lock:
self.cameras[index] = camera
Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"Programming Language :: Python :: 3.9",
"Topic :: Multimedia :: Graphics :: Capture :: Digital Camera",
],
packages=['picamera2', 'picamera2.encoders', 'picamera2.outputs', 'picamera2.previews', 'picamera2.allocators'],
packages=['picamera2', 'picamera2.devices', 'picamera2.encoders', 'picamera2.outputs', 'picamera2.previews',
'picamera2.allocators'],
python_requires='>=3.9',
licence='BSD 2-Clause License',
install_requires=['numpy', 'PiDNG', 'piexif', 'pillow', 'simplejpeg', 'v4l2-python3', 'python-prctl', 'av'],
Expand Down
28 changes: 28 additions & 0 deletions tests/imx708_device.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/bin/python3

from picamera2 import Picamera2
from picamera2.devices.imx708 import IMX708

camera_info = Picamera2.global_camera_info()
camera_num = next((c['Num'] for c in camera_info if c['Model'] == 'imx708'), None)

if camera_num is not None:
with IMX708(camera_num) as cam:
cam.set_sensor_hdr_mode(True)
picam2 = Picamera2(camera_num)
if len(picam2.sensor_modes) != 1:
print("ERROR: We should only report 1 sensor HDR mode")
picam2.close()

cam.set_sensor_hdr_mode(False)
picam2 = Picamera2(camera_num)
if len(picam2.sensor_modes) <= 1:
print("ERROR: We should report > 1 sensor non-HDR modes")
picam2.close()

cam = IMX708(camera_num)
cam.set_sensor_hdr_mode(True)
picam2 = Picamera2(camera_num)
if len(picam2.sensor_modes) != 1:
print("ERROR: We should only report 1 sensor HDR mode")
picam2.close()
1 change: 1 addition & 0 deletions tests/test_list.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ tests/easy_video2.py
tests/egl_leak.py
tests/encoder_start_stop.py
tests/ffmpeg_abort.py
tests/imx708_device.py
tests/large_datagram.py
tests/mjpeg_server.py
tests/no_raw.py
Expand Down
Loading