From patchwork Tue Nov 26 23:36:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 2367 Return-Path: Received: from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net [195.74.38.228]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7ABB26136C for ; Wed, 27 Nov 2019 00:39:39 +0100 (CET) X-Halon-ID: 022e8134-10a6-11ea-a0b9-005056917f90 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (p54ac5865.dip0.t-ipconnect.de [84.172.88.101]) by bin-vsp-out-02.atm.binero.net (Halon) with ESMTPA id 022e8134-10a6-11ea-a0b9-005056917f90; Wed, 27 Nov 2019 00:39:37 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 27 Nov 2019 00:36:09 +0100 Message-Id: <20191126233620.1695316-20-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191126233620.1695316-1-niklas.soderlund@ragnatech.se> References: <20191126233620.1695316-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 19/30] libcamera: v4l2_videodevice: Add new buffer interface 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-List-Received-Date: Tue, 26 Nov 2019 23:39:39 -0000 Extend V4L2VideoDevice with two new functions, one to deal with allocating buffers from the video device and one to prepare the video device to use external buffers. The two new functions intend to replace exportBuffers() and importBuffers() once the transition to the FrameBuffer interface is complete. Signed-off-by: Niklas Söderlund --- src/libcamera/include/v4l2_videodevice.h | 4 + src/libcamera/v4l2_videodevice.cpp | 126 ++++++++++++++++++++++- 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/src/libcamera/include/v4l2_videodevice.h b/src/libcamera/include/v4l2_videodevice.h index 254f8797af42dd8a..f4cbcfbd26ea540c 100644 --- a/src/libcamera/include/v4l2_videodevice.h +++ b/src/libcamera/include/v4l2_videodevice.h @@ -162,6 +162,8 @@ public: int exportBuffers(BufferPool *pool); int importBuffers(BufferPool *pool); + int allocateBuffers(unsigned int count, std::vector *buffers); + int externalBuffers(unsigned int count); int releaseBuffers(); int queueBuffer(Buffer *buffer); @@ -197,6 +199,7 @@ private: int requestBuffers(unsigned int count); int createPlane(BufferMemory *buffer, unsigned int index, unsigned int plane, unsigned int length); + FrameBuffer *createBuffer(struct v4l2_buffer buf); int exportDmaBuffer(unsigned int index, unsigned int plane); Buffer *dequeueBuffer(); @@ -208,6 +211,7 @@ private: enum v4l2_memory memoryType_; BufferPool *bufferPool_; + V4L2BufferCache *cache_; std::map queuedBuffers_; EventNotifier *fdEvent_; diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index c82f2829601bd14c..9fe66018ec502626 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -377,7 +377,8 @@ const std::string V4L2DeviceFormat::toString() const * \param[in] deviceNode The file-system path to the video device node */ V4L2VideoDevice::V4L2VideoDevice(const std::string &deviceNode) - : V4L2Device(deviceNode), bufferPool_(nullptr), fdEvent_(nullptr) + : V4L2Device(deviceNode), bufferPool_(nullptr), cache_(nullptr), + fdEvent_(nullptr) { /* * We default to an MMAP based CAPTURE video device, however this will @@ -1042,6 +1043,100 @@ int V4L2VideoDevice::importBuffers(BufferPool *pool) return 0; } +/** + * \brief Operate using buffers allocated from local video device + * \param[in] count Number of buffers to allocate + * \param[out] buffers Vector to store local buffers + * \return 0 on success or a negative error code otherwise + */ +int V4L2VideoDevice::allocateBuffers(unsigned int count, std::vector *buffers) +{ + unsigned int i; + int ret; + + if (cache_) { + LOG(V4L2, Error) << "Can't allocate buffers when cache exists"; + return -EINVAL; + } + + memoryType_ = V4L2_MEMORY_MMAP; + + ret = requestBuffers(count); + if (ret < 0) + return ret; + + for (i = 0; i < count; ++i) { + struct v4l2_buffer buf = {}; + struct v4l2_plane planes[VIDEO_MAX_PLANES] = {}; + + buf.index = i; + buf.type = bufferType_; + buf.memory = memoryType_; + buf.length = VIDEO_MAX_PLANES; + buf.m.planes = planes; + + ret = ioctl(VIDIOC_QUERYBUF, &buf); + if (ret < 0) { + LOG(V4L2, Error) + << "Unable to query buffer " << i << ": " + << strerror(-ret); + goto err_buf; + } + + FrameBuffer *buffer = createBuffer(buf); + if (!buffer) { + LOG(V4L2, Error) << "Unable to create buffer"; + ret = -EINVAL; + goto err_buf; + } + + buffers->push_back(buffer); + } + + cache_ = new V4L2BufferCache(*buffers); + + return count; +err_buf: + requestBuffers(0); + + for (FrameBuffer *buffer : *buffers) + delete buffer; + + buffers->clear(); + + return ret; +} + +FrameBuffer *V4L2VideoDevice::createBuffer(struct v4l2_buffer buf) +{ + const unsigned int numPlanes = V4L2_TYPE_IS_MULTIPLANAR(buf.type) ? buf.length : 1; + std::vector planes; + FrameBuffer *frame = nullptr; + + for (unsigned int nplane = 0; nplane < numPlanes; nplane++) { + int fd = exportDmaBuffer(buf.index, nplane); + if (fd < 0) + goto out; + + FrameBuffer::Plane plane; + plane.fd = fd; + plane.length = V4L2_TYPE_IS_MULTIPLANAR(buf.type) ? + buf.m.planes[nplane].length : buf.length; + + planes.emplace_back(plane); + } + + if (!planes.empty()) + frame = new FrameBuffer(planes); + else + LOG(V4L2, Error) << "Failed to get planes"; +out: + for (FrameBuffer::Plane &plane : planes) + ::close(plane.fd); + + return frame; +} + int V4L2VideoDevice::exportDmaBuffer(unsigned int index, unsigned int plane) { struct v4l2_exportbuffer expbuf = {}; @@ -1062,6 +1157,35 @@ int V4L2VideoDevice::exportDmaBuffer(unsigned int index, unsigned int plane) return expbuf.fd; } +/** + * \brief Operate using buffers imported from external source + * \param[in] count Number of buffers to prepare for + * \return 0 on success or a negative error code otherwise + */ +int V4L2VideoDevice::externalBuffers(unsigned int count) +{ + /* + * We can only prepare the device to use external buffers when no + * internal buffers have been allocated. + */ + if (cache_) + return 0; + + int ret; + + memoryType_ = V4L2_MEMORY_DMABUF; + + ret = requestBuffers(count); + if (ret) + return ret; + + cache_ = new V4L2BufferCache(count); + + LOG(V4L2, Debug) << "provided for " << count << " external buffers"; + + return 0; +} + /** * \brief Release all internally allocated buffers */