[libcamera-devel,v2,07/19] py: Move MappedFrameBuffer to libcamera.utils
diff mbox series

Message ID 20220524114610.41848-8-tomi.valkeinen@ideasonboard.com
State Accepted
Headers show
Series
  • More misc Python patches
Related show

Commit Message

Tomi Valkeinen May 24, 2022, 11:45 a.m. UTC
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

Comments

Laurent Pinchart May 26, 2022, 3:31 p.m. UTC | #1
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

Patch
diff mbox series

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