From patchwork Mon Dec 23 07:26:20 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 2449 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 2C03F605D0 for ; Mon, 23 Dec 2019 08:26:54 +0100 (CET) Received: from neptunite.amanokami.net (173-16-160-11.client.mchsi.com [173.16.160.11]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 1C0DE330; Mon, 23 Dec 2019 08:26:52 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1577086013; bh=IXYGWPXGfQwEnLjlRtnoBfAV1KHfvNGI+ukb5UFk0EU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=s8Ul/Kv62iEDGNjpd58l2yckf60TLARF4VnsKRYSqDxN6hsrSXNZZnDqUurT/F28i cw14NUkZ9REv4YsjWLiy95GSeynhX7ER3PbXBYoPVYISCvb8FwPDoLSwkEflli14pL NgulvUjey2qT9Fib4Sn0jdN0i+VEBEYW1Tr3cjmI= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Dec 2019 01:26:20 -0600 Message-Id: <20191223072620.13022-7-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191223072620.13022-1-paul.elder@ideasonboard.com> References: <20191223072620.13022-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 6/6] v4l2: v4l2-compat: add buffer state tracking to V4L2CameraProxy 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: Mon, 23 Dec 2019 07:26:54 -0000 Add a way for V4L2CameraProxy to cache the state of all the completed buffers as v4l2_buffers. This reduces the number of cross-thread calls, since the newly added V4L2CameraProxy::updateBuffers(), which goes through V4L2Camera::completedBuffers(), does not need to be called across the thread boundary. Also move the v4l2_buffer flag-setting logic to V4L2CameraProxy. Signed-off-by: Paul Elder --- New in v3 --- src/v4l2/v4l2_camera.cpp | 36 ++++++--------- src/v4l2/v4l2_camera.h | 7 ++- src/v4l2/v4l2_camera_proxy.cpp | 80 +++++++++++++++++++++++++++------- src/v4l2/v4l2_camera_proxy.h | 3 ++ 4 files changed, 84 insertions(+), 42 deletions(-) diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp index 2d33be9f..403e24f6 100644 --- a/src/v4l2/v4l2_camera.cpp +++ b/src/v4l2/v4l2_camera.cpp @@ -70,6 +70,19 @@ void V4L2Camera::getStreamConfig(StreamConfiguration *streamConfig) *streamConfig = config_->at(0); } +std::vector V4L2Camera::completedBuffers() +{ + std::vector v; + + bufferLock_.lock(); + for (std::unique_ptr &fmd : completedBuffers_) + v.push_back(*fmd.get()); + completedBuffers_.clear(); + bufferLock_.unlock(); + + return v; +} + void V4L2Camera::requestComplete(Request *request) { if (request->status() == Request::RequestCancelled) @@ -80,7 +93,7 @@ void V4L2Camera::requestComplete(Request *request) Buffer *buffer = request->buffers().begin()->second; std::unique_ptr fmd = utils::make_unique(buffer); - completedBuffers_.push(std::move(fmd)); + completedBuffers_.push_back(std::move(fmd)); bufferLock_.unlock(); bufferSema_.release(); @@ -225,24 +238,3 @@ void V4L2Camera::qbuf(int *ret, unsigned int index) *ret = 0; } - -int V4L2Camera::dqbuf(struct v4l2_buffer *arg, bool nonblock) -{ - if (nonblock && !bufferSema_.tryAcquire()) - return -EAGAIN; - else - bufferSema_.acquire(); - - bufferLock_.lock(); - FrameMetadata *fmd = completedBuffers_.front().get(); - completedBuffers_.pop(); - bufferLock_.unlock(); - - arg->bytesused = fmd->bytesused(); - arg->field = V4L2_FIELD_NONE; - arg->timestamp.tv_sec = fmd->timestamp() / 1000000000; - arg->timestamp.tv_usec = fmd->timestamp() % 1000000; - arg->sequence = fmd->sequence(); - - return 0; -} diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h index 13418b6b..43ab8d02 100644 --- a/src/v4l2/v4l2_camera.h +++ b/src/v4l2/v4l2_camera.h @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -51,6 +50,7 @@ public: void open(int *ret); void close(int *ret); void getStreamConfig(StreamConfiguration *streamConfig); + std::vector completedBuffers(); void mmap(void **ret, unsigned int index); @@ -63,8 +63,8 @@ public: void streamOff(int *ret); void qbuf(int *ret, unsigned int index); - int dqbuf(struct v4l2_buffer *arg, bool nonblock); + Semaphore bufferSema_; private: void requestComplete(Request *request); @@ -74,11 +74,10 @@ private: unsigned int bufferCount_; bool isRunning_; - Semaphore bufferSema_; std::mutex bufferLock_; std::deque> pendingRequests_; - std::queue> completedBuffers_; + std::deque> completedBuffers_; }; #endif /* __V4L2_CAMERA_H__ */ diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index b0acd477..4e303500 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -101,6 +101,9 @@ void *V4L2CameraProxy::mmap(void *addr, size_t length, int prot, int flags, void *val; vcam_->invokeMethod(&V4L2Camera::mmap, ConnectionTypeBlocking, &val, index); + + buffers_[index].flags |= V4L2_BUF_FLAG_MAPPED; + return val; } @@ -173,6 +176,35 @@ void V4L2CameraProxy::querycap(std::shared_ptr camera) memset(capabilities_.reserved, 0, sizeof(capabilities_.reserved)); } +void V4L2CameraProxy::updateBuffers() +{ + std::vector completedBuffers = vcam_->completedBuffers(); + for (FrameMetadata &fmd : completedBuffers) { + /* \todo is this index valid if the buffer status != success? */ + struct v4l2_buffer &buf = buffers_[fmd.index()]; + + switch (fmd.status()) { + case Buffer::Status::BufferSuccess: + buf.index = fmd.index(); + buf.bytesused = fmd.bytesused(); + buf.field = V4L2_FIELD_NONE; + buf.timestamp.tv_sec = fmd.timestamp() / 1000000000; + buf.timestamp.tv_usec = fmd.timestamp() % 1000000; + buf.sequence = fmd.sequence(); + + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.length = curV4L2Format_.fmt.pix.sizeimage; + buf.memory = V4L2_MEMORY_MMAP; + buf.m.offset = buf.index * curV4L2Format_.fmt.pix.sizeimage; + break; + case Buffer::Status::BufferError: + buf.flags |= V4L2_BUF_FLAG_ERROR; + default: + break; + } + } +} + int V4L2CameraProxy::vidioc_querycap(struct v4l2_capability *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_querycap"; @@ -344,13 +376,21 @@ int V4L2CameraProxy::vidioc_querybuf(struct v4l2_buffer *arg) arg->index >= stream->buffers().size()) return -EINVAL; - unsigned int index = arg->index; - memset(arg, 0, sizeof(*arg)); - arg->index = index; - arg->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - arg->length = curV4L2Format_.fmt.pix.sizeimage; - arg->memory = V4L2_MEMORY_MMAP; - arg->m.offset = arg->index * curV4L2Format_.fmt.pix.sizeimage; + /* \todo make updateBuffers() get only one buffer? */ + updateBuffers(); + + if (buffers_.size() <= arg->index) { + struct v4l2_buffer buf; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.length = curV4L2Format_.fmt.pix.sizeimage; + buf.memory = V4L2_MEMORY_MMAP; + buf.m.offset = arg->index * curV4L2Format_.fmt.pix.sizeimage; + + buffers_.resize(arg->index + 1); + buffers_[arg->index] = buf; + } + + memcpy(arg, &buffers_[arg->index], sizeof(*arg)); return 0; } @@ -388,19 +428,23 @@ int V4L2CameraProxy::vidioc_dqbuf(struct v4l2_buffer *arg) !validateMemoryType(arg->memory)) return -EINVAL; - arg->index = currentBuf_; - currentBuf_ = (currentBuf_ + 1) % bufferCount_; + if (nonBlocking_ && !vcam_->bufferSema_.tryAcquire()) + return -EAGAIN; + else + vcam_->bufferSema_.acquire(); - int ret = vcam_->dqbuf(arg, nonBlocking_); - if (ret < 0) - return ret; + updateBuffers(); - arg->flags &= ~V4L2_BUF_FLAG_QUEUED; - arg->flags |= V4L2_BUF_FLAG_DONE; + memcpy(arg, &buffers_[arg->index], sizeof(*arg)); - arg->length = sizeimage_; + struct v4l2_buffer &buf = buffers_[arg->index]; + arg->index = currentBuf_; + currentBuf_ = (currentBuf_ + 1) % bufferCount_; + buf.flags &= ~V4L2_BUF_FLAG_QUEUED; + buf.flags |= V4L2_BUF_FLAG_DONE; + buf.length = sizeimage_; - return ret; + return 0; } int V4L2CameraProxy::vidioc_streamon(int *arg) @@ -426,6 +470,10 @@ int V4L2CameraProxy::vidioc_streamoff(int *arg) int ret; vcam_->invokeMethod(&V4L2Camera::streamOff, ConnectionTypeBlocking, &ret); + + for (struct v4l2_buffer &buf : buffers_) + buf.flags &= ~V4L2_BUF_FLAG_QUEUED; + return ret; } diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index 51fdbe19..19688717 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -40,6 +40,7 @@ private: void setFmtFromConfig(StreamConfiguration &streamConfig); unsigned int calculateSizeImage(StreamConfiguration &streamConfig); void querycap(std::shared_ptr camera); + void updateBuffers(); int vidioc_querycap(struct v4l2_capability *arg); int vidioc_enum_fmt(struct v4l2_fmtdesc *arg); @@ -64,6 +65,8 @@ private: unsigned int currentBuf_; unsigned int sizeimage_; + std::vector buffers_; + std::unique_ptr vcam_; };