Message ID | 20220524114610.41848-8-tomi.valkeinen@ideasonboard.com |
---|---|
State | Accepted |
Headers | show |
Series |
|
Related | show |
Hi Tomi, Thank you for the patch. On Tue, May 24, 2022 at 02:45:58PM +0300, Tomi Valkeinen wrote: > Move MappedFrameBuffer to libcamera.utils, instead of extending > FrameBuffer class with a new mmap() method. This keeps us more aligned > to the C++ API. "utils" is a name we use in libcamera/base/utils.h already, for an entirely different purpose, but I don't think it will create too much confusion as Python users should not see the C++ utils.h API. We can always bikeshed this naming question later if needed. Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> > --- > src/py/cam/cam.py | 5 +- > src/py/cam/cam_qt.py | 3 +- > src/py/libcamera/__init__.py | 80 ------------------- > src/py/libcamera/meson.build | 4 + > .../MappedFrameBuffer.py} | 10 --- > src/py/libcamera/utils/__init__.py | 4 + > 6 files changed, 13 insertions(+), 93 deletions(-) > copy src/py/libcamera/{__init__.py => utils/MappedFrameBuffer.py} (93%) > create mode 100644 src/py/libcamera/utils/__init__.py > > diff --git a/src/py/cam/cam.py b/src/py/cam/cam.py > index 66df18bf..64f67e86 100755 > --- a/src/py/cam/cam.py > +++ b/src/py/cam/cam.py > @@ -9,6 +9,7 @@ > import argparse > import binascii > import libcamera as libcam > +import libcamera.utils > import sys > import traceback > > @@ -327,7 +328,7 @@ def request_handler(state, ctx, req): > > crcs = [] > if ctx['opt-crc']: > - with fb.mmap() as mfb: > + with libcamera.utils.MappedFrameBuffer(fb) as mfb: > plane_crcs = [binascii.crc32(p) for p in mfb.planes] > crcs.append(plane_crcs) > > @@ -345,7 +346,7 @@ def request_handler(state, ctx, req): > print(f'\t{ctrl} = {val}') > > if ctx['opt-save-frames']: > - with fb.mmap() as mfb: > + 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: > diff --git a/src/py/cam/cam_qt.py b/src/py/cam/cam_qt.py > index bff1175b..70bdb7bb 100644 > --- a/src/py/cam/cam_qt.py > +++ b/src/py/cam/cam_qt.py > @@ -9,6 +9,7 @@ from PIL import Image > from PIL.ImageQt import ImageQt > from PyQt5 import QtCore, QtGui, QtWidgets > import libcamera as libcam > +import libcamera.utils > import numpy as np > import sys > > @@ -285,7 +286,7 @@ class MainWindow(QtWidgets.QWidget): > controlsLayout.addStretch() > > def buf_to_qpixmap(self, stream, fb): > - with fb.mmap() as mfb: > + with libcamera.utils.MappedFrameBuffer(fb) as mfb: > cfg = stream.configuration > > if cfg.pixel_format == libcam.formats.MJPEG: > diff --git a/src/py/libcamera/__init__.py b/src/py/libcamera/__init__.py > index 0d7da9e2..e234a5e4 100644 > --- a/src/py/libcamera/__init__.py > +++ b/src/py/libcamera/__init__.py > @@ -2,83 +2,3 @@ > # Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> > > from ._libcamera import * > - > - > -class MappedFrameBuffer: > - def __init__(self, fb): > - self.__fb = fb > - > - def __enter__(self): > - import os > - import mmap > - > - fb = self.__fb > - > - # Collect information about the buffers > - > - bufinfos = {} > - > - for i in range(fb.num_planes): > - fd = fb.fd(i) > - > - if fd not in bufinfos: > - buflen = os.lseek(fd, 0, os.SEEK_END) > - bufinfos[fd] = {'maplen': 0, 'buflen': buflen} > - else: > - buflen = bufinfos[fd]['buflen'] > - > - if fb.offset(i) > buflen or fb.offset(i) + fb.length(i) > buflen: > - raise RuntimeError(f'plane is out of buffer: buffer length={buflen}, ' + > - f'plane offset={fb.offset(i)}, plane length={fb.length(i)}') > - > - bufinfos[fd]['maplen'] = max(bufinfos[fd]['maplen'], fb.offset(i) + fb.length(i)) > - > - # mmap the buffers > - > - maps = [] > - > - for fd, info in bufinfos.items(): > - map = mmap.mmap(fd, info['maplen'], mmap.MAP_SHARED, mmap.PROT_READ | mmap.PROT_WRITE) > - info['map'] = map > - maps.append(map) > - > - self.__maps = tuple(maps) > - > - # Create memoryviews for the planes > - > - planes = [] > - > - for i in range(fb.num_planes): > - fd = fb.fd(i) > - info = bufinfos[fd] > - > - mv = memoryview(info['map']) > - > - start = fb.offset(i) > - end = fb.offset(i) + fb.length(i) > - > - mv = mv[start:end] > - > - planes.append(mv) > - > - self.__planes = tuple(planes) > - > - return self > - > - def __exit__(self, exc_type, exc_value, exc_traceback): > - for p in self.__planes: > - p.release() > - > - for mm in self.__maps: > - mm.close() > - > - @property > - def planes(self): > - return self.__planes > - > - > -def __FrameBuffer__mmap(self): > - return MappedFrameBuffer(self) > - > - > -FrameBuffer.mmap = __FrameBuffer__mmap > diff --git a/src/py/libcamera/meson.build b/src/py/libcamera/meson.build > index 0a7b65f3..b705ac1f 100644 > --- a/src/py/libcamera/meson.build > +++ b/src/py/libcamera/meson.build > @@ -72,6 +72,10 @@ run_command('ln', '-fsT', files('__init__.py'), > meson.current_build_dir() / '__init__.py', > check: true) > > +run_command('ln', '-fsT', meson.current_source_dir() / 'utils', > + meson.current_build_dir() / 'utils', > + check: true) > + > install_data(['__init__.py'], install_dir : destdir) > > # \todo Generate stubs when building. See https://peps.python.org/pep-0484/#stub-files > diff --git a/src/py/libcamera/__init__.py b/src/py/libcamera/utils/MappedFrameBuffer.py > similarity index 93% > copy from src/py/libcamera/__init__.py > copy to src/py/libcamera/utils/MappedFrameBuffer.py > index 0d7da9e2..e7dd16ec 100644 > --- a/src/py/libcamera/__init__.py > +++ b/src/py/libcamera/utils/MappedFrameBuffer.py > @@ -1,9 +1,6 @@ > # SPDX-License-Identifier: LGPL-2.1-or-later > # Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> > > -from ._libcamera import * > - > - > class MappedFrameBuffer: > def __init__(self, fb): > self.__fb = fb > @@ -75,10 +72,3 @@ class MappedFrameBuffer: > @property > def planes(self): > return self.__planes > - > - > -def __FrameBuffer__mmap(self): > - return MappedFrameBuffer(self) > - > - > -FrameBuffer.mmap = __FrameBuffer__mmap > diff --git a/src/py/libcamera/utils/__init__.py b/src/py/libcamera/utils/__init__.py > new file mode 100644 > index 00000000..4a23ce36 > --- /dev/null > +++ b/src/py/libcamera/utils/__init__.py > @@ -0,0 +1,4 @@ > +# SPDX-License-Identifier: LGPL-2.1-or-later > +# Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> > + > +from .MappedFrameBuffer import MappedFrameBuffer
diff --git a/src/py/cam/cam.py b/src/py/cam/cam.py index 66df18bf..64f67e86 100755 --- a/src/py/cam/cam.py +++ b/src/py/cam/cam.py @@ -9,6 +9,7 @@ import argparse import binascii import libcamera as libcam +import libcamera.utils import sys import traceback @@ -327,7 +328,7 @@ def request_handler(state, ctx, req): crcs = [] if ctx['opt-crc']: - with fb.mmap() as mfb: + with libcamera.utils.MappedFrameBuffer(fb) as mfb: plane_crcs = [binascii.crc32(p) for p in mfb.planes] crcs.append(plane_crcs) @@ -345,7 +346,7 @@ def request_handler(state, ctx, req): print(f'\t{ctrl} = {val}') if ctx['opt-save-frames']: - with fb.mmap() as mfb: + 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: diff --git a/src/py/cam/cam_qt.py b/src/py/cam/cam_qt.py index bff1175b..70bdb7bb 100644 --- a/src/py/cam/cam_qt.py +++ b/src/py/cam/cam_qt.py @@ -9,6 +9,7 @@ from PIL import Image from PIL.ImageQt import ImageQt from PyQt5 import QtCore, QtGui, QtWidgets import libcamera as libcam +import libcamera.utils import numpy as np import sys @@ -285,7 +286,7 @@ class MainWindow(QtWidgets.QWidget): controlsLayout.addStretch() def buf_to_qpixmap(self, stream, fb): - with fb.mmap() as mfb: + with libcamera.utils.MappedFrameBuffer(fb) as mfb: cfg = stream.configuration if cfg.pixel_format == libcam.formats.MJPEG: diff --git a/src/py/libcamera/__init__.py b/src/py/libcamera/__init__.py index 0d7da9e2..e234a5e4 100644 --- a/src/py/libcamera/__init__.py +++ b/src/py/libcamera/__init__.py @@ -2,83 +2,3 @@ # Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> from ._libcamera import * - - -class MappedFrameBuffer: - def __init__(self, fb): - self.__fb = fb - - def __enter__(self): - import os - import mmap - - fb = self.__fb - - # Collect information about the buffers - - bufinfos = {} - - for i in range(fb.num_planes): - fd = fb.fd(i) - - if fd not in bufinfos: - buflen = os.lseek(fd, 0, os.SEEK_END) - bufinfos[fd] = {'maplen': 0, 'buflen': buflen} - else: - buflen = bufinfos[fd]['buflen'] - - if fb.offset(i) > buflen or fb.offset(i) + fb.length(i) > buflen: - raise RuntimeError(f'plane is out of buffer: buffer length={buflen}, ' + - f'plane offset={fb.offset(i)}, plane length={fb.length(i)}') - - bufinfos[fd]['maplen'] = max(bufinfos[fd]['maplen'], fb.offset(i) + fb.length(i)) - - # mmap the buffers - - maps = [] - - for fd, info in bufinfos.items(): - map = mmap.mmap(fd, info['maplen'], mmap.MAP_SHARED, mmap.PROT_READ | mmap.PROT_WRITE) - info['map'] = map - maps.append(map) - - self.__maps = tuple(maps) - - # Create memoryviews for the planes - - planes = [] - - for i in range(fb.num_planes): - fd = fb.fd(i) - info = bufinfos[fd] - - mv = memoryview(info['map']) - - start = fb.offset(i) - end = fb.offset(i) + fb.length(i) - - mv = mv[start:end] - - planes.append(mv) - - self.__planes = tuple(planes) - - return self - - def __exit__(self, exc_type, exc_value, exc_traceback): - for p in self.__planes: - p.release() - - for mm in self.__maps: - mm.close() - - @property - def planes(self): - return self.__planes - - -def __FrameBuffer__mmap(self): - return MappedFrameBuffer(self) - - -FrameBuffer.mmap = __FrameBuffer__mmap diff --git a/src/py/libcamera/meson.build b/src/py/libcamera/meson.build index 0a7b65f3..b705ac1f 100644 --- a/src/py/libcamera/meson.build +++ b/src/py/libcamera/meson.build @@ -72,6 +72,10 @@ run_command('ln', '-fsT', files('__init__.py'), meson.current_build_dir() / '__init__.py', check: true) +run_command('ln', '-fsT', meson.current_source_dir() / 'utils', + meson.current_build_dir() / 'utils', + check: true) + install_data(['__init__.py'], install_dir : destdir) # \todo Generate stubs when building. See https://peps.python.org/pep-0484/#stub-files diff --git a/src/py/libcamera/__init__.py b/src/py/libcamera/utils/MappedFrameBuffer.py similarity index 93% copy from src/py/libcamera/__init__.py copy to src/py/libcamera/utils/MappedFrameBuffer.py index 0d7da9e2..e7dd16ec 100644 --- a/src/py/libcamera/__init__.py +++ b/src/py/libcamera/utils/MappedFrameBuffer.py @@ -1,9 +1,6 @@ # SPDX-License-Identifier: LGPL-2.1-or-later # Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> -from ._libcamera import * - - class MappedFrameBuffer: def __init__(self, fb): self.__fb = fb @@ -75,10 +72,3 @@ class MappedFrameBuffer: @property def planes(self): return self.__planes - - -def __FrameBuffer__mmap(self): - return MappedFrameBuffer(self) - - -FrameBuffer.mmap = __FrameBuffer__mmap diff --git a/src/py/libcamera/utils/__init__.py b/src/py/libcamera/utils/__init__.py new file mode 100644 index 00000000..4a23ce36 --- /dev/null +++ b/src/py/libcamera/utils/__init__.py @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> + +from .MappedFrameBuffer import MappedFrameBuffer
Move MappedFrameBuffer to libcamera.utils, instead of extending FrameBuffer class with a new mmap() method. This keeps us more aligned to the C++ API. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> --- src/py/cam/cam.py | 5 +- src/py/cam/cam_qt.py | 3 +- src/py/libcamera/__init__.py | 80 ------------------- src/py/libcamera/meson.build | 4 + .../MappedFrameBuffer.py} | 10 --- src/py/libcamera/utils/__init__.py | 4 + 6 files changed, 13 insertions(+), 93 deletions(-) copy src/py/libcamera/{__init__.py => utils/MappedFrameBuffer.py} (93%) create mode 100644 src/py/libcamera/utils/__init__.py