[libcamera-devel] [PATCH 19/20] libcamera: pipeline: simple: Support usage of multiple streams
paul.elder at ideasonboard.com
paul.elder at ideasonboard.com
Tue Mar 2 08:09:33 CET 2021
Hi Laurent,
On Mon, Feb 01, 2021 at 12:47:01AM +0200, Laurent Pinchart wrote:
> To extend the multi-stream support to runtime operation of the pipeline,
> expand the converter queue to store multiple output buffers, and update
> the request queuing and buffer completion handlers accordingly.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> ---
> src/libcamera/pipeline/simple/simple.cpp | 93 ++++++++++++++----------
> 1 file changed, 54 insertions(+), 39 deletions(-)
>
> diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
> index 58e5f0d23139..55a5528611c8 100644
> --- a/src/libcamera/pipeline/simple/simple.cpp
> +++ b/src/libcamera/pipeline/simple/simple.cpp
> @@ -173,7 +173,7 @@ public:
>
> std::vector<std::unique_ptr<FrameBuffer>> converterBuffers_;
> bool useConverter_;
> - std::queue<FrameBuffer *> converterQueue_;
> + std::queue<std::map<unsigned int, FrameBuffer *>> converterQueue_;
> };
>
> class SimpleCameraConfiguration : public CameraConfiguration
> @@ -762,10 +762,12 @@ int SimplePipelineHandler::exportFrameBuffers(Camera *camera, Stream *stream,
> * Export buffers on the converter or capture video node, depending on
> * whether the converter is used or not.
> */
> - if (data->useConverter_)
> - return converter_->exportBuffers(0, count, buffers);
> - else
> + if (data->useConverter_) {
> + unsigned int index = stream - &data->streams_.front();
> + return converter_->exportBuffers(index, count, buffers);
> + } else {
> return data->video_->exportBuffers(count, buffers);
> + }
> }
>
> int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] ControlList *controls)
> @@ -830,25 +832,30 @@ void SimplePipelineHandler::stop(Camera *camera)
> int SimplePipelineHandler::queueRequestDevice(Camera *camera, Request *request)
> {
> SimpleCameraData *data = cameraData(camera);
> - Stream *stream = &data->streams_[0];
> + int ret;
>
> - FrameBuffer *buffer = request->findBuffer(stream);
> - if (!buffer) {
> - LOG(SimplePipeline, Error)
> - << "Attempt to queue request with invalid stream";
> - return -ENOENT;
> - }
> + std::map<unsigned int, FrameBuffer *> buffers;
>
> - /*
> - * If conversion is needed, push the buffer to the converter queue, it
> - * will be handed to the converter in the capture completion handler.
> - */
> - if (data->useConverter_) {
> - data->converterQueue_.push(buffer);
> - return 0;
> + for (auto &[stream, buffer] : request->buffers()) {
> + /*
> + * If conversion is needed, push the buffer to the converter
> + * queue, it will be handed to the converter in the capture
> + * completion handler.
> + */
> + if (data->useConverter_) {
> + unsigned int index = stream - &data->streams_.front();
> + buffers.emplace(index, buffer);
> + } else {
> + ret = data->video_->queueBuffer(buffer);
> + if (ret < 0)
> + return ret;
> + }
> }
>
> - return data->video_->queueBuffer(buffer);
> + if (data->useConverter_)
> + data->converterQueue_.push(std::move(buffers));
> +
> + return 0;
> }
>
> /* -----------------------------------------------------------------------------
> @@ -1020,24 +1027,34 @@ void SimplePipelineHandler::bufferReady(FrameBuffer *buffer)
> * point converting an erroneous buffer.
> */
> if (buffer->metadata().status != FrameMetadata::FrameSuccess) {
> - if (data->useConverter_) {
> - /* Requeue the buffer for capture. */
> - data->video_->queueBuffer(buffer);
> + if (!data->useConverter_) {
> + /* No conversion, just complete the request. */
> + Request *request = buffer->request();
> + completeBuffer(request, buffer);
> + completeRequest(request);
> + return;
> + }
> +
> + /*
> + * The converter is in use. Requeue the internal buffer for
> + * capture, and complete the request with all the user-facing
> + * buffers.
> + */
> + data->video_->queueBuffer(buffer);
>
> - /*
> - * Get the next user-facing buffer to complete the
> - * request.
> - */
> - if (data->converterQueue_.empty())
> - return;
> + if (data->converterQueue_.empty())
> + return;
>
> - buffer = data->converterQueue_.front();
> - data->converterQueue_.pop();
> + Request *request = nullptr;
> + for (auto &item : data->converterQueue_.front()) {
> + FrameBuffer *outputBuffer = item.second;
> + request = outputBuffer->request();
> + completeBuffer(request, outputBuffer);
> }
> + data->converterQueue_.pop();
>
> - Request *request = buffer->request();
> - completeBuffer(request, buffer);
> - completeRequest(request);
> + if (request)
This check doesn't seem necessary, as we return early if the
converterQueue_ is empty, so the loop will always run once. Is it just
to appease coverity?
Reviewed-by: Paul Elder <paul.elder at ideasonboard.com>
> + completeRequest(request);
> return;
> }
>
> @@ -1052,10 +1069,8 @@ void SimplePipelineHandler::bufferReady(FrameBuffer *buffer)
> return;
> }
>
> - FrameBuffer *output = data->converterQueue_.front();
> + converter_->queueBuffers(buffer, data->converterQueue_.front());
> data->converterQueue_.pop();
> -
> - converter_->queueBuffers(buffer, { { 0, output } });
> return;
> }
>
> @@ -1078,10 +1093,10 @@ void SimplePipelineHandler::converterOutputDone(FrameBuffer *buffer)
> {
> ASSERT(activeCamera_);
>
> - /* Complete the request. */
> + /* Complete the buffer and the request. */
> Request *request = buffer->request();
> - completeBuffer(request, buffer);
> - completeRequest(request);
> + if (completeBuffer(request, buffer))
> + completeRequest(request);
> }
>
> REGISTER_PIPELINE_HANDLER(SimplePipelineHandler)
More information about the libcamera-devel
mailing list