py: cam: Convert ctx and state to classes
Convert ctx and state dicts to classes. No functional changes. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
parent
bb1cbd53d2
commit
6eb1143e27
5 changed files with 380 additions and 398 deletions
|
@ -6,6 +6,7 @@
|
||||||
# \todo Convert ctx and state dicts to proper classes, and move relevant
|
# \todo Convert ctx and state dicts to proper classes, and move relevant
|
||||||
# functions to those classes.
|
# functions to those classes.
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
import argparse
|
import argparse
|
||||||
import binascii
|
import binascii
|
||||||
import libcamera as libcam
|
import libcamera as libcam
|
||||||
|
@ -14,64 +15,52 @@ import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
|
||||||
class CustomAction(argparse.Action):
|
class CameraContext:
|
||||||
def __init__(self, option_strings, dest, **kwargs):
|
camera: libcam.Camera
|
||||||
super().__init__(option_strings, dest, default={}, **kwargs)
|
id: str
|
||||||
|
idx: int
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
opt_stream: str
|
||||||
if len(namespace.camera) == 0:
|
opt_strict_formats: bool
|
||||||
print(f'Option {option_string} requires a --camera context')
|
opt_crc: bool
|
||||||
sys.exit(-1)
|
opt_metadata: bool
|
||||||
|
opt_save_frames: bool
|
||||||
|
opt_capture: int
|
||||||
|
|
||||||
if self.type == bool:
|
stream_names: dict[libcam.Stream, str]
|
||||||
values = True
|
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):
|
||||||
|
print('Properties for', self.id)
|
||||||
|
|
||||||
if self.nargs == '+':
|
for name, prop in self.camera.properties.items():
|
||||||
if current not in data:
|
|
||||||
data[current] = []
|
|
||||||
|
|
||||||
data[current] += values
|
|
||||||
else:
|
|
||||||
data[current] = values
|
|
||||||
|
|
||||||
|
|
||||||
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))
|
print('\t{}: {}'.format(name, prop))
|
||||||
|
|
||||||
|
def do_cmd_list_controls(self):
|
||||||
|
print('Controls for', self.id)
|
||||||
|
|
||||||
def do_cmd_list_controls(ctx):
|
for name, prop in self.camera.controls.items():
|
||||||
camera = ctx['camera']
|
|
||||||
|
|
||||||
print('Controls for', ctx['id'])
|
|
||||||
|
|
||||||
for name, prop in camera.controls.items():
|
|
||||||
print('\t{}: {}'.format(name, prop))
|
print('\t{}: {}'.format(name, prop))
|
||||||
|
|
||||||
|
def do_cmd_info(self):
|
||||||
def do_cmd_info(ctx):
|
print('Stream info for', self.id)
|
||||||
camera = ctx['camera']
|
|
||||||
|
|
||||||
print('Stream info for', ctx['id'])
|
|
||||||
|
|
||||||
roles = [libcam.StreamRole.Viewfinder]
|
roles = [libcam.StreamRole.Viewfinder]
|
||||||
|
|
||||||
camconfig = camera.generate_configuration(roles)
|
camconfig = self.camera.generate_configuration(roles)
|
||||||
if camconfig is None:
|
if camconfig is None:
|
||||||
raise Exception('Generating config failed')
|
raise Exception('Generating config failed')
|
||||||
|
|
||||||
|
@ -85,23 +74,17 @@ def do_cmd_info(ctx):
|
||||||
for size in formats.sizes(fmt):
|
for size in formats.sizes(fmt):
|
||||||
print('\t -', size)
|
print('\t -', size)
|
||||||
|
|
||||||
|
def acquire(self):
|
||||||
|
self.camera.acquire()
|
||||||
|
|
||||||
def acquire(ctx):
|
def release(self):
|
||||||
camera = ctx['camera']
|
self.camera.release()
|
||||||
|
|
||||||
camera.acquire()
|
def __parse_streams(self):
|
||||||
|
|
||||||
|
|
||||||
def release(ctx):
|
|
||||||
camera = ctx['camera']
|
|
||||||
|
|
||||||
camera.release()
|
|
||||||
|
|
||||||
|
|
||||||
def parse_streams(ctx):
|
|
||||||
streams = []
|
streams = []
|
||||||
|
|
||||||
for stream_desc in ctx['opt-stream']:
|
for stream_desc in self.opt_stream:
|
||||||
|
stream_opts: dict[str, Any]
|
||||||
stream_opts = {'role': libcam.StreamRole.Viewfinder}
|
stream_opts = {'role': libcam.StreamRole.Viewfinder}
|
||||||
|
|
||||||
for stream_opt in stream_desc.split(','):
|
for stream_opt in stream_desc.split(','):
|
||||||
|
@ -145,15 +128,12 @@ def parse_streams(ctx):
|
||||||
|
|
||||||
return streams
|
return streams
|
||||||
|
|
||||||
|
def configure(self):
|
||||||
def configure(ctx):
|
streams = self.__parse_streams()
|
||||||
camera = ctx['camera']
|
|
||||||
|
|
||||||
streams = parse_streams(ctx)
|
|
||||||
|
|
||||||
roles = [opts['role'] for opts in streams]
|
roles = [opts['role'] for opts in streams]
|
||||||
|
|
||||||
camconfig = camera.generate_configuration(roles)
|
camconfig = self.camera.generate_configuration(roles)
|
||||||
if camconfig is None:
|
if camconfig is None:
|
||||||
raise Exception('Generating config failed')
|
raise Exception('Generating config failed')
|
||||||
|
|
||||||
|
@ -175,32 +155,29 @@ def configure(ctx):
|
||||||
print('Camera configuration invalid')
|
print('Camera configuration invalid')
|
||||||
exit(-1)
|
exit(-1)
|
||||||
elif stat == libcam.CameraConfiguration.Status.Adjusted:
|
elif stat == libcam.CameraConfiguration.Status.Adjusted:
|
||||||
if ctx['opt-strict-formats']:
|
if self.opt_strict_formats:
|
||||||
print('Adjusting camera configuration disallowed by --strict-formats argument')
|
print('Adjusting camera configuration disallowed by --strict-formats argument')
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
print('Camera configuration adjusted')
|
print('Camera configuration adjusted')
|
||||||
|
|
||||||
r = camera.configure(camconfig)
|
r = self.camera.configure(camconfig)
|
||||||
if r != 0:
|
if r != 0:
|
||||||
raise Exception('Configure failed')
|
raise Exception('Configure failed')
|
||||||
|
|
||||||
ctx['stream-names'] = {}
|
self.stream_names = {}
|
||||||
ctx['streams'] = []
|
self.streams = []
|
||||||
|
|
||||||
for idx, stream_config in enumerate(camconfig):
|
for idx, stream_config in enumerate(camconfig):
|
||||||
stream = stream_config.stream
|
stream = stream_config.stream
|
||||||
ctx['streams'].append(stream)
|
self.streams.append(stream)
|
||||||
ctx['stream-names'][stream] = 'stream' + str(idx)
|
self.stream_names[stream] = 'stream' + str(idx)
|
||||||
print('{}-{}: stream config {}'.format(ctx['id'], ctx['stream-names'][stream], stream.configuration))
|
print('{}-{}: stream config {}'.format(self.id, self.stream_names[stream], stream.configuration))
|
||||||
|
|
||||||
|
def alloc_buffers(self):
|
||||||
|
allocator = libcam.FrameBufferAllocator(self.camera)
|
||||||
|
|
||||||
def alloc_buffers(ctx):
|
for stream in self.streams:
|
||||||
camera = ctx['camera']
|
|
||||||
|
|
||||||
allocator = libcam.FrameBufferAllocator(camera)
|
|
||||||
|
|
||||||
for idx, stream in enumerate(ctx['streams']):
|
|
||||||
ret = allocator.allocate(stream)
|
ret = allocator.allocate(stream)
|
||||||
if ret < 0:
|
if ret < 0:
|
||||||
print('Cannot allocate buffers')
|
print('Cannot allocate buffers')
|
||||||
|
@ -208,30 +185,27 @@ def alloc_buffers(ctx):
|
||||||
|
|
||||||
allocated = len(allocator.buffers(stream))
|
allocated = len(allocator.buffers(stream))
|
||||||
|
|
||||||
print('{}-{}: Allocated {} buffers'.format(ctx['id'], ctx['stream-names'][stream], allocated))
|
print('{}-{}: Allocated {} buffers'.format(self.id, self.stream_names[stream], allocated))
|
||||||
|
|
||||||
ctx['allocator'] = allocator
|
self.allocator = allocator
|
||||||
|
|
||||||
|
def create_requests(self):
|
||||||
def create_requests(ctx):
|
self.requests = []
|
||||||
camera = ctx['camera']
|
|
||||||
|
|
||||||
ctx['requests'] = []
|
|
||||||
|
|
||||||
# Identify the stream with the least number of buffers
|
# Identify the stream with the least number of buffers
|
||||||
num_bufs = min([len(ctx['allocator'].buffers(stream)) for stream in ctx['streams']])
|
num_bufs = min([len(self.allocator.buffers(stream)) for stream in self.streams])
|
||||||
|
|
||||||
requests = []
|
requests = []
|
||||||
|
|
||||||
for buf_num in range(num_bufs):
|
for buf_num in range(num_bufs):
|
||||||
request = camera.create_request(ctx['idx'])
|
request = self.camera.create_request(self.idx)
|
||||||
|
|
||||||
if request is None:
|
if request is None:
|
||||||
print('Can not create request')
|
print('Can not create request')
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
for stream in ctx['streams']:
|
for stream in self.streams:
|
||||||
buffers = ctx['allocator'].buffers(stream)
|
buffers = self.allocator.buffers(stream)
|
||||||
buffer = buffers[buf_num]
|
buffer = buffers[buf_num]
|
||||||
|
|
||||||
ret = request.add_buffer(stream, buffer)
|
ret = request.add_buffer(stream, buffer)
|
||||||
|
@ -241,93 +215,67 @@ def create_requests(ctx):
|
||||||
|
|
||||||
requests.append(request)
|
requests.append(request)
|
||||||
|
|
||||||
ctx['requests'] = requests
|
self.requests = requests
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self.camera.start()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.camera.stop()
|
||||||
|
|
||||||
|
def queue_requests(self):
|
||||||
|
for request in self.requests:
|
||||||
|
self.camera.queue_request(request)
|
||||||
|
self.reqs_queued += 1
|
||||||
|
|
||||||
|
del self.requests
|
||||||
|
|
||||||
|
|
||||||
def start(ctx):
|
class CaptureState:
|
||||||
camera = ctx['camera']
|
cm: libcam.CameraManager
|
||||||
|
contexts: list[CameraContext]
|
||||||
|
renderer: Any
|
||||||
|
|
||||||
camera.start()
|
def __init__(self, cm, contexts):
|
||||||
|
self.cm = cm
|
||||||
|
self.contexts = contexts
|
||||||
|
|
||||||
|
# Called from renderer when there is a libcamera event
|
||||||
def stop(ctx):
|
def event_handler(self):
|
||||||
camera = ctx['camera']
|
|
||||||
|
|
||||||
camera.stop()
|
|
||||||
|
|
||||||
|
|
||||||
def queue_requests(ctx):
|
|
||||||
camera = ctx['camera']
|
|
||||||
|
|
||||||
for request in ctx['requests']:
|
|
||||||
camera.queue_request(request)
|
|
||||||
ctx['reqs-queued'] += 1
|
|
||||||
|
|
||||||
del ctx['requests']
|
|
||||||
|
|
||||||
|
|
||||||
def capture_init(contexts):
|
|
||||||
for ctx in contexts:
|
|
||||||
acquire(ctx)
|
|
||||||
|
|
||||||
for ctx in contexts:
|
|
||||||
configure(ctx)
|
|
||||||
|
|
||||||
for ctx in contexts:
|
|
||||||
alloc_buffers(ctx)
|
|
||||||
|
|
||||||
for ctx in contexts:
|
|
||||||
create_requests(ctx)
|
|
||||||
|
|
||||||
|
|
||||||
def capture_start(contexts):
|
|
||||||
for ctx in contexts:
|
|
||||||
start(ctx)
|
|
||||||
|
|
||||||
for ctx in contexts:
|
|
||||||
queue_requests(ctx)
|
|
||||||
|
|
||||||
|
|
||||||
# Called from renderer when there is a libcamera event
|
|
||||||
def event_handler(state):
|
|
||||||
try:
|
try:
|
||||||
cm = state['cm']
|
self.cm.read_event()
|
||||||
contexts = state['contexts']
|
|
||||||
|
|
||||||
cm.read_event()
|
reqs = self.cm.get_ready_requests()
|
||||||
|
|
||||||
reqs = cm.get_ready_requests()
|
|
||||||
|
|
||||||
for req in reqs:
|
for req in reqs:
|
||||||
ctx = next(ctx for ctx in contexts if ctx['idx'] == req.cookie)
|
ctx = next(ctx for ctx in self.contexts if ctx.idx == req.cookie)
|
||||||
request_handler(state, ctx, req)
|
self.__request_handler(ctx, req)
|
||||||
|
|
||||||
running = any(ctx['reqs-completed'] < ctx['opt-capture'] for ctx in contexts)
|
running = any(ctx.reqs_completed < ctx.opt_capture for ctx in self.contexts)
|
||||||
return running
|
return running
|
||||||
except Exception:
|
except Exception:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def __request_handler(self, ctx, req):
|
||||||
def request_handler(state, ctx, req):
|
|
||||||
if req.status != libcam.Request.Status.Complete:
|
if req.status != libcam.Request.Status.Complete:
|
||||||
raise Exception('{}: Request failed: {}'.format(ctx['id'], req.status))
|
raise Exception('{}: Request failed: {}'.format(ctx.id, req.status))
|
||||||
|
|
||||||
buffers = req.buffers
|
buffers = req.buffers
|
||||||
|
|
||||||
# Compute the frame rate. The timestamp is arbitrarily retrieved from
|
# Compute the frame rate. The timestamp is arbitrarily retrieved from
|
||||||
# the first buffer, as all buffers should have matching timestamps.
|
# the first buffer, as all buffers should have matching timestamps.
|
||||||
ts = buffers[next(iter(buffers))].metadata.timestamp
|
ts = buffers[next(iter(buffers))].metadata.timestamp
|
||||||
last = ctx.get('last', 0)
|
last = ctx.last
|
||||||
fps = 1000000000.0 / (ts - last) if (last != 0 and (ts - last) != 0) else 0
|
fps = 1000000000.0 / (ts - last) if (last != 0 and (ts - last) != 0) else 0
|
||||||
ctx['last'] = ts
|
ctx.last = ts
|
||||||
ctx['fps'] = fps
|
ctx.fps = fps
|
||||||
|
|
||||||
for stream, fb in buffers.items():
|
for stream, fb in buffers.items():
|
||||||
stream_name = ctx['stream-names'][stream]
|
stream_name = ctx.stream_names[stream]
|
||||||
|
|
||||||
crcs = []
|
crcs = []
|
||||||
if ctx['opt-crc']:
|
if ctx.opt_crc:
|
||||||
with libcamera.utils.MappedFrameBuffer(fb) as mfb:
|
with libcamera.utils.MappedFrameBuffer(fb) as mfb:
|
||||||
plane_crcs = [binascii.crc32(p) for p in mfb.planes]
|
plane_crcs = [binascii.crc32(p) for p in mfb.planes]
|
||||||
crcs.append(plane_crcs)
|
crcs.append(plane_crcs)
|
||||||
|
@ -336,57 +284,102 @@ def request_handler(state, ctx, req):
|
||||||
|
|
||||||
print('{:.6f} ({:.2f} fps) {}-{}: seq {}, bytes {}, CRCs {}'
|
print('{:.6f} ({:.2f} fps) {}-{}: seq {}, bytes {}, CRCs {}'
|
||||||
.format(ts / 1000000000, fps,
|
.format(ts / 1000000000, fps,
|
||||||
ctx['id'], stream_name,
|
ctx.id, stream_name,
|
||||||
meta.sequence, meta.bytesused,
|
meta.sequence, meta.bytesused,
|
||||||
crcs))
|
crcs))
|
||||||
|
|
||||||
if ctx['opt-metadata']:
|
if ctx.opt_metadata:
|
||||||
reqmeta = req.metadata
|
reqmeta = req.metadata
|
||||||
for ctrl, val in reqmeta.items():
|
for ctrl, val in reqmeta.items():
|
||||||
print(f'\t{ctrl} = {val}')
|
print(f'\t{ctrl} = {val}')
|
||||||
|
|
||||||
if ctx['opt-save-frames']:
|
if ctx.opt_save_frames:
|
||||||
with libcamera.utils.MappedFrameBuffer(fb) as mfb:
|
with libcamera.utils.MappedFrameBuffer(fb) as mfb:
|
||||||
filename = 'frame-{}-{}-{}.data'.format(ctx['id'], stream_name, ctx['reqs-completed'])
|
filename = 'frame-{}-{}-{}.data'.format(ctx.id, stream_name, ctx.reqs_completed)
|
||||||
with open(filename, 'wb') as f:
|
with open(filename, 'wb') as f:
|
||||||
for p in mfb.planes:
|
for p in mfb.planes:
|
||||||
f.write(p)
|
f.write(p)
|
||||||
|
|
||||||
state['renderer'].request_handler(ctx, req)
|
self.renderer.request_handler(ctx, req)
|
||||||
|
|
||||||
ctx['reqs-completed'] += 1
|
ctx.reqs_completed += 1
|
||||||
|
|
||||||
|
# Called from renderer when it has finished with a request
|
||||||
# Called from renderer when it has finished with a request
|
def request_processed(self, ctx, req):
|
||||||
def request_prcessed(ctx, req):
|
if ctx.reqs_queued < ctx.opt_capture:
|
||||||
camera = ctx['camera']
|
|
||||||
|
|
||||||
if ctx['reqs-queued'] < ctx['opt-capture']:
|
|
||||||
req.reuse()
|
req.reuse()
|
||||||
camera.queue_request(req)
|
ctx.camera.queue_request(req)
|
||||||
ctx['reqs-queued'] += 1
|
ctx.reqs_queued += 1
|
||||||
|
|
||||||
|
def __capture_init(self):
|
||||||
|
for ctx in self.contexts:
|
||||||
|
ctx.acquire()
|
||||||
|
|
||||||
|
for ctx in self.contexts:
|
||||||
|
ctx.configure()
|
||||||
|
|
||||||
|
for ctx in self.contexts:
|
||||||
|
ctx.alloc_buffers()
|
||||||
|
|
||||||
|
for ctx in self.contexts:
|
||||||
|
ctx.create_requests()
|
||||||
|
|
||||||
|
def __capture_start(self):
|
||||||
|
for ctx in self.contexts:
|
||||||
|
ctx.start()
|
||||||
|
|
||||||
|
for ctx in self.contexts:
|
||||||
|
ctx.queue_requests()
|
||||||
|
|
||||||
|
def __capture_deinit(self):
|
||||||
|
for ctx in self.contexts:
|
||||||
|
ctx.stop()
|
||||||
|
|
||||||
|
for ctx in self.contexts:
|
||||||
|
ctx.release()
|
||||||
|
|
||||||
|
def do_cmd_capture(self):
|
||||||
|
self.__capture_init()
|
||||||
|
|
||||||
|
self.renderer.setup()
|
||||||
|
|
||||||
|
self.__capture_start()
|
||||||
|
|
||||||
|
self.renderer.run()
|
||||||
|
|
||||||
|
self.__capture_deinit()
|
||||||
|
|
||||||
|
|
||||||
def capture_deinit(contexts):
|
class CustomAction(argparse.Action):
|
||||||
for ctx in contexts:
|
def __init__(self, option_strings, dest, **kwargs):
|
||||||
stop(ctx)
|
super().__init__(option_strings, dest, default={}, **kwargs)
|
||||||
|
|
||||||
for ctx in contexts:
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
release(ctx)
|
if len(namespace.camera) == 0:
|
||||||
|
print(f'Option {option_string} requires a --camera context')
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
if self.type == bool:
|
||||||
|
values = True
|
||||||
|
|
||||||
|
current = namespace.camera[-1]
|
||||||
|
|
||||||
|
data = getattr(namespace, self.dest)
|
||||||
|
|
||||||
|
if self.nargs == '+':
|
||||||
|
if current not in data:
|
||||||
|
data[current] = []
|
||||||
|
|
||||||
|
data[current] += values
|
||||||
|
else:
|
||||||
|
data[current] = values
|
||||||
|
|
||||||
|
|
||||||
def do_cmd_capture(state):
|
def do_cmd_list(cm):
|
||||||
capture_init(state['contexts'])
|
print('Available cameras:')
|
||||||
|
|
||||||
renderer = state['renderer']
|
for idx, c in enumerate(cm.cameras):
|
||||||
|
print(f'{idx + 1}: {c.id}')
|
||||||
renderer.setup()
|
|
||||||
|
|
||||||
capture_start(state['contexts'])
|
|
||||||
|
|
||||||
renderer.run()
|
|
||||||
|
|
||||||
capture_deinit(state['contexts'])
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -422,39 +415,28 @@ def main():
|
||||||
print('Unable to find camera', cam_idx)
|
print('Unable to find camera', cam_idx)
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
contexts.append({
|
ctx = CameraContext(camera, cam_idx)
|
||||||
'camera': camera,
|
ctx.opt_capture = args.capture.get(cam_idx, 0)
|
||||||
'idx': cam_idx,
|
ctx.opt_crc = args.crc.get(cam_idx, False)
|
||||||
'id': 'cam' + str(cam_idx),
|
ctx.opt_save_frames = args.save_frames.get(cam_idx, False)
|
||||||
'reqs-queued': 0,
|
ctx.opt_metadata = args.metadata.get(cam_idx, False)
|
||||||
'reqs-completed': 0,
|
ctx.opt_strict_formats = args.strict_formats.get(cam_idx, False)
|
||||||
'opt-capture': args.capture.get(cam_idx, False),
|
ctx.opt_stream = args.stream.get(cam_idx, ['role=viewfinder'])
|
||||||
'opt-crc': args.crc.get(cam_idx, False),
|
contexts.append(ctx)
|
||||||
'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']),
|
|
||||||
})
|
|
||||||
|
|
||||||
for ctx in contexts:
|
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:
|
for ctx in contexts:
|
||||||
if args.list_properties:
|
if args.list_properties:
|
||||||
do_cmd_list_props(ctx)
|
ctx.do_cmd_list_props()
|
||||||
if args.list_controls:
|
if args.list_controls:
|
||||||
do_cmd_list_controls(ctx)
|
ctx.do_cmd_list_controls()
|
||||||
if args.info:
|
if args.info:
|
||||||
do_cmd_info(ctx)
|
ctx.do_cmd_info()
|
||||||
|
|
||||||
if args.capture:
|
if args.capture:
|
||||||
|
state = CaptureState(cm, contexts)
|
||||||
state = {
|
|
||||||
'cm': cm,
|
|
||||||
'contexts': contexts,
|
|
||||||
'event_handler': event_handler,
|
|
||||||
'request_prcessed': request_prcessed,
|
|
||||||
}
|
|
||||||
|
|
||||||
if args.renderer == 'null':
|
if args.renderer == 'null':
|
||||||
import cam_null
|
import cam_null
|
||||||
|
@ -472,9 +454,9 @@ def main():
|
||||||
print('Bad renderer', args.renderer)
|
print('Bad renderer', args.renderer)
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
state['renderer'] = renderer
|
state.renderer = renderer
|
||||||
|
|
||||||
do_cmd_capture(state)
|
state.do_cmd_capture()
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ class KMSRenderer:
|
||||||
def __init__(self, state):
|
def __init__(self, state):
|
||||||
self.state = state
|
self.state = state
|
||||||
|
|
||||||
self.cm = state['cm']
|
self.cm = state.cm
|
||||||
self.contexts = state['contexts']
|
self.contexts = state.contexts
|
||||||
self.running = False
|
self.running = False
|
||||||
|
|
||||||
card = pykms.Card()
|
card = pykms.Card()
|
||||||
|
@ -92,7 +92,7 @@ class KMSRenderer:
|
||||||
if old:
|
if old:
|
||||||
req = old['camreq']
|
req = old['camreq']
|
||||||
ctx = old['camctx']
|
ctx = old['camctx']
|
||||||
self.state['request_prcessed'](ctx, req)
|
self.state.request_processed(ctx, req)
|
||||||
|
|
||||||
def queue(self, drmreq):
|
def queue(self, drmreq):
|
||||||
if not self.next:
|
if not self.next:
|
||||||
|
@ -108,7 +108,7 @@ class KMSRenderer:
|
||||||
|
|
||||||
idx = 0
|
idx = 0
|
||||||
for ctx in self.contexts:
|
for ctx in self.contexts:
|
||||||
for stream in ctx['streams']:
|
for stream in ctx.streams:
|
||||||
|
|
||||||
cfg = stream.configuration
|
cfg = stream.configuration
|
||||||
fmt = cfg.pixel_format
|
fmt = cfg.pixel_format
|
||||||
|
@ -125,7 +125,7 @@ class KMSRenderer:
|
||||||
'size': cfg.size,
|
'size': cfg.size,
|
||||||
})
|
})
|
||||||
|
|
||||||
for fb in ctx['allocator'].buffers(stream):
|
for fb in ctx.allocator.buffers(stream):
|
||||||
w = cfg.size.width
|
w = cfg.size.width
|
||||||
h = cfg.size.height
|
h = cfg.size.height
|
||||||
fds = []
|
fds = []
|
||||||
|
@ -148,7 +148,7 @@ class KMSRenderer:
|
||||||
self.handle_page_flip(ev.seq, ev.time)
|
self.handle_page_flip(ev.seq, ev.time)
|
||||||
|
|
||||||
def readcam(self, fd):
|
def readcam(self, fd):
|
||||||
self.running = self.state['event_handler'](self.state)
|
self.running = self.state.event_handler()
|
||||||
|
|
||||||
def readkey(self, fileobj):
|
def readkey(self, fileobj):
|
||||||
sys.stdin.readline()
|
sys.stdin.readline()
|
||||||
|
|
|
@ -9,8 +9,8 @@ class NullRenderer:
|
||||||
def __init__(self, state):
|
def __init__(self, state):
|
||||||
self.state = state
|
self.state = state
|
||||||
|
|
||||||
self.cm = state['cm']
|
self.cm = state.cm
|
||||||
self.contexts = state['contexts']
|
self.contexts = state.contexts
|
||||||
|
|
||||||
self.running = False
|
self.running = False
|
||||||
|
|
||||||
|
@ -37,11 +37,11 @@ class NullRenderer:
|
||||||
print('Exiting...')
|
print('Exiting...')
|
||||||
|
|
||||||
def readcam(self, fd):
|
def readcam(self, fd):
|
||||||
self.running = self.state['event_handler'](self.state)
|
self.running = self.state.event_handler()
|
||||||
|
|
||||||
def readkey(self, fileobj):
|
def readkey(self, fileobj):
|
||||||
sys.stdin.readline()
|
sys.stdin.readline()
|
||||||
self.running = False
|
self.running = False
|
||||||
|
|
||||||
def request_handler(self, ctx, req):
|
def request_handler(self, ctx, req):
|
||||||
self.state['request_prcessed'](ctx, req)
|
self.state.request_processed(ctx, req)
|
||||||
|
|
|
@ -176,8 +176,8 @@ class QtRenderer:
|
||||||
def __init__(self, state):
|
def __init__(self, state):
|
||||||
self.state = state
|
self.state = state
|
||||||
|
|
||||||
self.cm = state['cm']
|
self.cm = state.cm
|
||||||
self.contexts = state['contexts']
|
self.contexts = state.contexts
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
self.app = QtWidgets.QApplication([])
|
self.app = QtWidgets.QApplication([])
|
||||||
|
@ -185,7 +185,7 @@ class QtRenderer:
|
||||||
windows = []
|
windows = []
|
||||||
|
|
||||||
for ctx in self.contexts:
|
for ctx in self.contexts:
|
||||||
for stream in ctx['streams']:
|
for stream in ctx.streams:
|
||||||
window = MainWindow(ctx, stream)
|
window = MainWindow(ctx, stream)
|
||||||
window.show()
|
window.show()
|
||||||
windows.append(window)
|
windows.append(window)
|
||||||
|
@ -206,7 +206,7 @@ class QtRenderer:
|
||||||
print('Exiting...')
|
print('Exiting...')
|
||||||
|
|
||||||
def readcam(self):
|
def readcam(self):
|
||||||
running = self.state['event_handler'](self.state)
|
running = self.state.event_handler()
|
||||||
|
|
||||||
if not running:
|
if not running:
|
||||||
self.app.quit()
|
self.app.quit()
|
||||||
|
@ -223,7 +223,7 @@ class QtRenderer:
|
||||||
|
|
||||||
wnd.handle_request(stream, fb)
|
wnd.handle_request(stream, fb)
|
||||||
|
|
||||||
self.state['request_prcessed'](ctx, req)
|
self.state.request_processed(ctx, req)
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
for w in self.windows:
|
for w in self.windows:
|
||||||
|
@ -254,7 +254,7 @@ class MainWindow(QtWidgets.QWidget):
|
||||||
group.setLayout(groupLayout)
|
group.setLayout(groupLayout)
|
||||||
controlsLayout.addWidget(group)
|
controlsLayout.addWidget(group)
|
||||||
|
|
||||||
lab = QtWidgets.QLabel(ctx['id'])
|
lab = QtWidgets.QLabel(ctx.id)
|
||||||
groupLayout.addWidget(lab)
|
groupLayout.addWidget(lab)
|
||||||
|
|
||||||
self.frameLabel = QtWidgets.QLabel()
|
self.frameLabel = QtWidgets.QLabel()
|
||||||
|
@ -265,7 +265,7 @@ class MainWindow(QtWidgets.QWidget):
|
||||||
group.setLayout(groupLayout)
|
group.setLayout(groupLayout)
|
||||||
controlsLayout.addWidget(group)
|
controlsLayout.addWidget(group)
|
||||||
|
|
||||||
camera = ctx['camera']
|
camera = ctx.camera
|
||||||
|
|
||||||
for k, v in camera.properties.items():
|
for k, v in camera.properties.items():
|
||||||
lab = QtWidgets.QLabel()
|
lab = QtWidgets.QLabel()
|
||||||
|
@ -308,4 +308,4 @@ class MainWindow(QtWidgets.QWidget):
|
||||||
self.label.setPixmap(pix)
|
self.label.setPixmap(pix)
|
||||||
|
|
||||||
self.frameLabel.setText('Queued: {}\nDone: {}\nFps: {:.2f}'
|
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))
|
||||||
|
|
|
@ -142,7 +142,7 @@ class QtRenderer:
|
||||||
self.window = window
|
self.window = window
|
||||||
|
|
||||||
def run(self):
|
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())
|
camnotif.activated.connect(lambda _: self.readcam())
|
||||||
|
|
||||||
keynotif = QtCore.QSocketNotifier(sys.stdin.fileno(), QtCore.QSocketNotifier.Read)
|
keynotif = QtCore.QSocketNotifier(sys.stdin.fileno(), QtCore.QSocketNotifier.Read)
|
||||||
|
@ -155,7 +155,7 @@ class QtRenderer:
|
||||||
print('Exiting...')
|
print('Exiting...')
|
||||||
|
|
||||||
def readcam(self):
|
def readcam(self):
|
||||||
running = self.state['event_handler'](self.state)
|
running = self.state.event_handler()
|
||||||
|
|
||||||
if not running:
|
if not running:
|
||||||
self.app.quit()
|
self.app.quit()
|
||||||
|
@ -184,12 +184,12 @@ class MainWindow(QtWidgets.QWidget):
|
||||||
self.reqqueue = {}
|
self.reqqueue = {}
|
||||||
self.current = {}
|
self.current = {}
|
||||||
|
|
||||||
for ctx in self.state['contexts']:
|
for ctx in self.state.contexts:
|
||||||
|
|
||||||
self.reqqueue[ctx['idx']] = []
|
self.reqqueue[ctx.idx] = []
|
||||||
self.current[ctx['idx']] = []
|
self.current[ctx.idx] = []
|
||||||
|
|
||||||
for stream in ctx['streams']:
|
for stream in ctx.streams:
|
||||||
self.textures[stream] = None
|
self.textures[stream] = None
|
||||||
|
|
||||||
num_tiles = len(self.textures)
|
num_tiles = len(self.textures)
|
||||||
|
@ -312,12 +312,12 @@ class MainWindow(QtWidgets.QWidget):
|
||||||
if len(queue) == 0:
|
if len(queue) == 0:
|
||||||
continue
|
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]:
|
if self.current[ctx_idx]:
|
||||||
old = self.current[ctx_idx]
|
old = self.current[ctx_idx]
|
||||||
self.current[ctx_idx] = None
|
self.current[ctx_idx] = None
|
||||||
self.state['request_prcessed'](ctx, old)
|
self.state.request_processed(ctx, old)
|
||||||
|
|
||||||
next_req = queue.pop(0)
|
next_req = queue.pop(0)
|
||||||
self.current[ctx_idx] = next_req
|
self.current[ctx_idx] = next_req
|
||||||
|
@ -336,8 +336,8 @@ class MainWindow(QtWidgets.QWidget):
|
||||||
|
|
||||||
size = self.size()
|
size = self.size()
|
||||||
|
|
||||||
for idx, ctx in enumerate(self.state['contexts']):
|
for idx, ctx in enumerate(self.state.contexts):
|
||||||
for stream in ctx['streams']:
|
for stream in ctx.streams:
|
||||||
if self.textures[stream] is None:
|
if self.textures[stream] is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -359,5 +359,5 @@ class MainWindow(QtWidgets.QWidget):
|
||||||
assert(b)
|
assert(b)
|
||||||
|
|
||||||
def handle_request(self, ctx, req):
|
def handle_request(self, ctx, req):
|
||||||
self.reqqueue[ctx['idx']].append(req)
|
self.reqqueue[ctx.idx].append(req)
|
||||||
self.update()
|
self.update()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue