From patchwork Tue Jun 16 13:12:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4045 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1D16C603C1 for ; Tue, 16 Jun 2020 15:13:02 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="co4hZomT"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:2807:bdfa:f6a:8e53]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 87ECDF9; Tue, 16 Jun 2020 15:13:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592313181; bh=7vjHnnbiDV2VTJ53YxEGoLpKJy4AIIKtV8qdhPYFsfU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=co4hZomTAK/R+HVuMlPBzq1ZYkHRGYz58X+S6qPxsIZeA0aV+iATzuMMtAa9hVKqj B7fttjp4iY0fI/MOPf7CdmWek2936yoZQvT1wuqjREuX2QKUL/hO+12yyGFyXTz/gm Js8GQuz1y3a3rmNHbj3m3KapQPrRF1AOAU7YbzWw= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Tue, 16 Jun 2020 22:12:30 +0900 Message-Id: <20200616131244.70308-2-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200616131244.70308-1-paul.elder@ideasonboard.com> References: <20200616131244.70308-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 01/15] v4l2: v4l2_compat: Support multiple open 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, 16 Jun 2020 13:13:02 -0000 Previously, since we acquired the libcamera camera upon open(), it was impossible to support multiple open, as any subsequent opens would return error because the camera would already be acquired. To fix this, we first initialize the camera in the first call to V4L2CameraProxy::open(), just to heat up the stream format cache. We then add an exclusive lock on the V4L2Camera. All vidioc ioctls prior to reqbufs > 0 (except for s_fmt) are able to access the camera without this exclusive lock. A call to reqbufs > 0 (and s_fmt) will take the lock, and the lock will be released at reqbufs = 0. While the lock is taken, the eventfd that should be signaled (and cleared) by V4L2Camera and V4L2CameraProxy is set to the fd that has taken the lock, and is cleared when the lock is released. In case close() is called without a reqbufs = 0 first, the lock is also released on close(). We also add a mapping of fd to boolean to keep track of which fds opened the camera in non-blocking mode. Signed-off-by: Paul Elder --- src/v4l2/v4l2_camera.cpp | 9 +- src/v4l2/v4l2_camera.h | 1 + src/v4l2/v4l2_camera_proxy.cpp | 202 ++++++++++++++++++++++--------- src/v4l2/v4l2_camera_proxy.h | 47 ++++--- src/v4l2/v4l2_compat_manager.cpp | 25 ++-- 5 files changed, 194 insertions(+), 90 deletions(-) diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp index 9a1ebc8..2557320 100644 --- a/src/v4l2/v4l2_camera.cpp +++ b/src/v4l2/v4l2_camera.cpp @@ -17,7 +17,8 @@ using namespace libcamera; LOG_DECLARE_CATEGORY(V4L2Compat); V4L2Camera::V4L2Camera(std::shared_ptr camera) - : camera_(camera), isRunning_(false), bufferAllocator_(nullptr) + : camera_(camera), isRunning_(false), bufferAllocator_(nullptr), + efd_(-1) { camera_->requestCompleted.connect(this, &V4L2Camera::requestComplete); } @@ -29,7 +30,6 @@ V4L2Camera::~V4L2Camera() int V4L2Camera::open() { - /* \todo Support multiple open. */ if (camera_->acquire() < 0) { LOG(V4L2Compat, Error) << "Failed to acquire camera"; return -EINVAL; @@ -59,6 +59,11 @@ void V4L2Camera::bind(int efd) efd_ = efd; } +void V4L2Camera::unbind() +{ + efd_ = -1; +} + void V4L2Camera::getStreamConfig(StreamConfiguration *streamConfig) { *streamConfig = config_->at(0); diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h index 33f5eb0..30114ed 100644 --- a/src/v4l2/v4l2_camera.h +++ b/src/v4l2/v4l2_camera.h @@ -40,6 +40,7 @@ public: int open(); void close(); void bind(int efd); + void unbind(); void getStreamConfig(StreamConfiguration *streamConfig); std::vector completedBuffers(); diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 13db428..594dd13 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -33,45 +33,68 @@ LOG_DECLARE_CATEGORY(V4L2Compat); V4L2CameraProxy::V4L2CameraProxy(unsigned int index, std::shared_ptr camera) : refcount_(0), index_(index), bufferCount_(0), currentBuf_(0), - vcam_(std::make_unique(camera)) + vcam_(std::make_unique(camera)), efd_(-1), + acquiredFd_(-1), initialized_(false) { querycap(camera); } -int V4L2CameraProxy::open(bool nonBlocking) +int V4L2CameraProxy::open(int fd, bool nonBlocking) { - LOG(V4L2Compat, Debug) << "Servicing open"; + LOG(V4L2Compat, Debug) << "Servicing open fd = " << fd; - int ret = vcam_->open(); - if (ret < 0) { - errno = -ret; - return -1; - } + nonBlockingFds_[fd] = nonBlocking; - nonBlocking_ = nonBlocking; + refcount_++; + + if (initialized_) + return 0; + + /* + * We will open the camera here, once, and keep it open until the last + * fd is closed. Before any reqbufs with count > 0 is called, anybody + * can call any ioctl. Once reqbufs is called with count > 0, the + * exclusive lock will be assigned to that fd, in acquiredFd_. At this + * point, no other fd can call any ioctl (except for querycap, try_fmt, + * g/s_priority, and enum/g/s_input), and they will return -EBUSY. + * After reqbufs is called with count = 0, the exclusive lock will be + * released. + */ + + initialized_ = true; + + int ret = vcam_->open(); + if (ret < 0) + return ret; vcam_->getStreamConfig(&streamConfig_); setFmtFromConfig(streamConfig_); sizeimage_ = calculateSizeImage(streamConfig_); - refcount_++; - return 0; } -void V4L2CameraProxy::dup() +void V4L2CameraProxy::dup(int oldfd, int newfd) { + nonBlockingFds_[newfd] = nonBlockingFds_[oldfd]; refcount_++; } -void V4L2CameraProxy::close() +void V4L2CameraProxy::close(int fd) { - LOG(V4L2Compat, Debug) << "Servicing close"; + LOG(V4L2Compat, Debug) << "Servicing close fd = " << fd; + + nonBlockingFds_.erase(fd); + + if (acquiredFd_ == fd) + acquiredFd_ = -1; if (--refcount_ > 0) return; vcam_->close(); + + initialized_ = false; } void *V4L2CameraProxy::mmap(void *addr, size_t length, int prot, int flags, @@ -220,9 +243,10 @@ int V4L2CameraProxy::vidioc_querycap(struct v4l2_capability *arg) return 0; } -int V4L2CameraProxy::vidioc_enum_fmt(struct v4l2_fmtdesc *arg) +int V4L2CameraProxy::vidioc_enum_fmt(int fd, struct v4l2_fmtdesc *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_fmt"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_fmt fd = " << fd; + if (!validateBufferType(arg->type) || arg->index >= streamConfig_.formats().pixelformats().size()) @@ -236,9 +260,10 @@ int V4L2CameraProxy::vidioc_enum_fmt(struct v4l2_fmtdesc *arg) return 0; } -int V4L2CameraProxy::vidioc_g_fmt(struct v4l2_format *arg) +int V4L2CameraProxy::vidioc_g_fmt(int fd, struct v4l2_format *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_g_fmt"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_g_fmt fd = " << fd; + if (!validateBufferType(arg->type)) return -EINVAL; @@ -274,9 +299,13 @@ void V4L2CameraProxy::tryFormat(struct v4l2_format *arg) arg->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; } -int V4L2CameraProxy::vidioc_s_fmt(struct v4l2_format *arg) +int V4L2CameraProxy::vidioc_s_fmt(int fd, struct v4l2_format *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_s_fmt"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_s_fmt fd = " << fd; + + int ret = lock(fd); + if (ret < 0) + return ret; if (!validateBufferType(arg->type)) return -EINVAL; @@ -284,9 +313,9 @@ int V4L2CameraProxy::vidioc_s_fmt(struct v4l2_format *arg) tryFormat(arg); Size size(arg->fmt.pix.width, arg->fmt.pix.height); - int ret = vcam_->configure(&streamConfig_, size, - v4l2ToDrm(arg->fmt.pix.pixelformat), - bufferCount_); + ret = vcam_->configure(&streamConfig_, size, + v4l2ToDrm(arg->fmt.pix.pixelformat), + bufferCount_); if (ret < 0) return -EINVAL; @@ -301,9 +330,9 @@ int V4L2CameraProxy::vidioc_s_fmt(struct v4l2_format *arg) return 0; } -int V4L2CameraProxy::vidioc_try_fmt(struct v4l2_format *arg) +int V4L2CameraProxy::vidioc_try_fmt(int fd, struct v4l2_format *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_try_fmt"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_try_fmt fd = " << fd; if (!validateBufferType(arg->type)) return -EINVAL; @@ -328,11 +357,14 @@ int V4L2CameraProxy::freeBuffers() return 0; } -int V4L2CameraProxy::vidioc_reqbufs(struct v4l2_requestbuffers *arg) +int V4L2CameraProxy::vidioc_reqbufs(int fd, struct v4l2_requestbuffers *arg) { - int ret; + LOG(V4L2Compat, Debug) << "Servicing vidioc_reqbufs fd = " << fd; + - LOG(V4L2Compat, Debug) << "Servicing vidioc_reqbufs"; + int ret = lock(fd); + if (ret < 0) + return ret; if (!validateBufferType(arg->type) || !validateMemoryType(arg->memory)) @@ -341,9 +373,21 @@ int V4L2CameraProxy::vidioc_reqbufs(struct v4l2_requestbuffers *arg) LOG(V4L2Compat, Debug) << arg->count << " buffers requested "; arg->capabilities = V4L2_BUF_CAP_SUPPORTS_MMAP; + memset(arg->reserved, 0, sizeof(arg->reserved)); - if (arg->count == 0) + if (arg->count == 0) { + unlock(fd); return freeBuffers(); + } + + if (bufferCount_ > 0) { + ret = freeBuffers(); + if (ret < 0) { + LOG(V4L2Compat, Error) + << "Failed to free libcamera buffers for re-reqbufs"; + return ret; + } + } Size size(curV4L2Format_.fmt.pix.width, curV4L2Format_.fmt.pix.height); ret = vcam_->configure(&streamConfig_, size, @@ -386,6 +430,7 @@ int V4L2CameraProxy::vidioc_reqbufs(struct v4l2_requestbuffers *arg) buf.memory = V4L2_MEMORY_MMAP; buf.m.offset = i * curV4L2Format_.fmt.pix.sizeimage; buf.index = i; + buf.flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; buffers_[i] = buf; } @@ -395,9 +440,13 @@ int V4L2CameraProxy::vidioc_reqbufs(struct v4l2_requestbuffers *arg) return 0; } -int V4L2CameraProxy::vidioc_querybuf(struct v4l2_buffer *arg) +int V4L2CameraProxy::vidioc_querybuf(int fd, struct v4l2_buffer *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_querybuf"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_querybuf fd = " << fd; + + int ret = lock(fd); + if (ret < 0) + return ret; if (!validateBufferType(arg->type) || arg->index >= bufferCount_) @@ -410,17 +459,21 @@ int V4L2CameraProxy::vidioc_querybuf(struct v4l2_buffer *arg) return 0; } -int V4L2CameraProxy::vidioc_qbuf(struct v4l2_buffer *arg) +int V4L2CameraProxy::vidioc_qbuf(int fd, struct v4l2_buffer *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_qbuf, index = " - << arg->index; + << arg->index << " fd = " << fd; + + int ret = lock(fd); + if (ret < 0) + return ret; if (!validateBufferType(arg->type) || !validateMemoryType(arg->memory) || arg->index >= bufferCount_) return -EINVAL; - int ret = vcam_->qbuf(arg->index); + ret = vcam_->qbuf(arg->index); if (ret < 0) return ret; @@ -430,15 +483,19 @@ int V4L2CameraProxy::vidioc_qbuf(struct v4l2_buffer *arg) return ret; } -int V4L2CameraProxy::vidioc_dqbuf(struct v4l2_buffer *arg) +int V4L2CameraProxy::vidioc_dqbuf(int fd, struct v4l2_buffer *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_dqbuf"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_dqbuf fd = " << fd; + + int ret = lock(fd); + if (ret < 0) + return ret; if (!validateBufferType(arg->type) || !validateMemoryType(arg->memory)) return -EINVAL; - if (!nonBlocking_) + if (!nonBlockingFds_[fd]) vcam_->bufferSema_.acquire(); else if (!vcam_->bufferSema_.tryAcquire()) return -EAGAIN; @@ -454,16 +511,20 @@ int V4L2CameraProxy::vidioc_dqbuf(struct v4l2_buffer *arg) currentBuf_ = (currentBuf_ + 1) % bufferCount_; uint64_t data; - int ret = ::read(efd_, &data, sizeof(data)); + ret = ::read(efd_, &data, sizeof(data)); if (ret != sizeof(data)) LOG(V4L2Compat, Error) << "Failed to clear eventfd POLLIN"; return 0; } -int V4L2CameraProxy::vidioc_streamon(int *arg) +int V4L2CameraProxy::vidioc_streamon(int fd, int *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_streamon"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_streamon fd = " << fd; + + int ret = lock(fd); + if (ret < 0) + return ret; if (!validateBufferType(*arg)) return -EINVAL; @@ -473,14 +534,18 @@ int V4L2CameraProxy::vidioc_streamon(int *arg) return vcam_->streamOn(); } -int V4L2CameraProxy::vidioc_streamoff(int *arg) +int V4L2CameraProxy::vidioc_streamoff(int fd, int *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_streamoff"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_streamoff fd = " << fd; + + int ret = lock(fd); + if (ret < 0) + return ret; if (!validateBufferType(*arg)) return -EINVAL; - int ret = vcam_->streamOff(); + ret = vcam_->streamOff(); for (struct v4l2_buffer &buf : buffers_) buf.flags &= ~(V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE); @@ -488,7 +553,7 @@ int V4L2CameraProxy::vidioc_streamoff(int *arg) return ret; } -int V4L2CameraProxy::ioctl(unsigned long request, void *arg) +int V4L2CameraProxy::ioctl(int fd, unsigned long request, void *arg) { int ret; switch (request) { @@ -496,34 +561,34 @@ int V4L2CameraProxy::ioctl(unsigned long request, void *arg) ret = vidioc_querycap(static_cast(arg)); break; case VIDIOC_ENUM_FMT: - ret = vidioc_enum_fmt(static_cast(arg)); + ret = vidioc_enum_fmt(fd, static_cast(arg)); break; case VIDIOC_G_FMT: - ret = vidioc_g_fmt(static_cast(arg)); + ret = vidioc_g_fmt(fd, static_cast(arg)); break; case VIDIOC_S_FMT: - ret = vidioc_s_fmt(static_cast(arg)); + ret = vidioc_s_fmt(fd, static_cast(arg)); break; case VIDIOC_TRY_FMT: - ret = vidioc_try_fmt(static_cast(arg)); + ret = vidioc_try_fmt(fd, static_cast(arg)); break; case VIDIOC_REQBUFS: - ret = vidioc_reqbufs(static_cast(arg)); + ret = vidioc_reqbufs(fd, static_cast(arg)); break; case VIDIOC_QUERYBUF: - ret = vidioc_querybuf(static_cast(arg)); + ret = vidioc_querybuf(fd, static_cast(arg)); break; case VIDIOC_QBUF: - ret = vidioc_qbuf(static_cast(arg)); + ret = vidioc_qbuf(fd, static_cast(arg)); break; case VIDIOC_DQBUF: - ret = vidioc_dqbuf(static_cast(arg)); + ret = vidioc_dqbuf(fd, static_cast(arg)); break; case VIDIOC_STREAMON: - ret = vidioc_streamon(static_cast(arg)); + ret = vidioc_streamon(fd, static_cast(arg)); break; case VIDIOC_STREAMOFF: - ret = vidioc_streamoff(static_cast(arg)); + ret = vidioc_streamoff(fd, static_cast(arg)); break; default: ret = -ENOTTY; @@ -538,10 +603,37 @@ int V4L2CameraProxy::ioctl(unsigned long request, void *arg) return ret; } -void V4L2CameraProxy::bind(int fd) +/** + * \brief Acquire an exclusive lock on the V4L2Camera + * + * \return Zero on success or if already acquired, and negative error on + * failure. + */ +int V4L2CameraProxy::lock(int fd) { + if (acquiredFd_ == fd) + return 0; + + if (acquiredFd_ >= 0) + return -EBUSY; + efd_ = fd; vcam_->bind(fd); + + acquiredFd_ = fd; + + return 0; +} + +void V4L2CameraProxy::unlock(int fd) +{ + if (acquiredFd_ != fd) + return; + + efd_ = -1; + vcam_->unbind(); + + acquiredFd_ = -1; } struct PixelFormatPlaneInfo { diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index b5a9801..90e518c 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -26,15 +26,13 @@ class V4L2CameraProxy public: V4L2CameraProxy(unsigned int index, std::shared_ptr camera); - int open(bool nonBlocking); - void dup(); - void close(); + int open(int fd, bool nonBlocking); + void dup(int oldfd, int newfd); + void close(int fd); void *mmap(void *addr, size_t length, int prot, int flags, __off64_t offset); int munmap(void *addr, size_t length); - int ioctl(unsigned long request, void *arg); - - void bind(int fd); + int ioctl(int fd, unsigned long request, void *arg); private: bool validateBufferType(uint32_t type); @@ -47,16 +45,19 @@ private: int freeBuffers(); int vidioc_querycap(struct v4l2_capability *arg); - int vidioc_enum_fmt(struct v4l2_fmtdesc *arg); - int vidioc_g_fmt(struct v4l2_format *arg); - int vidioc_s_fmt(struct v4l2_format *arg); - int vidioc_try_fmt(struct v4l2_format *arg); - int vidioc_reqbufs(struct v4l2_requestbuffers *arg); - int vidioc_querybuf(struct v4l2_buffer *arg); - int vidioc_qbuf(struct v4l2_buffer *arg); - int vidioc_dqbuf(struct v4l2_buffer *arg); - int vidioc_streamon(int *arg); - int vidioc_streamoff(int *arg); + int vidioc_enum_fmt(int fd, struct v4l2_fmtdesc *arg); + int vidioc_g_fmt(int fd, struct v4l2_format *arg); + int vidioc_s_fmt(int fd, struct v4l2_format *arg); + int vidioc_try_fmt(int fd, struct v4l2_format *arg); + int vidioc_reqbufs(int fd, struct v4l2_requestbuffers *arg); + int vidioc_querybuf(int fd, struct v4l2_buffer *arg); + int vidioc_qbuf(int fd, struct v4l2_buffer *arg); + int vidioc_dqbuf(int fd, struct v4l2_buffer *arg); + int vidioc_streamon(int fd, int *arg); + int vidioc_streamoff(int fd, int *arg); + + int lock(int fd); + void unlock(int fd); static unsigned int bplMultiplier(uint32_t format); static unsigned int imageSize(uint32_t format, unsigned int width, @@ -67,7 +68,6 @@ private: unsigned int refcount_; unsigned int index_; - bool nonBlocking_; struct v4l2_format curV4L2Format_; StreamConfiguration streamConfig_; @@ -82,6 +82,19 @@ private: std::unique_ptr vcam_; int efd_; + + std::map nonBlockingFds_; + /* + * This is an exclusive lock on the camera. When this is not taken, + * anybody can call any ioctl before reqbufs. reqbufs with count > 0 + * will claim this lock, and reqbufs with count = 0 will release it. + * Any ioctl is called while the lock is taken will return -EBUSY + * (if applicable, eg. try_fmt, querycap, g/s_priority, and + * enum/g/s_input are exempt). + */ + int acquiredFd_; + + bool initialized_; }; #endif /* __V4L2_CAMERA_PROXY_H__ */ diff --git a/src/v4l2/v4l2_compat_manager.cpp b/src/v4l2/v4l2_compat_manager.cpp index 9298c0f..ce1eace 100644 --- a/src/v4l2/v4l2_compat_manager.cpp +++ b/src/v4l2/v4l2_compat_manager.cpp @@ -148,24 +148,17 @@ int V4L2CompatManager::openat(int dirfd, const char *path, int oflag, mode_t mod fops_.close(fd); - unsigned int camera_index = static_cast(ret); - - V4L2CameraProxy *proxy = proxies_[camera_index].get(); - ret = proxy->open(oflag & O_NONBLOCK); - if (ret < 0) - return ret; - int efd = eventfd(0, EFD_SEMAPHORE | ((oflag & O_CLOEXEC) ? EFD_CLOEXEC : 0) | ((oflag & O_NONBLOCK) ? EFD_NONBLOCK : 0)); - if (efd < 0) { - int err = errno; - proxy->close(); - errno = err; + if (efd < 0) return efd; - } - proxy->bind(efd); + unsigned int camera_index = static_cast(ret); + + V4L2CameraProxy *proxy = proxies_[camera_index].get(); + proxy->open(efd, oflag & O_NONBLOCK); + devices_.emplace(efd, proxy); return efd; @@ -181,7 +174,7 @@ int V4L2CompatManager::dup(int oldfd) if (device != devices_.end()) { V4L2CameraProxy *proxy = device->second; devices_[newfd] = proxy; - proxy->dup(); + proxy->dup(oldfd, newfd); } return newfd; @@ -191,7 +184,7 @@ int V4L2CompatManager::close(int fd) { V4L2CameraProxy *proxy = getProxy(fd); if (proxy) { - proxy->close(); + proxy->close(fd); devices_.erase(fd); return 0; } @@ -237,5 +230,5 @@ int V4L2CompatManager::ioctl(int fd, unsigned long request, void *arg) if (!proxy) return fops_.ioctl(fd, request, arg); - return proxy->ioctl(request, arg); + return proxy->ioctl(fd, request, arg); } From patchwork Tue Jun 16 13:12:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4046 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0212F61F24 for ; Tue, 16 Jun 2020 15:13:04 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="WxbsQKe2"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:2807:bdfa:f6a:8e53]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 820ABF9; Tue, 16 Jun 2020 15:13:02 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592313183; bh=ixlFXZxogr8vUn3rqaonr1O8urYXVk596ihDKMCdhUM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WxbsQKe2jRvSkiJIaaJEDpeezOe4asNhgAwvmPgq2Fn8iz+hl3HB5zGRSc9HBfM1e bpws8VPiXjHXuca7CQum38jn5hy9fg63PkRapjv9lWFTJRO8Z6LKn2XmUHzGVKvmor K/PogF9Qnyhbr5CU7jxRUbDTK/PJcwBQOeyFxKnQ= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Tue, 16 Jun 2020 22:12:31 +0900 Message-Id: <20200616131244.70308-3-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200616131244.70308-1-paul.elder@ideasonboard.com> References: <20200616131244.70308-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 02/15] v4l2: v4l2_camera_proxy: Check for null arg values in ioctl handlers 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, 16 Jun 2020 13:13:04 -0000 The ioctl handlers currently don't check if arg is null, so if it ever is, it will cause a segfault. Check that arg is null and return -EFAULT in all vidioc ioctl handlers. Signed-off-by: Paul Elder --- src/v4l2/v4l2_camera_proxy.cpp | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 594dd13..5b74b53 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -238,6 +238,9 @@ int V4L2CameraProxy::vidioc_querycap(struct v4l2_capability *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_querycap"; + if (arg == nullptr) + return -EFAULT; + *arg = capabilities_; return 0; @@ -247,6 +250,8 @@ int V4L2CameraProxy::vidioc_enum_fmt(int fd, struct v4l2_fmtdesc *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_fmt fd = " << fd; + if (arg == nullptr) + return -EFAULT; if (!validateBufferType(arg->type) || arg->index >= streamConfig_.formats().pixelformats().size()) @@ -264,6 +269,8 @@ int V4L2CameraProxy::vidioc_g_fmt(int fd, struct v4l2_format *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_g_fmt fd = " << fd; + if (arg == nullptr) + return -EFAULT; if (!validateBufferType(arg->type)) return -EINVAL; @@ -303,6 +310,9 @@ int V4L2CameraProxy::vidioc_s_fmt(int fd, struct v4l2_format *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_s_fmt fd = " << fd; + if (arg == nullptr) + return -EFAULT; + int ret = lock(fd); if (ret < 0) return ret; @@ -334,6 +344,9 @@ int V4L2CameraProxy::vidioc_try_fmt(int fd, struct v4l2_format *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_try_fmt fd = " << fd; + if (arg == nullptr) + return -EFAULT; + if (!validateBufferType(arg->type)) return -EINVAL; @@ -361,6 +374,8 @@ int V4L2CameraProxy::vidioc_reqbufs(int fd, struct v4l2_requestbuffers *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_reqbufs fd = " << fd; + if (arg == nullptr) + return -EFAULT; int ret = lock(fd); if (ret < 0) @@ -444,6 +459,9 @@ int V4L2CameraProxy::vidioc_querybuf(int fd, struct v4l2_buffer *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_querybuf fd = " << fd; + if (arg == nullptr) + return -EFAULT; + int ret = lock(fd); if (ret < 0) return ret; @@ -461,8 +479,10 @@ int V4L2CameraProxy::vidioc_querybuf(int fd, struct v4l2_buffer *arg) int V4L2CameraProxy::vidioc_qbuf(int fd, struct v4l2_buffer *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_qbuf, index = " - << arg->index << " fd = " << fd; + LOG(V4L2Compat, Debug) << "Servicing vidioc_qbuf fd = " << fd; + + if (arg == nullptr) + return -EFAULT; int ret = lock(fd); if (ret < 0) @@ -487,6 +507,9 @@ int V4L2CameraProxy::vidioc_dqbuf(int fd, struct v4l2_buffer *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_dqbuf fd = " << fd; + if (arg == nullptr) + return -EFAULT; + int ret = lock(fd); if (ret < 0) return ret; @@ -522,6 +545,9 @@ int V4L2CameraProxy::vidioc_streamon(int fd, int *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_streamon fd = " << fd; + if (arg == nullptr) + return -EFAULT; + int ret = lock(fd); if (ret < 0) return ret; @@ -538,6 +564,9 @@ int V4L2CameraProxy::vidioc_streamoff(int fd, int *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_streamoff fd = " << fd; + if (arg == nullptr) + return -EFAULT; + int ret = lock(fd); if (ret < 0) return ret; From patchwork Tue Jun 16 13:12:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4047 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 03549603C1 for ; Tue, 16 Jun 2020 15:13:06 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="TVUKLDtT"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:2807:bdfa:f6a:8e53]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 74F7BF9; Tue, 16 Jun 2020 15:13:04 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592313185; bh=8h2S8jtP297Dfd4jnIvA20at3UGgn8S1dwpKQAOs2us=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TVUKLDtTf9J4JcVlviDW3q/jZKe+Th2Rb6c6y9YuUDMKKdw3hll2+Pda4WENPswT8 1wSoHpocQW1ZEDDPXH8fUdIF2CfeDc5C8b+fkyjkE/wQkdXPmDXsnFEWZD0NKCKXzO 3LqmtdRlqMF/dfH9/ucClY73sOT8i5WQozfq1EhM= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Tue, 16 Jun 2020 22:12:32 +0900 Message-Id: <20200616131244.70308-4-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200616131244.70308-1-paul.elder@ideasonboard.com> References: <20200616131244.70308-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 03/15] v4l2: v4l2_camera_proxy: Fix v4l2-compliance support for extended formats 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, 16 Jun 2020 13:13:06 -0000 Fix the following v4l2-compliance error: fail: v4l2-compliance.cpp(652): !(caps & V4L2_CAP_EXT_PIX_FORMAT) Simply add V4L2_CAP_EXT_PIX_FORMAT to capabilities in querycap. Signed-off-by: Paul Elder Acked-by: Jacopo Mondi --- src/v4l2/v4l2_camera_proxy.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 5b74b53..d899853 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -202,7 +202,9 @@ void V4L2CameraProxy::querycap(std::shared_ptr camera) sizeof(capabilities_.bus_info)); /* \todo Put this in a header/config somewhere. */ capabilities_.version = KERNEL_VERSION(5, 2, 0); - capabilities_.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + capabilities_.device_caps = V4L2_CAP_VIDEO_CAPTURE + | V4L2_CAP_STREAMING + | V4L2_CAP_EXT_PIX_FORMAT; capabilities_.capabilities = capabilities_.device_caps | V4L2_CAP_DEVICE_CAPS; memset(capabilities_.reserved, 0, sizeof(capabilities_.reserved)); From patchwork Tue Jun 16 13:12:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4048 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E08E2603C1 for ; Tue, 16 Jun 2020 15:13:07 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="BH4WwXXY"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:2807:bdfa:f6a:8e53]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 677EFF9; Tue, 16 Jun 2020 15:13:06 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592313187; bh=1L1rh8oULEbcXBYHA607Rw3RyBVtMB3vEmT1OMSyPLk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=BH4WwXXYCSVUFpQSdz1yKQEFNZRPcLSvQ4pWsrYjsH6/RZJl3HUSzaJ4ic+fdaMHI Cc75FYg7YhcmNqFrbZOJR/vH2gQgkLWucdHGKzNRN9XBuAOzUmhWu2r8wUyRt2r5p4 jOMjR4+f9O8MHDPGbzutl7apPYpzRUyRtbD/RYWw= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Tue, 16 Jun 2020 22:12:33 +0900 Message-Id: <20200616131244.70308-5-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200616131244.70308-1-paul.elder@ideasonboard.com> References: <20200616131244.70308-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 04/15] v4l2: v4l2_camera_proxy: Implement VIDIOC_G/S_PRIORITY 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, 16 Jun 2020 13:13:08 -0000 Implement VIDIOC_G_PRIORITY and VIDIOC_S_PRIORITY, according to what v4l2-compliance wants. Signed-off-by: Paul Elder Reviewed-by: Jacopo Mondi --- src/v4l2/v4l2_camera_proxy.cpp | 48 +++++++++++++++++++++++++++++++++- src/v4l2/v4l2_camera_proxy.h | 4 +++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index d899853..f268f7a 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -34,7 +34,7 @@ V4L2CameraProxy::V4L2CameraProxy(unsigned int index, std::shared_ptr camera) : refcount_(0), index_(index), bufferCount_(0), currentBuf_(0), vcam_(std::make_unique(camera)), efd_(-1), - acquiredFd_(-1), initialized_(false) + v4l2RecordPriorityFd_(-1), acquiredFd_(-1), initialized_(false) { querycap(camera); } @@ -44,6 +44,7 @@ int V4L2CameraProxy::open(int fd, bool nonBlocking) LOG(V4L2Compat, Debug) << "Servicing open fd = " << fd; nonBlockingFds_[fd] = nonBlocking; + priorities_[fd] = V4L2_PRIORITY_DEFAULT; refcount_++; @@ -77,6 +78,7 @@ int V4L2CameraProxy::open(int fd, bool nonBlocking) void V4L2CameraProxy::dup(int oldfd, int newfd) { nonBlockingFds_[newfd] = nonBlockingFds_[oldfd]; + priorities_[newfd] = V4L2_PRIORITY_DEFAULT; refcount_++; } @@ -85,6 +87,7 @@ void V4L2CameraProxy::close(int fd) LOG(V4L2Compat, Debug) << "Servicing close fd = " << fd; nonBlockingFds_.erase(fd); + priorities_.erase(fd); if (acquiredFd_ == fd) acquiredFd_ = -1; @@ -357,6 +360,43 @@ int V4L2CameraProxy::vidioc_try_fmt(int fd, struct v4l2_format *arg) return 0; } +int V4L2CameraProxy::vidioc_g_priority(int fd, enum v4l2_priority *arg) +{ + LOG(V4L2Compat, Debug) << "Servicing vidioc_g_priority fd = " << fd; + + if (arg == nullptr) + return -EFAULT; + + if (v4l2RecordPriorityFd_ != -1) + *arg = V4L2_PRIORITY_RECORD; + else + *arg = priorities_[fd]; + + return 0; +} + +int V4L2CameraProxy::vidioc_s_priority(int fd, enum v4l2_priority *arg) +{ + LOG(V4L2Compat, Debug) + << "Servicing vidioc_s_priority fd = " << fd + << " prio = " << ((arg == nullptr) ? -1 : (int)*arg); + + if (arg == nullptr) + return -EFAULT; + + if (v4l2RecordPriorityFd_ != -1 && v4l2RecordPriorityFd_ != fd) + return -EBUSY; + + if (*arg == V4L2_PRIORITY_RECORD) + v4l2RecordPriorityFd_ = fd; + else if (v4l2RecordPriorityFd_ == fd) + v4l2RecordPriorityFd_ = -1; + + priorities_[fd] = *arg; + + return 0; +} + int V4L2CameraProxy::freeBuffers() { LOG(V4L2Compat, Debug) << "Freeing libcamera bufs"; @@ -603,6 +643,12 @@ int V4L2CameraProxy::ioctl(int fd, unsigned long request, void *arg) case VIDIOC_TRY_FMT: ret = vidioc_try_fmt(fd, static_cast(arg)); break; + case VIDIOC_G_PRIORITY: + ret = vidioc_g_priority(fd, static_cast(arg)); + break; + case VIDIOC_S_PRIORITY: + ret = vidioc_s_priority(fd, static_cast(arg)); + break; case VIDIOC_REQBUFS: ret = vidioc_reqbufs(fd, static_cast(arg)); break; diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index 90e518c..a0c373d 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -49,6 +49,8 @@ private: int vidioc_g_fmt(int fd, struct v4l2_format *arg); int vidioc_s_fmt(int fd, struct v4l2_format *arg); int vidioc_try_fmt(int fd, struct v4l2_format *arg); + int vidioc_g_priority(int fd, enum v4l2_priority *arg); + int vidioc_s_priority(int fd, enum v4l2_priority *arg); int vidioc_reqbufs(int fd, struct v4l2_requestbuffers *arg); int vidioc_querybuf(int fd, struct v4l2_buffer *arg); int vidioc_qbuf(int fd, struct v4l2_buffer *arg); @@ -84,6 +86,8 @@ private: int efd_; std::map nonBlockingFds_; + std::map priorities_; + int v4l2RecordPriorityFd_; /* * This is an exclusive lock on the camera. When this is not taken, * anybody can call any ioctl before reqbufs. reqbufs with count > 0 From patchwork Tue Jun 16 13:12:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4049 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E2C75603C1 for ; Tue, 16 Jun 2020 15:13:09 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="rPuq2sbi"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:2807:bdfa:f6a:8e53]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 5A332F9; Tue, 16 Jun 2020 15:13:08 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592313189; bh=y/vOLRN6xRrkRkkvDb1TKpC5d0iLmLjQLru3wnFYy5o=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rPuq2sbiCTaMNYTB/cOQH8Sv81i2IGhjsKyA89LZ8+theEXo1G716CVm6CF55imLK UU6HWd5Ol4REt8IbS9GKq3X6Ec3g/M/aCMb3DyR65N308pIHNQsXTMC31VYqFgMfcv oN9w5Tfa0mpwx26ZI8Ocf5ogZnxAXmqeoeOPv5BE= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Tue, 16 Jun 2020 22:12:34 +0900 Message-Id: <20200616131244.70308-6-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200616131244.70308-1-paul.elder@ideasonboard.com> References: <20200616131244.70308-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 05/15] v4l2: v4l2_camera_proxy: Implement VIDIOC_ENUMINPUT, VIDIOC_G/S_INPUT 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, 16 Jun 2020 13:13:10 -0000 Implement VIDIOC_ENUMINPUT, VIDIOC_G_INPUT, and VIDIOC_S_INPUT. Only the zeroth input device is supported, and the info returned by enuminput is hardcoded and basic. This is sufficient to pass v4l2-compliance. Signed-off-by: Paul Elder Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/v4l2/v4l2_camera_proxy.cpp | 54 ++++++++++++++++++++++++++++++++++ src/v4l2/v4l2_camera_proxy.h | 3 ++ 2 files changed, 57 insertions(+) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index f268f7a..6c0dacc 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -397,6 +397,51 @@ int V4L2CameraProxy::vidioc_s_priority(int fd, enum v4l2_priority *arg) return 0; } +int V4L2CameraProxy::vidioc_enuminput(int fd, struct v4l2_input *arg) +{ + LOG(V4L2Compat, Debug) << "Servicing vidioc_enuminput fd = " << fd; + + if (arg == nullptr) + return -EFAULT; + + if (arg->index != 0) + return -EINVAL; + + memset(arg, 0, sizeof(*arg)); + + utils::strlcpy(reinterpret_cast(arg->name), + reinterpret_cast(capabilities_.card), + sizeof(arg->name)); + arg->type = V4L2_INPUT_TYPE_CAMERA; + + return 0; +} + +int V4L2CameraProxy::vidioc_g_input(int fd, int *arg) +{ + LOG(V4L2Compat, Debug) << "Servicing vidioc_g_input fd = " << fd; + + if (arg == nullptr) + return -EFAULT; + + *arg = 0; + + return 0; +} + +int V4L2CameraProxy::vidioc_s_input(int fd, int *arg) +{ + LOG(V4L2Compat, Debug) << "Servicing vidioc_s_input fd = " << fd; + + if (arg == nullptr) + return -EFAULT; + + if (*arg != 0) + return -EINVAL; + + return 0; +} + int V4L2CameraProxy::freeBuffers() { LOG(V4L2Compat, Debug) << "Freeing libcamera bufs"; @@ -649,6 +694,15 @@ int V4L2CameraProxy::ioctl(int fd, unsigned long request, void *arg) case VIDIOC_S_PRIORITY: ret = vidioc_s_priority(fd, static_cast(arg)); break; + case VIDIOC_ENUMINPUT: + ret = vidioc_enuminput(fd, static_cast(arg)); + break; + case VIDIOC_G_INPUT: + ret = vidioc_g_input(fd, static_cast(arg)); + break; + case VIDIOC_S_INPUT: + ret = vidioc_s_input(fd, static_cast(arg)); + break; case VIDIOC_REQBUFS: ret = vidioc_reqbufs(fd, static_cast(arg)); break; diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index a0c373d..2e90bfd 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -51,6 +51,9 @@ private: int vidioc_try_fmt(int fd, struct v4l2_format *arg); int vidioc_g_priority(int fd, enum v4l2_priority *arg); int vidioc_s_priority(int fd, enum v4l2_priority *arg); + int vidioc_enuminput(int fd, struct v4l2_input *arg); + int vidioc_g_input(int fd, int *arg); + int vidioc_s_input(int fd, int *arg); int vidioc_reqbufs(int fd, struct v4l2_requestbuffers *arg); int vidioc_querybuf(int fd, struct v4l2_buffer *arg); int vidioc_qbuf(int fd, struct v4l2_buffer *arg); From patchwork Tue Jun 16 13:12:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4050 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C0A2961F72 for ; Tue, 16 Jun 2020 15:13:11 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="b4zV8t3+"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:2807:bdfa:f6a:8e53]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 4E8C7F9; Tue, 16 Jun 2020 15:13:10 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592313191; bh=gl4mx3/Yjp1Q2s0ElCcmgkIMgV6HnAGak8Vw6uEIPpU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=b4zV8t3+kCPZpIy0SbTJRWAQOiQ5GDqXqLJtWLGbHt5le6RxE2NN9OGFbXOP4sdbw Esq4QxR8KxQdiwO5wRO9+XG9BBrkjLnO0QGB7xlZoA7Mjx+elneLsWQI0ZGZjkFeyN cHVjAk8cNDArpbtBshJJngCDdxs/HnWmxNzvaUI8= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Tue, 16 Jun 2020 22:12:35 +0900 Message-Id: <20200616131244.70308-7-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200616131244.70308-1-paul.elder@ideasonboard.com> References: <20200616131244.70308-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 06/15] v4l2: v4l2_camera_proxy: Implement VIDIOC_ENUM_FRAMESIZES 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, 16 Jun 2020 13:13:12 -0000 Implement VIDIOC_ENUM_FRAMESIZES in the V4L2 compatibility layer. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart Reviewed-by: Jacopo Mondi --- src/v4l2/v4l2_camera_proxy.cpp | 24 ++++++++++++++++++++++++ src/v4l2/v4l2_camera_proxy.h | 1 + 2 files changed, 25 insertions(+) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 6c0dacc..a5fa478 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -251,6 +251,27 @@ int V4L2CameraProxy::vidioc_querycap(struct v4l2_capability *arg) return 0; } +int V4L2CameraProxy::vidioc_enum_framesizes(int fd, struct v4l2_frmsizeenum *arg) +{ + LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_framesizes fd = " << fd; + + if (arg == nullptr) + return -EFAULT; + + PixelFormat argFormat = v4l2ToDrm(arg->pixel_format); + const std::vector &frameSizes = streamConfig_.formats().sizes(argFormat); + + if (arg->index >= frameSizes.size()) + return -EINVAL; + + arg->type = V4L2_FRMSIZE_TYPE_DISCRETE; + arg->discrete.width = frameSizes[arg->index].width; + arg->discrete.height = frameSizes[arg->index].height; + memset(arg->reserved, 0, sizeof(arg->reserved)); + + return 0; +} + int V4L2CameraProxy::vidioc_enum_fmt(int fd, struct v4l2_fmtdesc *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_fmt fd = " << fd; @@ -676,6 +697,9 @@ int V4L2CameraProxy::ioctl(int fd, unsigned long request, void *arg) case VIDIOC_QUERYCAP: ret = vidioc_querycap(static_cast(arg)); break; + case VIDIOC_ENUM_FRAMESIZES: + ret = vidioc_enum_framesizes(fd, static_cast(arg)); + break; case VIDIOC_ENUM_FMT: ret = vidioc_enum_fmt(fd, static_cast(arg)); break; diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index 2e90bfd..2ff9571 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -45,6 +45,7 @@ private: int freeBuffers(); int vidioc_querycap(struct v4l2_capability *arg); + int vidioc_enum_framesizes(int fd, struct v4l2_frmsizeenum *arg); int vidioc_enum_fmt(int fd, struct v4l2_fmtdesc *arg); int vidioc_g_fmt(int fd, struct v4l2_format *arg); int vidioc_s_fmt(int fd, struct v4l2_format *arg); From patchwork Tue Jun 16 13:12:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4051 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 907A1603C1 for ; Tue, 16 Jun 2020 15:13:13 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="T1jkgizz"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:2807:bdfa:f6a:8e53]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 23A3427B; Tue, 16 Jun 2020 15:13:11 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592313193; bh=qL9mHOTkjqrNC+F0L1UKd3hnhH93GVHRsF3LET6gRk0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=T1jkgizzQwBBCsfYsJJmcGzDj/eJOuD4blSc+L1o4TKKCfcYiIS6zoGBDxxWcrv2U lmwl+9slGTEqOqVejj+ktM13NDySBBDdbCLrzFfVgziW1G2/3ZkNEU4U3BGSJejK4e aN1gHQ2meVnX/pgm2nR1vao4K5JdfKWWhZedbH+s= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Tue, 16 Jun 2020 22:12:36 +0900 Message-Id: <20200616131244.70308-8-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200616131244.70308-1-paul.elder@ideasonboard.com> References: <20200616131244.70308-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 07/15] v4l2: v4l2_camera_proxy: Fix v4l2-compliance format tests 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, 16 Jun 2020 13:13:13 -0000 Fix v4l2-compliance format tests, for enum_fmt, try_fmt, and g/s_fmt. Signed-off-by: Paul Elder --- src/v4l2/v4l2_camera_proxy.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index a5fa478..fd2785f 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -179,6 +179,9 @@ void V4L2CameraProxy::setFmtFromConfig(StreamConfiguration &streamConfig) curV4L2Format_.fmt.pix.width, curV4L2Format_.fmt.pix.height); curV4L2Format_.fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; + curV4L2Format_.fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + curV4L2Format_.fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_601; + curV4L2Format_.fmt.pix.quantization = V4L2_QUANTIZATION_LIM_RANGE; } unsigned int V4L2CameraProxy::calculateSizeImage(StreamConfiguration &streamConfig) @@ -283,11 +286,15 @@ int V4L2CameraProxy::vidioc_enum_fmt(int fd, struct v4l2_fmtdesc *arg) arg->index >= streamConfig_.formats().pixelformats().size()) return -EINVAL; + /* \todo Set V4L2_FMT_FLAG_COMPRESSED for compressed formats. */ + arg->flags = 0; /* \todo Add map from format to description. */ - utils::strlcpy(reinterpret_cast(arg->description), "Video Format Description", - sizeof(arg->description)); + utils::strlcpy(reinterpret_cast(arg->description), + "Video Format Description", sizeof(arg->description)); arg->pixelformat = drmToV4L2(streamConfig_.formats().pixelformats()[arg->index]); + memset(arg->reserved, 0, sizeof(arg->reserved)); + return 0; } @@ -330,6 +337,9 @@ void V4L2CameraProxy::tryFormat(struct v4l2_format *arg) arg->fmt.pix.width, arg->fmt.pix.height); arg->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; + arg->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + arg->fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_601; + arg->fmt.pix.quantization = V4L2_QUANTIZATION_LIM_RANGE; } int V4L2CameraProxy::vidioc_s_fmt(int fd, struct v4l2_format *arg) From patchwork Tue Jun 16 13:12:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4052 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6E22361F72 for ; Tue, 16 Jun 2020 15:13:15 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="rijpeSy5"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:2807:bdfa:f6a:8e53]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 00D4DF9; Tue, 16 Jun 2020 15:13:13 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592313195; bh=X6Y22/HXPaFaIt3DLstO462rDuQfw/K1Wx07VMwjTHg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rijpeSy5wCwSAZWsMTYkAyMu3WpA936d5sogAOyvizDxSaqkJU1BJTiLC/7WvLeoF ovtYwBGTtXj5GcuRAV//GUco4YYypkvj6kb0KcZQlPNKFRo/PiocoVkHhg+IzobvoP 0FEZb87aWKJE00rnPvXD01zwvazo6OEbxDv8fgDg= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Tue, 16 Jun 2020 22:12:37 +0900 Message-Id: <20200616131244.70308-9-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200616131244.70308-1-paul.elder@ideasonboard.com> References: <20200616131244.70308-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 08/15] v4l2: v4l2_camera: Re-validate configuration after adjusted 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, 16 Jun 2020 13:13:16 -0000 If the camera configuration has been adjusted, validate it again to ensure that it's valid, before configuring the camera with it. Signed-off-by: Paul Elder --- src/v4l2/v4l2_camera.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp index 2557320..fdbf461 100644 --- a/src/v4l2/v4l2_camera.cpp +++ b/src/v4l2/v4l2_camera.cpp @@ -119,11 +119,18 @@ int V4L2Camera::configure(StreamConfiguration *streamConfigOut, LOG(V4L2Compat, Debug) << "Configuration invalid"; return -EINVAL; } - if (validation == CameraConfiguration::Adjusted) + if (validation == CameraConfiguration::Adjusted) { LOG(V4L2Compat, Debug) << "Configuration adjusted"; + validation = config_->validate(); + if (validation != CameraConfiguration::Valid) { + LOG(V4L2Compat, Error) + << "Configuration adjusted but not valid"; + return -EINVAL; + } + } - LOG(V4L2Compat, Debug) << "Validated configuration is: " - << streamConfig.toString(); + LOG(V4L2Compat, Debug) + << "Validated configuration is: " << streamConfig.toString(); int ret = camera_->configure(config_.get()); if (ret < 0) From patchwork Tue Jun 16 13:12:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4053 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5D13061F72 for ; Tue, 16 Jun 2020 15:13:17 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="XEn7KEX8"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:2807:bdfa:f6a:8e53]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E741AF9; Tue, 16 Jun 2020 15:13:15 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592313197; bh=d0nXpwSQo/5EWRBjCr9n31E3PtQ9sPzZ/S0qcDne9TY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XEn7KEX8Y15DhxMEwOGd45pgem/doN3K0BBmpXK7o/juXw5Z3d4z8UKb9D/sf9EyK 3y9NrnPVIzsO7OlmA/GHjBA4Ce5rvDQrNxHW3AmKB+qOeS5U4dtDCnqPH4FiW7/nC/ zy0xOnYY4Oiu0tnTbYYstYp4MhgtCJk6es4Mx6Is= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Tue, 16 Jun 2020 22:12:38 +0900 Message-Id: <20200616131244.70308-10-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200616131244.70308-1-paul.elder@ideasonboard.com> References: <20200616131244.70308-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 09/15] v4l2: v4l2_cammera_proxy: Reset buffer flags on streamoff when already off 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, 16 Jun 2020 13:13:17 -0000 If VIDIOC_STREAMOFF is called when the stream is already off, just reset the buffer status flags and return. Add a streaming flag to V4L2CameraProxy to track the streaming status. Signed-off-by: Paul Elder --- src/v4l2/v4l2_camera_proxy.cpp | 18 +++++++++++++++++- src/v4l2/v4l2_camera_proxy.h | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index fd2785f..63b4124 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -34,7 +34,8 @@ V4L2CameraProxy::V4L2CameraProxy(unsigned int index, std::shared_ptr camera) : refcount_(0), index_(index), bufferCount_(0), currentBuf_(0), vcam_(std::make_unique(camera)), efd_(-1), - v4l2RecordPriorityFd_(-1), acquiredFd_(-1), initialized_(false) + v4l2RecordPriorityFd_(-1), acquiredFd_(-1), initialized_(false), + streaming_(false) { querycap(camera); } @@ -628,6 +629,9 @@ int V4L2CameraProxy::vidioc_dqbuf(int fd, struct v4l2_buffer *arg) if (arg == nullptr) return -EFAULT; + if (!streaming_) + return -EINVAL; + int ret = lock(fd); if (ret < 0) return ret; @@ -666,6 +670,9 @@ int V4L2CameraProxy::vidioc_streamon(int fd, int *arg) if (arg == nullptr) return -EFAULT; + if (streaming_) + return 0; + int ret = lock(fd); if (ret < 0) return ret; @@ -674,6 +681,7 @@ int V4L2CameraProxy::vidioc_streamon(int fd, int *arg) return -EINVAL; currentBuf_ = 0; + streaming_ = true; return vcam_->streamOn(); } @@ -685,6 +693,12 @@ int V4L2CameraProxy::vidioc_streamoff(int fd, int *arg) if (arg == nullptr) return -EFAULT; + if (!streaming_) { + for (unsigned int i = 0; i < bufferCount_; i++) + buffers_[i].flags &= ~(V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE); + return 0; + } + int ret = lock(fd); if (ret < 0) return ret; @@ -697,6 +711,8 @@ int V4L2CameraProxy::vidioc_streamoff(int fd, int *arg) for (struct v4l2_buffer &buf : buffers_) buf.flags &= ~(V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE); + streaming_ = false; + return ret; } diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index 2ff9571..28b2fa0 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -103,6 +103,7 @@ private: int acquiredFd_; bool initialized_; + bool streaming_; }; #endif /* __V4L2_CAMERA_PROXY_H__ */ From patchwork Tue Jun 16 13:12:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4054 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4FC2B603C4 for ; Tue, 16 Jun 2020 15:13:19 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="mC5v9Btv"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:2807:bdfa:f6a:8e53]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id D9E94F9; Tue, 16 Jun 2020 15:13:17 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592313199; bh=2CS7/Khg/CLRDpVz0F3dcbSNJwsFYdeHXv0NRP0c4ao=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mC5v9Btveo+SGhgcY073lkTc/a/KrZfN0S2KLAJDhJ1Vpy27LeOlw+ecElRGxzkLN BupM9WxgCJaM+3Girq20cht4xrNoD2IjNezYIzUTlozhnxNUHRHmGUQrRXhMOmsOXQ g5tHBiVhd7NQsCmHLvny3uTZkQaOO0X1V5WpG0TM= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Tue, 16 Jun 2020 22:12:39 +0900 Message-Id: <20200616131244.70308-11-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200616131244.70308-1-paul.elder@ideasonboard.com> References: <20200616131244.70308-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 10/15] v4l2: v4l2_camera_proxy: Call streamoff on reqbufs 0 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, 16 Jun 2020 13:13:19 -0000 VIDIOC_REQBUFS with count = 0 should also exhibit the same effects as VIDIOC_STREAMOFF if the stream is on. Although V4L2Camera::streamOff is called in the handler for VIDIOC_REQBUFS in V4L2CameraProxy, there is still some state in V4L2CameraProxy that needs to be reset, so call V4L2CameraProxy::vidioc_streamoff. Signed-off-by: Paul Elder --- src/v4l2/v4l2_camera_proxy.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 63b4124..45e4656 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -510,6 +510,13 @@ int V4L2CameraProxy::vidioc_reqbufs(int fd, struct v4l2_requestbuffers *arg) memset(arg->reserved, 0, sizeof(arg->reserved)); if (arg->count == 0) { + if (streaming_) { + int argStreamoff = arg->type; + ret = vidioc_streamoff(fd, &argStreamoff); + if (ret < 0) + return ret; + } + unlock(fd); return freeBuffers(); } From patchwork Tue Jun 16 13:12:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4055 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 42B56603C4 for ; Tue, 16 Jun 2020 15:13:21 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="np8UUjBb"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:2807:bdfa:f6a:8e53]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id CC919F9; Tue, 16 Jun 2020 15:13:19 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592313201; bh=yuqLnijTDViHfOA7LOUcmXFi1YyYFV/vI2MR1Bl9FmM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=np8UUjBb3Cs4CKmbZsVv0YTXBNNE/Qtf85oNYsoFtR3XuBG81sXw0TZf7F3NaUrH4 Vy9tcQjqtcqNuhSw5iZnNYxQpq4R7F1ukJX2kI7G4WeBXsj20y8HwV9ewfQkczyX4V DIVbOU5jcGApOKHhg8UN4WpORehD3xTe9nEXs3Hg= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Tue, 16 Jun 2020 22:12:40 +0900 Message-Id: <20200616131244.70308-12-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200616131244.70308-1-paul.elder@ideasonboard.com> References: <20200616131244.70308-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 11/15] v4l2: v4l2_camera: Don't use libcamera::Semaphore for available buffers 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, 16 Jun 2020 13:13:21 -0000 In V4L2, a blocked dqbuf should not not also block a streamoff. This means that on streamoff, the blocked dqbuf must return (with error). We cannot do this with the libcamera semaphore, so pull out the necessary components of a semaphore, and put them into V4L2Camera, so that dqbuf from V4L2CameraProxy can wait on a disjunct condition of the availability of the semaphore or the stopping of the stream. Signed-off-by: Paul Elder --- src/v4l2/v4l2_camera.cpp | 32 ++++++++++++++++++++++++++++++-- src/v4l2/v4l2_camera.h | 8 +++++++- src/v4l2/v4l2_camera_proxy.cpp | 11 +++++++++-- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp index fdbf461..f0ec54b 100644 --- a/src/v4l2/v4l2_camera.cpp +++ b/src/v4l2/v4l2_camera.cpp @@ -18,7 +18,7 @@ LOG_DECLARE_CATEGORY(V4L2Compat); V4L2Camera::V4L2Camera(std::shared_ptr camera) : camera_(camera), isRunning_(false), bufferAllocator_(nullptr), - efd_(-1) + efd_(-1), bufferAvailableCount_(0) { camera_->requestCompleted.connect(this, &V4L2Camera::requestComplete); } @@ -100,7 +100,9 @@ void V4L2Camera::requestComplete(Request *request) if (ret != sizeof(data)) LOG(V4L2Compat, Error) << "Failed to signal eventfd POLLIN"; - bufferSema_.release(); + MutexLocker locker(bufferMutex_); + bufferAvailableCount_++; + bufferCV_.notify_all(); } int V4L2Camera::configure(StreamConfiguration *streamConfigOut, @@ -151,6 +153,7 @@ int V4L2Camera::allocBuffers(unsigned int count) void V4L2Camera::freeBuffers() { Stream *stream = *camera_->streams().begin(); + bufferAllocator_->free(stream); } @@ -168,6 +171,7 @@ FileDescriptor V4L2Camera::getBufferFd(unsigned int index) int V4L2Camera::streamOn() { + MutexLocker locker(isRunningMutex_); if (isRunning_) return 0; @@ -191,6 +195,7 @@ int V4L2Camera::streamOn() int V4L2Camera::streamOff() { + MutexLocker locker(isRunningMutex_); /* \todo Restore buffers to reqbufs state? */ if (!isRunning_) return 0; @@ -200,12 +205,15 @@ int V4L2Camera::streamOff() return ret == -EACCES ? -EBUSY : ret; isRunning_ = false; + bufferCV_.notify_all(); return 0; } int V4L2Camera::qbuf(unsigned int index) { + MutexLocker locker(isRunningMutex_); + std::unique_ptr request = std::unique_ptr(camera_->createRequest(index)); if (!request) { @@ -234,3 +242,23 @@ int V4L2Camera::qbuf(unsigned int index) return 0; } + +void V4L2Camera::waitForBufferAvailable() +{ + MutexLocker locker(bufferMutex_); + bufferCV_.wait(locker, [&] { + return bufferAvailableCount_ >= 1 || !isRunning_; + }); + if (isRunning_) + bufferAvailableCount_--; +} + +bool V4L2Camera::isBufferAvailable() +{ + MutexLocker locker(bufferMutex_); + if (bufferAvailableCount_ < 1) + return false; + + bufferAvailableCount_--; + return true; +} diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h index 30114ed..81dcbe2 100644 --- a/src/v4l2/v4l2_camera.h +++ b/src/v4l2/v4l2_camera.h @@ -57,7 +57,8 @@ public: int qbuf(unsigned int index); - Semaphore bufferSema_; + void waitForBufferAvailable(); + bool isBufferAvailable(); private: void requestComplete(Request *request); @@ -65,6 +66,7 @@ private: std::shared_ptr camera_; std::unique_ptr config_; + Mutex isRunningMutex_; bool isRunning_; std::mutex bufferLock_; @@ -74,6 +76,10 @@ private: std::deque> completedBuffers_; int efd_; + + Mutex bufferMutex_; + std::condition_variable bufferCV_; + unsigned int bufferAvailableCount_; }; #endif /* __V4L2_CAMERA_H__ */ diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 45e4656..079961a 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -648,10 +648,17 @@ int V4L2CameraProxy::vidioc_dqbuf(int fd, struct v4l2_buffer *arg) return -EINVAL; if (!nonBlockingFds_[fd]) - vcam_->bufferSema_.acquire(); - else if (!vcam_->bufferSema_.tryAcquire()) + vcam_->waitForBufferAvailable(); + else if (!vcam_->isBufferAvailable()) return -EAGAIN; + /* + * We need to check here again in case stream was turned off while we + * were blocked on dqbuf. + */ + if (!streaming_) + return -EINVAL; + updateBuffers(); struct v4l2_buffer &buf = buffers_[currentBuf_]; From patchwork Tue Jun 16 13:12:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4056 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1C43E61F24 for ; Tue, 16 Jun 2020 15:13:23 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="aMYA9Shz"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:2807:bdfa:f6a:8e53]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A6854F9; Tue, 16 Jun 2020 15:13:21 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592313202; bh=nJZWEniJHxfwcC9SzvRwPbm3r/26GoPB7tpGWPcRba4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aMYA9ShzUOwDCRYCud3DWMnf8hFgBiIf7gIIgCn+hTSO2zF4BchalVW2dFEm7mFeT QHMgKUxT/RMgbknrUiwoDMbjjpLkFK7w/BpAe9mE4V8uYfy2MOWgq+3yJuUxnsMlZY wkub+1WGUQw94Lks6d1PfS617VA7jSBKrCIz51bQ= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Tue, 16 Jun 2020 22:12:41 +0900 Message-Id: <20200616131244.70308-13-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200616131244.70308-1-paul.elder@ideasonboard.com> References: <20200616131244.70308-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 12/15] v4l2: v4l2_camera_proxy: Add sequence number 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, 16 Jun 2020 13:13:23 -0000 Populate the sequence number field in the V4L2 buffers. Reset upon streamon. Signed-off-by: Paul Elder --- src/v4l2/v4l2_camera_proxy.cpp | 4 +++- src/v4l2/v4l2_camera_proxy.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 079961a..81f9282 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -33,7 +33,7 @@ LOG_DECLARE_CATEGORY(V4L2Compat); V4L2CameraProxy::V4L2CameraProxy(unsigned int index, std::shared_ptr camera) : refcount_(0), index_(index), bufferCount_(0), currentBuf_(0), - vcam_(std::make_unique(camera)), efd_(-1), + sequence_(0), vcam_(std::make_unique(camera)), efd_(-1), v4l2RecordPriorityFd_(-1), acquiredFd_(-1), initialized_(false), streaming_(false) { @@ -665,6 +665,7 @@ int V4L2CameraProxy::vidioc_dqbuf(int fd, struct v4l2_buffer *arg) buf.flags &= ~V4L2_BUF_FLAG_QUEUED; buf.length = sizeimage_; + buf.sequence = sequence_++; *arg = buf; currentBuf_ = (currentBuf_ + 1) % bufferCount_; @@ -696,6 +697,7 @@ int V4L2CameraProxy::vidioc_streamon(int fd, int *arg) currentBuf_ = 0; streaming_ = true; + sequence_ = 0; return vcam_->streamOn(); } diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index 28b2fa0..1d8e9a6 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -82,6 +82,8 @@ private: unsigned int currentBuf_; unsigned int sizeimage_; + uint32_t sequence_; + std::vector buffers_; std::map mmaps_; From patchwork Tue Jun 16 13:12:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4057 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id F41FC61F24 for ; Tue, 16 Jun 2020 15:13:24 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="dIbT/Wzb"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:2807:bdfa:f6a:8e53]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8050EF9; Tue, 16 Jun 2020 15:13:23 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592313204; bh=DPvSHDRp8TzqSJUTVCDUJSUfdzWl+oRyQNMNklCfEh8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dIbT/WzbkuKXgmpmMQAhb8N3WopapxMlyKuvwUq7sPS1LSGpwPb51S6wM2mW4eyDb omI6guhgXzErycxFuUEHnYd8uDK81U2GjUcVt9Y3JhbosfbBf1FJ5YT+D86KhUpO7Z MGbQrETCiOgaDiSgeW4qOHnfIAlOwwXRjPe29WoA= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Tue, 16 Jun 2020 22:12:42 +0900 Message-Id: <20200616131244.70308-14-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200616131244.70308-1-paul.elder@ideasonboard.com> References: <20200616131244.70308-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 13/15] v4l2: v4l2_camera: Clear pending requests on freeBuffers 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, 16 Jun 2020 13:13:25 -0000 V4L2 allows buffer queueing before streamon while libcamera does not. The compatibility layer thus saves these buffers in a pending queue until streamon, and then automatically queues them. However, this pending queue is not cleared when the buffers a freed, so if buffers are queued, the stream is not started, buffers are freed, more buffers are queued, and the stream is finally started, then the first set of buffers will be used-after-free. Fix this by clearing the pending quest queue upon the buffers being freed. Signed-off-by: Paul Elder Reviewed-by: Jacopo Mondi --- src/v4l2/v4l2_camera.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp index f0ec54b..bae270a 100644 --- a/src/v4l2/v4l2_camera.cpp +++ b/src/v4l2/v4l2_camera.cpp @@ -155,6 +155,7 @@ void V4L2Camera::freeBuffers() Stream *stream = *camera_->streams().begin(); bufferAllocator_->free(stream); + pendingRequests_.clear(); } FileDescriptor V4L2Camera::getBufferFd(unsigned int index) From patchwork Tue Jun 16 13:12:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4058 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E640961F24 for ; Tue, 16 Jun 2020 15:13:26 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="RqIi8Hx0"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:2807:bdfa:f6a:8e53]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 72E83F9; Tue, 16 Jun 2020 15:13:25 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592313206; bh=Vg+VhUMfWG85xqFp+x3bZG6byHh7LtUaycY5Sws99SQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RqIi8Hx0skHbaLAl7tPBMUG/dFQBffqTlt2CIBohLZ9aupqJUMXHTrr7qhU2C3lm+ qiB62pIrCafFMHj6IuJq/HlbJjUUti0OPE6lEgMS1D4w9qN4GhFRT1HXXO2CHNhsMT c3yJYVhFGUYP2Enp411gDwUXMaASvKcIA6hxqooo= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Tue, 16 Jun 2020 22:12:43 +0900 Message-Id: <20200616131244.70308-15-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200616131244.70308-1-paul.elder@ideasonboard.com> References: <20200616131244.70308-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 14/15] v4l2: v4l2_camera_proxy: Check arg->index bounds for querybuf, qbuf, dqbuf 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, 16 Jun 2020 13:13:27 -0000 There were no bounds checks for the index argument for VIDIOC_QUERYBUF, VIDIOC_QBUF, and VIDIOC_DQBUF. Add them. Signed-off-by: Paul Elder Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/v4l2/v4l2_camera_proxy.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 81f9282..e4d534a 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -588,6 +588,9 @@ int V4L2CameraProxy::vidioc_querybuf(int fd, struct v4l2_buffer *arg) if (arg == nullptr) return -EFAULT; + if (arg->index >= bufferCount_) + return -EINVAL; + int ret = lock(fd); if (ret < 0) return ret; @@ -610,6 +613,9 @@ int V4L2CameraProxy::vidioc_qbuf(int fd, struct v4l2_buffer *arg) if (arg == nullptr) return -EFAULT; + if (arg->index >= bufferCount_) + return -EINVAL; + int ret = lock(fd); if (ret < 0) return ret; @@ -639,6 +645,9 @@ int V4L2CameraProxy::vidioc_dqbuf(int fd, struct v4l2_buffer *arg) if (!streaming_) return -EINVAL; + if (arg->index >= bufferCount_) + return -EINVAL; + int ret = lock(fd); if (ret < 0) return ret; From patchwork Tue Jun 16 13:12:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4059 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D291A61F5D for ; Tue, 16 Jun 2020 15:13:28 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="tpfahY/N"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:2807:bdfa:f6a:8e53]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 65AF6F9; Tue, 16 Jun 2020 15:13:27 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592313208; bh=8t2tCJhQDZS3vUQddiGqmGmlZ4XrNCv3BJMlmZi6MAQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tpfahY/NGwey34fkInwNJgiSBQu779KXx4UgkKRH+PpaC9hQ+e5OXZSaroAEkevaU 3MAw055LHigISu22Z8Xm72DPWWbO0JxnYa2F0Q8VX4Gh1gpI+C9bWDywQO16NmBKfx /ed8Szz6VEM2JNSzjkuloEdZB3mzdR6wYvrAsiuE= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Tue, 16 Jun 2020 22:12:44 +0900 Message-Id: <20200616131244.70308-16-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200616131244.70308-1-paul.elder@ideasonboard.com> References: <20200616131244.70308-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 15/15] v4l2: v4l2_camera_proxy: Fix v4l2-compliance streaming tests 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, 16 Jun 2020 13:13:29 -0000 Fix v4l2-compliance streaming tests, for reqbufs, qbuf, dqbuf, and streamon. Signed-off-by: Paul Elder --- src/v4l2/v4l2_camera_proxy.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index e4d534a..fca728a 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -232,7 +232,6 @@ void V4L2CameraProxy::updateBuffers() buf.timestamp.tv_usec = fmd.timestamp % 1000000; buf.sequence = fmd.sequence; - buf.flags |= V4L2_BUF_FLAG_DONE; break; case FrameMetadata::FrameError: buf.flags |= V4L2_BUF_FLAG_ERROR; @@ -517,6 +516,9 @@ int V4L2CameraProxy::vidioc_reqbufs(int fd, struct v4l2_requestbuffers *arg) return ret; } + if (!mmaps_.empty()) + return -EBUSY; + unlock(fd); return freeBuffers(); } @@ -616,6 +618,9 @@ int V4L2CameraProxy::vidioc_qbuf(int fd, struct v4l2_buffer *arg) if (arg->index >= bufferCount_) return -EINVAL; + if (buffers_[arg->index].flags & V4L2_BUF_FLAG_QUEUED) + return -EINVAL; + int ret = lock(fd); if (ret < 0) return ret; @@ -629,9 +634,12 @@ int V4L2CameraProxy::vidioc_qbuf(int fd, struct v4l2_buffer *arg) if (ret < 0) return ret; - arg->flags |= V4L2_BUF_FLAG_QUEUED; + arg->flags |= V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_MAPPED; arg->flags &= ~V4L2_BUF_FLAG_DONE; + buffers_[arg->index].flags |= V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_MAPPED; + buffers_[arg->index].flags &= ~V4L2_BUF_FLAG_DONE; + return ret; } @@ -694,6 +702,9 @@ int V4L2CameraProxy::vidioc_streamon(int fd, int *arg) if (arg == nullptr) return -EFAULT; + if (bufferCount_ == 0) + return -EINVAL; + if (streaming_) return 0;