blob: 20e36133cc50f1e9e7085ee3e5f136e38fec9824 [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 "hal_adapter/zsl_helper.h"
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <utility>
#include <vector>
#include <base/bind.h>
#include <base/check.h>
#include <base/check_op.h>
#include <base/numerics/safe_conversions.h>
#include <base/optional.h>
#include <camera/camera_metadata.h>
#include <sync/sync.h>
#include <system/camera_metadata.h>
#include "cros-camera/common.h"
#include "cros-camera/constants.h"
#include "cros-camera/utils/camera_config.h"
namespace {
static constexpr int64_t kOverrideCurrentTimestampNotSet = -1;
bool IsInputStream(camera3_stream_t* stream) {
return stream->stream_type == CAMERA3_STREAM_INPUT ||
stream->stream_type == CAMERA3_STREAM_BIDIRECTIONAL;
}
bool IsOutputStream(camera3_stream_t* stream) {
return stream->stream_type == CAMERA3_STREAM_OUTPUT ||
stream->stream_type == CAMERA3_STREAM_BIDIRECTIONAL;
}
int64_t GetTimestamp(const android::CameraMetadata& android_metadata) {
camera_metadata_ro_entry_t entry;
if (android_metadata.exists(ANDROID_SENSOR_TIMESTAMP)) {
entry = android_metadata.find(ANDROID_SENSOR_TIMESTAMP);
return entry.data.i64[0];
}
LOGF(ERROR) << "Cannot find sensor timestamp in ZSL buffer";
return static_cast<int64_t>(-1);
}
} // namespace
namespace cros {
ZslBuffer::ZslBuffer()
: metadata_ready(false), buffer_ready(false), selected(false) {}
ZslBuffer::ZslBuffer(uint32_t frame_number,
const camera3_stream_buffer_t& buffer)
: frame_number(frame_number),
buffer(buffer),
metadata_ready(false),
buffer_ready(false),
selected(false) {}
ZslBufferManager::ZslBufferManager()
: initialized_(false), buffer_manager_(nullptr) {}
ZslBufferManager::~ZslBufferManager() {
Reset();
}
bool ZslBufferManager::Initialize(size_t pool_size,
const camera3_stream_t* output_stream) {
DCHECK(buffer_pool_.empty());
// |buffer_manager_| could be set by SetCameraBufferManagerForTesting().
if (!buffer_manager_) {
buffer_manager_ = CameraBufferManager::GetInstance();
}
bool success = true;
output_stream_ = output_stream;
{
base::AutoLock l(buffer_pool_lock_);
buffer_pool_.reserve(pool_size);
for (size_t i = 0; i < pool_size; ++i) {
uint32_t stride;
buffer_handle_t buffer;
if (buffer_manager_->Allocate(
output_stream_->width, output_stream_->height,
ZslHelper::kZslPixelFormat,
GRALLOC_USAGE_HW_CAMERA_ZSL | GRALLOC_USAGE_SW_READ_OFTEN |
GRALLOC_USAGE_SW_WRITE_OFTEN,
&buffer, &stride) != 0) {
LOGF(ERROR) << "Failed to allocate buffer";
success = false;
break;
}
buffer_pool_.push_back(buffer);
free_buffers_.push(&buffer_pool_.back());
buffer_to_buffer_pointer_map_[buffer] = &buffer_pool_.back();
}
}
if (!success) {
Reset();
return false;
}
initialized_ = true;
return true;
}
buffer_handle_t* ZslBufferManager::GetBuffer() {
base::AutoLock buffer_pool_lock(buffer_pool_lock_);
if (!initialized_) {
LOGF(ERROR) << "ZSL buffer manager has not been initialized";
return nullptr;
}
if (free_buffers_.empty()) {
LOGF(ERROR) << "No more buffer left in the pool. This shouldn't happen";
return nullptr;
}
buffer_handle_t* buffer = free_buffers_.front();
free_buffers_.pop();
return buffer;
}
bool ZslBufferManager::ReleaseBuffer(buffer_handle_t buffer_to_release) {
base::AutoLock buffer_pool_lock(buffer_pool_lock_);
if (!initialized_) {
LOGF(ERROR) << "ZSL buffer manager has not been initialized";
return false;
}
auto it = buffer_to_buffer_pointer_map_.find(buffer_to_release);
if (it == buffer_to_buffer_pointer_map_.end()) {
LOGF(ERROR) << "The released buffer doesn't belong to ZSL buffer manager";
return false;
}
free_buffers_.push(it->second);
return true;
}
void ZslBufferManager::Reset() {
initialized_ = false;
base::AutoLock l(buffer_pool_lock_);
for (auto& buffer : buffer_pool_) {
buffer_manager_->Free(buffer);
}
buffer_pool_.clear();
free_buffers_ = {};
buffer_to_buffer_pointer_map_.clear();
}
void ZslBufferManager::SetCameraBufferManagerForTesting(
CameraBufferManager* buffer_manager) {
buffer_manager_ = buffer_manager;
}
// static
bool ZslHelper::TryAddEnableZslKey(android::CameraMetadata* metadata) {
// Determine if it's possible for us to enable our in-house ZSL solution. Note
// that we may end up not enabling it in situations where we cannot allocate
// sufficient private buffers or the camera HAL client's stream configuration
// wouldn't allow us to set up the streams we need.
if (!metadata->exists(ANDROID_REQUEST_AVAILABLE_CAPABILITIES)) {
return false;
}
const auto cap_entry = metadata->find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
if (std::find(cap_entry.data.u8, cap_entry.data.u8 + cap_entry.count,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING) ==
cap_entry.data.u8 + cap_entry.count) {
return false;
}
// See if the camera HAL already supports ZSL.
if (!metadata->exists(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS)) {
return false;
}
auto entry = metadata->find(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS);
if (std::find(entry.data.i32, entry.data.i32 + entry.count,
ANDROID_CONTROL_ENABLE_ZSL) != entry.data.i32 + entry.count) {
LOGF(INFO) << "Device supports vendor-provided ZSL";
return false;
}
std::vector<int32_t> new_request_keys{entry.data.i32,
entry.data.i32 + entry.count};
new_request_keys.push_back(ANDROID_CONTROL_ENABLE_ZSL);
if (metadata->update(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,
new_request_keys.data(), new_request_keys.size()) != 0) {
LOGF(ERROR) << "Failed to add ANDROID_CONTROL_ENABLE_ZSL to metadata";
return false;
}
LOGF(INFO) << "Added ANDROID_CONTROL_ENABLE_ZSL to static metadata";
return true;
}
ZslHelper::ZslHelper(const camera_metadata_t* static_info)
: zsl_buffer_manager_(new ZslBufferManager),
fence_sync_thread_("FenceSyncThread"),
override_current_timestamp_for_testing_(kOverrideCurrentTimestampNotSet) {
VLOGF_ENTER();
if (!IsCapabilitySupported(
static_info,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING)) {
LOGF(INFO) << "Private reprocessing not supported, ZSL won't be enabled";
return;
}
uint32_t bi_width, bi_height;
if (!SelectZslStreamSize(static_info, &bi_width, &bi_height,
&bi_stream_min_frame_duration_)) {
LOGF(ERROR) << "Failed to select stream sizes for ZSL.";
return;
}
LOGF(INFO) << "Selected ZSL stream size = " << bi_width << "x" << bi_height;
// Create ZSL streams
bi_stream_ = std::make_unique<camera3_stream_t>();
bi_stream_->stream_type = CAMERA3_STREAM_BIDIRECTIONAL;
bi_stream_->width = bi_width;
bi_stream_->height = bi_height;
bi_stream_->format = kZslPixelFormat;
if (!fence_sync_thread_.Start()) {
LOGF(ERROR) << "Fence sync thread failed to start";
}
partial_result_count_ = [&]() {
camera_metadata_ro_entry entry;
if (find_camera_metadata_ro_entry(
static_info, ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry) != 0) {
return 1;
}
return entry.data.i32[0];
}();
max_num_input_streams_ = [&]() {
camera_metadata_ro_entry_t entry;
if (find_camera_metadata_ro_entry(
static_info, ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS, &entry) != 0) {
LOGF(ERROR) << "Failed to get maximum number of input streams.";
return 0;
}
return entry.data.i32[0];
}();
timestamp_source_ = [&]() {
camera_metadata_ro_entry_t entry;
if (find_camera_metadata_ro_entry(
static_info, ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE, &entry) != 0) {
LOGF(ERROR) << "Failed to get timestamp source. Assuming it's UNKNOWN.";
return ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;
}
return static_cast<
camera_metadata_enum_android_sensor_info_timestamp_source_t>(
entry.data.u8[0]);
}();
auto camera_config =
cros::CameraConfig::Create(cros::constants::kCrosCameraConfigPathString);
// We're casting an int to int64_t here. Make sure the configured time doesn't
// overflow (roughly 2.1s).
zsl_lookback_ns_ = base::strict_cast<int64_t>(camera_config->GetInteger(
cros::constants::kCrosZslLookback,
base::checked_cast<int>(kZslDefaultLookbackNs)));
LOGF(INFO) << "Configured ZSL lookback time = " << zsl_lookback_ns_;
}
ZslHelper::~ZslHelper() {
fence_sync_thread_.Stop();
}
bool ZslHelper::AttachZslStream(camera3_stream_configuration_t* stream_list,
std::vector<camera3_stream_t*>* streams) {
if (!CanEnableZsl(streams)) {
return false;
}
stream_list->num_streams++;
streams->push_back(bi_stream_.get());
// There could be memory reallocation happening after the push_back call.
stream_list->streams = streams->data();
VLOGF(1) << "Attached ZSL streams. The list of streams after attaching:";
for (size_t i = 0; i < stream_list->num_streams; ++i) {
VLOGF(1) << "i = " << i
<< ", type = " << stream_list->streams[i]->stream_type
<< ", size = " << stream_list->streams[i]->width << "x"
<< stream_list->streams[i]->height
<< ", format = " << stream_list->streams[i]->format;
}
return true;
}
bool ZslHelper::Initialize(const camera3_stream_configuration_t* stream_list) {
auto GetStillCaptureMaxBuffers =
[&](const camera3_stream_configuration_t* stream_list) {
uint32_t max_buffers = 0;
for (size_t i = 0; i < stream_list->num_streams; ++i) {
auto* stream = stream_list->streams[i];
if (!IsOutputStream(stream)) {
continue;
}
// If our private usage flag is specified, we know only this stream
// will be used for ZSL capture.
if (stream->usage & cros::GRALLOC_USAGE_STILL_CAPTURE) {
return stream->max_buffers;
} else if (stream->format == HAL_PIXEL_FORMAT_BLOB) {
max_buffers += stream->max_buffers;
}
}
return max_buffers;
};
base::AutoLock ring_buffer_lock(ring_buffer_lock_);
// First, clear all the buffers and states.
ring_buffer_.clear();
zsl_buffer_manager_->Reset();
// Determine at most how many buffers would be selected for private
// reprocessing simultaneously.
bi_stream_max_buffers_ = 0;
for (uint32_t i = 0; i < stream_list->num_streams; i++) {
auto* stream = stream_list->streams[i];
if (stream == bi_stream_.get()) {
bi_stream_max_buffers_ = stream->max_buffers;
break;
}
}
if (bi_stream_max_buffers_ == 0) {
LOGF(ERROR) << "Failed to acquire max_buffers for the private stream";
return false;
}
VLOGF(1) << "Max buffers for private stream = " << bi_stream_max_buffers_;
// Determine at most how many still capture buffers would be in-flight.
uint32_t still_max_buffers = GetStillCaptureMaxBuffers(stream_list);
if (still_max_buffers == 0) {
LOGF(ERROR) << "Failed to acquire max_buffers for the still capture stream";
return false;
}
VLOGF(1) << "Max buffers for still capture streams = " << still_max_buffers;
// We look back at most
// ceil(|zsl_lookback_ns_| / |bi_stream_min_frame_duration_| frames, and there
// will be at most |bi_stream_max_buffers_| being processed. We also need to
// have |still_max_buffers| additional buffers in the buffer pool.
if (!zsl_buffer_manager_->Initialize(
static_cast<size_t>(std::ceil(static_cast<double>(zsl_lookback_ns_) /
bi_stream_min_frame_duration_)) +
bi_stream_max_buffers_ + still_max_buffers,
bi_stream_.get())) {
LOGF(ERROR) << "Failed to initialize ZSL buffer manager";
return false;
}
return true;
}
bool ZslHelper::CanEnableZsl(std::vector<camera3_stream_t*>* streams) {
size_t num_input_streams = 0;
bool has_still_capture_output_stream = false;
bool has_zsl_output_stream = false;
for (auto* stream : (*streams)) {
if (IsInputStream(stream)) {
num_input_streams++;
}
if (IsOutputStream(stream) &&
(stream->format == HAL_PIXEL_FORMAT_BLOB ||
(stream->usage & GRALLOC_USAGE_STILL_CAPTURE))) {
has_still_capture_output_stream = true;
}
if (IsOutputStream(stream) &&
(stream->usage & GRALLOC_USAGE_HW_CAMERA_ZSL) ==
GRALLOC_USAGE_HW_CAMERA_ZSL) {
has_zsl_output_stream = true;
}
}
return num_input_streams < max_num_input_streams_ // Has room for an extra
// input stream for ZSL.
&& has_still_capture_output_stream // Has a stream for still capture.
&& !has_zsl_output_stream; // HAL doesn't support multiple raw output
// streams.
}
bool ZslHelper::IsZslRequested(camera_metadata_t* settings) {
bool enable_zsl = [&]() {
camera_metadata_ro_entry_t entry;
if (find_camera_metadata_ro_entry(settings, ANDROID_CONTROL_ENABLE_ZSL,
&entry) == 0) {
return static_cast<bool>(entry.data.u8[0]);
}
return false;
}();
if (!enable_zsl) {
return false;
}
// We can only enable ZSL when capture intent is also still capture.
camera_metadata_ro_entry_t entry;
if (find_camera_metadata_ro_entry(settings, ANDROID_CONTROL_CAPTURE_INTENT,
&entry) == 0) {
return entry.data.u8[0] == ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE ||
entry.data.u8[0] == ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG;
}
return false;
}
bool ZslHelper::IsAttachedZslBuffer(const camera3_stream_buffer_t* buffer) {
return buffer && buffer->stream == bi_stream_.get();
}
bool ZslHelper::IsTransformedZslBuffer(const camera3_stream_buffer_t* buffer) {
return buffer && buffer->stream == bi_stream_.get();
}
void ZslHelper::TryReleaseBuffer() {
ring_buffer_lock_.AssertAcquired();
// Check if the oldest buffer is already too old to be selected. In which
// case, we can remove it from our ring buffer. If the buffer is not selected,
// we release it back to the buffer pool. If the buffer is selected, we
// release it when it returns from ProcessZslCaptureResult.
if (ring_buffer_.empty()) {
return;
}
const ZslBuffer& oldest_buffer = ring_buffer_.back();
if (oldest_buffer.selected) {
ring_buffer_.pop_back();
return;
}
if (!oldest_buffer.metadata_ready) {
return;
}
auto timestamp = GetTimestamp(oldest_buffer.metadata);
DCHECK_NE(timestamp, -1);
if (GetCurrentTimestamp() - timestamp <= zsl_lookback_ns_) {
// Buffer is too new that we should keep it. This will happen for the
// initial buffers.
return;
}
if (!zsl_buffer_manager_->ReleaseBuffer(*oldest_buffer.buffer.buffer)) {
LOGF(ERROR) << "Unable to release the oldest buffer";
return;
}
ring_buffer_.pop_back();
}
bool ZslHelper::ProcessZslCaptureRequest(
camera3_capture_request_t* request,
std::vector<camera3_stream_buffer_t>* output_buffers,
internal::ScopedCameraMetadata* settings,
SelectionStrategy strategy) {
if (request->input_buffer != nullptr) {
return false;
}
bool transformed = false;
if (IsZslRequested(settings->get())) {
transformed = TransformRequest(request, settings, strategy);
if (!transformed) {
LOGF(ERROR) << "Failed to find a suitable ZSL buffer";
}
} else {
AttachRequest(request, output_buffers);
}
return transformed;
}
void ZslHelper::AttachRequest(
camera3_capture_request_t* request,
std::vector<camera3_stream_buffer_t>* output_buffers) {
VLOGF_ENTER();
base::AutoLock l(ring_buffer_lock_);
TryReleaseBuffer();
auto* buffer = zsl_buffer_manager_->GetBuffer();
if (buffer == nullptr) {
LOGF(ERROR) << "Failed to acquire a ZSL buffer";
return;
}
// Attach our ZSL output buffer.
camera3_stream_buffer_t stream_buffer;
stream_buffer.buffer = buffer;
stream_buffer.stream = bi_stream_.get();
stream_buffer.acquire_fence = stream_buffer.release_fence = -1;
ZslBuffer zsl_buffer(request->frame_number, stream_buffer);
ring_buffer_.push_front(std::move(zsl_buffer));
output_buffers->push_back(std::move(stream_buffer));
request->num_output_buffers++;
}
bool ZslHelper::TransformRequest(camera3_capture_request_t* request,
internal::ScopedCameraMetadata* settings,
SelectionStrategy strategy) {
VLOGF_ENTER();
base::AutoLock l(ring_buffer_lock_);
auto GetJpegOrientation = [&](const camera_metadata_t* settings) {
camera_metadata_ro_entry_t entry;
if (find_camera_metadata_ro_entry(settings, ANDROID_JPEG_ORIENTATION,
&entry) != 0) {
LOGF(ERROR) << "Failed to find JPEG orientation, defaulting to 0";
return 0;
}
return *entry.data.i32;
};
// Select the best buffer.
ZslBufferIterator selected_buffer_it = SelectZslBuffer(strategy);
if (selected_buffer_it == ring_buffer_.end()) {
LOGF(WARNING) << "Unable to find a suitable ZSL buffer. Request will not "
"be transformed.";
return false;
}
LOGF(INFO) << "Transforming request into ZSL reprocessing request";
request->input_buffer = &selected_buffer_it->buffer;
request->input_buffer->stream = bi_stream_.get();
request->input_buffer->acquire_fence = -1;
request->input_buffer->release_fence = -1;
// The result metadata for the RAW buffers come from the preview frames. We
// need to add JPEG orientation back so that the resulting JPEG is of the
// correct orientation.
int32_t jpeg_orientation = GetJpegOrientation(settings->get());
if (selected_buffer_it->metadata.update(ANDROID_JPEG_ORIENTATION,
&jpeg_orientation, 1) != 0) {
LOGF(ERROR) << "Failed to update JPEG_ORIENTATION";
}
// Note that camera device adapter would take ownership of this pointer.
settings->reset(selected_buffer_it->metadata.release());
return true;
}
void ZslHelper::ProcessZslCaptureResult(
const camera3_capture_result_t* result,
const camera3_stream_buffer_t** attached_output,
const camera3_stream_buffer_t** transformed_input) {
VLOGF_ENTER();
for (size_t i = 0; i < result->num_output_buffers; ++i) {
if (IsAttachedZslBuffer(&result->output_buffers[i])) {
*attached_output = &result->output_buffers[i];
break;
}
}
if (result->input_buffer && IsTransformedZslBuffer(result->input_buffer)) {
*transformed_input = result->input_buffer;
ReleaseStreamBuffer(*result->input_buffer);
}
base::AutoLock ring_buffer_lock(ring_buffer_lock_);
auto it = std::find_if(ring_buffer_.begin(), ring_buffer_.end(),
[&](const ZslBuffer& buffer) {
return buffer.frame_number == result->frame_number;
});
if (it == ring_buffer_.end()) {
return;
}
for (size_t i = 0; i < result->num_output_buffers; ++i) {
if (result->output_buffers[i].stream == bi_stream_.get()) {
WaitAttachedFrame(result->frame_number,
result->output_buffers[i].release_fence);
break;
}
}
if (result->partial_result != 0) { // Result has metadata. Merge it.
it->metadata.append(result->result);
if (result->partial_result == partial_result_count_) {
it->metadata_ready = true;
}
}
}
void ZslHelper::WaitAttachedFrame(uint32_t frame_number, int release_fence) {
fence_sync_thread_.task_runner()->PostTask(
FROM_HERE,
base::Bind(&ZslHelper::WaitAttachedFrameOnFenceSyncThread,
base::Unretained(this), frame_number, release_fence));
}
void ZslHelper::WaitAttachedFrameOnFenceSyncThread(uint32_t frame_number,
int release_fence) {
if (release_fence != -1 &&
sync_wait(release_fence, ZslHelper::kZslSyncWaitTimeoutMs)) {
LOGF(WARNING) << "Failed to wait for release fence on attached ZSL buffer";
} else {
base::AutoLock ring_buffer_lock(ring_buffer_lock_);
auto it = std::find_if(ring_buffer_.begin(), ring_buffer_.end(),
[&](const ZslBuffer& buffer) {
return buffer.frame_number == frame_number;
});
if (it != ring_buffer_.end()) {
it->buffer_ready = true;
}
return;
}
fence_sync_thread_.task_runner()->PostTask(
FROM_HERE,
base::Bind(&ZslHelper::WaitAttachedFrameOnFenceSyncThread,
base::Unretained(this), frame_number, release_fence));
}
void ZslHelper::ReleaseStreamBuffer(camera3_stream_buffer_t buffer) {
fence_sync_thread_.task_runner()->PostTask(
FROM_HERE, base::Bind(&ZslHelper::ReleaseStreamBufferOnFenceSyncThread,
base::Unretained(this), base::Passed(&buffer)));
}
void ZslHelper::ReleaseStreamBufferOnFenceSyncThread(
camera3_stream_buffer_t buffer) {
if (buffer.release_fence != -1 &&
sync_wait(buffer.release_fence, ZslHelper::kZslSyncWaitTimeoutMs)) {
LOGF(WARNING) << "Failed to wait for release fence on ZSL input buffer";
} else {
if (!zsl_buffer_manager_->ReleaseBuffer(*buffer.buffer)) {
LOGF(ERROR) << "Failed to release this stream buffer";
}
// The above error should only happen when the mapping in buffer manager
// becomes invalid somwhow. It's not recoverable, so we don't retry here.
return;
}
fence_sync_thread_.task_runner()->PostTask(
FROM_HERE, base::Bind(&ZslHelper::ReleaseStreamBufferOnFenceSyncThread,
base::Unretained(this), base::Passed(&buffer)));
}
bool ZslHelper::IsCapabilitySupported(const camera_metadata_t* static_info,
uint8_t capability) {
camera_metadata_ro_entry_t entry;
if (find_camera_metadata_ro_entry(
static_info, ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry) == 0) {
return std::find(entry.data.u8, entry.data.u8 + entry.count, capability) !=
entry.data.u8 + entry.count;
}
return false;
}
bool ZslHelper::SelectZslStreamSize(const camera_metadata_t* static_info,
uint32_t* bi_width,
uint32_t* bi_height,
int64_t* min_frame_duration) {
VLOGF_ENTER();
*bi_width = 0;
*bi_height = 0;
camera_metadata_ro_entry entry;
if (find_camera_metadata_ro_entry(
static_info, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
&entry) != 0) {
LOGF(ERROR) << "Failed to find stream configurations map";
return false;
}
VLOGF(1) << "Iterating stream configuration map for ZSL streams";
for (size_t i = 0; i < entry.count; i += 4) {
const int32_t& format = entry.data.i32[i + STREAM_CONFIG_FORMAT_INDEX];
if (format != kZslPixelFormat)
continue;
const int32_t& width = entry.data.i32[i + STREAM_CONFIG_WIDTH_INDEX];
const int32_t& height = entry.data.i32[i + STREAM_CONFIG_HEIGHT_INDEX];
const int32_t& direction =
entry.data.i32[i + STREAM_CONFIG_DIRECTION_INDEX];
VLOGF(1) << "format = " << format << ", "
<< "width = " << width << ", "
<< "height = " << height << ", "
<< "direction = " << direction;
if (direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT) {
if (width * height > (*bi_width) * (*bi_height)) {
*bi_width = width;
*bi_height = height;
}
}
}
if (*bi_width == 0 || *bi_height == 0) {
LOGF(ERROR) << "Failed to select ZSL stream size";
return false;
}
*min_frame_duration = 0;
if (find_camera_metadata_ro_entry(
static_info, ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS, &entry) !=
0) {
LOGF(ERROR) << "Failed to find the minimum frame durations";
return false;
}
for (size_t i = 0; i < entry.count; i += 4) {
const int64_t& format = entry.data.i64[i + FRAME_DURATION_FOMRAT_INDEX];
const int64_t& width = entry.data.i64[i + FRAME_DURATION_WIDTH_INDEX];
const int64_t& height = entry.data.i64[i + FRAME_DURATION_HEIGHT_INDEX];
const int64_t& duration = entry.data.i64[i + FRAME_DURATION_DURATION_INDEX];
if (format == kZslPixelFormat && width == *bi_width &&
height == *bi_height) {
*min_frame_duration = duration;
break;
}
}
if (*min_frame_duration == 0) {
LOGF(ERROR) << "Failed to find the minimum frame duration for the selected "
"ZSL stream";
return false;
}
return true;
}
ZslHelper::ZslBufferIterator ZslHelper::SelectZslBuffer(
SelectionStrategy strategy) {
ring_buffer_lock_.AssertAcquired();
if (strategy == LAST_SUBMITTED) {
for (auto it = ring_buffer_.begin(); it != ring_buffer_.end(); it++) {
if (it->metadata_ready && it->buffer_ready && !it->selected) {
it->selected = true;
return it;
}
}
LOGF(WARNING) << "Failed to find a unselected submitted ZSL buffer";
return ring_buffer_.end();
}
// For CLOSEST or CLOSEST_3A strategies.
int64_t cur_timestamp = GetCurrentTimestamp();
LOGF(INFO) << "Current timestamp = " << cur_timestamp;
ZslBufferIterator selected_buffer_it = ring_buffer_.end();
int64_t min_diff = zsl_lookback_ns_;
int64_t ideal_timestamp = cur_timestamp - zsl_lookback_ns_;
for (auto it = ring_buffer_.begin(); it != ring_buffer_.end(); it++) {
if (!it->metadata_ready || !it->buffer_ready || it->selected) {
continue;
}
int64_t timestamp = GetTimestamp(it->metadata);
bool satisfy_3a = strategy == CLOSEST ||
(strategy == CLOSEST_3A && Is3AConverged(it->metadata));
int64_t diff = timestamp - ideal_timestamp;
VLOGF(1) << "Candidate timestamp = " << timestamp
<< " (Satisfy 3A = " << satisfy_3a << ", "
<< "Difference from desired timestamp = " << diff << ")";
if (diff > kZslLookbackLengthNs) {
continue;
} else if (diff < 0) {
// We don't select buffers that are older than what is displayed.
break;
}
if (satisfy_3a) {
if (diff < min_diff) {
min_diff = diff;
selected_buffer_it = it;
} else {
// Not possible to find a better buffer
break;
}
}
}
if (selected_buffer_it == ring_buffer_.end()) {
LOGF(WARNING)
<< "Failed to a find suitable ZSL buffer with the given strategy";
return selected_buffer_it;
}
LOGF(INFO) << "Timestamp of the selected buffer = "
<< GetTimestamp(selected_buffer_it->metadata);
selected_buffer_it->selected = true;
return selected_buffer_it;
}
int64_t ZslHelper::GetCurrentTimestamp() {
if (override_current_timestamp_for_testing_ !=
kOverrideCurrentTimestampNotSet) {
return override_current_timestamp_for_testing_;
}
struct timespec t = {};
clock_gettime(
timestamp_source_ == ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN
? CLOCK_MONOTONIC
: CLOCK_BOOTTIME /* ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME */,
&t);
return static_cast<int64_t>(t.tv_sec) * 1000000000LL + t.tv_nsec;
}
bool ZslHelper::Is3AConverged(const android::CameraMetadata& android_metadata) {
auto GetState = [&](size_t tag) {
camera_metadata_ro_entry_t entry;
if (android_metadata.exists(tag)) {
entry = android_metadata.find(tag);
return entry.data.u8[0];
}
LOGF(ERROR) << "Cannot find the metadata for "
<< get_camera_metadata_tag_name(tag);
return static_cast<uint8_t>(0);
};
uint8_t ae_mode = GetState(ANDROID_CONTROL_AE_MODE);
uint8_t ae_state = GetState(ANDROID_CONTROL_AE_STATE);
bool ae_converged = [&]() {
if (ae_mode != ANDROID_CONTROL_AE_MODE_OFF) {
if (ae_state != ANDROID_CONTROL_AE_STATE_CONVERGED &&
ae_state != ANDROID_CONTROL_AE_STATE_FLASH_REQUIRED &&
ae_state != ANDROID_CONTROL_AE_STATE_LOCKED) {
return false;
}
}
return true;
}();
if (!ae_converged) {
return false;
}
uint8_t af_mode = GetState(ANDROID_CONTROL_AF_MODE);
uint8_t af_state = GetState(ANDROID_CONTROL_AF_STATE);
bool af_converged = [&]() {
if (af_mode != ANDROID_CONTROL_AF_MODE_OFF) {
if (af_state != ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED &&
af_state != ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED) {
return false;
}
}
return true;
}();
if (!af_converged) {
return false;
}
uint8_t awb_mode = GetState(ANDROID_CONTROL_AWB_MODE);
uint8_t awb_state = GetState(ANDROID_CONTROL_AWB_STATE);
bool awb_converged = [&]() {
if (awb_mode != ANDROID_CONTROL_AWB_MODE_OFF) {
if (awb_state != ANDROID_CONTROL_AWB_STATE_CONVERGED &&
awb_state != ANDROID_CONTROL_AWB_STATE_LOCKED) {
return false;
}
}
return true;
}();
// We won't reach here if neither AE nor AF is converged.
return awb_converged;
}
void ZslHelper::SetZslBufferManagerForTesting(
std::unique_ptr<ZslBufferManager> zsl_buffer_manager) {
zsl_buffer_manager_ = std::move(zsl_buffer_manager);
}
void ZslHelper::OverrideCurrentTimestampForTesting(int64_t timestamp) {
override_current_timestamp_for_testing_ = timestamp;
}
} // namespace cros