diff options
Diffstat (limited to 'src/libcamera')
-rw-r--r-- | src/libcamera/pipeline/ipu3/cio2.cpp | 58 | ||||
-rw-r--r-- | src/libcamera/pipeline/ipu3/cio2.h | 7 | ||||
-rw-r--r-- | src/libcamera/pipeline/ipu3/ipu3.cpp | 67 |
3 files changed, 60 insertions, 72 deletions
diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp index d698cd80..885e2ca0 100644 --- a/src/libcamera/pipeline/ipu3/cio2.cpp +++ b/src/libcamera/pipeline/ipu3/cio2.cpp @@ -213,31 +213,16 @@ int CIO2Device::exportBuffers(unsigned int count, return output_->exportBuffers(count, buffers); } -FrameBuffer *CIO2Device::getBuffer() -{ - if (availableBuffers_.empty()) { - LOG(IPU3, Error) << "CIO2 buffer underrun"; - return nullptr; - } - - FrameBuffer *buffer = availableBuffers_.front(); - - availableBuffers_.pop(); - - return buffer; -} - -void CIO2Device::putBuffer(FrameBuffer *buffer) -{ - availableBuffers_.push(buffer); -} - int CIO2Device::start() { - int ret = output_->allocateBuffers(CIO2_BUFFER_COUNT, &buffers_); + int ret = output_->exportBuffers(CIO2_BUFFER_COUNT, &buffers_); if (ret < 0) return ret; + ret = output_->importBuffers(CIO2_BUFFER_COUNT); + if (ret) + LOG(IPU3, Error) << "Failed to import CIO2 buffers"; + for (std::unique_ptr<FrameBuffer> &buffer : buffers_) availableBuffers_.push(buffer.get()); @@ -257,11 +242,42 @@ int CIO2Device::stop() return ret; } -int CIO2Device::queueBuffer(FrameBuffer *buffer) +int CIO2Device::queueBuffer(Request *request, FrameBuffer *rawBuffer) { + FrameBuffer *buffer = rawBuffer; + + /* If no buffer is provided in the request, use an internal one. */ + if (!buffer) { + if (availableBuffers_.empty()) { + LOG(IPU3, Error) << "CIO2 buffer underrun"; + return -EINVAL; + } + + buffer = availableBuffers_.front(); + availableBuffers_.pop(); + } + + buffer->setRequest(request); + return output_->queueBuffer(buffer); } +void CIO2Device::tryReturnBuffer(FrameBuffer *buffer) +{ + /* + * \todo Once more pipelines deal with buffers that may be allocated + * internally or externally this pattern might become a common need. At + * that point this check should be moved to something clever in + * FrameBuffer. + */ + for (const std::unique_ptr<FrameBuffer> &buf : buffers_) { + if (buf.get() == buffer) { + availableBuffers_.push(buffer); + break; + } + } +} + void CIO2Device::freeBuffers() { /* The default std::queue constructor is explicit with gcc 5 and 6. */ diff --git a/src/libcamera/pipeline/ipu3/cio2.h b/src/libcamera/pipeline/ipu3/cio2.h index 47c6f010..dc764b10 100644 --- a/src/libcamera/pipeline/ipu3/cio2.h +++ b/src/libcamera/pipeline/ipu3/cio2.h @@ -18,6 +18,7 @@ namespace libcamera { class CameraSensor; class FrameBuffer; class MediaDevice; +class Request; class V4L2DeviceFormat; class V4L2Subdevice; class V4L2VideoDevice; @@ -40,15 +41,13 @@ public: int exportBuffers(unsigned int count, std::vector<std::unique_ptr<FrameBuffer>> *buffers); - FrameBuffer *getBuffer(); - void putBuffer(FrameBuffer *buffer); - int start(); int stop(); CameraSensor *sensor() { return sensor_; } - int queueBuffer(FrameBuffer *buffer); + int queueBuffer(Request *request, FrameBuffer *rawBuffer); + void tryReturnBuffer(FrameBuffer *buffer); Signal<FrameBuffer *> bufferReady; private: diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 4818027e..6c43169e 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -122,7 +122,6 @@ public: } void imguOutputBufferReady(FrameBuffer *buffer); - void imguInputBufferReady(FrameBuffer *buffer); void cio2BufferReady(FrameBuffer *buffer); CIO2Device cio2_; @@ -737,25 +736,24 @@ void PipelineHandlerIPU3::stop(Camera *camera) int PipelineHandlerIPU3::queueRequestDevice(Camera *camera, Request *request) { IPU3CameraData *data = cameraData(camera); - FrameBuffer *buffer; int error = 0; - /* Get a CIO2 buffer, associate it with the request and queue it. */ - buffer = data->cio2_.getBuffer(); - if (!buffer) - return -EINVAL; - - buffer->setRequest(request); - data->cio2_.queueBuffer(buffer); + /* + * Queue a buffer on the CIO2, using the raw stream buffer provided in + * the request, if any, or a CIO2 internal buffer otherwise. + */ + FrameBuffer *rawBuffer = request->findBuffer(&data->rawStream_); + error = data->cio2_.queueBuffer(request, rawBuffer); + if (error) + return error; + /* Queue all buffers from the request aimed for the ImgU. */ for (auto it : request->buffers()) { IPU3Stream *stream = static_cast<IPU3Stream *>(it.first); - buffer = it.second; - - /* Skip raw streams, they are copied from the CIO2 buffer. */ if (stream->raw_) continue; + FrameBuffer *buffer = it.second; int ret = stream->device_->dev->queueBuffer(buffer); if (ret < 0) error = ret; @@ -885,8 +883,8 @@ int PipelineHandlerIPU3::registerCameras() */ data->cio2_.bufferReady.connect(data.get(), &IPU3CameraData::cio2BufferReady); - data->imgu_->input_->bufferReady.connect(data.get(), - &IPU3CameraData::imguInputBufferReady); + data->imgu_->input_->bufferReady.connect(&data->cio2_, + &CIO2Device::tryReturnBuffer); data->imgu_->output_.dev->bufferReady.connect(data.get(), &IPU3CameraData::imguOutputBufferReady); data->imgu_->viewfinder_.dev->bufferReady.connect(data.get(), @@ -916,22 +914,6 @@ int PipelineHandlerIPU3::registerCameras() */ /** - * \brief Handle buffers completion at the ImgU input - * \param[in] buffer The completed buffer - * - * Buffers completed from the ImgU input are immediately queued back to the - * CIO2 unit to continue frame capture. - */ -void IPU3CameraData::imguInputBufferReady(FrameBuffer *buffer) -{ - /* \todo Handle buffer failures when state is set to BufferError. */ - if (buffer->metadata().status == FrameMetadata::FrameCancelled) - return; - - cio2_.putBuffer(buffer); -} - -/** * \brief Handle buffers completion at the ImgU output * \param[in] buffer The completed buffer * @@ -963,27 +945,18 @@ void IPU3CameraData::cio2BufferReady(FrameBuffer *buffer) return; Request *request = buffer->request(); - FrameBuffer *raw = request->findBuffer(&rawStream_); - if (!raw) { - /* No RAW buffers present, just queue to IMGU. */ - imgu_->input_->queueBuffer(buffer); + /* + * If the request contains a buffer for the RAW stream only, complete it + * now as there's no need for ImgU processing. + */ + if (request->findBuffer(&rawStream_) && + pipe_->completeBuffer(camera_, request, buffer)) { + pipe_->completeRequest(camera_, request); return; } - /* RAW buffers present, special care is needed. */ - if (request->buffers().size() > 1) - imgu_->input_->queueBuffer(buffer); - - if (raw->copyFrom(buffer)) - LOG(IPU3, Debug) << "Copy of FrameBuffer failed"; - - pipe_->completeBuffer(camera_, request, raw); - - if (request->buffers().size() == 1) { - cio2_.putBuffer(buffer); - pipe_->completeRequest(camera_, request); - } + imgu_->input_->queueBuffer(buffer); } /* ----------------------------------------------------------------------------- |