[{"id":391,"web_url":"https://patchwork.libcamera.org/comment/391/","msgid":"<20190117215531.GK6484@bigcity.dyn.berto.se>","date":"2019-01-17T21:55:31","subject":"Re: [libcamera-devel] [PATCH v4 1/2] libcamera: Add V4L2 Device\n\tobject","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/people/5/","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"content":"Hi Kieran,\n\nThanks for your persistence with this series :-)\n\nOn 2019-01-17 21:27:02 +0000, Kieran Bingham wrote:\n> Provide a helper V4L2 device object capable of interacting with the\n> V4L2 Linux Kernel APIs.\n> \n> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\nReviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n\n> ---\n>  src/libcamera/include/v4l2_device.h |  60 +++++++++\n>  src/libcamera/meson.build           |   2 +\n>  src/libcamera/v4l2_device.cpp       | 186 ++++++++++++++++++++++++++++\n>  3 files changed, 248 insertions(+)\n>  create mode 100644 src/libcamera/include/v4l2_device.h\n>  create mode 100644 src/libcamera/v4l2_device.cpp\n> \n> diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h\n> new file mode 100644\n> index 000000000000..474c05b58cef\n> --- /dev/null\n> +++ b/src/libcamera/include/v4l2_device.h\n> @@ -0,0 +1,60 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * v4l2_device.h - V4L2 Device\n> + */\n> +#ifndef __LIBCAMERA_V4L2_DEVICE_H__\n> +#define __LIBCAMERA_V4L2_DEVICE_H__\n> +\n> +#include <string>\n> +\n> +#include <linux/videodev2.h>\n> +\n> +namespace libcamera {\n> +\n> +struct V4L2Capability final : v4l2_capability {\n> +\tconst char *driver() const\n> +\t{\n> +\t\treturn reinterpret_cast<const char *>(v4l2_capability::driver);\n> +\t}\n> +\tconst char *card() const\n> +\t{\n> +\t\treturn reinterpret_cast<const char *>(v4l2_capability::card);\n> +\t}\n> +\tconst char *bus_info() const\n> +\t{\n> +\t\treturn reinterpret_cast<const char *>(v4l2_capability::bus_info);\n> +\t}\n> +\n> +\tbool isCapture() const { return capabilities & V4L2_CAP_VIDEO_CAPTURE; }\n> +\tbool isOutput() const { return capabilities & V4L2_CAP_VIDEO_OUTPUT; }\n> +\tbool hasStreaming() const { return capabilities & V4L2_CAP_STREAMING; }\n> +};\n> +\n> +class V4L2Device\n> +{\n> +public:\n> +\tV4L2Device(const std::string &devnode);\n> +\tV4L2Device(const V4L2Device &) = delete;\n> +\t~V4L2Device();\n> +\n> +\tvoid operator=(const V4L2Device &) = delete;\n> +\n> +\tint open();\n> +\tbool isOpen() const;\n> +\tvoid close();\n> +\n> +\tconst char *driverName() const { return caps_.driver(); }\n> +\tconst char *deviceName() const { return caps_.card(); }\n> +\tconst char *busName() const { return caps_.bus_info(); }\n> +\n> +private:\n> +\tstd::string devnode_;\n> +\tint fd_;\n> +\tV4L2Capability caps_;\n> +};\n> +\n> +} /* namespace libcamera */\n> +\n> +#endif /* __LIBCAMERA_V4L2_DEVICE_H__ */\n> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> index abf9a71d4172..f9f25c0ecf15 100644\n> --- a/src/libcamera/meson.build\n> +++ b/src/libcamera/meson.build\n> @@ -11,6 +11,7 @@ libcamera_sources = files([\n>      'pipeline_handler.cpp',\n>      'signal.cpp',\n>      'timer.cpp',\n> +    'v4l2_device.cpp',\n>  ])\n>  \n>  libcamera_headers = files([\n> @@ -21,6 +22,7 @@ libcamera_headers = files([\n>      'include/media_object.h',\n>      'include/pipeline_handler.h',\n>      'include/utils.h',\n> +    'include/v4l2_device.h',\n>  ])\n>  \n>  libcamera_internal_includes =  include_directories('include')\n> diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp\n> new file mode 100644\n> index 000000000000..54b53de37510\n> --- /dev/null\n> +++ b/src/libcamera/v4l2_device.cpp\n> @@ -0,0 +1,186 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * v4l2_device.cpp - V4L2 Device\n> + */\n> +\n> +#include <fcntl.h>\n> +#include <string.h>\n> +#include <sys/ioctl.h>\n> +#include <sys/mman.h>\n> +#include <unistd.h>\n> +\n> +#include \"log.h\"\n> +#include \"v4l2_device.h\"\n> +\n> +/**\n> + * \\file v4l2_device.h\n> + * \\brief V4L2 Device API\n> + */\n> +namespace libcamera {\n> +\n> +/**\n> + * \\struct V4L2Capability\n> + * \\brief struct v4l2_capability object wrapper and helpers\n> + *\n> + * The V4L2Capability structure manages the information returned by the\n> + * VIDIOC_QUERYCAP ioctl.\n> + */\n> +\n> +/**\n> + * \\fn const char *V4L2Capability::driver()\n> + * \\brief Retrieve the driver module name\n> + * \\return The string containing the name of the driver module\n> + */\n> +\n> +/**\n> + * \\fn const char *V4L2Capability::card()\n> + * \\brief Retrieve the device card name\n> + * \\return The string containing the device name\n> + */\n> +\n> +/**\n> + * \\fn const char *V4L2Capability::bus_info()\n> + * \\brief Retrieve the location of the device in the system\n> + * \\return The string containing the device location\n> + */\n> +\n> +/**\n> + * \\fn bool V4L2Capability::isCapture()\n> + * \\brief Identify if the device is capable of capturing video\n> + * \\return True if the device can capture video frames\n> + */\n> +\n> +/**\n> + * \\fn bool V4L2Capability::isOutput()\n> + * \\brief Identify if the device is capable of outputting video\n> + * \\return True if the device can output video frames\n> + */\n> +\n> +/**\n> + * \\fn bool V4L2Capability::hasStreaming()\n> + * \\brief Determine if the device can perform Streaming I/O\n> + * \\return True if the device provides Streaming I/O IOCTLs\n> + */\n> +\n> +/**\n> + * \\class V4L2Device\n> + * \\brief V4L2Device object and API\n> + *\n> + * The V4L2 Device API class models an instance of a V4L2 device node.\n> + * It is constructed with the path to a V4L2 video device node. The device node\n> + * is only opened upon a call to open() which must be checked for success.\n> + *\n> + * The device capabilities are validated when the device is opened and the\n> + * device is rejected if it is not a suitable V4L2 capture or output device, or\n> + * if the device does not support streaming I/O.\n> + *\n> + * No API call other than open(), isOpen() and close() shall be called on an\n> + * unopened device instance.\n> + *\n> + * Upon destruction any device left open will be closed, and any resources\n> + * released.\n> + */\n> +\n> +/**\n> + * \\brief Construct a V4L2Device\n> + * \\param devnode The file-system path to the video device node\n> + */\n> +V4L2Device::V4L2Device(const std::string &devnode)\n> +\t: devnode_(devnode), fd_(-1)\n> +{\n> +}\n> +\n> +V4L2Device::~V4L2Device()\n> +{\n> +\tclose();\n> +}\n> +\n> +/**\n> + * \\brief Open a V4L2 device and query its capabilities\n> + * \\return 0 on success, or a negative error code otherwise\n> + */\n> +int V4L2Device::open()\n> +{\n> +\tint ret;\n> +\n> +\tif (isOpen()) {\n> +\t\tLOG(Error) << \"Device already open\";\n> +\t\treturn -EBUSY;\n> +\t}\n> +\n> +\tret = ::open(devnode_.c_str(), O_RDWR);\n> +\tif (ret < 0) {\n> +\t\tret = -errno;\n> +\t\tLOG(Error) << \"Failed to open V4L2 device '\" << devnode_\n> +\t\t\t   << \"': \" << strerror(-ret);\n> +\t\treturn ret;\n> +\t}\n> +\tfd_ = ret;\n> +\n> +\tret = ioctl(fd_, VIDIOC_QUERYCAP, &caps_);\n> +\tif (ret < 0) {\n> +\t\tret = -errno;\n> +\t\tLOG(Error) << \"Failed to query device capabilities: \"\n> +\t\t\t   << strerror(-ret);\n> +\t\treturn ret;\n> +\t}\n> +\n> +\tLOG(Debug) << \"Opened '\" << devnode_ << \"' \"\n> +\t\t   << caps_.bus_info() << \": \" << caps_.driver()\n> +\t\t   << \": \" << caps_.card();\n> +\n> +\tif (!caps_.isCapture() && !caps_.isOutput()) {\n> +\t\tLOG(Debug) << \"Device is not a supported type\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tif (!caps_.hasStreaming()) {\n> +\t\tLOG(Error) << \"Device does not support streaming I/O\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n> +/**\n> + * \\brief Check if device is successfully opened\n> + * \\return True if the device is open, false otherwise\n> + */\n> +bool V4L2Device::isOpen() const\n> +{\n> +\treturn fd_ != -1;\n> +}\n> +\n> +/**\n> + * \\brief Close the device, releasing any resources acquired by open()\n> + */\n> +void V4L2Device::close()\n> +{\n> +\tif (fd_ < 0)\n> +\t\treturn;\n> +\n> +\t::close(fd_);\n> +\tfd_ = -1;\n> +}\n> +\n> +/**\n> + * \\fn const char *V4L2Device::driverName()\n> + * \\brief Retrieve the name of the V4L2 device driver\n> + * \\return The string containing the driver name\n> + */\n> +\n> +/**\n> + * \\fn const char *V4L2Device::deviceName()\n> + * \\brief Retrieve the name of the V4L2 device\n> + * \\return The string containing the device name\n> + */\n> +\n> +/**\n> + * \\fn const char *V4L2Device::busName()\n> + * \\brief Retrieve the location of the device in the system\n> + * \\return The string containing the device location\n> + */\n> +\n> +} /* namespace libcamera */\n> -- \n> 2.17.1\n> \n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","headers":{"Return-Path":"<niklas.soderlund@ragnatech.se>","Received":["from mail-lj1-x244.google.com (mail-lj1-x244.google.com\n\t[IPv6:2a00:1450:4864:20::244])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id EB2AC60C78\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 17 Jan 2019 22:55:33 +0100 (CET)","by mail-lj1-x244.google.com with SMTP id u89-v6so9928529lje.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 17 Jan 2019 13:55:33 -0800 (PST)","from localhost (89-233-230-99.cust.bredband2.com. [89.233.230.99])\n\tby smtp.gmail.com with ESMTPSA id\n\t11-v6sm425321ljv.1.2019.01.17.13.55.32\n\t(version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256);\n\tThu, 17 Jan 2019 13:55:32 -0800 (PST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=ragnatech-se.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:content-transfer-encoding:in-reply-to\n\t:user-agent; bh=T9Vf869rX6LXwruduGG4ZtiowYeTwJZmzoefatBS/04=;\n\tb=0L9B39bcYvIeHkbrso4DZRm0+Bq8kNTr9mTQ6T8F8xjw8rNI++RFevbsBZeCXXIT/W\n\tnT8F2KCy2MB439dGiPnydAbHscBU/+u5SBv4zsh2D+5z6BtBsS1kvaH6JrHTI+UWjGkH\n\tW49eM8hmKKmMSRBNitEYCX7SW4Af7tDRlb+mt99RE2zYeEff3wzBDLv9VQZ6nQB9qqEl\n\tL1ur6wP2taSqDPMQPwTGjR7DUDYZzc8WVNXxueXkID+dDtgX21TnbjmQwtuQvLC/qEpB\n\tRh3fpZpiTcQCRIW/WlFZCHtpT5FZ6qe3CaVa+NHuxhKEG8ZTZbJL6siDagXypqZRsZJW\n\tHxdA==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:content-transfer-encoding\n\t:in-reply-to:user-agent;\n\tbh=T9Vf869rX6LXwruduGG4ZtiowYeTwJZmzoefatBS/04=;\n\tb=EQvdexfqEWpd6ccn5+hV8XTRk4G2FtnUNKO99qZps77D8uklgrS1yISGmc8AS7JuMI\n\tqAwy2kZnFQu4e2uQLTmdBrfvPJa5L/+qSEIUfA/qqFEQ8mF8jfBOzbfkNwUt3HNMhSDY\n\tk3oPNvJmwPncmNZu7ZVddhnNsGUgpS17b/9Z3xvaKxo2CStOz+gdBVu99KgTFj8sykXs\n\tQ3/G40QyBE5K0IL/8EJbkE0Y602N8NP74H7krZXz2WLfLE/9vNCViy6y8qIZjJjP3Kkr\n\tbe759NVmydNSEMBF43eRisJ7KDn7wVxZ0TvzKkDs9gKuabl4eY6Lo4xtv6nAZx+o6kDt\n\tefKA==","X-Gm-Message-State":"AJcUukeJy7HYSx3Y24J7wnGbXBm69LrFheXSH7mkj+4fXtO8eAs9IpuV\n\tS9pWQyAE9ZOCB0EVadq19Og1gw==","X-Google-Smtp-Source":"ALg8bN7ZhG+xyeINEHDw4/PM3jqSYJtM92CO+zexmeDvueZDHzOqir4Uycm8MRQv3DD8CvT/qY/kNA==","X-Received":"by 2002:a2e:9ad0:: with SMTP id\n\tp16-v6mr11453723ljj.102.1547762133063; \n\tThu, 17 Jan 2019 13:55:33 -0800 (PST)","Date":"Thu, 17 Jan 2019 22:55:31 +0100","From":"Niklas =?iso-8859-1?q?S=F6derlund?= <niklas.soderlund@ragnatech.se>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"LibCamera Devel <libcamera-devel@lists.libcamera.org>","Message-ID":"<20190117215531.GK6484@bigcity.dyn.berto.se>","References":"<20190117212703.24047-1-kieran.bingham@ideasonboard.com>\n\t<20190117212703.24047-2-kieran.bingham@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=iso-8859-1","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20190117212703.24047-2-kieran.bingham@ideasonboard.com>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH v4 1/2] libcamera: Add V4L2 Device\n\tobject","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","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":"Thu, 17 Jan 2019 21:55:34 -0000"}}]