[libcamera-devel] [PATCH v3 6/6] v4l2: v4l2-compat: add buffer state tracking to V4L2CameraProxy
Paul Elder
paul.elder at ideasonboard.com
Mon Dec 23 08:26:20 CET 2019
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 <paul.elder at ideasonboard.com>
---
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<FrameMetadata> V4L2Camera::completedBuffers()
+{
+ std::vector<FrameMetadata> v;
+
+ bufferLock_.lock();
+ for (std::unique_ptr<FrameMetadata> &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<FrameMetadata> fmd =
utils::make_unique<FrameMetadata>(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 <deque>
#include <linux/videodev2.h>
#include <mutex>
-#include <queue>
#include <libcamera/buffer.h>
#include <libcamera/camera.h>
@@ -51,6 +50,7 @@ public:
void open(int *ret);
void close(int *ret);
void getStreamConfig(StreamConfiguration *streamConfig);
+ std::vector<FrameMetadata> 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<std::unique_ptr<Request>> pendingRequests_;
- std::queue<std::unique_ptr<FrameMetadata>> completedBuffers_;
+ std::deque<std::unique_ptr<FrameMetadata>> 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> camera)
memset(capabilities_.reserved, 0, sizeof(capabilities_.reserved));
}
+void V4L2CameraProxy::updateBuffers()
+{
+ std::vector<FrameMetadata> 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> 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<struct v4l2_buffer> buffers_;
+
std::unique_ptr<V4L2Camera> vcam_;
};
--
2.23.0
More information about the libcamera-devel
mailing list