[libcamera-devel] [PATCH v2 2/5] libcamera: pipeline: uvcvideo: Add internal request queue
Nícolas F. R. A. Prado
nfraprado at collabora.com
Wed Sep 1 00:37:02 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:
- Added a counter to keep track of the number of available buffer slots
- Moved cancellation of pending requests to after video devices stop
- Added error log on failure to process controls
src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 98 ++++++++++++++++----
1 file changed, 81 insertions(+), 17 deletions(-)
diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
index 5977312a795d..5e73a8e682dd 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>
@@ -46,8 +47,22 @@ public:
ControlInfoMap::Map *ctrls);
void bufferReady(FrameBuffer *buffer);
+ void queuePendingRequests();
+ void cancelPendingRequests();
+
+ void setAvailableBufferSlotCount(unsigned int count) { availableBufferSlotCount_ = count; }
+
std::unique_ptr<V4L2VideoDevice> video_;
Stream stream_;
+
+ std::queue<Request *> pendingRequests_;
+
+private:
+ int processControls(Request *request);
+ int processControl(ControlList *controls, unsigned int id,
+ const ControlValue &value);
+
+ unsigned int availableBufferSlotCount_;
};
class UVCCameraConfiguration : public CameraConfiguration
@@ -83,10 +98,6 @@ public:
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(Camera *camera)
{
return static_cast<UVCCameraData *>(camera->_d());
@@ -240,6 +251,8 @@ int PipelineHandlerUVC::start(Camera *camera, [[maybe_unused]] const ControlList
if (ret < 0)
return ret;
+ data->setAvailableBufferSlotCount(kUVCBufferSlotCount);
+
ret = data->video_->streamOn();
if (ret < 0) {
data->video_->releaseBuffers();
@@ -253,10 +266,11 @@ void PipelineHandlerUVC::stop(Camera *camera)
{
UVCCameraData *data = cameraData(camera);
data->video_->streamOff();
+ data->cancelPendingRequests();
data->video_->releaseBuffers();
}
-int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id,
+int UVCCameraData::processControl(ControlList *controls, unsigned int id,
const ControlValue &value)
{
uint32_t cid;
@@ -337,9 +351,9 @@ int PipelineHandlerUVC::processControl(ControlList *controls, unsigned int id,
return 0;
}
-int PipelineHandlerUVC::processControls(UVCCameraData *data, Request *request)
+int UVCCameraData::processControls(Request *request)
{
- ControlList controls(data->video_->controls());
+ ControlList controls(video_->controls());
for (auto it : request->controls()) {
unsigned int id = it.first;
@@ -353,7 +367,7 @@ int PipelineHandlerUVC::processControls(UVCCameraData *data, Request *request)
<< "Setting control " << utils::hex(ctrl.first)
<< " to " << ctrl.second.toString();
- int ret = data->video_->setControls(&controls);
+ int ret = video_->setControls(&controls);
if (ret) {
LOG(UVC, Error) << "Failed to set controls: " << ret;
return ret < 0 ? ret : -EINVAL;
@@ -365,21 +379,16 @@ int PipelineHandlerUVC::processControls(UVCCameraData *data, Request *request)
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;
}
@@ -670,6 +679,61 @@ void UVCCameraData::bufferReady(FrameBuffer *buffer)
pipe()->completeBuffer(request, buffer);
pipe()->completeRequest(request);
+
+ availableBufferSlotCount_++;
+
+ queuePendingRequests();
+}
+
+void UVCCameraData::queuePendingRequests()
+{
+ while (!pendingRequests_.empty() && availableBufferSlotCount_) {
+ Request *request = pendingRequests_.front();
+ FrameBuffer *buffer = request->findBuffer(&stream_);
+
+ int ret = processControls(request);
+ if (ret < 0) {
+ LOG(UVC, Error) << "Failed to process controls with"
+ << " error " << ret << ". Cancelling"
+ << " buffer.";
+ buffer->cancel();
+ pipe()->completeBuffer(request, buffer);
+ pipe()->completeRequest(request);
+ pendingRequests_.pop();
+
+ continue;
+ }
+
+ ret = video_->queueBuffer(buffer);
+ if (ret < 0) {
+ LOG(UVC, Error) << "Failed to queue buffer with error "
+ << ret << ". Cancelling buffer.";
+ buffer->cancel();
+ pipe()->completeBuffer(request, buffer);
+ pipe()->completeRequest(request);
+ pendingRequests_.pop();
+
+ continue;
+ }
+
+ availableBufferSlotCount_--;
+
+ pendingRequests_.pop();
+ }
+}
+
+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();
+ }
}
REGISTER_PIPELINE_HANDLER(PipelineHandlerUVC)
--
2.33.0
More information about the libcamera-devel
mailing list