libcamera: v4l2_videodevice: Signal buffer completion at streamoff time
When stopping the stream buffers have been queued, in which case their completion is never be notified to the user. This can lead to memory leaks. Fix it by notifying completion of all queued buffers with the status set to error. As a result the base PipelineHandler implementation can be simplified, as all requests complete as the result of stopping the stream. The stop() method that manually completes all queued requests isn't needed anymore. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
This commit is contained in:
parent
a2bcf6feee
commit
4e79b2ef31
10 changed files with 34 additions and 40 deletions
|
@ -51,7 +51,7 @@ private:
|
||||||
friend class PipelineHandler;
|
friend class PipelineHandler;
|
||||||
|
|
||||||
int prepare();
|
int prepare();
|
||||||
void complete(Status status);
|
void complete();
|
||||||
|
|
||||||
bool completeBuffer(Buffer *buffer);
|
bool completeBuffer(Buffer *buffer);
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ private:
|
||||||
|
|
||||||
const uint64_t cookie_;
|
const uint64_t cookie_;
|
||||||
Status status_;
|
Status status_;
|
||||||
|
bool cancelled_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace libcamera */
|
} /* namespace libcamera */
|
||||||
|
|
|
@ -74,7 +74,7 @@ public:
|
||||||
const std::set<Stream *> &streams) = 0;
|
const std::set<Stream *> &streams) = 0;
|
||||||
|
|
||||||
virtual int start(Camera *camera) = 0;
|
virtual int start(Camera *camera) = 0;
|
||||||
virtual void stop(Camera *camera);
|
virtual void stop(Camera *camera) = 0;
|
||||||
|
|
||||||
virtual int queueRequest(Camera *camera, Request *request);
|
virtual int queueRequest(Camera *camera, Request *request);
|
||||||
|
|
||||||
|
|
|
@ -711,8 +711,6 @@ void PipelineHandlerIPU3::stop(Camera *camera)
|
||||||
if (ret)
|
if (ret)
|
||||||
LOG(IPU3, Warning) << "Failed to stop camera "
|
LOG(IPU3, Warning) << "Failed to stop camera "
|
||||||
<< camera->name();
|
<< camera->name();
|
||||||
|
|
||||||
PipelineHandler::stop(camera);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request)
|
int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request)
|
||||||
|
|
|
@ -354,8 +354,6 @@ void PipelineHandlerRkISP1::stop(Camera *camera)
|
||||||
LOG(RkISP1, Warning)
|
LOG(RkISP1, Warning)
|
||||||
<< "Failed to stop camera " << camera->name();
|
<< "Failed to stop camera " << camera->name();
|
||||||
|
|
||||||
PipelineHandler::stop(camera);
|
|
||||||
|
|
||||||
activeCamera_ = nullptr;
|
activeCamera_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -220,7 +220,6 @@ void PipelineHandlerUVC::stop(Camera *camera)
|
||||||
{
|
{
|
||||||
UVCCameraData *data = cameraData(camera);
|
UVCCameraData *data = cameraData(camera);
|
||||||
data->video_->streamOff();
|
data->video_->streamOff();
|
||||||
PipelineHandler::stop(camera);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int PipelineHandlerUVC::processControls(UVCCameraData *data, Request *request)
|
int PipelineHandlerUVC::processControls(UVCCameraData *data, Request *request)
|
||||||
|
|
|
@ -222,7 +222,6 @@ void PipelineHandlerVimc::stop(Camera *camera)
|
||||||
{
|
{
|
||||||
VimcCameraData *data = cameraData(camera);
|
VimcCameraData *data = cameraData(camera);
|
||||||
data->video_->streamOff();
|
data->video_->streamOff();
|
||||||
PipelineHandler::stop(camera);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int PipelineHandlerVimc::processControls(VimcCameraData *data, Request *request)
|
int PipelineHandlerVimc::processControls(VimcCameraData *data, Request *request)
|
||||||
|
|
|
@ -328,31 +328,7 @@ const ControlInfoMap &PipelineHandler::controls(Camera *camera)
|
||||||
*
|
*
|
||||||
* This method stops capturing and processing requests immediately. All pending
|
* This method stops capturing and processing requests immediately. All pending
|
||||||
* requests are cancelled and complete immediately in an error state.
|
* requests are cancelled and complete immediately in an error state.
|
||||||
*
|
|
||||||
* Pipeline handlers shall override this method to stop the pipeline, ensure
|
|
||||||
* that all pending request completion signaled through completeRequest() have
|
|
||||||
* returned, and call the base implementation of the stop() method as the last
|
|
||||||
* step of their implementation. The base implementation cancels all requests
|
|
||||||
* queued but not yet complete.
|
|
||||||
*/
|
*/
|
||||||
void PipelineHandler::stop(Camera *camera)
|
|
||||||
{
|
|
||||||
CameraData *data = cameraData(camera);
|
|
||||||
|
|
||||||
while (!data->queuedRequests_.empty()) {
|
|
||||||
Request *request = data->queuedRequests_.front();
|
|
||||||
data->queuedRequests_.pop_front();
|
|
||||||
|
|
||||||
while (!request->pending_.empty()) {
|
|
||||||
Buffer *buffer = *request->pending_.begin();
|
|
||||||
buffer->cancel();
|
|
||||||
completeBuffer(camera, request, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
request->complete(Request::RequestCancelled);
|
|
||||||
camera->requestComplete(request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \fn PipelineHandler::queueRequest()
|
* \fn PipelineHandler::queueRequest()
|
||||||
|
@ -420,15 +396,16 @@ bool PipelineHandler::completeBuffer(Camera *camera, Request *request,
|
||||||
*/
|
*/
|
||||||
void PipelineHandler::completeRequest(Camera *camera, Request *request)
|
void PipelineHandler::completeRequest(Camera *camera, Request *request)
|
||||||
{
|
{
|
||||||
request->complete(Request::RequestComplete);
|
request->complete();
|
||||||
|
|
||||||
CameraData *data = cameraData(camera);
|
CameraData *data = cameraData(camera);
|
||||||
|
|
||||||
while (!data->queuedRequests_.empty()) {
|
while (!data->queuedRequests_.empty()) {
|
||||||
request = data->queuedRequests_.front();
|
request = data->queuedRequests_.front();
|
||||||
if (request->hasPendingBuffers())
|
if (request->status() == Request::RequestPending)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
ASSERT(!request->hasPendingBuffers());
|
||||||
data->queuedRequests_.pop_front();
|
data->queuedRequests_.pop_front();
|
||||||
camera->requestComplete(request);
|
camera->requestComplete(request);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ LOG_DEFINE_CATEGORY(Request)
|
||||||
*/
|
*/
|
||||||
Request::Request(Camera *camera, uint64_t cookie)
|
Request::Request(Camera *camera, uint64_t cookie)
|
||||||
: camera_(camera), controls_(camera), cookie_(cookie),
|
: camera_(camera), controls_(camera), cookie_(cookie),
|
||||||
status_(RequestPending)
|
status_(RequestPending), cancelled_(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,14 +199,15 @@ int Request::prepare()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Complete a queued request
|
* \brief Complete a queued request
|
||||||
* \param[in] status The request completion status
|
|
||||||
*
|
*
|
||||||
* Mark the request as complete by updating its status to \a status.
|
* 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(Status status)
|
void Request::complete()
|
||||||
{
|
{
|
||||||
ASSERT(!hasPendingBuffers());
|
ASSERT(!hasPendingBuffers());
|
||||||
status_ = status;
|
status_ = cancelled_ ? RequestCancelled : RequestComplete;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -229,6 +230,9 @@ bool Request::completeBuffer(Buffer *buffer)
|
||||||
|
|
||||||
buffer->setRequest(nullptr);
|
buffer->setRequest(nullptr);
|
||||||
|
|
||||||
|
if (buffer->status() == Buffer::BufferCancelled)
|
||||||
|
cancelled_ = true;
|
||||||
|
|
||||||
return !hasPendingBuffers();
|
return !hasPendingBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1089,7 +1089,9 @@ int V4L2VideoDevice::streamOn()
|
||||||
* \brief Stop the video stream
|
* \brief Stop the video stream
|
||||||
*
|
*
|
||||||
* Buffers that are still queued when the video stream is stopped are
|
* Buffers that are still queued when the video stream is stopped are
|
||||||
* implicitly dequeued, but no bufferReady signal is emitted for them.
|
* immediately dequeued with their status set to Buffer::BufferError,
|
||||||
|
* and the bufferReady signal is emitted for them. The order in which those
|
||||||
|
* buffers are dequeued is not specified.
|
||||||
*
|
*
|
||||||
* \return 0 on success or a negative error code otherwise
|
* \return 0 on success or a negative error code otherwise
|
||||||
*/
|
*/
|
||||||
|
@ -1104,6 +1106,16 @@ int V4L2VideoDevice::streamOff()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Send back all queued buffers. */
|
||||||
|
for (auto it : queuedBuffers_) {
|
||||||
|
unsigned int index = it.first;
|
||||||
|
Buffer *buffer = it.second;
|
||||||
|
|
||||||
|
buffer->index_ = index;
|
||||||
|
buffer->cancel();
|
||||||
|
bufferReady.emit(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
queuedBuffers_.clear();
|
queuedBuffers_.clear();
|
||||||
fdEvent_->setEnabled(false);
|
fdEvent_->setEnabled(false);
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,9 @@ protected:
|
||||||
std::cout << "Received capture buffer: " << buffer->index()
|
std::cout << "Received capture buffer: " << buffer->index()
|
||||||
<< " sequence " << buffer->sequence() << std::endl;
|
<< " sequence " << buffer->sequence() << std::endl;
|
||||||
|
|
||||||
|
if (buffer->status() != Buffer::BufferSuccess)
|
||||||
|
return;
|
||||||
|
|
||||||
output_->queueBuffer(buffer);
|
output_->queueBuffer(buffer);
|
||||||
framesCaptured_++;
|
framesCaptured_++;
|
||||||
}
|
}
|
||||||
|
@ -104,6 +107,9 @@ protected:
|
||||||
std::cout << "Received output buffer: " << buffer->index()
|
std::cout << "Received output buffer: " << buffer->index()
|
||||||
<< " sequence " << buffer->sequence() << std::endl;
|
<< " sequence " << buffer->sequence() << std::endl;
|
||||||
|
|
||||||
|
if (buffer->status() != Buffer::BufferSuccess)
|
||||||
|
return;
|
||||||
|
|
||||||
capture_->queueBuffer(buffer);
|
capture_->queueBuffer(buffer);
|
||||||
framesOutput_++;
|
framesOutput_++;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue