From 33914c4cee632bd2d77dba16014d97f06fa1db35 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 3 Jul 2021 18:33:55 +0300 Subject: libcamera: pipeline: simple: Move bufferReady handler to SimpleCameraData To use multiple cameras at the same time, a per-camera buffer ready handler is needed. Move the bufferReady() function connected to the V4L2VideoDevice bufferReady signal from the SimplePipelineHandler class to the SimpleCameraData class. Signed-off-by: Laurent Pinchart Tested-by: Martin Kepplinger --- src/libcamera/pipeline/simple/simple.cpp | 188 +++++++++++++++---------------- 1 file changed, 92 insertions(+), 96 deletions(-) (limited to 'src') diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index e06d2740..582c9ba4 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -181,6 +181,7 @@ public: int setupLinks(); int setupFormats(V4L2SubdeviceFormat *format, V4L2Subdevice::Whence whence); + void bufferReady(FrameBuffer *buffer); unsigned int streamIndex(const Stream *stream) const { @@ -308,8 +309,6 @@ private: const MediaPad *acquirePipeline(SimpleCameraData *data); void releasePipeline(SimpleCameraData *data); - void bufferReady(FrameBuffer *buffer); - MediaDevice *media_; std::map entities_; @@ -627,6 +626,93 @@ int SimpleCameraData::setupFormats(V4L2SubdeviceFormat *format, return 0; } +void SimpleCameraData::bufferReady(FrameBuffer *buffer) +{ + SimplePipelineHandler *pipe = SimpleCameraData::pipe(); + + /* + * If an error occurred during capture, or if the buffer was cancelled, + * complete the request, even if the converter is in use as there's no + * point converting an erroneous buffer. + */ + if (buffer->metadata().status != FrameMetadata::FrameSuccess) { + if (!useConverter_) { + /* No conversion, just complete the request. */ + Request *request = buffer->request(); + pipe->completeBuffer(request, buffer); + pipe->completeRequest(request); + return; + } + + /* + * The converter is in use. Requeue the internal buffer for + * capture (unless the stream is being stopped), and complete + * the request with all the user-facing buffers. + */ + if (buffer->metadata().status != FrameMetadata::FrameCancelled) + video_->queueBuffer(buffer); + + if (converterQueue_.empty()) + return; + + Request *request = nullptr; + for (auto &item : converterQueue_.front()) { + FrameBuffer *outputBuffer = item.second; + request = outputBuffer->request(); + pipe->completeBuffer(request, outputBuffer); + } + converterQueue_.pop(); + + if (request) + pipe->completeRequest(request); + return; + } + + /* + * Record the sensor's timestamp in the request metadata. The request + * needs to be obtained from the user-facing buffer, as internal + * buffers are free-wheeling and have no request associated with them. + * + * \todo The sensor timestamp should be better estimated by connecting + * to the V4L2Device::frameStart signal if the platform provides it. + */ + Request *request = buffer->request(); + + if (useConverter_ && !converterQueue_.empty()) { + const std::map &outputs = + converterQueue_.front(); + if (!outputs.empty()) { + FrameBuffer *outputBuffer = outputs.begin()->second; + if (outputBuffer) + request = outputBuffer->request(); + } + } + + if (request) + request->metadata().set(controls::SensorTimestamp, + buffer->metadata().timestamp); + + /* + * Queue the captured and the request buffer to the converter if format + * conversion is needed. If there's no queued request, just requeue the + * captured buffer for capture. + */ + if (useConverter_) { + if (converterQueue_.empty()) { + video_->queueBuffer(buffer); + return; + } + + converter_->queueBuffers(buffer, converterQueue_.front()); + converterQueue_.pop(); + return; + } + + /* Otherwise simply complete the request. */ + pipe->completeBuffer(request, buffer); + pipe->completeRequest(request); +} + void SimpleCameraData::converterInputDone(FrameBuffer *buffer) { /* Queue the input buffer back for capture. */ @@ -929,6 +1015,8 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL return ret; } + video->bufferReady.connect(data, &SimpleCameraData::bufferReady); + ret = video->streamOn(); if (ret < 0) { stop(camera); @@ -963,6 +1051,8 @@ void SimplePipelineHandler::stop(Camera *camera) video->streamOff(); video->releaseBuffers(); + video->bufferReady.disconnect(data, &SimpleCameraData::bufferReady); + data->converterBuffers_.clear(); activeCamera_ = nullptr; @@ -1143,8 +1233,6 @@ bool SimplePipelineHandler::match(DeviceEnumerator *enumerator) << ": " << strerror(-ret); return false; } - - video->bufferReady.connect(this, &SimplePipelineHandler::bufferReady); break; case MediaEntity::Type::V4L2Subdevice: @@ -1259,98 +1347,6 @@ void SimplePipelineHandler::releasePipeline(SimpleCameraData *data) } } -/* ----------------------------------------------------------------------------- - * Buffer Handling - */ - -void SimplePipelineHandler::bufferReady(FrameBuffer *buffer) -{ - ASSERT(activeCamera_); - SimpleCameraData *data = cameraData(activeCamera_); - - /* - * If an error occurred during capture, or if the buffer was cancelled, - * complete the request, even if the converter is in use as there's no - * point converting an erroneous buffer. - */ - if (buffer->metadata().status != FrameMetadata::FrameSuccess) { - 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 (unless the stream is being stopped), and complete - * the request with all the user-facing buffers. - */ - if (buffer->metadata().status != FrameMetadata::FrameCancelled) - data->video_->queueBuffer(buffer); - - if (data->converterQueue_.empty()) - return; - - Request *request = nullptr; - for (auto &item : data->converterQueue_.front()) { - FrameBuffer *outputBuffer = item.second; - request = outputBuffer->request(); - completeBuffer(request, outputBuffer); - } - data->converterQueue_.pop(); - - if (request) - completeRequest(request); - return; - } - - /* - * Record the sensor's timestamp in the request metadata. The request - * needs to be obtained from the user-facing buffer, as internal - * buffers are free-wheeling and have no request associated with them. - * - * \todo The sensor timestamp should be better estimated by connecting - * to the V4L2Device::frameStart signal if the platform provides it. - */ - Request *request = buffer->request(); - - if (data->useConverter_ && !data->converterQueue_.empty()) { - const std::map &outputs = - data->converterQueue_.front(); - if (!outputs.empty()) { - FrameBuffer *outputBuffer = outputs.begin()->second; - if (outputBuffer) - request = outputBuffer->request(); - } - } - - if (request) - request->metadata().set(controls::SensorTimestamp, - buffer->metadata().timestamp); - - /* - * Queue the captured and the request buffer to the converter if format - * conversion is needed. If there's no queued request, just requeue the - * captured buffer for capture. - */ - if (data->useConverter_) { - if (data->converterQueue_.empty()) { - data->video_->queueBuffer(buffer); - return; - } - - data->converter_->queueBuffers(buffer, data->converterQueue_.front()); - data->converterQueue_.pop(); - return; - } - - /* Otherwise simply complete the request. */ - completeBuffer(request, buffer); - completeRequest(request); -} - REGISTER_PIPELINE_HANDLER(SimplePipelineHandler) } /* namespace libcamera */ -- cgit v1.2.1