android: post_processor: Make post processing async

Introduce a dedicated worker class derived from libcamera::Thread.
The worker class maintains a queue for post-processing requests
and waits for a post-processing request to become available.
It will process them as per FIFO before de-queuing it from the
queue.

The entire post-processing handling iteration is locked under
streamsProcessMutex_ which helps us to queue all the post-processing
request at once, before any of the post-processing completion slot
(streamProcessingComplete()) is allowed to run for post-processing
requests completing in parallel. This helps us to manage both
synchronous and asynchronous errors encountered during the entire
post processing operation. Since a post-processing operation can
even complete after CameraDevice::requestComplete() has returned,
we need to check and complete the descriptor from
streamProcessingComplete() running in the PostProcessorWorker's
thread.

This patch also implements a flush() for the PostProcessorWorker
class which is responsible to purge post-processing requests
queued up while a camera is stopping/flushing. It is hooked with
CameraStream::flush(), which isn't used currently but will be
used when we handle flush/stop scenarios in greater detail
subsequently (in a different patchset).

The libcamera request completion handler CameraDevice::requestComplete()
assumes that the request that has just completed is at the front of the
queue. Now that the post-processor runs asynchronously, this isn't true
anymore, a request being post-processed will stay in the queue and a new
libcamera request may complete. Remove that assumption, and use the
request cookie to obtain the Camera3RequestDescriptor.

Signed-off-by: Umang Jain <umang.jain@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Hirokazu Honda <hiroh@chromium.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
Umang Jain 2021-10-26 12:51:48 +05:30
parent 05862a7e35
commit b1cefe38f3
3 changed files with 153 additions and 34 deletions

View file

@ -99,6 +99,7 @@ int CameraStream::configure()
if (ret)
return ret;
worker_ = std::make_unique<PostProcessorWorker>(postProcessor_.get());
postProcessor_->processComplete.connect(
this, [&](Camera3RequestDescriptor::StreamBuffer *streamBuffer,
PostProcessor::Status status) {
@ -112,6 +113,8 @@ int CameraStream::configure()
cameraDevice_->streamProcessingComplete(streamBuffer,
bufferStatus);
});
worker_->start();
}
if (type_ == Type::Internal) {
@ -178,10 +181,6 @@ int CameraStream::process(Camera3RequestDescriptor::StreamBuffer *streamBuffer)
streamBuffer->fence = -1;
}
/*
* \todo Buffer mapping and processing should be moved to a
* separate thread.
*/
const StreamConfiguration &output = configuration();
streamBuffer->dstBuffer = std::make_unique<CameraBuffer>(
*streamBuffer->camera3Buffer, output.pixelFormat, output.size,
@ -191,11 +190,19 @@ int CameraStream::process(Camera3RequestDescriptor::StreamBuffer *streamBuffer)
return -EINVAL;
}
postProcessor_->process(streamBuffer);
worker_->queueRequest(streamBuffer);
return 0;
}
void CameraStream::flush()
{
if (!postProcessor_)
return;
worker_->flush();
}
FrameBuffer *CameraStream::getBuffer()
{
if (!allocator_)
@ -223,3 +230,87 @@ void CameraStream::putBuffer(FrameBuffer *buffer)
buffers_.push_back(buffer);
}
CameraStream::PostProcessorWorker::PostProcessorWorker(PostProcessor *postProcessor)
: postProcessor_(postProcessor)
{
}
CameraStream::PostProcessorWorker::~PostProcessorWorker()
{
{
libcamera::MutexLocker lock(mutex_);
state_ = State::Stopped;
}
cv_.notify_one();
wait();
}
void CameraStream::PostProcessorWorker::start()
{
{
libcamera::MutexLocker lock(mutex_);
ASSERT(state_ != State::Running);
state_ = State::Running;
}
Thread::start();
}
void CameraStream::PostProcessorWorker::queueRequest(Camera3RequestDescriptor::StreamBuffer *dest)
{
{
MutexLocker lock(mutex_);
ASSERT(state_ == State::Running);
requests_.push(dest);
}
cv_.notify_one();
}
void CameraStream::PostProcessorWorker::run()
{
MutexLocker locker(mutex_);
while (1) {
cv_.wait(locker, [&] {
return state_ != State::Running || !requests_.empty();
});
if (state_ != State::Running)
break;
Camera3RequestDescriptor::StreamBuffer *streamBuffer = requests_.front();
requests_.pop();
locker.unlock();
postProcessor_->process(streamBuffer);
locker.lock();
}
if (state_ == State::Flushing) {
std::queue<Camera3RequestDescriptor::StreamBuffer *> requests =
std::move(requests_);
locker.unlock();
while (!requests.empty()) {
postProcessor_->processComplete.emit(
requests.front(), PostProcessor::Status::Error);
requests.pop();
}
locker.lock();
state_ = State::Stopped;
}
}
void CameraStream::PostProcessorWorker::flush()
{
libcamera::MutexLocker lock(mutex_);
state_ = State::Flushing;
lock.unlock();
cv_.notify_one();
}