py: Move MappedFrameBuffer to libcamera.utils
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> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
parent
210ce547a4
commit
9e4388cca5
6 changed files with 87 additions and 83 deletions
|
@ -9,6 +9,7 @@
|
||||||
import argparse
|
import argparse
|
||||||
import binascii
|
import binascii
|
||||||
import libcamera as libcam
|
import libcamera as libcam
|
||||||
|
import libcamera.utils
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
@ -327,7 +328,7 @@ def request_handler(state, ctx, req):
|
||||||
|
|
||||||
crcs = []
|
crcs = []
|
||||||
if ctx['opt-crc']:
|
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]
|
plane_crcs = [binascii.crc32(p) for p in mfb.planes]
|
||||||
crcs.append(plane_crcs)
|
crcs.append(plane_crcs)
|
||||||
|
|
||||||
|
@ -345,7 +346,7 @@ def request_handler(state, ctx, req):
|
||||||
print(f'\t{ctrl} = {val}')
|
print(f'\t{ctrl} = {val}')
|
||||||
|
|
||||||
if ctx['opt-save-frames']:
|
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'])
|
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:
|
||||||
|
|
|
@ -9,6 +9,7 @@ from PIL import Image
|
||||||
from PIL.ImageQt import ImageQt
|
from PIL.ImageQt import ImageQt
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
import libcamera as libcam
|
import libcamera as libcam
|
||||||
|
import libcamera.utils
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
@ -285,7 +286,7 @@ class MainWindow(QtWidgets.QWidget):
|
||||||
controlsLayout.addStretch()
|
controlsLayout.addStretch()
|
||||||
|
|
||||||
def buf_to_qpixmap(self, stream, fb):
|
def buf_to_qpixmap(self, stream, fb):
|
||||||
with fb.mmap() as mfb:
|
with libcamera.utils.MappedFrameBuffer(fb) as mfb:
|
||||||
cfg = stream.configuration
|
cfg = stream.configuration
|
||||||
|
|
||||||
if cfg.pixel_format == libcam.formats.MJPEG:
|
if cfg.pixel_format == libcam.formats.MJPEG:
|
||||||
|
|
|
@ -2,83 +2,3 @@
|
||||||
# Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
|
# Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
|
||||||
|
|
||||||
from ._libcamera import *
|
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
|
|
||||||
|
|
|
@ -72,6 +72,10 @@ run_command('ln', '-fsT', files('__init__.py'),
|
||||||
meson.current_build_dir() / '__init__.py',
|
meson.current_build_dir() / '__init__.py',
|
||||||
check: true)
|
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)
|
install_data(['__init__.py'], install_dir : destdir)
|
||||||
|
|
||||||
# \todo Generate stubs when building. See https://peps.python.org/pep-0484/#stub-files
|
# \todo Generate stubs when building. See https://peps.python.org/pep-0484/#stub-files
|
||||||
|
|
74
src/py/libcamera/utils/MappedFrameBuffer.py
Normal file
74
src/py/libcamera/utils/MappedFrameBuffer.py
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
# Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
|
||||||
|
|
||||||
|
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
|
4
src/py/libcamera/utils/__init__.py
Normal file
4
src/py/libcamera/utils/__init__.py
Normal file
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue