From patchwork Sun Feb 3 11:00:54 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 490 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 776EF60DB8 for ; Sun, 3 Feb 2019 12:01:07 +0100 (CET) Received: from localhost.localdomain (218.182-78-194.adsl-static.isp.belgacom.be [194.78.182.218]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 24DF741; Sun, 3 Feb 2019 12:01:07 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1549191667; bh=vADjpcRolxRvmqMSCf9mbfAOlHvYZfvFHgaf20N6v7U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Ecayt8CmuFd1N784orcPDUEoiUrVO2P/mGtVwe6ywks4ErONXmbAkTkTZAb3JlzD8 htgd3fusIxV5u91/l3lWBzX24PXnlKXAmMVhHUZndnIrgPhIizsmvBxIjgd5wGGFzM VER563935bZFZozVAAqdakRMIaID9y51jzky7E9Q= From: Kieran Bingham To: LibCamera Devel Date: Sun, 3 Feb 2019 12:00:54 +0100 Message-Id: <20190203110102.5663-4-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20190203110102.5663-1-kieran.bingham@ideasonboard.com> References: <20190203110102.5663-1-kieran.bingham@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 03/11] libcamera: v4l2_device: Request buffers from the device X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 03 Feb 2019 11:01:07 -0000 Provide a requestBuffers() interface to allocate buffers from the V4L2Device and keep a vector of the buffers in the V4L2Device object for later queue and dequeue operations. Signed-off-by: Kieran Bingham --- include/libcamera/buffer.h | 4 +- src/libcamera/include/v4l2_device.h | 10 +++ src/libcamera/v4l2_device.cpp | 111 +++++++++++++++++++++++++++- 3 files changed, 122 insertions(+), 3 deletions(-) diff --git a/include/libcamera/buffer.h b/include/libcamera/buffer.h index e730fc0f84fd..97fab5c65cce 100644 --- a/include/libcamera/buffer.h +++ b/include/libcamera/buffer.h @@ -71,10 +71,10 @@ public: void free(); unsigned int count() const { return buffers_.size(); }; - const std::vector &buffers() { return buffers_; }; + std::vector &buffers() { return buffers_; }; private: - virtual int allocateMemory() = 0; + virtual int allocateMemory() { return 0; }; BufferPool::Memory memory_; std::vector buffers_; diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h index 9e9eada94130..6599ce2d761c 100644 --- a/src/libcamera/include/v4l2_device.h +++ b/src/libcamera/include/v4l2_device.h @@ -8,6 +8,7 @@ #define __LIBCAMERA_V4L2_DEVICE_H__ #include +#include #include @@ -76,6 +77,7 @@ public: }; class MediaEntity; + class V4L2Device { public: @@ -97,6 +99,8 @@ public: int format(V4L2DeviceFormat *fmt); int setFormat(V4L2DeviceFormat *fmt); + BufferPool *requestBuffers(unsigned int qty = 8); + private: int getFormatSingleplane(V4L2DeviceFormat *fmt); int setFormatSingleplane(V4L2DeviceFormat *fmt); @@ -104,10 +108,16 @@ private: int getFormatMultiplane(V4L2DeviceFormat *fmt); int setFormatMultiplane(V4L2DeviceFormat *fmt); + int requestBuffers(unsigned int qty, std::vector &buffers); + std::string deviceNode_; int fd_; V4L2Capability caps_; + enum v4l2_buf_type bufferType_; + enum v4l2_memory memoryType_; + + BufferPool *bufferPool_; }; } /* namespace libcamera */ diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp index d507ea9700b3..8bcd8bbc34f6 100644 --- a/src/libcamera/v4l2_device.cpp +++ b/src/libcamera/v4l2_device.cpp @@ -10,6 +10,9 @@ #include #include #include +#include + +#include #include "log.h" #include "media_object.h" @@ -187,8 +190,14 @@ V4L2Buffer::V4L2Buffer(struct v4l2_buffer &vb) * \param deviceNode The file-system path to the video device node */ V4L2Device::V4L2Device(const std::string &deviceNode) - : deviceNode_(deviceNode), fd_(-1) + : deviceNode_(deviceNode), fd_(-1), bufferPool_(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; } /** @@ -205,6 +214,8 @@ V4L2Device::V4L2Device(const MediaEntity &entity) V4L2Device::~V4L2Device() { close(); + + delete bufferPool_; } /** @@ -305,6 +316,104 @@ void V4L2Device::close() * \return The string containing the device location */ +/** + * \brief Request \a qty buffers to be allocated from the device and returned + * as a BufferPool + * \return A BufferPool containing the device buffers, or nullptr if the + * allocation fails + */ +BufferPool *V4L2Device::requestBuffers(unsigned int qty) +{ + int ret; + + if (bufferPool_) { + LOG(V4L2, Warning) << "Pre-existing buffer pool will be lost"; + delete bufferPool_; + } + + bufferPool_ = new BufferPool(BufferPool::Internal); + + ret = requestBuffers(qty, bufferPool_->buffers()); + if (ret) { + delete bufferPool_; + bufferPool_ = nullptr; + return nullptr; + } + + return bufferPool_; +} + +/** + * \brief Request \a qty buffers from the V4L2Device and track Buffer + * representations within the specified \a buffers target. + */ +int V4L2Device::requestBuffers(unsigned int qty, std::vector &buffers) +{ + struct v4l2_requestbuffers rb = {}; + unsigned int i; + int ret; + + rb.count = qty; + rb.type = bufferType_; + rb.memory = memoryType_; /** \todo Support dmaBuf memoryTypes */ + + ret = ioctl(fd_, VIDIOC_REQBUFS, &rb); + if (ret < 0) { + ret = -errno; + LOG(V4L2, Error) + << "Unable to request " << qty << " buffers: " + << strerror(-ret); + return ret; + } + + LOG(V4L2, Debug) + << deviceNode_ << ":" << rb.count << " buffers requested."; + + if (memoryType_ != V4L2_MEMORY_MMAP) { + LOG(V4L2, Error) + << "Non-mmap allocations are not yet supported."; + return -EINVAL; + } + + /* Map the buffers. */ + for (i = 0; i < rb.count; ++i) { + struct v4l2_plane planes[VIDEO_MAX_PLANES] = {}; + struct v4l2_buffer buf = {}; + struct Buffer *buffer; + + 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) { + LOG(V4L2, Error) + << "Unable to query buffer " << i << ": " + << strerror(errno); + return ret; + } + + if (V4L2_TYPE_IS_MULTIPLANAR(buf.type)) { + for (unsigned int p = 0; p < buf.length; ++p) + LOG(V4L2, Debug) + << "plane: " << p + << " length: " << buf.m.planes[p].length + << " offset: " + << buf.m.planes[p].data_offset; + } else { + LOG(V4L2, Debug) << "length: " << buf.length + << " offset: " << buf.m.offset; + } + + buffer = new V4L2Buffer(buf); + buffers.push_back(buffer); + } + + return 0; +} + /** * \brief Retrieve the image format set on the V4L2 device * \return 0 for success, a negative error code otherwise