diff options
author | Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> | 2022-05-09 13:10:20 +0300 |
---|---|---|
committer | Kieran Bingham <kieran.bingham@ideasonboard.com> | 2022-05-10 13:53:43 +0200 |
commit | 8aa02271fd716ed046970a0b1f89176963303f50 (patch) | |
tree | da81430f03dc967addbdec3c143001b1490c751d /src/py/libcamera/__init__.py | |
parent | 5cb17e0c138aa3afef92e8d95d876d2bd94516ed (diff) |
Add Python bindings
Add libcamera Python bindings. pybind11 is used to generate the C++ <->
Python layer.
We use pybind11 'smart_holder' version to avoid issues with private
destructors and shared_ptr. There is also an alternative solution here:
https://github.com/pybind/pybind11/pull/2067
Only a subset of libcamera classes are exposed. Implementing and testing
the wrapper classes is challenging, and as such only classes that I have
needed have been added so far.
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>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Diffstat (limited to 'src/py/libcamera/__init__.py')
-rw-r--r-- | src/py/libcamera/__init__.py | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/src/py/libcamera/__init__.py b/src/py/libcamera/__init__.py new file mode 100644 index 00000000..0d7da9e2 --- /dev/null +++ b/src/py/libcamera/__init__.py @@ -0,0 +1,84 @@ +# 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 + + 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 |