summaryrefslogtreecommitdiff
path: root/src/libcamera/v4l2_device.cpp
diff options
context:
space:
mode:
authorJacopo Mondi <jacopo@jmondi.org>2019-06-12 13:09:57 +0100
committerJacopo Mondi <jacopo@jmondi.org>2019-06-19 15:46:44 +0200
commit3a6c4bd146cc6647daf458bbc048bd861e702f62 (patch)
treefe44a23f524bd1d82b541985bddf83a275ae725a /src/libcamera/v4l2_device.cpp
parent20807a8c17e629b93d293ef0a0bdbd686ce84823 (diff)
libcamera: Rename V4L2Device to V4L2VideoDevice
In preparation of creating a new V4L2Device base class, rename V4L2Device to V4L2VideoDevice. This is a project wide rename without any intended functional change. Signed-off-by: Jacopo Mondi <jacopo@jmondi.org> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'src/libcamera/v4l2_device.cpp')
-rw-r--r--src/libcamera/v4l2_device.cpp1126
1 files changed, 0 insertions, 1126 deletions
diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp
deleted file mode 100644
index e14fc610..00000000
--- a/src/libcamera/v4l2_device.cpp
+++ /dev/null
@@ -1,1126 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2019, Google Inc.
- *
- * v4l2_device.cpp - V4L2 Device
- */
-
-#include "v4l2_device.h"
-
-#include <fcntl.h>
-#include <iomanip>
-#include <sstream>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <vector>
-
-#include <libcamera/buffer.h>
-#include <libcamera/event_notifier.h>
-
-#include "log.h"
-#include "media_device.h"
-#include "media_object.h"
-
-/**
- * \file v4l2_device.h
- * \brief V4L2 Device API
- */
-namespace libcamera {
-
-LOG_DEFINE_CATEGORY(V4L2)
-
-/**
- * \struct V4L2Capability
- * \brief struct v4l2_capability object wrapper and helpers
- *
- * The V4L2Capability structure manages the information returned by the
- * VIDIOC_QUERYCAP ioctl.
- */
-
-/**
- * \fn V4L2Capability::driver()
- * \brief Retrieve the driver module name
- * \return The string containing the name of the driver module
- */
-
-/**
- * \fn V4L2Capability::card()
- * \brief Retrieve the device card name
- * \return The string containing the device name
- */
-
-/**
- * \fn V4L2Capability::bus_info()
- * \brief Retrieve the location of the device in the system
- * \return The string containing the device location
- */
-
-/**
- * \fn V4L2Capability::device_caps()
- * \brief Retrieve the capabilities of the device
- * \return The device specific capabilities if V4L2_CAP_DEVICE_CAPS is set or
- * driver capabilities otherwise
- */
-
-/**
- * \fn V4L2Capability::isMultiplanar()
- * \brief Identify if the device implements the V4L2 multiplanar APIs
- * \return True if the device supports multiplanar APIs
- */
-
-/**
- * \fn V4L2Capability::isCapture()
- * \brief Identify if the device captures data
- * \return True if the device can capture data
- */
-
-/**
- * \fn V4L2Capability::isOutput()
- * \brief Identify if the device outputs data
- * \return True if the device can output data
- */
-
-/**
- * \fn V4L2Capability::isVideo()
- * \brief Identify if the device captures or outputs images
- * \return True if the device can capture or output images
- */
-
-/**
- * \fn V4L2Capability::isMeta()
- * \brief Identify if the device captures or outputs image meta-data
- *
- * \todo Add support for META_CAPTURE introduced in Linux v5.0
- *
- * \return True if the device can capture or output image meta-data
- */
-
-/**
- * \fn V4L2Capability::isVideoCapture()
- * \brief Identify if the device captures images
- * \return True if the device can capture images
- */
-
-/**
- * \fn V4L2Capability::isVideoOutput()
- * \brief Identify if the device outputs images
- * \return True if the device can output images
- */
-
-/**
- * \fn V4L2Capability::isMetaCapture()
- * \brief Identify if the device captures image meta-data
- * \return True if the device can capture image meta-data
- */
-
-/**
- * \fn V4L2Capability::isMetaOutput()
- * \brief Identify if the device outputs image meta-data
- * \return True if the device can output image meta-data
- */
-
-/**
- * \fn V4L2Capability::hasStreaming()
- * \brief Determine if the device can perform Streaming I/O
- * \return True if the device provides Streaming I/O IOCTLs
- */
-
-/**
- * \class V4L2DeviceFormat
- * \brief The V4L2 device image format and sizes
- *
- * This class describes the image format and resolution to be programmed on a
- * V4L2 video device. The image format is defined by a fourcc code (as specified
- * by the V4L2 API with the V4L2_PIX_FMT_* macros), a resolution (width and
- * height) and one to three planes with configurable line stride and a total
- * per-plane size in bytes.
- *
- * Image formats, as defined by the V4L2 APIs, are categorised as packed,
- * semi-planar and planar, and describe the layout of the image pixel components
- * stored in memory.
- *
- * Packed image formats store pixel components one after the other, in a
- * contiguous memory area. Examples of packed image formats are YUYV
- * permutations, RGB with different pixel sub-sampling ratios such as RGB565 or
- * RGB666 or Raw-Bayer formats such as SRGGB8 or SGRBG12.
- *
- * Semi-planar and planar image formats store the pixel components in separate
- * and possibly non-contiguous memory areas, named planes, whose sizes depend on
- * the pixel components sub-sampling ratios, which are defined by the format.
- * Semi-planar formats use two planes to store pixel components and notable
- * examples of such formats are the NV12 and NV16 formats, while planar formats
- * use three planes to store pixel components and notable examples are YUV422
- * and YUV420.
- *
- * Image formats supported by the V4L2 API are defined and described in Section
- * number 2 of the "Part I - Video for Linux API" chapter of the "Linux Media
- * Infrastructure userspace API", part of the Linux kernel documentation.
- *
- * In the context of this document, packed image formats are referred to as
- * "packed formats" and semi-planar and planar image formats are referred to as
- * "planar formats".
- *
- * V4L2 also defines two different sets of APIs to work with devices that store
- * planes in contiguous or separate memory areas. They are named "Single-plane
- * APIs" and "Multi-plane APIs" respectively and are documented in Section 2.1
- * and Section 2.2 of the above mentioned "Part I - Video for Linux API"
- * documentation.
- *
- * The single-plane API allows, among other parameters, the configuration of the
- * image resolution, the pixel format and the stride length. In that case the
- * stride applies to all planes (possibly sub-sampled). The multi-plane API
- * allows configuring the resolution, the pixel format and a per-plane stride
- * length and total size.
- *
- * Packed image formats, which occupy a single memory area, are easily described
- * through the single-plane API. When used on a device that implements the
- * multi-plane API, only the size and stride information contained in the first
- * plane are taken into account.
- *
- * Planar image formats, which occupy distinct memory areas, are easily
- * described through the multi-plane APIs. When used on a device that implements
- * the single-plane API, all planes are stored one after the other in a
- * contiguous memory area, and it is not possible to configure per-plane stride
- * length and size, but only a global stride length which is applied to all
- * planes.
- *
- * The V4L2DeviceFormat class describes both packed and planar image formats,
- * regardless of the API type (single or multi plane) implemented by the device
- * the format has to be applied to. The total size and bytes per line of images
- * represented with packed formats are configured using the first entry of the
- * V4L2DeviceFormat::planes array, while the per-plane size and per-plane stride
- * length of images represented with planar image formats are configured using
- * the opportune number of entries of the V4L2DeviceFormat::planes array, as
- * prescribed by the image format definition (semi-planar formats use 2 entries,
- * while planar formats use the whole 3 entries). The number of valid entries of
- * the V4L2DeviceFormat::planes array is defined by the
- * V4L2DeviceFormat::planesCount value.
- */
-
-/**
- * \var V4L2DeviceFormat::size
- * \brief The image size in pixels
- */
-
-/**
- * \var V4L2DeviceFormat::fourcc
- * \brief The fourcc code describing the pixel encoding scheme
- *
- * The fourcc code, as defined by the V4L2 API with the V4L2_PIX_FMT_* macros,
- * that identifies the image format pixel encoding scheme.
- */
-
-/**
- * \var V4L2DeviceFormat::planes
- * \brief The per-plane memory size information
- *
- * Images are stored in memory in one or more data planes. Each data plane has a
- * specific line stride and memory size, which could differ from the image
- * visible sizes to accommodate padding at the end of lines and end of planes.
- * Only the first \ref planesCount entries are considered valid.
- */
-
-/**
- * \var V4L2DeviceFormat::planesCount
- * \brief The number of valid data planes
- */
-
-/**
- * \brief Assemble and return a string describing the format
- * \return A string describing the V4L2DeviceFormat
- */
-const std::string V4L2DeviceFormat::toString() const
-{
- std::stringstream ss;
-
- ss.fill(0);
- ss << size.toString() << "-0x" << std::hex << std::setw(8) << fourcc;
-
- return ss.str();
-}
-
-/**
- * \class V4L2Device
- * \brief V4L2Device object and API
- *
- * The V4L2 Device API class models an instance of a V4L2 device node.
- * It is constructed with the path to a V4L2 video device node. The device node
- * is only opened upon a call to open() which must be checked for success.
- *
- * The device capabilities are validated when the device is opened and the
- * device is rejected if it is not a suitable V4L2 capture or output device, or
- * if the device does not support streaming I/O.
- *
- * No API call other than open(), isOpen() and close() shall be called on an
- * unopened device instance.
- *
- * The V4L2Device class tracks queued buffers and handles buffer events. It
- * automatically dequeues completed buffers and emits the \ref bufferReady
- * signal.
- *
- * Upon destruction any device left open will be closed, and any resources
- * released.
- */
-
-/**
- * \brief Construct a V4L2Device
- * \param[in] deviceNode The file-system path to the video device node
- */
-V4L2Device::V4L2Device(const std::string &deviceNode)
- : deviceNode_(deviceNode), fd_(-1), bufferPool_(nullptr),
- queuedBuffersCount_(0), fdEvent_(nullptr)
-{
- /*
- * We default to an MMAP based CAPTURE device, however this will be
- * updated based upon the device capabilities.
- */
- bufferType_ = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- memoryType_ = V4L2_MEMORY_MMAP;
-}
-
-/**
- * \brief Construct a V4L2Device from a MediaEntity
- * \param[in] entity The MediaEntity to build the device from
- *
- * Construct a V4L2Device from a MediaEntity's device node path.
- */
-V4L2Device::V4L2Device(const MediaEntity *entity)
- : V4L2Device(entity->deviceNode())
-{
-}
-
-V4L2Device::~V4L2Device()
-{
- close();
-}
-
-/**
- * \brief Open a V4L2 device and query its capabilities
- * \return 0 on success or a negative error code otherwise
- */
-int V4L2Device::open()
-{
- int ret;
-
- if (isOpen()) {
- LOG(V4L2, Error) << "Device already open";
- return -EBUSY;
- }
-
- ret = ::open(deviceNode_.c_str(), O_RDWR | O_NONBLOCK);
- if (ret < 0) {
- ret = -errno;
- LOG(V4L2, Error)
- << "Failed to open V4L2 device: " << strerror(-ret);
- return ret;
- }
- fd_ = ret;
-
- ret = ioctl(fd_, VIDIOC_QUERYCAP, &caps_);
- if (ret < 0) {
- ret = -errno;
- LOG(V4L2, Error)
- << "Failed to query device capabilities: "
- << strerror(-ret);
- return ret;
- }
-
- LOG(V4L2, Debug)
- << "Opened device " << caps_.bus_info() << ": "
- << caps_.driver() << ": " << caps_.card();
-
- if (!caps_.hasStreaming()) {
- LOG(V4L2, Error) << "Device does not support streaming I/O";
- return -EINVAL;
- }
-
- /*
- * Set buffer type and wait for read notifications on CAPTURE devices
- * (POLLIN), and write notifications for OUTPUT devices (POLLOUT).
- */
- if (caps_.isVideoCapture()) {
- fdEvent_ = new EventNotifier(fd_, EventNotifier::Read);
- bufferType_ = caps_.isMultiplanar()
- ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
- : V4L2_BUF_TYPE_VIDEO_CAPTURE;
- } else if (caps_.isVideoOutput()) {
- fdEvent_ = new EventNotifier(fd_, EventNotifier::Write);
- bufferType_ = caps_.isMultiplanar()
- ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
- : V4L2_BUF_TYPE_VIDEO_OUTPUT;
- } else if (caps_.isMetaCapture()) {
- fdEvent_ = new EventNotifier(fd_, EventNotifier::Read);
- bufferType_ = V4L2_BUF_TYPE_META_CAPTURE;
- } else if (caps_.isMetaOutput()) {
- fdEvent_ = new EventNotifier(fd_, EventNotifier::Write);
- bufferType_ = V4L2_BUF_TYPE_META_OUTPUT;
- } else {
- LOG(V4L2, Error) << "Device is not a supported type";
- return -EINVAL;
- }
-
- fdEvent_->activated.connect(this, &V4L2Device::bufferAvailable);
- fdEvent_->setEnabled(false);
-
- return 0;
-}
-
-/**
- * \brief Check if device is successfully opened
- * \return True if the device is open, false otherwise
- */
-bool V4L2Device::isOpen() const
-{
- return fd_ != -1;
-}
-
-/**
- * \brief Close the device, releasing any resources acquired by open()
- */
-void V4L2Device::close()
-{
- if (fd_ < 0)
- return;
-
- releaseBuffers();
- delete fdEvent_;
-
- ::close(fd_);
- fd_ = -1;
-}
-
-/**
- * \fn V4L2Device::driverName()
- * \brief Retrieve the name of the V4L2 device driver
- * \return The string containing the driver name
- */
-
-/**
- * \fn V4L2Device::deviceName()
- * \brief Retrieve the name of the V4L2 device
- * \return The string containing the device name
- */
-
-/**
- * \fn V4L2Device::busName()
- * \brief Retrieve the location of the device in the system
- * \return The string containing the device location
- */
-
-/**
- * \fn V4L2Device::deviceNode()
- * \brief Retrieve the video device node path
- * \return The video device device node path
- */
-
-std::string V4L2Device::logPrefix() const
-{
- return deviceNode_ + (V4L2_TYPE_IS_OUTPUT(bufferType_) ? "[out]" : "[cap]");
-}
-
-/**
- * \brief Retrieve the image format set on the V4L2 device
- * \param[out] format The image format applied on the device
- * \return 0 on success or a negative error code otherwise
- */
-int V4L2Device::getFormat(V4L2DeviceFormat *format)
-{
- if (caps_.isMeta())
- return getFormatMeta(format);
- else if (caps_.isMultiplanar())
- return getFormatMultiplane(format);
- else
- return getFormatSingleplane(format);
-}
-
-/**
- * \brief Configure an image format on the V4L2 device
- * \param[inout] format The image format to apply to the device
- *
- * Apply the supplied \a format to the device, and return the actually
- * applied format parameters, as \ref V4L2Device::getFormat would do.
- *
- * \return 0 on success or a negative error code otherwise
- */
-int V4L2Device::setFormat(V4L2DeviceFormat *format)
-{
- if (caps_.isMeta())
- return setFormatMeta(format);
- else if (caps_.isMultiplanar())
- return setFormatMultiplane(format);
- else
- return setFormatSingleplane(format);
-}
-
-int V4L2Device::getFormatMeta(V4L2DeviceFormat *format)
-{
- struct v4l2_format v4l2Format = {};
- struct v4l2_meta_format *pix = &v4l2Format.fmt.meta;
- int ret;
-
- v4l2Format.type = bufferType_;
- ret = ioctl(fd_, VIDIOC_G_FMT, &v4l2Format);
- if (ret) {
- ret = -errno;
- LOG(V4L2, Error) << "Unable to get format: " << strerror(-ret);
- return ret;
- }
-
- format->size.width = 0;
- format->size.height = 0;
- format->fourcc = pix->dataformat;
- format->planesCount = 1;
- format->planes[0].bpl = pix->buffersize;
- format->planes[0].size = pix->buffersize;
-
- return 0;
-}
-
-int V4L2Device::setFormatMeta(V4L2DeviceFormat *format)
-{
- struct v4l2_format v4l2Format = {};
- struct v4l2_meta_format *pix = &v4l2Format.fmt.meta;
- int ret;
-
- v4l2Format.type = bufferType_;
- pix->dataformat = format->fourcc;
- pix->buffersize = format->planes[0].size;
- ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Format);
- if (ret) {
- ret = -errno;
- LOG(V4L2, Error) << "Unable to set format: " << strerror(-ret);
- return ret;
- }
-
- /*
- * Return to caller the format actually applied on the device,
- * which might differ from the requested one.
- */
- format->size.width = 0;
- format->size.height = 0;
- format->fourcc = format->fourcc;
- format->planesCount = 1;
- format->planes[0].bpl = pix->buffersize;
- format->planes[0].size = pix->buffersize;
-
- return 0;
-}
-
-int V4L2Device::getFormatMultiplane(V4L2DeviceFormat *format)
-{
- struct v4l2_format v4l2Format = {};
- struct v4l2_pix_format_mplane *pix = &v4l2Format.fmt.pix_mp;
- int ret;
-
- v4l2Format.type = bufferType_;
- ret = ioctl(fd_, VIDIOC_G_FMT, &v4l2Format);
- if (ret) {
- ret = -errno;
- LOG(V4L2, Error) << "Unable to get format: " << strerror(-ret);
- return ret;
- }
-
- format->size.width = pix->width;
- format->size.height = pix->height;
- format->fourcc = pix->pixelformat;
- format->planesCount = pix->num_planes;
-
- for (unsigned int i = 0; i < format->planesCount; ++i) {
- format->planes[i].bpl = pix->plane_fmt[i].bytesperline;
- format->planes[i].size = pix->plane_fmt[i].sizeimage;
- }
-
- return 0;
-}
-
-int V4L2Device::setFormatMultiplane(V4L2DeviceFormat *format)
-{
- struct v4l2_format v4l2Format = {};
- struct v4l2_pix_format_mplane *pix = &v4l2Format.fmt.pix_mp;
- int ret;
-
- v4l2Format.type = bufferType_;
- pix->width = format->size.width;
- pix->height = format->size.height;
- pix->pixelformat = format->fourcc;
- pix->num_planes = format->planesCount;
- pix->field = V4L2_FIELD_NONE;
-
- for (unsigned int i = 0; i < pix->num_planes; ++i) {
- pix->plane_fmt[i].bytesperline = format->planes[i].bpl;
- pix->plane_fmt[i].sizeimage = format->planes[i].size;
- }
-
- ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Format);
- if (ret) {
- ret = -errno;
- LOG(V4L2, Error) << "Unable to set format: " << strerror(-ret);
- return ret;
- }
-
- /*
- * Return to caller the format actually applied on the device,
- * which might differ from the requested one.
- */
- format->size.width = pix->width;
- format->size.height = pix->height;
- format->fourcc = pix->pixelformat;
- format->planesCount = pix->num_planes;
- for (unsigned int i = 0; i < format->planesCount; ++i) {
- format->planes[i].bpl = pix->plane_fmt[i].bytesperline;
- format->planes[i].size = pix->plane_fmt[i].sizeimage;
- }
-
- return 0;
-}
-
-int V4L2Device::getFormatSingleplane(V4L2DeviceFormat *format)
-{
- struct v4l2_format v4l2Format = {};
- struct v4l2_pix_format *pix = &v4l2Format.fmt.pix;
- int ret;
-
- v4l2Format.type = bufferType_;
- ret = ioctl(fd_, VIDIOC_G_FMT, &v4l2Format);
- if (ret) {
- ret = -errno;
- LOG(V4L2, Error) << "Unable to get format: " << strerror(-ret);
- return ret;
- }
-
- format->size.width = pix->width;
- format->size.height = pix->height;
- format->fourcc = pix->pixelformat;
- format->planesCount = 1;
- format->planes[0].bpl = pix->bytesperline;
- format->planes[0].size = pix->sizeimage;
-
- return 0;
-}
-
-int V4L2Device::setFormatSingleplane(V4L2DeviceFormat *format)
-{
- struct v4l2_format v4l2Format = {};
- struct v4l2_pix_format *pix = &v4l2Format.fmt.pix;
- int ret;
-
- v4l2Format.type = bufferType_;
- pix->width = format->size.width;
- pix->height = format->size.height;
- pix->pixelformat = format->fourcc;
- pix->bytesperline = format->planes[0].bpl;
- pix->field = V4L2_FIELD_NONE;
- ret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Format);
- if (ret) {
- ret = -errno;
- LOG(V4L2, Error) << "Unable to set format: " << strerror(-ret);
- return ret;
- }
-
- /*
- * Return to caller the format actually applied on the device,
- * which might differ from the requested one.
- */
- format->size.width = pix->width;
- format->size.height = pix->height;
- format->fourcc = pix->pixelformat;
- format->planesCount = 1;
- format->planes[0].bpl = pix->bytesperline;
- format->planes[0].size = pix->sizeimage;
-
- return 0;
-}
-
-/**
- * \brief Enumerate all pixel formats and frame sizes
- *
- * Enumerate all pixel formats and frame sizes supported by the video device.
- *
- * \return A list of the supported device formats
- */
-ImageFormats V4L2Device::formats()
-{
- ImageFormats formats;
-
- for (unsigned int pixelformat : enumPixelformats()) {
- std::vector<SizeRange> sizes = enumSizes(pixelformat);
- if (sizes.empty())
- return {};
-
- if (formats.addFormat(pixelformat, sizes)) {
- LOG(V4L2, Error)
- << "Could not add sizes for pixel format "
- << pixelformat;
- return {};
- }
- }
-
- return formats;
-}
-
-int V4L2Device::requestBuffers(unsigned int count)
-{
- struct v4l2_requestbuffers rb = {};
- int ret;
-
- rb.count = count;
- rb.type = bufferType_;
- rb.memory = memoryType_;
-
- ret = ioctl(fd_, VIDIOC_REQBUFS, &rb);
- if (ret < 0) {
- ret = -errno;
- LOG(V4L2, Error)
- << "Unable to request " << count << " buffers: "
- << strerror(-ret);
- return ret;
- }
-
- LOG(V4L2, Debug) << rb.count << " buffers requested.";
-
- return rb.count;
-}
-
-/**
- * \brief Request buffers to be allocated from the device and stored in the
- * buffer pool provided.
- * \param[out] pool BufferPool to populate with buffers
- * \return 0 on success or a negative error code otherwise
- */
-int V4L2Device::exportBuffers(BufferPool *pool)
-{
- unsigned int allocatedBuffers;
- unsigned int i;
- int ret;
-
- memoryType_ = V4L2_MEMORY_MMAP;
-
- ret = requestBuffers(pool->count());
- if (ret < 0)
- return ret;
-
- allocatedBuffers = ret;
- if (allocatedBuffers < pool->count()) {
- LOG(V4L2, Error) << "Not enough buffers provided by V4L2Device";
- requestBuffers(0);
- return -ENOMEM;
- }
-
- /* Map the buffers. */
- for (i = 0; i < pool->count(); ++i) {
- struct v4l2_plane planes[VIDEO_MAX_PLANES] = {};
- struct v4l2_buffer buf = {};
- Buffer &buffer = pool->buffers()[i];
-
- buf.index = i;
- buf.type = bufferType_;
- buf.memory = memoryType_;
- buf.length = VIDEO_MAX_PLANES;
- buf.m.planes = planes;
-
- ret = ioctl(fd_, VIDIOC_QUERYBUF, &buf);
- if (ret < 0) {
- ret = -errno;
- LOG(V4L2, Error)
- << "Unable to query buffer " << i << ": "
- << strerror(-ret);
- break;
- }
-
- if (V4L2_TYPE_IS_MULTIPLANAR(buf.type)) {
- for (unsigned int p = 0; p < buf.length; ++p) {
- ret = createPlane(&buffer, p,
- buf.m.planes[p].length);
- if (ret)
- break;
- }
- } else {
- ret = createPlane(&buffer, 0, buf.length);
- }
-
- if (ret) {
- LOG(V4L2, Error) << "Failed to create plane";
- break;
- }
- }
-
- if (ret) {
- requestBuffers(0);
- pool->destroyBuffers();
- return ret;
- }
-
- bufferPool_ = pool;
-
- return 0;
-}
-
-int V4L2Device::createPlane(Buffer *buffer, unsigned int planeIndex,
- unsigned int length)
-{
- struct v4l2_exportbuffer expbuf = {};
- int ret;
-
- LOG(V4L2, Debug)
- << "Buffer " << buffer->index()
- << " plane " << planeIndex
- << ": length=" << length;
-
- expbuf.type = bufferType_;
- expbuf.index = buffer->index();
- expbuf.plane = planeIndex;
- expbuf.flags = O_RDWR;
-
- ret = ioctl(fd_, VIDIOC_EXPBUF, &expbuf);
- if (ret < 0) {
- ret = -errno;
- LOG(V4L2, Error)
- << "Failed to export buffer: " << strerror(-ret);
- return ret;
- }
-
- buffer->planes().emplace_back();
- Plane &plane = buffer->planes().back();
- plane.setDmabuf(expbuf.fd, length);
- ::close(expbuf.fd);
-
- return 0;
-}
-
-std::vector<unsigned int> V4L2Device::enumPixelformats()
-{
- std::vector<unsigned int> formats;
- int ret;
-
- for (unsigned int index = 0; ; index++) {
- struct v4l2_fmtdesc pixelformatEnum = {};
- pixelformatEnum.index = index;
- pixelformatEnum.type = bufferType_;
-
- ret = ioctl(fd_, VIDIOC_ENUM_FMT, &pixelformatEnum);
- if (ret)
- break;
-
- formats.push_back(pixelformatEnum.pixelformat);
- }
-
- if (ret && errno != EINVAL) {
- ret = -errno;
- LOG(V4L2, Error)
- << "Unable to enumerate pixel formats: "
- << strerror(-ret);
- return {};
- }
-
- return formats;
-}
-
-std::vector<SizeRange> V4L2Device::enumSizes(unsigned int pixelFormat)
-{
- std::vector<SizeRange> sizes;
- int ret;
-
- for (unsigned int index = 0;; index++) {
- struct v4l2_frmsizeenum frameSize = {};
- frameSize.index = index;
- frameSize.pixel_format = pixelFormat;
-
- ret = ioctl(fd_, VIDIOC_ENUM_FRAMESIZES, &frameSize);
- if (ret)
- break;
-
- if (index != 0 &&
- frameSize.type != V4L2_FRMSIZE_TYPE_DISCRETE) {
- LOG(V4L2, Error)
- << "Non-zero index for non discrete type";
- return {};
- }
-
- switch (frameSize.type) {
- case V4L2_FRMSIZE_TYPE_DISCRETE:
- sizes.emplace_back(frameSize.discrete.width,
- frameSize.discrete.height);
- break;
- case V4L2_FRMSIZE_TYPE_CONTINUOUS:
- sizes.emplace_back(frameSize.stepwise.min_width,
- frameSize.stepwise.min_height,
- frameSize.stepwise.max_width,
- frameSize.stepwise.max_height);
- break;
- case V4L2_FRMSIZE_TYPE_STEPWISE:
- sizes.emplace_back(frameSize.stepwise.min_width,
- frameSize.stepwise.min_height,
- frameSize.stepwise.max_width,
- frameSize.stepwise.max_height,
- frameSize.stepwise.step_width,
- frameSize.stepwise.step_height);
- break;
- default:
- LOG(V4L2, Error)
- << "Unknown VIDIOC_ENUM_FRAMESIZES type "
- << frameSize.type;
- return {};
- }
- }
-
- if (ret && errno != EINVAL) {
- ret = -errno;
- LOG(V4L2, Error)
- << "Unable to enumerate frame sizes: "
- << strerror(-ret);
- return {};
- }
-
- return sizes;
-}
-
-/**
- * \brief Import the externally allocated \a pool of buffers
- * \param[in] pool BufferPool of buffers to import
- * \return 0 on success or a negative error code otherwise
- */
-int V4L2Device::importBuffers(BufferPool *pool)
-{
- unsigned int allocatedBuffers;
- int ret;
-
- memoryType_ = V4L2_MEMORY_DMABUF;
-
- ret = requestBuffers(pool->count());
- if (ret < 0)
- return ret;
-
- allocatedBuffers = ret;
- if (allocatedBuffers < pool->count()) {
- LOG(V4L2, Error)
- << "Not enough buffers provided by V4L2Device";
- requestBuffers(0);
- return -ENOMEM;
- }
-
- LOG(V4L2, Debug) << "provided pool of " << pool->count() << " buffers";
- bufferPool_ = pool;
-
- return 0;
-}
-
-/**
- * \brief Release all internally allocated buffers
- */
-int V4L2Device::releaseBuffers()
-{
- LOG(V4L2, Debug) << "Releasing bufferPool";
-
- bufferPool_ = nullptr;
-
- return requestBuffers(0);
-}
-
-/**
- * \brief Queue a buffer into the device
- * \param[in] buffer The buffer to be queued
- *
- * For capture devices the \a buffer will be filled with data by the device.
- * For output devices the \a buffer shall contain valid data and will be
- * processed by the device. Once the device has finished processing the buffer,
- * it will be available for dequeue.
- *
- * \return 0 on success or a negative error code otherwise
- */
-int V4L2Device::queueBuffer(Buffer *buffer)
-{
- struct v4l2_buffer buf = {};
- struct v4l2_plane planes[VIDEO_MAX_PLANES] = {};
- int ret;
-
- buf.index = buffer->index();
- buf.type = bufferType_;
- buf.memory = memoryType_;
- buf.field = V4L2_FIELD_NONE;
-
- bool multiPlanar = V4L2_TYPE_IS_MULTIPLANAR(buf.type);
-
- if (buf.memory == V4L2_MEMORY_DMABUF) {
- if (multiPlanar) {
- for (unsigned int p = 0;
- p < buffer->planes().size();
- p++)
- planes[p].m.fd = buffer->planes()[p].dmabuf();
- } else {
- buf.m.fd = buffer->planes()[0].dmabuf();
- }
- }
-
- if (multiPlanar) {
- buf.length = buffer->planes().size();
- buf.m.planes = planes;
- }
-
- if (V4L2_TYPE_IS_OUTPUT(bufferType_)) {
- buf.bytesused = buffer->bytesused_;
- buf.sequence = buffer->sequence_;
- buf.timestamp.tv_sec = buffer->timestamp_ / 1000000000;
- buf.timestamp.tv_usec = (buffer->timestamp_ / 1000) % 1000000;
- }
-
- LOG(V4L2, Debug) << "Queueing buffer " << buf.index;
-
- ret = ioctl(fd_, VIDIOC_QBUF, &buf);
- if (ret < 0) {
- ret = -errno;
- LOG(V4L2, Error)
- << "Failed to queue buffer " << buf.index << ": "
- << strerror(-ret);
- return ret;
- }
-
- if (queuedBuffersCount_++ == 0)
- fdEvent_->setEnabled(true);
-
- return 0;
-}
-
-/**
- * \brief Dequeue the next available buffer from the device
- *
- * This method dequeues the next available buffer from the device. If no buffer
- * is available to be dequeued it will return nullptr immediately.
- *
- * \return A pointer to the dequeued buffer on success, or nullptr otherwise
- */
-Buffer *V4L2Device::dequeueBuffer()
-{
- struct v4l2_buffer buf = {};
- struct v4l2_plane planes[VIDEO_MAX_PLANES] = {};
- int ret;
-
- buf.type = bufferType_;
- buf.memory = memoryType_;
-
- if (V4L2_TYPE_IS_MULTIPLANAR(buf.type)) {
- buf.length = VIDEO_MAX_PLANES;
- buf.m.planes = planes;
- }
-
- ret = ioctl(fd_, VIDIOC_DQBUF, &buf);
- if (ret < 0) {
- ret = -errno;
- LOG(V4L2, Error)
- << "Failed to dequeue buffer: " << strerror(-ret);
- return nullptr;
- }
-
- ASSERT(buf.index < bufferPool_->count());
-
- if (--queuedBuffersCount_ == 0)
- fdEvent_->setEnabled(false);
-
- Buffer *buffer = &bufferPool_->buffers()[buf.index];
-
- buffer->bytesused_ = buf.bytesused;
- buffer->timestamp_ = buf.timestamp.tv_sec * 1000000000ULL
- + buf.timestamp.tv_usec * 1000ULL;
- buffer->sequence_ = buf.sequence;
- buffer->status_ = buf.flags & V4L2_BUF_FLAG_ERROR
- ? Buffer::BufferError : Buffer::BufferSuccess;
-
- return buffer;
-}
-
-/**
- * \brief Slot to handle completed buffer events from the V4L2 device
- * \param[in] notifier The event notifier
- *
- * When this slot is called, a Buffer has become available from the device, and
- * will be emitted through the bufferReady Signal.
- *
- * For Capture devices the Buffer will contain valid data.
- * For Output devices the Buffer can be considered empty.
- */
-void V4L2Device::bufferAvailable(EventNotifier *notifier)
-{
- Buffer *buffer = dequeueBuffer();
- if (!buffer)
- return;
-
- LOG(V4L2, Debug) << "Buffer " << buffer->index() << " is available";
-
- /* Notify anyone listening to the device. */
- bufferReady.emit(buffer);
-}
-
-/**
- * \var V4L2Device::bufferReady
- * \brief A Signal emitted when a buffer completes
- */
-
-/**
- * \brief Start the video stream
- * \return 0 on success or a negative error code otherwise
- */
-int V4L2Device::streamOn()
-{
- int ret;
-
- ret = ioctl(fd_, VIDIOC_STREAMON, &bufferType_);
- if (ret < 0) {
- ret = -errno;
- LOG(V4L2, Error)
- << "Failed to start streaming: " << strerror(-ret);
- return ret;
- }
-
- return 0;
-}
-
-/**
- * \brief Stop the video stream
- *
- * Buffers that are still queued when the video stream is stopped are
- * implicitly dequeued, but no bufferReady signal is emitted for them.
- *
- * \return 0 on success or a negative error code otherwise
- */
-int V4L2Device::streamOff()
-{
- int ret;
-
- ret = ioctl(fd_, VIDIOC_STREAMOFF, &bufferType_);
- if (ret < 0) {
- ret = -errno;
- LOG(V4L2, Error)
- << "Failed to stop streaming: " << strerror(-ret);
- return ret;
- }
-
- queuedBuffersCount_ = 0;
- fdEvent_->setEnabled(false);
-
- return 0;
-}
-
-/**
- * \brief Create a new video device instance from \a entity in media device
- * \a media
- * \param[in] media The media device where the entity is registered
- * \param[in] entity The media entity name
- *
- * Releasing memory of the newly created instance is responsibility of the
- * caller of this function.
- *
- * \return A newly created V4L2Device on success, nullptr otherwise
- */
-V4L2Device *V4L2Device::fromEntityName(const MediaDevice *media,
- const std::string &entity)
-{
- MediaEntity *mediaEntity = media->getEntityByName(entity);
- if (!mediaEntity)
- return nullptr;
-
- return new V4L2Device(mediaEntity);
-}
-
-} /* namespace libcamera */