Skip to content

Commit 07cf439

Browse files
pantheraleo-7davidplowman
authored andcommitted
minor refactor and cleanup, follow up to #1234
Signed-off-by: Asadullah Shaikh <asadshaikh20022002@gmail.com>
1 parent d9f988d commit 07cf439

File tree

3 files changed

+50
-55
lines changed

3 files changed

+50
-55
lines changed

picamera2/job.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ class Job(Generic[T]):
2525
"""
2626

2727
def __init__(self, functions: list[Callable[..., Union[
28-
tuple[Literal[False], None],
29-
tuple[Literal[True], Any],
28+
tuple[bool, Any],
3029
tuple[Literal[True], T]]]], signal_function=None
3130
):
3231
self._functions = functions

picamera2/picamera2.py

Lines changed: 40 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -320,9 +320,9 @@ def _reset_flags(self):
320320
self.camera = None
321321
self.camera_ctrl_info = {}
322322
self.camera_config = {}
323-
self.libcamera_config = None
323+
self.libcamera_config = {}
324324
self.streams = []
325-
self.stream_map = None
325+
self.stream_map = {}
326326
self.started = False
327327
self.stop_count = 0
328328
self.configure_count = 0
@@ -338,7 +338,7 @@ def _reset_flags(self):
338338
self._preview_stopped = threading.Event()
339339
self.camera_properties_ = {}
340340
self.controls = Controls(self)
341-
self.sensor_modes_ = None
341+
self.sensor_modes_ = []
342342
self._title_fields = []
343343
self._frame_drops = 0
344344

@@ -469,11 +469,11 @@ def _initialize_camera(self):
469469

470470
self.__identify_camera()
471471

472-
# Re-generate the controls list to someting easer to use.
472+
# Re-generate the controls list to something easier to use.
473473
for k, v in self.camera.controls.items():
474474
self.camera_ctrl_info[k.name] = (k, v)
475475

476-
# Re-generate the properties list to someting easer to use.
476+
# Re-generate the properties list to something easier to use.
477477
for k, v in self.camera.properties.items():
478478
self.camera_properties_[k.name] = utils.convert_from_libcamera_type(v)
479479

@@ -514,7 +514,7 @@ def sensor_modes(self) -> list[dict[str, Any]]:
514514
When called for the first time this will reconfigure the camera
515515
in order to read the modes.
516516
"""
517-
if self.sensor_modes_ is not None:
517+
if self.sensor_modes_:
518518
return self.sensor_modes_
519519

520520
raw_config = self.camera.generate_configuration([libcamera.StreamRole.Raw])
@@ -600,13 +600,11 @@ def start_preview(self, preview=None, **kwargs) -> None:
600600
preview = Preview.QTGL.value(**kwargs)
601601
else:
602602
preview = Preview.QT.value(**kwargs)
603-
if preview is None or preview is False: # i.e. None or False
603+
elif preview is False or preview is None:
604604
preview = Preview.NULL.value(**kwargs)
605605
elif isinstance(preview, Preview):
606606
preview = preview.value(**kwargs)
607-
else:
608-
# Assume it's already a preview object.
609-
pass
607+
# Assume it's already a preview object.
610608

611609
# The preview windows call the attach_preview method.
612610
self._preview_stopped.clear()
@@ -649,11 +647,11 @@ def close(self) -> None:
649647
self._cm.cleanup(self.camera_idx)
650648
self.is_open = False
651649
self.streams = []
652-
self.stream_map = None
650+
self.stream_map = {}
653651
self.camera = None
654652
self.camera_ctrl_info = {}
655653
self.camera_config = {}
656-
self.libcamera_config = None
654+
self.libcamera_config = {}
657655
self.preview_configuration = {}
658656
self.still_configuration = {}
659657
self.video_configuration = {}
@@ -886,9 +884,8 @@ def _update_libcamera_stream_config(libcamera_stream_config, stream_config, buff
886884
def _make_libcamera_config(self, camera_config):
887885
# Make a libcamera configuration object from our Python configuration.
888886

889-
# We will create each stream with the "viewfinder" role just to get the stream
890-
# configuration objects, and note the positions our named streams will have in
891-
# libcamera's stream list.
887+
# We will create each stream with the "viewfinder" role just to get the stream configuration
888+
# objects, and note the positions our named streams will have in libcamera's stream list.
892889
roles = [VIEWFINDER]
893890
index = 1
894891
self.main_index = 0
@@ -902,8 +899,7 @@ def _make_libcamera_config(self, camera_config):
902899
self.raw_index = index
903900
roles += [RAW]
904901

905-
# Make the libcamera configuration, and then we'll write all our parameters over
906-
# the ones it gave us.
902+
# Make the libcamera configuration, and then we'll write all our parameters over the ones it gave us.
907903
libcamera_config = self.camera.generate_configuration(roles)
908904
libcamera_config.orientation = utils.transform_to_orientation(camera_config["transform"])
909905
buffer_count = camera_config["buffer_count"]
@@ -924,19 +920,17 @@ def _make_libcamera_config(self, camera_config):
924920

925921
# We're always going to set up the sensor config fully.
926922
bit_depth = 0
927-
if camera_config['sensor'] is not None and 'bit_depth' in camera_config['sensor'] and \
928-
camera_config['sensor']['bit_depth'] is not None:
923+
if camera_config['sensor'] is not None and camera_config['sensor'].get('bit_depth') is not None:
929924
bit_depth = camera_config['sensor']['bit_depth']
930-
elif 'raw' in camera_config and camera_config['raw'] is not None and 'format' in camera_config['raw']:
925+
elif camera_config.get('raw') is not None and 'format' in camera_config['raw']:
931926
bit_depth = SensorFormat(camera_config['raw']['format']).bit_depth
932927
else:
933928
bit_depth = SensorFormat(self.sensor_format).bit_depth
934929

935930
output_size = None
936-
if camera_config['sensor'] is not None and 'output_size' in camera_config['sensor'] and \
937-
camera_config['sensor']['output_size'] is not None:
931+
if camera_config['sensor'] is not None and camera_config['sensor'].get('output_size') is not None:
938932
output_size = camera_config['sensor']['output_size']
939-
elif 'raw' in camera_config and camera_config['raw'] is not None and 'size' in camera_config['raw']:
933+
elif camera_config.get('raw') is not None and 'size' in camera_config['raw']:
940934
output_size = camera_config['raw']['size']
941935
else:
942936
output_size = camera_config['main']['size']
@@ -969,7 +963,7 @@ def score_format(desired, actual):
969963
@staticmethod
970964
def align_stream(stream_config, optimal=True) -> None:
971965
if optimal:
972-
# Adjust the image size so that all planes are a mutliple of 32/64 bytes wide.
966+
# Adjust the image size so that all planes are a multiple of 32/64 bytes wide.
973967
# This matches the hardware behaviour and means we can be more efficient.
974968
align = 32 if Picamera2.platform == Platform.Platform.VC4 else 64
975969
if stream_config["format"] in ("YUV420", "YVU420"):
@@ -984,7 +978,7 @@ def align_stream(stream_config, optimal=True) -> None:
984978
@staticmethod
985979
def align_configuration(config, optimal=True) -> None:
986980
Picamera2.align_stream(config["main"], optimal=optimal)
987-
if "lores" in config and config["lores"] is not None:
981+
if config.get("lores") is not None:
988982
Picamera2.align_stream(config["lores"], optimal=optimal)
989983
# No point aligning the raw stream, it wouldn't mean anything.
990984

@@ -1039,28 +1033,30 @@ def _update_camera_config(self, camera_config, libcamera_config):
10391033
sensor_config['output_size'] = utils.convert_from_libcamera_type(libcamera_config.sensor_config.output_size)
10401034
camera_config['sensor'] = sensor_config
10411035

1042-
def configure_(self, camera_config="preview"):
1036+
def configure_(self, camera_config):
10431037
"""Configure the camera system with the given configuration.
10441038
1045-
:param camera_config: Configuration, defaults to the 'preview' configuration
1046-
:type camera_config: dict, string or CameraConfiguration, optional
1047-
:raises RuntimeError: Failed to configure
1039+
:param camera_config: Camera configuration to be set
1040+
:type camera_config: str, dict or CameraConfiguration
1041+
:raises RuntimeError: Failed to configure at runtime
10481042
"""
10491043
if self.started:
10501044
raise RuntimeError("Camera must be stopped before configuring")
10511045

10521046
initial_config = camera_config
1047+
10531048
if isinstance(camera_config, str):
10541049
if camera_config == "preview":
10551050
camera_config = self.preview_configuration
10561051
elif camera_config == "still":
10571052
camera_config = self.still_configuration
1058-
else:
1053+
elif camera_config == "video":
10591054
camera_config = self.video_configuration
1055+
else:
1056+
_log.warning("Invalid name for `camera_config` given, assuming default 'preview' configuration")
1057+
camera_config = self.preview_configuration
10601058
elif isinstance(camera_config, dict):
10611059
camera_config = camera_config.copy()
1062-
elif camera_config is None:
1063-
camera_config = self.create_preview_configuration()
10641060

10651061
if isinstance(camera_config, CameraConfiguration):
10661062
if camera_config.raw is not None:
@@ -1077,7 +1073,7 @@ def configure_(self, camera_config="preview"):
10771073
camera_config['raw'] = None
10781074

10791075
# Mark ourselves as unconfigured.
1080-
self.libcamera_config = None
1076+
self.libcamera_config = {}
10811077
self.camera_config = {}
10821078

10831079
# Check the config and turn it into a libcamera config.
@@ -1122,10 +1118,9 @@ def configure_(self, camera_config="preview"):
11221118
if self.encode_stream_name is not None and self.encode_stream_name not in camera_config:
11231119
raise RuntimeError(f"Encode stream {self.encode_stream_name} was not defined")
11241120

1125-
# Decide whether we are going to keep hold of the last completed request, or
1126-
# whether capture requests will always wait for the next frame. If there's only
1127-
# one buffer, never hang on to the request because it would stall the pipeline
1128-
# instantly.
1121+
# Decide whether we are going to keep hold of the last completed request, or whether
1122+
# capture requests will always wait for the next frame. If there's only one buffer,
1123+
# never hang on to the request because it would stall the pipeline instantly.
11291124
if camera_config['queue'] and camera_config['buffer_count'] > 1:
11301125
self._max_queue_len = 1
11311126
else:
@@ -1134,16 +1129,19 @@ def configure_(self, camera_config="preview"):
11341129
# Allocate all the frame buffers.
11351130
self.streams = [stream_config.stream for stream_config in libcamera_config]
11361131
self.allocator.allocate(libcamera_config, camera_config.get("use_case"))
1132+
11371133
# Mark ourselves as configured.
11381134
self.libcamera_config = libcamera_config
11391135
self.camera_config = camera_config
1136+
11401137
# Fill in the embedded configuration structures if those were used.
11411138
if initial_config == "preview":
11421139
self.preview_configuration.update(camera_config)
11431140
elif initial_config == "still":
11441141
self.still_configuration.update(camera_config)
11451142
else:
11461143
self.video_configuration.update(camera_config)
1144+
11471145
# Set the controls directly so as to overwrite whatever is there.
11481146
self.controls = Controls(self, controls=self.camera_config['controls'])
11491147
self.configure_count += 1
@@ -1206,7 +1204,7 @@ def start(self, config=None, show_preview=False) -> None:
12061204
self.configure(config)
12071205
if not self.camera_config:
12081206
raise RuntimeError("Camera has not been configured")
1209-
# By default we will create an event loop is there isn't one running already.
1207+
# By default we will create an event loop if there isn't one running already.
12101208
if show_preview is not None and not self._event_loop_running:
12111209
self.start_preview(show_preview)
12121210
self.start_()
@@ -1269,8 +1267,7 @@ def set_controls(self, controls) -> None:
12691267
self.controls.set_controls(controls)
12701268

12711269
def process_requests(self, display) -> None:
1272-
# This is the function that the event loop, which runs externally to us, must
1273-
# call.
1270+
# This is the function that the event loop, which runs externally to us, must call.
12741271
requests = []
12751272
with self._requestslock:
12761273
requests = self._requests
@@ -1287,9 +1284,8 @@ def process_requests(self, display) -> None:
12871284
# "job" for us to execute here in order to accomplish what it wanted.
12881285

12891286
with self.lock:
1290-
# These new requests all have one "use" recorded, which is the one for
1291-
# being in this list. Increase by one, so it cant't get discarded in
1292-
# self.functions block.
1287+
# These new requests all have one "use" recorded, which is the one for being in
1288+
# this list. Increase by one, so it cant't get discarded in self.functions block.
12931289
for req in requests:
12941290
req.acquire()
12951291
self.completed_requests += requests
@@ -2580,7 +2576,7 @@ def wait_for_af_state(self, states):
25802576
return (af_state in states, af_state == controls.AfStateEnum.Focused)
25812577

25822578
# First wait for the scan to start. Once we've seen that, the AF cycle may:
2583-
# succeed, fail or could go back to Idle if it is cancelled.
2579+
# succeed, fail or could go back to idle if it is cancelled.
25842580
functions = [partial(wait_for_af_state, self, {controls.AfStateEnum.Scanning}),
25852581
partial(wait_for_af_state, self,
25862582
{controls.AfStateEnum.Focused, controls.AfStateEnum.Failed, controls.AfStateEnum.Idle})]

picamera2/request.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import time
66
from datetime import datetime
77
from pathlib import Path
8-
from typing import TYPE_CHECKING, Any, Dict, Optional, Union, cast
8+
from typing import TYPE_CHECKING, Any, Dict, Optional, Union
99

1010
import numpy as np
1111
import piexif
@@ -29,7 +29,7 @@
2929
class _MappedBuffer:
3030
def __init__(self, request: "CompletedRequest", stream: str, write: bool = True) -> None:
3131
if isinstance(stream, str):
32-
stream = cast(Dict[str, Any], request.stream_map)[stream]
32+
stream = request.stream_map[stream]
3333
assert request.request is not None
3434
self.__fb = request.request.buffers[stream]
3535
self.__sync = request.picam2.allocator.sync(request.picam2.allocator, self.__fb, write)
@@ -56,7 +56,7 @@ def __enter__(self) -> "MappedArray":
5656

5757
if self.__reshape:
5858
if isinstance(self.__stream, str):
59-
config = cast(Dict[str, Any], self.__request.config)[self.__stream]
59+
config = self.__request.config[self.__stream]
6060
else:
6161
config = self.__stream.configuration
6262

@@ -86,8 +86,8 @@ def __init__(self, request: Any, picam2: "Picamera2") -> None:
8686
self.picam2 = picam2
8787
self.stop_count: int = picam2.stop_count
8888
self.configure_count: int = picam2.configure_count
89-
self.config = cast(Dict[str, Any], self.picam2.camera_config).copy()
90-
self.stream_map = cast(Dict[str, Any], self.picam2.stream_map).copy()
89+
self.config = self.picam2.camera_config.copy()
90+
self.stream_map = self.picam2.stream_map.copy()
9191
with self.lock:
9292
self.syncs = [picam2.allocator.sync(self.picam2.allocator, buffer, False)
9393
for buffer in self.request.buffers.values()]
@@ -122,12 +122,12 @@ def release(self) -> None:
122122
assert self.request is not None
123123
self.picam2.allocator.release(self.request.buffers)
124124
self.request = None
125-
self.config = None
126-
self.stream_map = None
125+
self.config = {}
126+
self.stream_map = {}
127127

128128
def make_buffer(self, name: str) -> np.ndarray:
129129
"""Make a 1D numpy array from the named stream's buffer."""
130-
if cast(Dict[str, Any], self.stream_map).get(name) is None:
130+
if self.stream_map.get(name) is None:
131131
raise RuntimeError(f'Stream {name!r} is not defined')
132132
with _MappedBuffer(self, name, write=False) as b:
133133
return np.array(b, dtype=np.uint8)
@@ -244,7 +244,7 @@ def save(self, name: str, file_output: Any, format: Optional[str] = None,
244244
def save_dng(self, file_output: Any, name: str = "raw") -> None:
245245
"""Save a DNG RAW image of the raw stream's buffer."""
246246
# Don't use make_buffer(), this saves a copy.
247-
if self.stream_map.get(name, None) is None:
247+
if self.stream_map.get(name) is None:
248248
raise RuntimeError(f'Stream {name!r} is not defined')
249249
with _MappedBuffer(self, name, write=False) as b:
250250
buffer = np.array(b, copy=False, dtype=np.uint8)

0 commit comments

Comments
 (0)