From patchwork Wed May 18 13:13:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 15962 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 12159C3256 for ; Wed, 18 May 2022 13:14:07 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A204565669; Wed, 18 May 2022 15:14:06 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1652879646; bh=gn2amU8VE4PLh6T2oRe1CaqN5cONffQhEBi3RTvwtYI=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=g929QuppXhrWNVvzDa0PUOOn9mkepp1N3PgnbqoHmm82OU1xJGdTkcvbG+owf0oqp zvVk/jcf0IMjyDSvQMJInvZG5Xv/PumdHnK2NR+m0/K2sR7oN7bJGAHjwLY+RhZoc6 pIAVCNvoU+ONMvEycK1Q4K53n6f9KSwcHQkx8zoSIoe454ZfgTMQ/Qhr7xG/mrvTBA G7QDIBOY5nv9eWAng6+i1a8wLsGcBTy1EDIEmKp8pzdLpwOSeLBWZW07yZVZZJeyuc SivvKfG64IT2aQEJBvem03R0ct0s7FONnlxzlW/eGXxPD1qcK0nZHS0D/mwZpdTgX7 nkbjyHUxa/OIA== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 962F765659 for ; Wed, 18 May 2022 15:13:52 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="tqJei5gu"; dkim-atps=neutral Received: from deskari.lan (91-156-85-209.elisa-laajakaista.fi [91.156.85.209]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id F259F22BA; Wed, 18 May 2022 15:13:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1652879632; bh=gn2amU8VE4PLh6T2oRe1CaqN5cONffQhEBi3RTvwtYI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tqJei5guMG+oN+yR1Ez/Y0iFevD7Jpqc5ZWvJDXISq4hAojjvQx6q/P+CHtm8TAZn GmMvmmyiMVN0TmqtYPrwpsiuRlyCIWQbnCRynnVgaGhEnbBeDdSnOMB0+kQBPPPhTZ 93ccTP7KDNkl6TPeff8rrn44wCaHrwfIER577rGM= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Wed, 18 May 2022 16:13:23 +0300 Message-Id: <20220518131329.66994-13-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220518131329.66994-1-tomi.valkeinen@ideasonboard.com> References: <20220518131329.66994-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 12/18] py: implement PixelFormat class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Implement PixelFormat bindings properly with a PixelFormat class. Change the bindings to use the new class instead of a string. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- src/py/cam/cam.py | 2 +- src/py/cam/cam_kms.py | 10 +-------- src/py/cam/cam_qt.py | 4 +++- src/py/cam/cam_qtgl.py | 17 +-------------- src/py/cam/gl_helpers.py | 8 ------- src/py/libcamera/pymain.cpp | 42 ++++++++++++++++++------------------- 6 files changed, 27 insertions(+), 56 deletions(-) diff --git a/src/py/cam/cam.py b/src/py/cam/cam.py index c7da97d7..001fb9de 100755 --- a/src/py/cam/cam.py +++ b/src/py/cam/cam.py @@ -164,7 +164,7 @@ def configure(ctx): stream_config.size = (stream_opts['width'], stream_opts['height']) if 'pixelformat' in stream_opts: - stream_config.pixel_format = stream_opts['pixelformat'] + stream_config.pixel_format = libcam.PixelFormat(stream_opts['pixelformat']) stat = camconfig.validate() diff --git a/src/py/cam/cam_kms.py b/src/py/cam/cam_kms.py index d8ff0284..04381da1 100644 --- a/src/py/cam/cam_kms.py +++ b/src/py/cam/cam_kms.py @@ -5,14 +5,6 @@ import pykms import selectors import sys -FMT_MAP = { - 'RGB888': pykms.PixelFormat.RGB888, - 'YUYV': pykms.PixelFormat.YUYV, - 'ARGB8888': pykms.PixelFormat.ARGB8888, - 'XRGB8888': pykms.PixelFormat.XRGB8888, - 'NV12': pykms.PixelFormat.NV12, -} - class KMSRenderer: def __init__(self, state): @@ -120,7 +112,7 @@ class KMSRenderer: cfg = stream.configuration fmt = cfg.pixel_format - fmt = FMT_MAP[fmt] + fmt = pykms.PixelFormat(fmt.fourcc) plane = self.resman.reserve_generic_plane(self.crtc, fmt) assert(plane is not None) diff --git a/src/py/cam/cam_qt.py b/src/py/cam/cam_qt.py index fb485b9b..45a30aeb 100644 --- a/src/py/cam/cam_qt.py +++ b/src/py/cam/cam_qt.py @@ -87,6 +87,8 @@ def to_rgb(fmt, size, data): w = size[0] h = size[1] + fmt = str(fmt) + if fmt == 'YUYV': # YUV422 yuyv = data.reshape((h, w // 2 * 4)) @@ -293,7 +295,7 @@ class MainWindow(QtWidgets.QWidget): w, h = cfg.size pitch = cfg.stride - if cfg.pixel_format == 'MJPEG': + if str(cfg.pixel_format) == 'MJPEG': img = Image.open(BytesIO(mfb.planes[0])) qim = ImageQt(img).copy() pix = QtGui.QPixmap.fromImage(qim) diff --git a/src/py/cam/cam_qtgl.py b/src/py/cam/cam_qtgl.py index 8a95994e..261accb8 100644 --- a/src/py/cam/cam_qtgl.py +++ b/src/py/cam/cam_qtgl.py @@ -30,14 +30,6 @@ from OpenGL.GL import shaders from gl_helpers import * -# libcamera format string -> DRM fourcc -FMT_MAP = { - 'RGB888': 'RG24', - 'XRGB8888': 'XR24', - 'ARGB8888': 'AR24', - 'YUYV': 'YUYV', -} - class EglState: def __init__(self): @@ -204,12 +196,6 @@ class MainWindow(QtWidgets.QWidget): self.current[ctx['idx']] = [] for stream in ctx['streams']: - fmt = stream.configuration.pixel_format - size = stream.configuration.size - - if fmt not in FMT_MAP: - raise Exception('Unsupported pixel format: ' + str(fmt)) - self.textures[stream] = None num_tiles = len(self.textures) @@ -281,8 +267,7 @@ class MainWindow(QtWidgets.QWidget): def create_texture(self, stream, fb): cfg = stream.configuration - fmt = cfg.pixel_format - fmt = str_to_fourcc(FMT_MAP[fmt]) + fmt = cfg.pixel_format.fourcc w, h = cfg.size attribs = [ diff --git a/src/py/cam/gl_helpers.py b/src/py/cam/gl_helpers.py index ac5e6889..53b3e9df 100644 --- a/src/py/cam/gl_helpers.py +++ b/src/py/cam/gl_helpers.py @@ -30,14 +30,6 @@ def getglEGLImageTargetTexture2DOES(): glEGLImageTargetTexture2DOES = getglEGLImageTargetTexture2DOES() -# \todo This can be dropped when we have proper PixelFormat bindings -def str_to_fourcc(str): - assert(len(str) == 4) - fourcc = 0 - for i, v in enumerate([ord(c) for c in str]): - fourcc |= v << (i * 8) - return fourcc - def get_gl_extensions(): n = GLint() diff --git a/src/py/libcamera/pymain.cpp b/src/py/libcamera/pymain.cpp index af22205e..97b05903 100644 --- a/src/py/libcamera/pymain.cpp +++ b/src/py/libcamera/pymain.cpp @@ -8,7 +8,6 @@ /* * \todo Add geometry classes (Point, Rectangle...) * \todo Add bindings for the ControlInfo class - * \todo Add bindings for the PixelFormat class */ #include @@ -173,6 +172,7 @@ PYBIND11_MODULE(_libcamera, m) auto pyColorSpaceTransferFunction = py::enum_(pyColorSpace, "TransferFunction"); auto pyColorSpaceYcbcrEncoding = py::enum_(pyColorSpace, "YcbcrEncoding"); auto pyColorSpaceRange = py::enum_(pyColorSpace, "Range"); + auto pyPixelFormat = py::class_(m, "PixelFormat"); /* Global functions */ m.def("log_set_level", &logSetLevel); @@ -404,14 +404,7 @@ PYBIND11_MODULE(_libcamera, m) self.size.width = std::get<0>(size); self.size.height = std::get<1>(size); }) - .def_property( - "pixel_format", - [](StreamConfiguration &self) { - return self.pixelFormat.toString(); - }, - [](StreamConfiguration &self, std::string fmt) { - self.pixelFormat = PixelFormat::fromString(fmt); - }) + .def_readwrite("pixel_format", &StreamConfiguration::pixelFormat) .def_readwrite("stride", &StreamConfiguration::stride) .def_readwrite("frame_size", &StreamConfiguration::frameSize) .def_readwrite("buffer_count", &StreamConfiguration::bufferCount) @@ -420,22 +413,15 @@ PYBIND11_MODULE(_libcamera, m) .def_readwrite("color_space", &StreamConfiguration::colorSpace); pyStreamFormats - .def_property_readonly("pixel_formats", [](StreamFormats &self) { - std::vector fmts; - for (auto &fmt : self.pixelformats()) - fmts.push_back(fmt.toString()); - return fmts; - }) - .def("sizes", [](StreamFormats &self, const std::string &pixelFormat) { - auto fmt = PixelFormat::fromString(pixelFormat); + .def_property_readonly("pixel_formats", &StreamFormats::pixelformats) + .def("sizes", [](StreamFormats &self, const PixelFormat &pixelFormat) { std::vector> fmts; - for (const auto &s : self.sizes(fmt)) + for (const auto &s : self.sizes(pixelFormat)) fmts.push_back(std::make_tuple(s.width, s.height)); return fmts; }) - .def("range", [](StreamFormats &self, const std::string &pixelFormat) { - auto fmt = PixelFormat::fromString(pixelFormat); - const auto &range = self.range(fmt); + .def("range", [](StreamFormats &self, const PixelFormat &pixelFormat) { + const auto &range = self.range(pixelFormat); return make_tuple(std::make_tuple(range.hStep, range.vStep), std::make_tuple(range.min.width, range.min.height), std::make_tuple(range.max.width, range.max.height)); @@ -648,4 +634,18 @@ PYBIND11_MODULE(_libcamera, m) pyColorSpaceRange .value("Full", ColorSpace::Range::Full) .value("Limited", ColorSpace::Range::Limited); + + pyPixelFormat + .def(py::init<>()) + .def(py::init()) + .def(py::init<>([](const std::string &str) { + return PixelFormat::fromString(str); + })) + .def_property_readonly("fourcc", &PixelFormat::fourcc) + .def_property_readonly("modifier", &PixelFormat::modifier) + .def(py::self == py::self) + .def("__str__", &PixelFormat::toString) + .def("__repr__", [](const PixelFormat &self) { + return "libcamera.PixelFormat('" + self.toString() + "')"; + }); }