[libcamera-devel] [PATCH v2 13/19] py: cam: Convert ctx and state to classes
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Fri May 27 08:53:52 CEST 2022
Hi Tomi,
Thank you for the patch.
On Tue, May 24, 2022 at 02:46:04PM +0300, Tomi Valkeinen wrote:
> From: Tomi Valkeinen <tomi.valkeinen at iki.fi>
>
> Convert ctx and state dicts to classes. No functional changes.
>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
> ---
> src/py/cam/cam.py | 585 +++++++++++++++++++++--------------------
> src/py/cam/cam_kms.py | 12 +-
> src/py/cam/cam_null.py | 8 +-
> src/py/cam/cam_qt.py | 16 +-
> src/py/cam/cam_qtgl.py | 22 +-
> 5 files changed, 327 insertions(+), 316 deletions(-)
>
> diff --git a/src/py/cam/cam.py b/src/py/cam/cam.py
> index 64f67e86..f6e8232c 100755
> --- a/src/py/cam/cam.py
> +++ b/src/py/cam/cam.py
> @@ -6,6 +6,7 @@
> # \todo Convert ctx and state dicts to proper classes, and move relevant
> # functions to those classes.
>
> +from typing import Any
> import argparse
> import binascii
> import libcamera as libcam
> @@ -14,379 +15,400 @@ import sys
> import traceback
>
>
> -class CustomAction(argparse.Action):
> - def __init__(self, option_strings, dest, **kwargs):
> - super().__init__(option_strings, dest, default={}, **kwargs)
> +class CameraContext:
> + camera: libcam.Camera
> + id: str
> + idx: int
>
> - def __call__(self, parser, namespace, values, option_string=None):
> - if len(namespace.camera) == 0:
> - print(f'Option {option_string} requires a --camera context')
> - sys.exit(-1)
> + opt_stream: str
> + opt_strict_formats: bool
> + opt_crc: bool
> + opt_metadata: bool
> + opt_save_frames: bool
> + opt_capture: int
>
> - if self.type == bool:
> - values = True
> + stream_names: dict[libcam.Stream, str]
> + streams: list[libcam.Stream]
> + allocator: libcam.FrameBufferAllocator
> + requests: list[libcam.Request]
> + reqs_queued: int
> + reqs_completed: int
> + last: int = 0
> + fps: float
>
> - current = namespace.camera[-1]
> + def __init__(self, camera, idx):
> + self.camera = camera
> + self.idx = idx
> + self.id = 'cam' + str(idx)
> + self.reqs_queued = 0
> + self.reqs_completed = 0
>
> - data = getattr(namespace, self.dest)
> + def do_cmd_list_props(self):
> + camera = self.camera
>
> - if self.nargs == '+':
> - if current not in data:
> - data[current] = []
> + print('Properties for', self.id)
>
> - data[current] += values
> - else:
> - data[current] = values
> + for name, prop in camera.properties.items():
You can use self.camera here and drop the local variable. Same in a few
other functions below.
> + print('\t{}: {}'.format(name, prop))
>
> + def do_cmd_list_controls(self):
> + camera = self.camera
>
> -def do_cmd_list(cm):
> - print('Available cameras:')
> -
> - for idx, c in enumerate(cm.cameras):
> - print(f'{idx + 1}: {c.id}')
> -
> -
> -def do_cmd_list_props(ctx):
> - camera = ctx['camera']
> -
> - print('Properties for', ctx['id'])
> -
> - for name, prop in camera.properties.items():
> - print('\t{}: {}'.format(name, prop))
> -
> -
> -def do_cmd_list_controls(ctx):
> - camera = ctx['camera']
> -
> - print('Controls for', ctx['id'])
> -
> - for name, prop in camera.controls.items():
> - print('\t{}: {}'.format(name, prop))
> + print('Controls for', self.id)
>
> + for name, prop in camera.controls.items():
> + print('\t{}: {}'.format(name, prop))
>
> -def do_cmd_info(ctx):
> - camera = ctx['camera']
> + def do_cmd_info(self):
> + camera = self.camera
>
> - print('Stream info for', ctx['id'])
> + print('Stream info for', self.id)
>
> - roles = [libcam.StreamRole.Viewfinder]
> + roles = [libcam.StreamRole.Viewfinder]
>
> - camconfig = camera.generate_configuration(roles)
> - if camconfig is None:
> - raise Exception('Generating config failed')
> + camconfig = camera.generate_configuration(roles)
> + if camconfig is None:
> + raise Exception('Generating config failed')
>
> - for i, stream_config in enumerate(camconfig):
> - print('\t{}: {}'.format(i, stream_config))
> + for i, stream_config in enumerate(camconfig):
> + print('\t{}: {}'.format(i, stream_config))
>
> - formats = stream_config.formats
> - for fmt in formats.pixel_formats:
> - print('\t * Pixelformat:', fmt, formats.range(fmt))
> + formats = stream_config.formats
> + for fmt in formats.pixel_formats:
> + print('\t * Pixelformat:', fmt, formats.range(fmt))
>
> - for size in formats.sizes(fmt):
> - print('\t -', size)
> + for size in formats.sizes(fmt):
> + print('\t -', size)
>
> + def acquire(self):
> + camera = self.camera
>
> -def acquire(ctx):
> - camera = ctx['camera']
> + camera.acquire()
>
> - camera.acquire()
> + def release(self):
> + camera = self.camera
>
> + camera.release()
>
> -def release(ctx):
> - camera = ctx['camera']
> + def __parse_streams(self):
> + streams = []
>
> - camera.release()
> + for stream_desc in self.opt_stream:
> + stream_opts: dict[str, Any]
> + stream_opts = {'role': libcam.StreamRole.Viewfinder}
>
> + for stream_opt in stream_desc.split(','):
> + if stream_opt == 0:
> + continue
>
> -def parse_streams(ctx):
> - streams = []
> -
> - for stream_desc in ctx['opt-stream']:
> - stream_opts = {'role': libcam.StreamRole.Viewfinder}
> -
> - for stream_opt in stream_desc.split(','):
> - if stream_opt == 0:
> - continue
> -
> - arr = stream_opt.split('=')
> - if len(arr) != 2:
> - print('Bad stream option', stream_opt)
> - sys.exit(-1)
> -
> - key = arr[0]
> - value = arr[1]
> -
> - if key in ['width', 'height']:
> - value = int(value)
> - elif key == 'role':
> - rolemap = {
> - 'still': libcam.StreamRole.StillCapture,
> - 'raw': libcam.StreamRole.Raw,
> - 'video': libcam.StreamRole.VideoRecording,
> - 'viewfinder': libcam.StreamRole.Viewfinder,
> - }
> -
> - role = rolemap.get(value.lower(), None)
> + arr = stream_opt.split('=')
> + if len(arr) != 2:
> + print('Bad stream option', stream_opt)
> + sys.exit(-1)
Raising an exception would be better, but that's a candidate for another
patch as it's a functional change.
>
> - if role is None:
> - print('Bad stream role', value)
> + key = arr[0]
> + value = arr[1]
> +
> + if key in ['width', 'height']:
> + value = int(value)
> + elif key == 'role':
> + rolemap = {
> + 'still': libcam.StreamRole.StillCapture,
> + 'raw': libcam.StreamRole.Raw,
> + 'video': libcam.StreamRole.VideoRecording,
> + 'viewfinder': libcam.StreamRole.Viewfinder,
> + }
> +
> + role = rolemap.get(value.lower(), None)
> +
> + if role is None:
> + print('Bad stream role', value)
> + sys.exit(-1)
> +
> + value = role
> + elif key == 'pixelformat':
> + pass
> + else:
> + print('Bad stream option key', key)
> sys.exit(-1)
>
> - value = role
> - elif key == 'pixelformat':
> - pass
> - else:
> - print('Bad stream option key', key)
> - sys.exit(-1)
> + stream_opts[key] = value
>
> - stream_opts[key] = value
> + streams.append(stream_opts)
>
> - streams.append(stream_opts)
> + return streams
>
> - return streams
> + def configure(self):
> + camera = self.camera
>
> + streams = self.__parse_streams()
>
> -def configure(ctx):
> - camera = ctx['camera']
> + roles = [opts['role'] for opts in streams]
>
> - streams = parse_streams(ctx)
> + camconfig = camera.generate_configuration(roles)
> + if camconfig is None:
> + raise Exception('Generating config failed')
>
> - roles = [opts['role'] for opts in streams]
> + for idx, stream_opts in enumerate(streams):
> + stream_config = camconfig.at(idx)
>
> - camconfig = camera.generate_configuration(roles)
> - if camconfig is None:
> - raise Exception('Generating config failed')
> + if 'width' in stream_opts:
> + stream_config.size.width = stream_opts['width']
>
> - for idx, stream_opts in enumerate(streams):
> - stream_config = camconfig.at(idx)
> + if 'height' in stream_opts:
> + stream_config.size.height = stream_opts['height']
>
> - if 'width' in stream_opts:
> - stream_config.size.width = stream_opts['width']
> + if 'pixelformat' in stream_opts:
> + stream_config.pixel_format = libcam.PixelFormat(stream_opts['pixelformat'])
>
> - if 'height' in stream_opts:
> - stream_config.size.height = stream_opts['height']
> + stat = camconfig.validate()
>
> - if 'pixelformat' in stream_opts:
> - stream_config.pixel_format = libcam.PixelFormat(stream_opts['pixelformat'])
> + if stat == libcam.CameraConfiguration.Status.Invalid:
> + print('Camera configuration invalid')
> + exit(-1)
> + elif stat == libcam.CameraConfiguration.Status.Adjusted:
> + if self.opt_strict_formats:
> + print('Adjusting camera configuration disallowed by --strict-formats argument')
> + exit(-1)
>
> - stat = camconfig.validate()
> + print('Camera configuration adjusted')
>
> - if stat == libcam.CameraConfiguration.Status.Invalid:
> - print('Camera configuration invalid')
> - exit(-1)
> - elif stat == libcam.CameraConfiguration.Status.Adjusted:
> - if ctx['opt-strict-formats']:
> - print('Adjusting camera configuration disallowed by --strict-formats argument')
> - exit(-1)
> + r = camera.configure(camconfig)
> + if r != 0:
> + raise Exception('Configure failed')
>
> - print('Camera configuration adjusted')
> + self.stream_names = {}
> + self.streams = []
>
> - r = camera.configure(camconfig)
> - if r != 0:
> - raise Exception('Configure failed')
> + for idx, stream_config in enumerate(camconfig):
> + stream = stream_config.stream
> + self.streams.append(stream)
> + self.stream_names[stream] = 'stream' + str(idx)
> + print('{}-{}: stream config {}'.format(self.id, self.stream_names[stream], stream.configuration))
>
> - ctx['stream-names'] = {}
> - ctx['streams'] = []
> + def alloc_buffers(self):
> + camera = self.camera
>
> - for idx, stream_config in enumerate(camconfig):
> - stream = stream_config.stream
> - ctx['streams'].append(stream)
> - ctx['stream-names'][stream] = 'stream' + str(idx)
> - print('{}-{}: stream config {}'.format(ctx['id'], ctx['stream-names'][stream], stream.configuration))
> + allocator = libcam.FrameBufferAllocator(camera)
>
> + for stream in self.streams:
> + ret = allocator.allocate(stream)
> + if ret < 0:
> + print('Cannot allocate buffers')
> + exit(-1)
>
> -def alloc_buffers(ctx):
> - camera = ctx['camera']
> + allocated = len(allocator.buffers(stream))
>
> - allocator = libcam.FrameBufferAllocator(camera)
> + print('{}-{}: Allocated {} buffers'.format(self.id, self.stream_names[stream], allocated))
>
> - for idx, stream in enumerate(ctx['streams']):
> - ret = allocator.allocate(stream)
> - if ret < 0:
> - print('Cannot allocate buffers')
> - exit(-1)
> + self.allocator = allocator
>
> - allocated = len(allocator.buffers(stream))
> + def create_requests(self):
> + camera = self.camera
>
> - print('{}-{}: Allocated {} buffers'.format(ctx['id'], ctx['stream-names'][stream], allocated))
> + self.requests = []
>
> - ctx['allocator'] = allocator
> + # Identify the stream with the least number of buffers
> + num_bufs = min([len(self.allocator.buffers(stream)) for stream in self.streams])
>
> + requests = []
>
> -def create_requests(ctx):
> - camera = ctx['camera']
> + for buf_num in range(num_bufs):
> + request = camera.create_request(self.idx)
>
> - ctx['requests'] = []
> + if request is None:
> + print('Can not create request')
> + exit(-1)
>
> - # Identify the stream with the least number of buffers
> - num_bufs = min([len(ctx['allocator'].buffers(stream)) for stream in ctx['streams']])
> + for stream in self.streams:
> + buffers = self.allocator.buffers(stream)
> + buffer = buffers[buf_num]
>
> - requests = []
> + ret = request.add_buffer(stream, buffer)
> + if ret < 0:
> + print('Can not set buffer for request')
> + exit(-1)
>
> - for buf_num in range(num_bufs):
> - request = camera.create_request(ctx['idx'])
> + requests.append(request)
>
> - if request is None:
> - print('Can not create request')
> - exit(-1)
> + self.requests = requests
>
> - for stream in ctx['streams']:
> - buffers = ctx['allocator'].buffers(stream)
> - buffer = buffers[buf_num]
> + def start(self):
> + camera = self.camera
>
> - ret = request.add_buffer(stream, buffer)
> - if ret < 0:
> - print('Can not set buffer for request')
> - exit(-1)
> + camera.start()
>
> - requests.append(request)
> + def stop(self):
> + camera = self.camera
>
> - ctx['requests'] = requests
> + camera.stop()
>
> + def queue_requests(self):
> + camera = self.camera
>
> -def start(ctx):
> - camera = ctx['camera']
> + for request in self.requests:
> + camera.queue_request(request)
> + self.reqs_queued += 1
>
> - camera.start()
> + del self.requests
>
>
> -def stop(ctx):
> - camera = ctx['camera']
> +class CaptureState:
> + cm: libcam.CameraManager
> + contexts: list[CameraContext]
> + renderer: Any
>
> - camera.stop()
> + def __init__(self, cm, contexts):
> + self.cm = cm
> + self.contexts = contexts
>
> + # Called from renderer when there is a libcamera event
> + def event_handler(self):
> + try:
> + cm = self.cm
> + contexts = self.contexts
Same here, these local variables could possibly be dropped.
Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
>
> -def queue_requests(ctx):
> - camera = ctx['camera']
> + cm.read_event()
>
> - for request in ctx['requests']:
> - camera.queue_request(request)
> - ctx['reqs-queued'] += 1
> + reqs = cm.get_ready_requests()
>
> - del ctx['requests']
> + for req in reqs:
> + ctx = next(ctx for ctx in contexts if ctx.idx == req.cookie)
> + self.__request_handler(ctx, req)
>
> + running = any(ctx.reqs_completed < ctx.opt_capture for ctx in contexts)
> + return running
> + except Exception:
> + traceback.print_exc()
> + return False
>
> -def capture_init(contexts):
> - for ctx in contexts:
> - acquire(ctx)
> + def __request_handler(self, ctx, req):
> + if req.status != libcam.Request.Status.Complete:
> + raise Exception('{}: Request failed: {}'.format(ctx.id, req.status))
>
> - for ctx in contexts:
> - configure(ctx)
> + buffers = req.buffers
>
> - for ctx in contexts:
> - alloc_buffers(ctx)
> + # Compute the frame rate. The timestamp is arbitrarily retrieved from
> + # the first buffer, as all buffers should have matching timestamps.
> + ts = buffers[next(iter(buffers))].metadata.timestamp
> + last = ctx.last
> + fps = 1000000000.0 / (ts - last) if (last != 0 and (ts - last) != 0) else 0
> + ctx.last = ts
> + ctx.fps = fps
>
> - for ctx in contexts:
> - create_requests(ctx)
> + for stream, fb in buffers.items():
> + stream_name = ctx.stream_names[stream]
>
> + crcs = []
> + if ctx.opt_crc:
> + with libcamera.utils.MappedFrameBuffer(fb) as mfb:
> + plane_crcs = [binascii.crc32(p) for p in mfb.planes]
> + crcs.append(plane_crcs)
>
> -def capture_start(contexts):
> - for ctx in contexts:
> - start(ctx)
> + meta = fb.metadata
>
> - for ctx in contexts:
> - queue_requests(ctx)
> + print('{:.6f} ({:.2f} fps) {}-{}: seq {}, bytes {}, CRCs {}'
> + .format(ts / 1000000000, fps,
> + ctx.id, stream_name,
> + meta.sequence, meta.bytesused,
> + crcs))
>
> + if ctx.opt_metadata:
> + reqmeta = req.metadata
> + for ctrl, val in reqmeta.items():
> + print(f'\t{ctrl} = {val}')
>
> -# Called from renderer when there is a libcamera event
> -def event_handler(state):
> - try:
> - cm = state['cm']
> - contexts = state['contexts']
> + if ctx.opt_save_frames:
> + with libcamera.utils.MappedFrameBuffer(fb) as mfb:
> + filename = 'frame-{}-{}-{}.data'.format(ctx.id, stream_name, ctx.reqs_completed)
> + with open(filename, 'wb') as f:
> + for p in mfb.planes:
> + f.write(p)
>
> - cm.read_event()
> + self.renderer.request_handler(ctx, req)
>
> - reqs = cm.get_ready_requests()
> + ctx.reqs_completed += 1
>
> - for req in reqs:
> - ctx = next(ctx for ctx in contexts if ctx['idx'] == req.cookie)
> - request_handler(state, ctx, req)
> + # Called from renderer when it has finished with a request
> + def request_processed(self, ctx, req):
> + camera = ctx.camera
>
> - running = any(ctx['reqs-completed'] < ctx['opt-capture'] for ctx in contexts)
> - return running
> - except Exception:
> - traceback.print_exc()
> - return False
> + if ctx.reqs_queued < ctx.opt_capture:
> + req.reuse()
> + camera.queue_request(req)
> + ctx.reqs_queued += 1
>
> + def __capture_init(self):
> + for ctx in self.contexts:
> + ctx.acquire()
>
> -def request_handler(state, ctx, req):
> - if req.status != libcam.Request.Status.Complete:
> - raise Exception('{}: Request failed: {}'.format(ctx['id'], req.status))
> + for ctx in self.contexts:
> + ctx.configure()
>
> - buffers = req.buffers
> + for ctx in self.contexts:
> + ctx.alloc_buffers()
>
> - # Compute the frame rate. The timestamp is arbitrarily retrieved from
> - # the first buffer, as all buffers should have matching timestamps.
> - ts = buffers[next(iter(buffers))].metadata.timestamp
> - last = ctx.get('last', 0)
> - fps = 1000000000.0 / (ts - last) if (last != 0 and (ts - last) != 0) else 0
> - ctx['last'] = ts
> - ctx['fps'] = fps
> + for ctx in self.contexts:
> + ctx.create_requests()
>
> - for stream, fb in buffers.items():
> - stream_name = ctx['stream-names'][stream]
> + def __capture_start(self):
> + for ctx in self.contexts:
> + ctx.start()
>
> - crcs = []
> - if ctx['opt-crc']:
> - with libcamera.utils.MappedFrameBuffer(fb) as mfb:
> - plane_crcs = [binascii.crc32(p) for p in mfb.planes]
> - crcs.append(plane_crcs)
> + for ctx in self.contexts:
> + ctx.queue_requests()
>
> - meta = fb.metadata
> + def __capture_deinit(self):
> + for ctx in self.contexts:
> + ctx.stop()
>
> - print('{:.6f} ({:.2f} fps) {}-{}: seq {}, bytes {}, CRCs {}'
> - .format(ts / 1000000000, fps,
> - ctx['id'], stream_name,
> - meta.sequence, meta.bytesused,
> - crcs))
> + for ctx in self.contexts:
> + ctx.release()
>
> - if ctx['opt-metadata']:
> - reqmeta = req.metadata
> - for ctrl, val in reqmeta.items():
> - print(f'\t{ctrl} = {val}')
> + def do_cmd_capture(self):
> + self.__capture_init()
>
> - if ctx['opt-save-frames']:
> - with libcamera.utils.MappedFrameBuffer(fb) as mfb:
> - filename = 'frame-{}-{}-{}.data'.format(ctx['id'], stream_name, ctx['reqs-completed'])
> - with open(filename, 'wb') as f:
> - for p in mfb.planes:
> - f.write(p)
> + renderer = self.renderer
>
> - state['renderer'].request_handler(ctx, req)
> + renderer.setup()
>
> - ctx['reqs-completed'] += 1
> + self.__capture_start()
>
> + renderer.run()
>
> -# Called from renderer when it has finished with a request
> -def request_prcessed(ctx, req):
> - camera = ctx['camera']
> + self.__capture_deinit()
>
> - if ctx['reqs-queued'] < ctx['opt-capture']:
> - req.reuse()
> - camera.queue_request(req)
> - ctx['reqs-queued'] += 1
>
> +class CustomAction(argparse.Action):
> + def __init__(self, option_strings, dest, **kwargs):
> + super().__init__(option_strings, dest, default={}, **kwargs)
>
> -def capture_deinit(contexts):
> - for ctx in contexts:
> - stop(ctx)
> + def __call__(self, parser, namespace, values, option_string=None):
> + if len(namespace.camera) == 0:
> + print(f'Option {option_string} requires a --camera context')
> + sys.exit(-1)
>
> - for ctx in contexts:
> - release(ctx)
> + if self.type == bool:
> + values = True
>
> + current = namespace.camera[-1]
>
> -def do_cmd_capture(state):
> - capture_init(state['contexts'])
> + data = getattr(namespace, self.dest)
>
> - renderer = state['renderer']
> + if self.nargs == '+':
> + if current not in data:
> + data[current] = []
>
> - renderer.setup()
> + data[current] += values
> + else:
> + data[current] = values
>
> - capture_start(state['contexts'])
>
> - renderer.run()
> +def do_cmd_list(cm):
> + print('Available cameras:')
>
> - capture_deinit(state['contexts'])
> + for idx, c in enumerate(cm.cameras):
> + print(f'{idx + 1}: {c.id}')
>
>
> def main():
> @@ -422,39 +444,28 @@ def main():
> print('Unable to find camera', cam_idx)
> return -1
>
> - contexts.append({
> - 'camera': camera,
> - 'idx': cam_idx,
> - 'id': 'cam' + str(cam_idx),
> - 'reqs-queued': 0,
> - 'reqs-completed': 0,
> - 'opt-capture': args.capture.get(cam_idx, False),
> - 'opt-crc': args.crc.get(cam_idx, False),
> - 'opt-save-frames': args.save_frames.get(cam_idx, False),
> - 'opt-metadata': args.metadata.get(cam_idx, False),
> - 'opt-strict-formats': args.strict_formats.get(cam_idx, False),
> - 'opt-stream': args.stream.get(cam_idx, ['role=viewfinder']),
> - })
> + ctx = CameraContext(camera, cam_idx)
> + ctx.opt_capture = args.capture.get(cam_idx, 0)
> + ctx.opt_crc = args.crc.get(cam_idx, False)
> + ctx.opt_save_frames = args.save_frames.get(cam_idx, False)
> + ctx.opt_metadata = args.metadata.get(cam_idx, False)
> + ctx.opt_strict_formats = args.strict_formats.get(cam_idx, False)
> + ctx.opt_stream = args.stream.get(cam_idx, ['role=viewfinder'])
> + contexts.append(ctx)
>
> for ctx in contexts:
> - print('Using camera {} as {}'.format(ctx['camera'].id, ctx['id']))
> + print('Using camera {} as {}'.format(ctx.camera.id, ctx.id))
>
> for ctx in contexts:
> if args.list_properties:
> - do_cmd_list_props(ctx)
> + ctx.do_cmd_list_props()
> if args.list_controls:
> - do_cmd_list_controls(ctx)
> + ctx.do_cmd_list_controls()
> if args.info:
> - do_cmd_info(ctx)
> + ctx.do_cmd_info()
>
> if args.capture:
> -
> - state = {
> - 'cm': cm,
> - 'contexts': contexts,
> - 'event_handler': event_handler,
> - 'request_prcessed': request_prcessed,
> - }
> + state = CaptureState(cm, contexts)
>
> if args.renderer == 'null':
> import cam_null
> @@ -472,9 +483,9 @@ def main():
> print('Bad renderer', args.renderer)
> return -1
>
> - state['renderer'] = renderer
> + state.renderer = renderer
>
> - do_cmd_capture(state)
> + state.do_cmd_capture()
>
> return 0
>
> diff --git a/src/py/cam/cam_kms.py b/src/py/cam/cam_kms.py
> index 74cd3b38..213e0b03 100644
> --- a/src/py/cam/cam_kms.py
> +++ b/src/py/cam/cam_kms.py
> @@ -10,8 +10,8 @@ class KMSRenderer:
> def __init__(self, state):
> self.state = state
>
> - self.cm = state['cm']
> - self.contexts = state['contexts']
> + self.cm = state.cm
> + self.contexts = state.contexts
> self.running = False
>
> card = pykms.Card()
> @@ -92,7 +92,7 @@ class KMSRenderer:
> if old:
> req = old['camreq']
> ctx = old['camctx']
> - self.state['request_prcessed'](ctx, req)
> + self.state.request_processed(ctx, req)
>
> def queue(self, drmreq):
> if not self.next:
> @@ -108,7 +108,7 @@ class KMSRenderer:
>
> idx = 0
> for ctx in self.contexts:
> - for stream in ctx['streams']:
> + for stream in ctx.streams:
>
> cfg = stream.configuration
> fmt = cfg.pixel_format
> @@ -125,7 +125,7 @@ class KMSRenderer:
> 'size': cfg.size,
> })
>
> - for fb in ctx['allocator'].buffers(stream):
> + for fb in ctx.allocator.buffers(stream):
> w = cfg.size.width
> h = cfg.size.height
> fds = []
> @@ -148,7 +148,7 @@ class KMSRenderer:
> self.handle_page_flip(ev.seq, ev.time)
>
> def readcam(self, fd):
> - self.running = self.state['event_handler'](self.state)
> + self.running = self.state.event_handler()
>
> def readkey(self, fileobj):
> sys.stdin.readline()
> diff --git a/src/py/cam/cam_null.py b/src/py/cam/cam_null.py
> index a6da9671..45c5f467 100644
> --- a/src/py/cam/cam_null.py
> +++ b/src/py/cam/cam_null.py
> @@ -9,8 +9,8 @@ class NullRenderer:
> def __init__(self, state):
> self.state = state
>
> - self.cm = state['cm']
> - self.contexts = state['contexts']
> + self.cm = state.cm
> + self.contexts = state.contexts
>
> self.running = False
>
> @@ -37,11 +37,11 @@ class NullRenderer:
> print('Exiting...')
>
> def readcam(self, fd):
> - self.running = self.state['event_handler'](self.state)
> + self.running = self.state.event_handler()
>
> def readkey(self, fileobj):
> sys.stdin.readline()
> self.running = False
>
> def request_handler(self, ctx, req):
> - self.state['request_prcessed'](ctx, req)
> + self.state.request_processed(ctx, req)
> diff --git a/src/py/cam/cam_qt.py b/src/py/cam/cam_qt.py
> index 03096920..d638e9cc 100644
> --- a/src/py/cam/cam_qt.py
> +++ b/src/py/cam/cam_qt.py
> @@ -176,8 +176,8 @@ class QtRenderer:
> def __init__(self, state):
> self.state = state
>
> - self.cm = state['cm']
> - self.contexts = state['contexts']
> + self.cm = state.cm
> + self.contexts = state.contexts
>
> def setup(self):
> self.app = QtWidgets.QApplication([])
> @@ -185,7 +185,7 @@ class QtRenderer:
> windows = []
>
> for ctx in self.contexts:
> - for stream in ctx['streams']:
> + for stream in ctx.streams:
> window = MainWindow(ctx, stream)
> window.show()
> windows.append(window)
> @@ -206,7 +206,7 @@ class QtRenderer:
> print('Exiting...')
>
> def readcam(self):
> - running = self.state['event_handler'](self.state)
> + running = self.state.event_handler()
>
> if not running:
> self.app.quit()
> @@ -223,7 +223,7 @@ class QtRenderer:
>
> wnd.handle_request(stream, fb)
>
> - self.state['request_prcessed'](ctx, req)
> + self.state.request_processed(ctx, req)
>
> def cleanup(self):
> for w in self.windows:
> @@ -254,7 +254,7 @@ class MainWindow(QtWidgets.QWidget):
> group.setLayout(groupLayout)
> controlsLayout.addWidget(group)
>
> - lab = QtWidgets.QLabel(ctx['id'])
> + lab = QtWidgets.QLabel(ctx.id)
> groupLayout.addWidget(lab)
>
> self.frameLabel = QtWidgets.QLabel()
> @@ -265,7 +265,7 @@ class MainWindow(QtWidgets.QWidget):
> group.setLayout(groupLayout)
> controlsLayout.addWidget(group)
>
> - camera = ctx['camera']
> + camera = ctx.camera
>
> for k, v in camera.properties.items():
> lab = QtWidgets.QLabel()
> @@ -308,4 +308,4 @@ class MainWindow(QtWidgets.QWidget):
> self.label.setPixmap(pix)
>
> self.frameLabel.setText('Queued: {}\nDone: {}\nFps: {:.2f}'
> - .format(ctx['reqs-queued'], ctx['reqs-completed'], ctx['fps']))
> + .format(ctx.reqs_queued, ctx.reqs_completed, ctx.fps))
> diff --git a/src/py/cam/cam_qtgl.py b/src/py/cam/cam_qtgl.py
> index c9e367a2..5f7ccf1e 100644
> --- a/src/py/cam/cam_qtgl.py
> +++ b/src/py/cam/cam_qtgl.py
> @@ -142,7 +142,7 @@ class QtRenderer:
> self.window = window
>
> def run(self):
> - camnotif = QtCore.QSocketNotifier(self.state['cm'].efd, QtCore.QSocketNotifier.Read)
> + camnotif = QtCore.QSocketNotifier(self.state.cm.efd, QtCore.QSocketNotifier.Read)
> camnotif.activated.connect(lambda _: self.readcam())
>
> keynotif = QtCore.QSocketNotifier(sys.stdin.fileno(), QtCore.QSocketNotifier.Read)
> @@ -155,7 +155,7 @@ class QtRenderer:
> print('Exiting...')
>
> def readcam(self):
> - running = self.state['event_handler'](self.state)
> + running = self.state.event_handler()
>
> if not running:
> self.app.quit()
> @@ -184,12 +184,12 @@ class MainWindow(QtWidgets.QWidget):
> self.reqqueue = {}
> self.current = {}
>
> - for ctx in self.state['contexts']:
> + for ctx in self.state.contexts:
>
> - self.reqqueue[ctx['idx']] = []
> - self.current[ctx['idx']] = []
> + self.reqqueue[ctx.idx] = []
> + self.current[ctx.idx] = []
>
> - for stream in ctx['streams']:
> + for stream in ctx.streams:
> self.textures[stream] = None
>
> num_tiles = len(self.textures)
> @@ -312,12 +312,12 @@ class MainWindow(QtWidgets.QWidget):
> if len(queue) == 0:
> continue
>
> - ctx = next(ctx for ctx in self.state['contexts'] if ctx['idx'] == ctx_idx)
> + ctx = next(ctx for ctx in self.state.contexts if ctx.idx == ctx_idx)
>
> if self.current[ctx_idx]:
> old = self.current[ctx_idx]
> self.current[ctx_idx] = None
> - self.state['request_prcessed'](ctx, old)
> + self.state.request_processed(ctx, old)
>
> next_req = queue.pop(0)
> self.current[ctx_idx] = next_req
> @@ -336,8 +336,8 @@ class MainWindow(QtWidgets.QWidget):
>
> size = self.size()
>
> - for idx, ctx in enumerate(self.state['contexts']):
> - for stream in ctx['streams']:
> + for idx, ctx in enumerate(self.state.contexts):
> + for stream in ctx.streams:
> if self.textures[stream] is None:
> continue
>
> @@ -359,5 +359,5 @@ class MainWindow(QtWidgets.QWidget):
> assert(b)
>
> def handle_request(self, ctx, req):
> - self.reqqueue[ctx['idx']].append(req)
> + self.reqqueue[ctx.idx].append(req)
> self.update()
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list