[libcamera-devel] [PATCH v2] libcamera: pipeline: uvcvideo: Add internal request queue
Nícolas F. R. A. Prado
nfraprado at collabora.com
Mon Jul 5 20:24:34 CEST 2021
Add an internal queue that stores requests until there are v4l2 buffer
slots available. This avoids the need to cancel requests when there is a
shortage of said buffers.
Signed-off-by: Nícolas F. R. A. Prado <nfraprado at collabora.com>
---
Changes in v2:
- Thanks to Jacopo:
- Added missing call to cancelPendingRequests() in stop()
src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 65 +++++++++++++++++---
1 file changed, 55 insertions(+), 10 deletions(-)
diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
index 0f634b8da609..ee03b7ed7a7d 100644
--- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
+++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
@@ -10,6 +10,7 @@
#include <iomanip>
#include <math.h>
#include <memory>
+#include <queue>
#include <tuple>
#include <libcamera/base/log.h>
@@ -45,6 +46,11 @@ public:
ControlInfoMap::Map *ctrls);
void bufferReady(FrameBuffer *buffer);
+ void queuePendingRequests();
+ void cancelPendingRequests();
+
+ std::queue<Request *> pendingRequests_;
+
std::unique_ptr<V4L2VideoDevice> video_;
Stream stream_;
};
@@ -79,12 +85,13 @@ public:
bool match(DeviceEnumerator *enumerator) override;
+ int processControls(UVCCameraData *data, Request *request);
+
private:
std::string generateId(const UVCCameraData *data);
int processControl(ControlList *controls, unsigned int id,
const ControlValue &value);
- int processControls(UVCCameraData *data, Request *request);
UVCCameraData *cameraData(const Camera *camera)
{
@@ -253,6 +260,7 @@ int PipelineHandlerUVC::start(Camera *camera, [[maybe_unused]] const ControlList
void PipelineHandlerUVC::stop(Camera *camera)
{
UVCCameraData *data = cameraData(camera);
+ data->cancelPendingRequests();
data->video_->streamOff();
data->video_->releaseBuffers();
}
@@ -363,24 +371,59 @@ int PipelineHandlerUVC::processControls(UVCCameraData *data, Request *request)
return ret;
}
+void UVCCameraData::cancelPendingRequests()
+{
+ while (!pendingRequests_.empty()) {
+ Request *request = pendingRequests_.front();
+ FrameBuffer *buffer = request->findBuffer(&stream_);
+
+ buffer->cancel();
+ pipe_->completeBuffer(request, buffer);
+ pipe_->completeRequest(request);
+
+ pendingRequests_.pop();
+ }
+}
+
+void UVCCameraData::queuePendingRequests()
+{
+ PipelineHandlerUVC *pipe = static_cast<PipelineHandlerUVC *>(pipe_);
+
+ while (!pendingRequests_.empty()) {
+ Request *request = pendingRequests_.front();
+ FrameBuffer *buffer = request->findBuffer(&stream_);
+
+ int ret = pipe->processControls(this, request);
+ if (ret < 0) {
+ buffer->cancel();
+ pipe_->completeBuffer(request, buffer);
+ pipe_->completeRequest(request);
+ pendingRequests_.pop();
+ continue;
+ }
+
+ /* If we're missing v4l2 buffer slots, try again later */
+ ret = video_->queueBuffer(buffer);
+ if (ret < 0)
+ break;
+
+ pendingRequests_.pop();
+ }
+}
+
int PipelineHandlerUVC::queueRequestDevice(Camera *camera, Request *request)
{
UVCCameraData *data = cameraData(camera);
- FrameBuffer *buffer = request->findBuffer(&data->stream_);
- if (!buffer) {
+
+ if (!request->findBuffer(&data->stream_)) {
LOG(UVC, Error)
<< "Attempt to queue request with invalid stream";
return -ENOENT;
}
- int ret = processControls(data, request);
- if (ret < 0)
- return ret;
-
- ret = data->video_->queueBuffer(buffer);
- if (ret < 0)
- return ret;
+ data->pendingRequests_.push(request);
+ data->queuePendingRequests();
return 0;
}
@@ -668,6 +711,8 @@ void UVCCameraData::bufferReady(FrameBuffer *buffer)
pipe_->completeBuffer(request, buffer);
pipe_->completeRequest(request);
+
+ queuePendingRequests();
}
REGISTER_PIPELINE_HANDLER(PipelineHandlerUVC)
--
2.32.0
More information about the libcamera-devel
mailing list