Patch Detail
Show a patch.
GET /api/patches/4102/?format=api
{ "id": 4102, "url": "https://patchwork.libcamera.org/api/patches/4102/?format=api", "web_url": "https://patchwork.libcamera.org/patch/4102/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20200619120249.1084998-1-kieran.bingham@ideasonboard.com>", "date": "2020-06-19T12:02:49", "name": "[libcamera-devel] libcamera: pipelines: Add VIVID pipeline support", "commit_ref": null, "pull_url": null, "state": "not-applicable", "archived": false, "hash": "548229ce1b10882dcdad1d6744d94ac24dcde483", "submitter": { "id": 4, "url": "https://patchwork.libcamera.org/api/people/4/?format=api", "name": "Kieran Bingham", "email": "kieran.bingham@ideasonboard.com" }, "delegate": { "id": 11, "url": "https://patchwork.libcamera.org/api/users/11/?format=api", "username": "kbingham", "first_name": "Kieran", "last_name": "Bingham", "email": "kieran.bingham@ideasonboard.com" }, "mbox": "https://patchwork.libcamera.org/patch/4102/mbox/", "series": [ { "id": 1019, "url": "https://patchwork.libcamera.org/api/series/1019/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=1019", "date": "2020-06-19T12:02:49", "name": "[libcamera-devel] libcamera: pipelines: Add VIVID pipeline support", "version": 1, "mbox": "https://patchwork.libcamera.org/series/1019/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/4102/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/4102/checks/", "tags": {}, "headers": { "Return-Path": "<kieran.bingham@ideasonboard.com>", "Received": [ "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 96F2460103\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 19 Jun 2020 14:02:54 +0200 (CEST)", "from Q.local (cpc89242-aztw30-2-0-cust488.18-1.cable.virginm.net\n\t[86.31.129.233])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id E98EE552;\n\tFri, 19 Jun 2020 14:02:53 +0200 (CEST)" ], "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"uVJU5czI\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1592568174;\n\tbh=WcH/ni9TJfFpxXu1eCeWXbA1xVI3ib9pcnEpQb+o3Ak=;\n\th=From:To:Cc:Subject:Date:From;\n\tb=uVJU5czIWSe/oDI5KvPStNVYYZBCmx4gkGl+1RQwWemAhh7TUcjfOzzDrZYAQfRli\n\tAqxohm9HmesjutEJrc7ytxl8S82RvndSImj8NMEW5LZ7KFzNpImv0e5eEm0tnGAGtL\n\tZUm4ihH/JEpGGVFE6mIZQaaohohTWpRfJROTkj84=", "From": "Kieran Bingham <kieran.bingham@ideasonboard.com>", "To": "Paul Elder <paul.elder@ideasonboard.com>,\n\tlibcamera devel <libcamera-devel@lists.libcamera.org>", "Date": "Fri, 19 Jun 2020 13:02:49 +0100", "Message-Id": "<20200619120249.1084998-1-kieran.bingham@ideasonboard.com>", "X-Mailer": "git-send-email 2.25.1", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Subject": "[libcamera-devel] [PATCH] libcamera: pipelines: Add VIVID pipeline\n\tsupport", "X-BeenThere": "libcamera-devel@lists.libcamera.org", "X-Mailman-Version": "2.1.29", "Precedence": "list", "List-Id": "<libcamera-devel.lists.libcamera.org>", "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>", "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>", "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>", "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>", "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>", "X-List-Received-Date": "Fri, 19 Jun 2020 12:02:54 -0000" }, "content": "The VIVID driver supports more pixel formats and properties than the VIMC\ndriver, and can provide extended testing for libcamera.\n\nThe VIMC pipeline handler is duplicated and simplified to support the\nVIVID device.\n\nUnfortuantely, the VIVID device can not be handled by either of the\ngeneric UVC or Simple pipeline handlers.\n\nSigned-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n---\n meson_options.txt | 2 +-\n src/libcamera/pipeline/vivid/meson.build | 5 +\n src/libcamera/pipeline/vivid/vivid.cpp | 441 +++++++++++++++++++++++\n 3 files changed, 447 insertions(+), 1 deletion(-)\n create mode 100644 src/libcamera/pipeline/vivid/meson.build\n create mode 100644 src/libcamera/pipeline/vivid/vivid.cpp", "diff": "diff --git a/meson_options.txt b/meson_options.txt\nindex badace151bb6..dc4684df49b2 100644\n--- a/meson_options.txt\n+++ b/meson_options.txt\n@@ -16,7 +16,7 @@ option('gstreamer',\n \n option('pipelines',\n type : 'array',\n- choices : ['ipu3', 'raspberrypi', 'rkisp1', 'simple', 'uvcvideo', 'vimc'],\n+ choices : ['ipu3', 'raspberrypi', 'rkisp1', 'simple', 'uvcvideo', 'vimc', 'vivid'],\n description : 'Select which pipeline handlers to include')\n \n option('test',\ndiff --git a/src/libcamera/pipeline/vivid/meson.build b/src/libcamera/pipeline/vivid/meson.build\nnew file mode 100644\nindex 000000000000..086bb825387c\n--- /dev/null\n+++ b/src/libcamera/pipeline/vivid/meson.build\n@@ -0,0 +1,5 @@\n+# SPDX-License-Identifier: CC0-1.0\n+\n+libcamera_sources += files([\n+ 'vivid.cpp',\n+])\ndiff --git a/src/libcamera/pipeline/vivid/vivid.cpp b/src/libcamera/pipeline/vivid/vivid.cpp\nnew file mode 100644\nindex 000000000000..b811e33a0299\n--- /dev/null\n+++ b/src/libcamera/pipeline/vivid/vivid.cpp\n@@ -0,0 +1,441 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2018, Google Inc.\n+ *\n+ * vivid.cpp - Pipeline handler for the vivid capture device\n+ */\n+\n+#include <algorithm>\n+#include <iomanip>\n+#include <map>\n+#include <math.h>\n+#include <tuple>\n+\n+#include <linux/media-bus-format.h>\n+#include <linux/version.h>\n+\n+#include <libcamera/camera.h>\n+#include <libcamera/control_ids.h>\n+#include <libcamera/controls.h>\n+#include <libcamera/ipa/ipa_interface.h>\n+#include <libcamera/ipa/ipa_module_info.h>\n+#include <libcamera/request.h>\n+#include <libcamera/stream.h>\n+\n+#include \"libcamera/internal/camera_sensor.h\"\n+#include \"libcamera/internal/device_enumerator.h\"\n+#include \"libcamera/internal/ipa_manager.h\"\n+#include \"libcamera/internal/log.h\"\n+#include \"libcamera/internal/media_device.h\"\n+#include \"libcamera/internal/pipeline_handler.h\"\n+#include \"libcamera/internal/utils.h\"\n+#include \"libcamera/internal/v4l2_controls.h\"\n+#include \"libcamera/internal/v4l2_subdevice.h\"\n+#include \"libcamera/internal/v4l2_videodevice.h\"\n+\n+#define VIVID_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)\n+#define VIVID_CID_BUTTON (VIVID_CID_CUSTOM_BASE + 0)\n+#define VIVID_CID_BOOLEAN (VIVID_CID_CUSTOM_BASE + 1)\n+#define VIVID_CID_INTEGER (VIVID_CID_CUSTOM_BASE + 2)\n+#define VIVID_CID_INTEGER64 (VIVID_CID_CUSTOM_BASE + 3)\n+#define VIVID_CID_MENU (VIVID_CID_CUSTOM_BASE + 4)\n+#define VIVID_CID_STRING (VIVID_CID_CUSTOM_BASE + 5)\n+#define VIVID_CID_BITMASK (VIVID_CID_CUSTOM_BASE + 6)\n+#define VIVID_CID_INTMENU (VIVID_CID_CUSTOM_BASE + 7)\n+#define VIVID_CID_U32_ARRAY (VIVID_CID_CUSTOM_BASE + 8)\n+#define VIVID_CID_U16_MATRIX (VIVID_CID_CUSTOM_BASE + 9)\n+#define VIVID_CID_U8_4D_ARRAY (VIVID_CID_CUSTOM_BASE + 10)\n+\n+#define VIVID_CID_VIVID_BASE (0x00f00000 | 0xf000)\n+#define VIVID_CID_VIVID_CLASS (0x00f00000 | 1)\n+#define VIVID_CID_TEST_PATTERN (VIVID_CID_VIVID_BASE + 0)\n+#define VIVID_CID_OSD_TEXT_MODE (VIVID_CID_VIVID_BASE + 1)\n+#define VIVID_CID_HOR_MOVEMENT (VIVID_CID_VIVID_BASE + 2)\n+#define VIVID_CID_VERT_MOVEMENT (VIVID_CID_VIVID_BASE + 3)\n+#define VIVID_CID_SHOW_BORDER (VIVID_CID_VIVID_BASE + 4)\n+#define VIVID_CID_SHOW_SQUARE (VIVID_CID_VIVID_BASE + 5)\n+#define VIVID_CID_INSERT_SAV (VIVID_CID_VIVID_BASE + 6)\n+#define VIVID_CID_INSERT_EAV (VIVID_CID_VIVID_BASE + 7)\n+#define VIVID_CID_VBI_CAP_INTERLACED (VIVID_CID_VIVID_BASE + 8)\n+\n+#define VIVID_CID_HFLIP (VIVID_CID_VIVID_BASE + 20)\n+#define VIVID_CID_VFLIP (VIVID_CID_VIVID_BASE + 21)\n+#define VIVID_CID_STD_ASPECT_RATIO (VIVID_CID_VIVID_BASE + 22)\n+#define VIVID_CID_DV_TIMINGS_ASPECT_RATIO (VIVID_CID_VIVID_BASE + 23)\n+#define VIVID_CID_TSTAMP_SRC (VIVID_CID_VIVID_BASE + 24)\n+#define VIVID_CID_COLORSPACE (VIVID_CID_VIVID_BASE + 25)\n+#define VIVID_CID_XFER_FUNC (VIVID_CID_VIVID_BASE + 26)\n+#define VIVID_CID_YCBCR_ENC (VIVID_CID_VIVID_BASE + 27)\n+#define VIVID_CID_QUANTIZATION (VIVID_CID_VIVID_BASE + 28)\n+#define VIVID_CID_LIMITED_RGB_RANGE (VIVID_CID_VIVID_BASE + 29)\n+#define VIVID_CID_ALPHA_MODE (VIVID_CID_VIVID_BASE + 30)\n+#define VIVID_CID_HAS_CROP_CAP (VIVID_CID_VIVID_BASE + 31)\n+#define VIVID_CID_HAS_COMPOSE_CAP (VIVID_CID_VIVID_BASE + 32)\n+#define VIVID_CID_HAS_SCALER_CAP (VIVID_CID_VIVID_BASE + 33)\n+#define VIVID_CID_HAS_CROP_OUT (VIVID_CID_VIVID_BASE + 34)\n+#define VIVID_CID_HAS_COMPOSE_OUT (VIVID_CID_VIVID_BASE + 35)\n+#define VIVID_CID_HAS_SCALER_OUT (VIVID_CID_VIVID_BASE + 36)\n+#define VIVID_CID_LOOP_VIDEO (VIVID_CID_VIVID_BASE + 37)\n+#define VIVID_CID_SEQ_WRAP (VIVID_CID_VIVID_BASE + 38)\n+#define VIVID_CID_TIME_WRAP (VIVID_CID_VIVID_BASE + 39)\n+#define VIVID_CID_MAX_EDID_BLOCKS (VIVID_CID_VIVID_BASE + 40)\n+#define VIVID_CID_PERCENTAGE_FILL (VIVID_CID_VIVID_BASE + 41)\n+#define VIVID_CID_REDUCED_FPS (VIVID_CID_VIVID_BASE + 42)\n+#define VIVID_CID_HSV_ENC (VIVID_CID_VIVID_BASE + 43)\n+#define VIVID_CID_DISPLAY_PRESENT (VIVID_CID_VIVID_BASE + 44)\n+\n+#define VIVID_CID_STD_SIGNAL_MODE (VIVID_CID_VIVID_BASE + 60)\n+#define VIVID_CID_STANDARD (VIVID_CID_VIVID_BASE + 61)\n+#define VIVID_CID_DV_TIMINGS_SIGNAL_MODE (VIVID_CID_VIVID_BASE + 62)\n+#define VIVID_CID_DV_TIMINGS (VIVID_CID_VIVID_BASE + 63)\n+#define VIVID_CID_PERC_DROPPED (VIVID_CID_VIVID_BASE + 64)\n+#define VIVID_CID_DISCONNECT (VIVID_CID_VIVID_BASE + 65)\n+#define VIVID_CID_DQBUF_ERROR (VIVID_CID_VIVID_BASE + 66)\n+#define VIVID_CID_QUEUE_SETUP_ERROR (VIVID_CID_VIVID_BASE + 67)\n+#define VIVID_CID_BUF_PREPARE_ERROR (VIVID_CID_VIVID_BASE + 68)\n+#define VIVID_CID_START_STR_ERROR (VIVID_CID_VIVID_BASE + 69)\n+#define VIVID_CID_QUEUE_ERROR (VIVID_CID_VIVID_BASE + 70)\n+#define VIVID_CID_CLEAR_FB (VIVID_CID_VIVID_BASE + 71)\n+#define VIVID_CID_REQ_VALIDATE_ERROR (VIVID_CID_VIVID_BASE + 72)\n+\n+#define VIVID_CID_RADIO_SEEK_MODE (VIVID_CID_VIVID_BASE + 90)\n+#define VIVID_CID_RADIO_SEEK_PROG_LIM (VIVID_CID_VIVID_BASE + 91)\n+#define VIVID_CID_RADIO_RX_RDS_RBDS (VIVID_CID_VIVID_BASE + 92)\n+#define VIVID_CID_RADIO_RX_RDS_BLOCKIO (VIVID_CID_VIVID_BASE + 93)\n+\n+#define VIVID_CID_RADIO_TX_RDS_BLOCKIO (VIVID_CID_VIVID_BASE + 94)\n+\n+#define VIVID_CID_SDR_CAP_FM_DEVIATION (VIVID_CID_VIVID_BASE + 110)\n+\n+\n+namespace libcamera {\n+\n+LOG_DEFINE_CATEGORY(VIVID)\n+\n+class VividCameraData : public CameraData\n+{\n+public:\n+\tVividCameraData(PipelineHandler *pipe, MediaDevice *media)\n+\t\t: CameraData(pipe), media_(media), video_(nullptr)\n+\t{\n+\t}\n+\n+\t~VividCameraData()\n+\t{\n+\t\tdelete video_;\n+\t}\n+\n+\tint init();\n+\tvoid bufferReady(FrameBuffer *buffer);\n+\n+\tMediaDevice *media_;\n+\tV4L2VideoDevice *video_;\n+\tStream stream_;\n+};\n+\n+class VividCameraConfiguration : public CameraConfiguration\n+{\n+public:\n+\tVividCameraConfiguration();\n+\n+\tStatus validate() override;\n+};\n+\n+class PipelineHandlerVivid : public PipelineHandler\n+{\n+public:\n+\tPipelineHandlerVivid(CameraManager *manager);\n+\n+\tCameraConfiguration *generateConfiguration(Camera *camera,\n+\t\t\t\t\t\t const StreamRoles &roles) override;\n+\tint configure(Camera *camera, CameraConfiguration *config) override;\n+\n+\tint exportFrameBuffers(Camera *camera, Stream *stream,\n+\t\t\t std::vector<std::unique_ptr<FrameBuffer>> *buffers) override;\n+\n+\tint start(Camera *camera) override;\n+\tvoid stop(Camera *camera) override;\n+\n+\tint queueRequestDevice(Camera *camera, Request *request) override;\n+\n+\tbool match(DeviceEnumerator *enumerator) override;\n+\n+private:\n+\tint processControls(VividCameraData *data, Request *request);\n+\n+\tVividCameraData *cameraData(const Camera *camera)\n+\t{\n+\t\treturn static_cast<VividCameraData *>(\n+\t\t\tPipelineHandler::cameraData(camera));\n+\t}\n+};\n+\n+VividCameraConfiguration::VividCameraConfiguration()\n+\t: CameraConfiguration()\n+{\n+}\n+\n+CameraConfiguration::Status VividCameraConfiguration::validate()\n+{\n+\tStatus status = Valid;\n+\n+\tif (config_.empty())\n+\t\treturn Invalid;\n+\n+\t/* Cap the number of entries to the available streams. */\n+\tif (config_.size() > 1) {\n+\t\tconfig_.resize(1);\n+\t\tstatus = Adjusted;\n+\t}\n+\n+\tStreamConfiguration &cfg = config_[0];\n+\n+\t/* Adjust the pixel format. */\n+\tconst std::vector<libcamera::PixelFormat> formats = cfg.formats().pixelformats();\n+\tif (std::find(formats.begin(), formats.end(), cfg.pixelFormat) == formats.end()) {\n+\t\tcfg.pixelFormat = cfg.formats().pixelformats()[0];\n+\t\tLOG(VIVID, Debug) << \"Adjusting format to \" << cfg.pixelFormat.toString();\n+\t\tstatus = Adjusted;\n+\t}\n+\n+\tcfg.bufferCount = 4;\n+\n+\treturn status;\n+}\n+\n+PipelineHandlerVivid::PipelineHandlerVivid(CameraManager *manager)\n+\t: PipelineHandler(manager)\n+{\n+}\n+\n+CameraConfiguration *PipelineHandlerVivid::generateConfiguration(Camera *camera,\n+\t\t\t\t\t\t\t\t const StreamRoles &roles)\n+{\n+\tCameraConfiguration *config = new VividCameraConfiguration();\n+\tVividCameraData *data = cameraData(camera);\n+\n+\tif (roles.empty())\n+\t\treturn config;\n+\n+\tstd::map<V4L2PixelFormat, std::vector<SizeRange>> v4l2Formats =\n+\t\tdata->video_->formats();\n+\tstd::map<PixelFormat, std::vector<SizeRange>> deviceFormats;\n+\tstd::transform(v4l2Formats.begin(), v4l2Formats.end(),\n+\t\t std::inserter(deviceFormats, deviceFormats.begin()),\n+\t\t [&](const decltype(v4l2Formats)::value_type &format) {\n+\t\t\t return decltype(deviceFormats)::value_type{\n+\t\t\t\t format.first.toPixelFormat(),\n+\t\t\t\t format.second\n+\t\t\t };\n+\t\t });\n+\n+\tStreamFormats formats(deviceFormats);\n+\tStreamConfiguration cfg(formats);\n+\n+\tcfg.pixelFormat = PixelFormat(DRM_FORMAT_BGR888);\n+\tcfg.size = { 1280, 720 };\n+\tcfg.bufferCount = 4;\n+\n+\tconfig->addConfiguration(cfg);\n+\n+\tconfig->validate();\n+\n+\treturn config;\n+}\n+\n+int PipelineHandlerVivid::configure(Camera *camera, CameraConfiguration *config)\n+{\n+\tVividCameraData *data = cameraData(camera);\n+\tStreamConfiguration &cfg = config->at(0);\n+\tint ret;\n+\n+\tV4L2DeviceFormat format = {};\n+\tformat.fourcc = data->video_->toV4L2PixelFormat(cfg.pixelFormat);\n+\tformat.size = cfg.size;\n+\n+\tret = data->video_->setFormat(&format);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (format.size != cfg.size ||\n+\t format.fourcc != data->video_->toV4L2PixelFormat(cfg.pixelFormat))\n+\t\treturn -EINVAL;\n+\n+\tcfg.setStream(&data->stream_);\n+\tcfg.stride = format.planes[0].bpl;\n+\n+\treturn 0;\n+}\n+\n+int PipelineHandlerVivid::exportFrameBuffers(Camera *camera, Stream *stream,\n+\t\t\t\t\t std::vector<std::unique_ptr<FrameBuffer>> *buffers)\n+{\n+\tVividCameraData *data = cameraData(camera);\n+\tunsigned int count = stream->configuration().bufferCount;\n+\n+\treturn data->video_->exportBuffers(count, buffers);\n+}\n+\n+int PipelineHandlerVivid::start(Camera *camera)\n+{\n+\tVividCameraData *data = cameraData(camera);\n+\tunsigned int count = data->stream_.configuration().bufferCount;\n+\n+\tint ret = data->video_->importBuffers(count);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tret = data->video_->streamOn();\n+\tif (ret < 0) {\n+\t\tdata->ipa_->stop();\n+\t\tdata->video_->releaseBuffers();\n+\t\treturn ret;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+void PipelineHandlerVivid::stop(Camera *camera)\n+{\n+\tVividCameraData *data = cameraData(camera);\n+\tdata->video_->streamOff();\n+\tdata->video_->releaseBuffers();\n+}\n+\n+int PipelineHandlerVivid::processControls(VividCameraData *data, Request *request)\n+{\n+\tControlList controls(data->video_->controls());\n+\n+\tfor (auto it : request->controls()) {\n+\t\tunsigned int id = it.first;\n+\t\tunsigned int offset;\n+\t\tuint32_t cid;\n+\n+\t\tif (id == controls::Brightness) {\n+\t\t\tcid = V4L2_CID_BRIGHTNESS;\n+\t\t\toffset = 128;\n+\t\t} else if (id == controls::Contrast) {\n+\t\t\tcid = V4L2_CID_CONTRAST;\n+\t\t\toffset = 0;\n+\t\t} else if (id == controls::Saturation) {\n+\t\t\tcid = V4L2_CID_SATURATION;\n+\t\t\toffset = 0;\n+\t\t} else {\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tint32_t value = lroundf(it.second.get<float>() * 128 + offset);\n+\t\tcontrols.set(cid, utils::clamp(value, 0, 255));\n+\t}\n+\n+\tfor (const auto &ctrl : controls)\n+\t\tLOG(VIVID, Debug)\n+\t\t\t<< \"Setting control \" << utils::hex(ctrl.first)\n+\t\t\t<< \" to \" << ctrl.second.toString();\n+\n+\tint ret = data->video_->setControls(&controls);\n+\tif (ret) {\n+\t\tLOG(VIVID, Error) << \"Failed to set controls: \" << ret;\n+\t\treturn ret < 0 ? ret : -EINVAL;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int PipelineHandlerVivid::queueRequestDevice(Camera *camera, Request *request)\n+{\n+\tVividCameraData *data = cameraData(camera);\n+\tFrameBuffer *buffer = request->findBuffer(&data->stream_);\n+\tif (!buffer) {\n+\t\tLOG(VIVID, Error)\n+\t\t\t<< \"Attempt to queue request with invalid stream\";\n+\n+\t\treturn -ENOENT;\n+\t}\n+\n+\tint ret = processControls(data, request);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tret = data->video_->queueBuffer(buffer);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\treturn 0;\n+}\n+\n+bool PipelineHandlerVivid::match(DeviceEnumerator *enumerator)\n+{\n+\tDeviceMatch dm(\"vivid\");\n+\tdm.add(\"vivid-000-vid-cap\");\n+\n+\tMediaDevice *media = acquireMediaDevice(enumerator, dm);\n+\tif (!media)\n+\t\treturn false;\n+\n+\tstd::unique_ptr<VividCameraData> data = std::make_unique<VividCameraData>(this, media);\n+\n+\t/* Locate and open the capture video node. */\n+\tif (data->init())\n+\t\treturn false;\n+\n+\t/* Create and register the camera. */\n+\tstd::set<Stream *> streams{ &data->stream_ };\n+\tstd::shared_ptr<Camera> camera = Camera::create(this, data->video_->deviceName(), streams);\n+\tregisterCamera(std::move(camera), std::move(data));\n+\n+\treturn true;\n+}\n+\n+int VividCameraData::init()\n+{\n+\tvideo_ = new V4L2VideoDevice(media_->getEntityByName(\"vivid-000-vid-cap\"));\n+\tif (video_->open())\n+\t\treturn -ENODEV;\n+\n+\tvideo_->bufferReady.connect(this, &VividCameraData::bufferReady);\n+\n+\t/* Initialise the supported controls. */\n+\tconst ControlInfoMap &controls = video_->controls();\n+\tControlInfoMap::Map ctrls;\n+\n+\tfor (const auto &ctrl : controls) {\n+\t\tconst ControlId *id;\n+\t\tControlInfo info;\n+\n+\t\tswitch (ctrl.first->id()) {\n+\t\tcase V4L2_CID_BRIGHTNESS:\n+\t\t\tid = &controls::Brightness;\n+\t\t\tinfo = ControlInfo{ { -1.0f }, { 1.0f }, { 0.0f } };\n+\t\t\tbreak;\n+\t\tcase V4L2_CID_CONTRAST:\n+\t\t\tid = &controls::Contrast;\n+\t\t\tinfo = ControlInfo{ { 0.0f }, { 2.0f }, { 1.0f } };\n+\t\t\tbreak;\n+\t\tcase V4L2_CID_SATURATION:\n+\t\t\tid = &controls::Saturation;\n+\t\t\tinfo = ControlInfo{ { 0.0f }, { 2.0f }, { 1.0f } };\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tctrls.emplace(id, info);\n+\t}\n+\n+\tcontrolInfo_ = std::move(ctrls);\n+\n+\treturn 0;\n+}\n+\n+void VividCameraData::bufferReady(FrameBuffer *buffer)\n+{\n+\tRequest *request = buffer->request();\n+\n+\tpipe_->completeBuffer(camera_, request, buffer);\n+\tpipe_->completeRequest(camera_, request);\n+}\n+\n+REGISTER_PIPELINE_HANDLER(PipelineHandlerVivid);\n+\n+} /* namespace libcamera */\n", "prefixes": [ "libcamera-devel" ] }