blob: 5da681d9d2f66a2eabea17e9129e65d4b6f496f5 [file] [log] [blame]
/*
* Copyright 2019 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <utility>
#include "hal/ip/request_queue.h"
#include <sync/sync.h>
#include "cros-camera/common.h"
namespace cros {
CaptureRequest::CaptureRequest(camera3_capture_request_t* request)
: frame_number_(request->frame_number) {
output_stream_buffer_.stream = request->output_buffers[0].stream;
buffer_handle_ = *(request->output_buffers[0].buffer);
output_stream_buffer_.buffer = &buffer_handle_;
output_stream_buffer_.status = CAMERA3_BUFFER_STATUS_OK;
output_stream_buffer_.acquire_fence =
request->output_buffers[0].acquire_fence;
output_stream_buffer_.release_fence = -1;
}
CaptureRequest::~CaptureRequest() {}
const uint32_t CaptureRequest::GetFrameNumber() const {
return frame_number_;
}
const camera3_stream_buffer_t* CaptureRequest::GetOutputBuffer() const {
return &output_stream_buffer_;
}
void CaptureRequest::SetErrorBufferStatus() {
output_stream_buffer_.release_fence = output_stream_buffer_.acquire_fence;
output_stream_buffer_.status = CAMERA3_BUFFER_STATUS_ERROR;
}
RequestQueue::RequestQueue()
: lock_(),
queue_(),
new_request_available_(&lock_),
request_filled_(&lock_),
requests_being_filled_(0),
flushing_(false),
callback_ops_(nullptr) {}
RequestQueue::~RequestQueue() {
base::AutoLock l(lock_);
queue_.clear();
}
void RequestQueue::Push(camera3_capture_request_t* request) {
base::AutoLock l(lock_);
if (flushing_) {
CancelRequestLocked(std::make_unique<CaptureRequest>(request));
} else {
queue_.push_back(std::make_unique<CaptureRequest>(request));
new_request_available_.Signal();
}
}
std::unique_ptr<CaptureRequest> RequestQueue::Pop() {
std::unique_ptr<CaptureRequest> request = nullptr;
{
base::AutoLock l(lock_);
if (flushing_) {
return nullptr;
}
while (queue_.empty()) {
new_request_available_.Wait();
}
request = std::move(queue_.front());
requests_being_filled_++;
queue_.pop_front();
}
const camera3_stream_buffer_t* buffer = request->GetOutputBuffer();
if (buffer->acquire_fence != -1) {
if (sync_wait(buffer->acquire_fence, 300)) {
LOGF(ERROR) << "Timed out waiting on camera buffer acquire fence";
}
}
struct timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
uint64_t timestamp = time.tv_sec * 1000000000LL + time.tv_nsec;
NotifyShutter(request->GetFrameNumber(), timestamp);
return request;
}
bool RequestQueue::IsEmpty() {
base::AutoLock l(lock_);
return queue_.empty();
}
void RequestQueue::Flush() {
base::AutoLock l(lock_);
flushing_ = true;
while (requests_being_filled_ > 0) {
request_filled_.Wait();
}
while (!queue_.empty()) {
CancelRequestLocked(std::move(queue_.front()));
queue_.pop_front();
}
flushing_ = false;
}
void RequestQueue::SetCallbacks(const camera3_callback_ops_t* callback_ops) {
callback_ops_ = callback_ops;
}
void RequestQueue::NotifyShutter(uint32_t frame_number, uint64_t timestamp) {
if (!callback_ops_) {
LOGF(ERROR) << "Callbacks weren't set on the request queue.";
return;
}
camera3_notify_msg_t msg = {};
msg.type = CAMERA3_MSG_SHUTTER;
msg.message.shutter.frame_number = frame_number;
msg.message.shutter.timestamp = timestamp;
callback_ops_->notify(callback_ops_, &msg);
}
void RequestQueue::NotifyCaptureInternal(
std::unique_ptr<CaptureRequest> request) {
if (!callback_ops_) {
LOGF(ERROR) << "Callbacks weren't set on the request queue.";
return;
}
camera3_capture_result_t result = {};
result.frame_number = request->GetFrameNumber();
result.result = nullptr;
result.num_output_buffers = 1;
result.output_buffers = request->GetOutputBuffer();
result.partial_result = 1;
callback_ops_->process_capture_result(callback_ops_, &result);
// request goes out of scope and gets deleted at the end of this function
}
void RequestQueue::NotifyCapture(std::unique_ptr<CaptureRequest> request) {
NotifyCaptureInternal(std::move(request));
base::AutoLock l(lock_);
requests_being_filled_--;
request_filled_.Signal();
}
void RequestQueue::CancelRequestLocked(
std::unique_ptr<CaptureRequest> request) {
if (!callback_ops_) {
LOGF(ERROR) << "Callbacks weren't set on the request queue.";
return;
}
camera3_notify_msg_t msg = {};
msg.type = CAMERA3_MSG_ERROR;
msg.message.error.frame_number = request->GetFrameNumber();
msg.message.error.error_stream = nullptr;
msg.message.error.error_code = CAMERA3_MSG_ERROR_REQUEST;
callback_ops_->notify(callback_ops_, &msg);
request->SetErrorBufferStatus();
NotifyCaptureInternal(std::move(request));
}
void RequestQueue::NotifyError(std::unique_ptr<CaptureRequest> request) {
base::AutoLock l(lock_);
CancelRequestLocked(std::move(request));
requests_being_filled_--;
request_filled_.Signal();
}
} // namespace cros