summaryrefslogtreecommitdiff
path: root/src/py/libcamera/__init__.py
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ideasonboard.com>2022-05-09 13:10:20 +0300
committerKieran Bingham <kieran.bingham@ideasonboard.com>2022-05-10 13:53:43 +0200
commit8aa02271fd716ed046970a0b1f89176963303f50 (patch)
treeda81430f03dc967addbdec3c143001b1490c751d /src/py/libcamera/__init__.py
parent5cb17e0c138aa3afef92e8d95d876d2bd94516ed (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__.py84
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