@@ -10,6 +10,7 @@
#include <iomanip>
#include <math.h>
#include <memory>
+#include <queue>
#include <tuple>
#include <libcamera/base/log.h>
@@ -45,8 +46,13 @@ public:
ControlInfoMap::Map *ctrls);
void bufferReady(FrameBuffer *buffer);
+ void queuePendingRequests();
+ void cancelPendingRequests();
+
std::unique_ptr<V4L2VideoDevice> video_;
Stream stream_;
+
+ std::queue<Request *> pendingRequests_;
};
class UVCCameraConfiguration : public CameraConfiguration
@@ -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)
{
@@ -252,6 +259,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();
}
@@ -365,21 +373,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;
}
@@ -669,6 +672,49 @@ void UVCCameraData::bufferReady(FrameBuffer *buffer)
pipe_->completeBuffer(request, buffer);
pipe_->completeRequest(request);
+
+ queuePendingRequests();
+}
+
+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();
+ }
+}
+
+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)
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@collabora.com> --- src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 66 +++++++++++++++++--- 1 file changed, 56 insertions(+), 10 deletions(-)