Files
external_libcamera/src/libcamera/request.cpp
Jacopo Mondi bc6440792b libcamera: Improve Request life cycle tracking
The current logging to track the status of a Request when running the
Android camera HAL provide the following information:

When a Request is queued to libcamera:
HAL camera_device.cpp:1776 '\_SB_.PCI0.I2C2.CAM0': Queueing Request to libcamera with 1 HAL streams

When a Request completes:
Request request.cpp:268 Request has completed - cookie: 138508601719648

The queueing of a Request reports the number of streams it contains
while the completion of a Request reports the address of the associated
cookie.

This makes very hard to keep track of what Requests have completed, as
the logging associated with a queue/complete event does not allow to identify
a Request easily.

Add two more printouts to make it easier to track a Request life cycle.
To make it possible to print the Request cookie in the CameraDevice
class add a method to access it from the CameraRequest class.

The result looks like the following trace:

Request request.cpp:92 Created request - cookie: 140701719392768
HAL camera_device.cpp:1710 '\_SB_.PCI0.I2C2.CAM0': Queueing request 140701719392768 with 1 streams
HAL camera_device.cpp:1747 '\_SB_.PCI0.I2C2.CAM0': 0 - (4160x3104)[0x00000023] -> (4160x3104)[NV12] (direct)
...
Request request.cpp:268 Request has completed - cookie: 140701719392768
HAL camera_device.cpp:1800 '\_SB_.PCI0.I2C2.CAM0': Request 140701719392768 completed with 1 streams..

Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
2021-02-02 18:50:03 +01:00

304 lines
8.4 KiB
C++

/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2019, Google Inc.
*
* request.cpp - Capture request handling
*/
#include <libcamera/request.h>
#include <map>
#include <libcamera/buffer.h>
#include <libcamera/camera.h>
#include <libcamera/control_ids.h>
#include <libcamera/stream.h>
#include "libcamera/internal/camera_controls.h"
#include "libcamera/internal/log.h"
#include "libcamera/internal/tracepoints.h"
/**
* \file request.h
* \brief Describes a frame capture request to be processed by a camera
*/
namespace libcamera {
LOG_DEFINE_CATEGORY(Request)
/**
* \enum Request::Status
* Request completion status
* \var Request::RequestPending
* The request hasn't completed yet
* \var Request::RequestComplete
* The request has completed
* \var Request::RequestCancelled
* The request has been cancelled due to capture stop
*/
/**
* \enum Request::ReuseFlag
* Flags to control the behavior of Request::reuse()
* \var Request::Default
* Don't reuse buffers
* \var Request::ReuseBuffers
* Reuse the buffers that were previously added by addBuffer()
*/
/**
* \typedef Request::BufferMap
* \brief A map of Stream to FrameBuffer pointers
*/
/**
* \class Request
* \brief A frame capture request
*
* A Request allows an application to associate buffers and controls on a
* per-frame basis to be queued to the camera device for processing.
*/
/**
* \brief Create a capture request for a camera
* \param[in] camera The camera that creates the request
* \param[in] cookie Opaque cookie for application use
*
* The \a cookie is stored in the request and is accessible through the
* cookie() method at any time. It is typically used by applications to map the
* request to an external resource in the request completion handler, and is
* completely opaque to libcamera.
*
*/
Request::Request(Camera *camera, uint64_t cookie)
: camera_(camera), cookie_(cookie), status_(RequestPending),
cancelled_(false)
{
/**
* \todo Should the Camera expose a validator instance, to avoid
* creating a new instance for each request?
*/
validator_ = new CameraControlValidator(camera);
controls_ = new ControlList(controls::controls, validator_);
/**
* \todo: Add a validator for metadata controls.
*/
metadata_ = new ControlList(controls::controls);
LIBCAMERA_TRACEPOINT(request_construct, this);
LOG(Request, Debug) << "Created request - cookie: " << cookie_;
}
Request::~Request()
{
LIBCAMERA_TRACEPOINT(request_destroy, this);
delete metadata_;
delete controls_;
delete validator_;
}
/**
* \brief Reset the request for reuse
* \param[in] flags Indicate whether or not to reuse the buffers
*
* Reset the status and controls associated with the request, to allow it to
* be reused and requeued without destruction. This function shall be called
* prior to queueing the request to the camera, in lieu of constructing a new
* request. The application can reuse the buffers that were previously added
* to the request via addBuffer() by setting \a flags to ReuseBuffers.
*/
void Request::reuse(ReuseFlag flags)
{
LIBCAMERA_TRACEPOINT(request_reuse, this);
pending_.clear();
if (flags & ReuseBuffers) {
for (auto pair : bufferMap_) {
pair.second->request_ = this;
pending_.insert(pair.second);
}
} else {
bufferMap_.clear();
}
status_ = RequestPending;
cancelled_ = false;
controls_->clear();
metadata_->clear();
}
/**
* \fn Request::controls()
* \brief Retrieve the request's ControlList
*
* Requests store a list of controls to be applied to all frames captured for
* the request. They are created with an empty list of controls that can be
* accessed through this method and updated with ControlList::operator[]() or
* ControlList::update().
*
* Only controls supported by the camera to which this request will be
* submitted shall be included in the controls list. Attempting to add an
* unsupported control causes undefined behaviour.
*
* \return A reference to the ControlList in this request
*/
/**
* \fn Request::buffers()
* \brief Retrieve the request's streams to buffers map
*
* Return a reference to the map that associates each Stream part of the
* request to the FrameBuffer the Stream output should be directed to.
*
* \return The map of Stream to FrameBuffer
*/
/**
* \brief Add a FrameBuffer with its associated Stream to the Request
* \param[in] stream The stream the buffer belongs to
* \param[in] buffer The FrameBuffer to add to the request
*
* A reference to the buffer is stored in the request. The caller is responsible
* for ensuring that the buffer will remain valid until the request complete
* callback is called.
*
* A request can only contain one buffer per stream. If a buffer has already
* been added to the request for the same stream, this method returns -EEXIST.
*
* \return 0 on success or a negative error code otherwise
* \retval -EEXIST The request already contains a buffer for the stream
* \retval -EINVAL The buffer does not reference a valid Stream
*/
int Request::addBuffer(const Stream *stream, FrameBuffer *buffer)
{
if (!stream) {
LOG(Request, Error) << "Invalid stream reference";
return -EINVAL;
}
auto it = bufferMap_.find(stream);
if (it != bufferMap_.end()) {
LOG(Request, Error) << "FrameBuffer already set for stream";
return -EEXIST;
}
buffer->request_ = this;
pending_.insert(buffer);
bufferMap_[stream] = buffer;
return 0;
}
/**
* \var Request::bufferMap_
* \brief Mapping of streams to buffers for this request
*
* The bufferMap_ tracks the buffers associated with each stream. If a stream is
* not utilised in this request there will be no buffer for that stream in the
* map.
*/
/**
* \brief Return the buffer associated with a stream
* \param[in] stream The stream the buffer is associated to
* \return The buffer associated with the stream, or nullptr if the stream is
* not part of this request
*/
FrameBuffer *Request::findBuffer(const Stream *stream) const
{
const auto it = bufferMap_.find(stream);
if (it == bufferMap_.end())
return nullptr;
return it->second;
}
/**
* \fn Request::metadata()
* \brief Retrieve the request's metadata
* \todo Offer a read-only API towards applications while keeping a read/write
* API internally.
* \return The metadata associated with the request
*/
/**
* \fn Request::cookie()
* \brief Retrieve the cookie set when the request was created
* \return The request cookie
*/
/**
* \fn Request::status()
* \brief Retrieve the request completion status
*
* The request status indicates whether the request has completed successfully
* or with an error. When requests are created and before they complete the
* request status is set to RequestPending, and is updated at completion time
* to RequestComplete. If a request is cancelled at capture stop before it has
* completed, its status is set to RequestCancelled.
*
* \return The request completion status
*/
/**
* \fn Request::hasPendingBuffers()
* \brief Check if a request has buffers yet to be completed
*
* \return True if the request has buffers pending for completion, false
* otherwise
*/
/**
* \brief Complete a queued request
*
* Mark the request as complete by updating its status to RequestComplete,
* unless buffers have been cancelled in which case the status is set to
* RequestCancelled.
*/
void Request::complete()
{
ASSERT(!hasPendingBuffers());
status_ = cancelled_ ? RequestCancelled : RequestComplete;
LOG(Request, Debug)
<< "Request has completed - cookie: " << cookie_
<< (cancelled_ ? " [Cancelled]" : "");
LIBCAMERA_TRACEPOINT(request_complete, this);
}
/**
* \brief Complete a buffer for the request
* \param[in] buffer The buffer that has completed
*
* A request tracks the status of all buffers it contains through a set of
* pending buffers. This function removes the \a buffer from the set to mark it
* as complete. All buffers associate with the request shall be marked as
* complete by calling this function once and once only before reporting the
* request as complete with the complete() method.
*
* \return True if all buffers contained in the request have completed, false
* otherwise
*/
bool Request::completeBuffer(FrameBuffer *buffer)
{
LIBCAMERA_TRACEPOINT(request_complete_buffer, this, buffer);
int ret = pending_.erase(buffer);
ASSERT(ret == 1);
buffer->request_ = nullptr;
if (buffer->metadata().status == FrameMetadata::FrameCancelled)
cancelled_ = true;
return !hasPendingBuffers();
}
} /* namespace libcamera */