blob: 462c8a7ef8dee2e95eee361dd68b28a139203a1c [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 <cstdlib>
#include <utility>
#include <vector>
#include <base/bind.h>
#include <camera/camera_metadata.h>
#include <sync/sync.h>
#include <system/camera_metadata.h>
#include "cros-camera/common.h"
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_(CameraBufferManager::GetInstance()) {}
ZslBufferManager::~ZslBufferManager() {
if (free_buffers_.size() != buffer_pool_.size()) {
LOGF(WARNING) << "Not all ZSL buffers have been released";
}
for (auto& buffer : buffer_pool_) {
buffer_manager_->Free(buffer);
}
}
bool ZslBufferManager::Initialize(size_t pool_size,
camera3_stream_t* output_stream) {
output_stream_ = output_stream;
buffer_pool_.reserve(pool_size);
base::AutoLock buffer_pool_lock(buffer_pool_lock_);
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,
cros::GRALLOC, &buffer, &stride) != 0) {
LOGF(ERROR) << "Failed to allocate buffer";
// Free previously-allocated buffers.
for (auto& buffer : buffer_pool_) {
buffer_manager_->Free(buffer);
}
return false;
}
buffer_pool_.push_back(buffer);
free_buffers_.push(&buffer_pool_.back());
buffer_to_buffer_pointer_map_[buffer] = &buffer_pool_.back();
}
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;
}
ZslHelper::ZslHelper(const camera_metadata_t* static_info,
FrameNumberMapper* mapper)
: initialized_(false),
enabled_(false),
fence_sync_thread_("FenceSyncThread"),
frame_number_mapper_(mapper) {
VLOGF_ENTER();
if (IsCapabilitySupported(static_info, kZslCapability)) {
uint32_t bi_width, bi_height;
if (SelectZslStreamSize(static_info, &bi_width, &bi_height)) {
LOGF(INFO) << "Selected ZSL stream size: " << bi_width << "x"
<< bi_height;
// Create ZSL streams
bi_stream_ = std::make_unique<camera3_stream_t>();
memset(bi_stream_.get(), 0, sizeof(*bi_stream_.get()));
bi_stream_->stream_type = CAMERA3_STREAM_BIDIRECTIONAL;
bi_stream_->width = bi_width;
bi_stream_->height = bi_height;
bi_stream_->format = kZslPixelFormat;
// Initialize ZSL buffer manager
uint8_t max_pipeline_depth = [&]() {
camera_metadata_ro_entry entry;
if (find_camera_metadata_ro_entry(
static_info, ANDROID_REQUEST_PIPELINE_MAX_DEPTH, &entry) != 0) {
LOGF(ERROR) << "ANDROID_REQUEST_PIPELINE_MAX_DEPTH is missing from "
"static metadata!";
// This shouldn't happen, but assigning this a value just in case.
return static_cast<uint8_t>(20);
}
return entry.data.u8[0];
}();
if (zsl_buffer_manager_.Initialize(kZslBufferSize + max_pipeline_depth,
bi_stream_.get())) {
initialized_ = true;
} else {
LOGF(ERROR) << "Failed to initialize ZSL buffer manager";
}
} else {
LOGF(ERROR) << "Failed to select stream sizes for ZSL.";
}
} else {
LOGF(INFO) << "Device doesn't support ZSL. ZSL won't be enabled.";
}
if (!fence_sync_thread_.Start()) {
LOGF(ERROR) << "Fence sync thread failed to start";
initialized_ = false;
}
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]);
}();
}
ZslHelper::~ZslHelper() {
fence_sync_thread_.Stop();
}
bool ZslHelper::IsZslEnabled() {
base::AutoLock enabled_lock(enabled_lock_);
return enabled_;
}
void ZslHelper::SetZslEnabled(bool enabled) {
base::AutoLock enabled_lock(enabled_lock_);
if (enabled != enabled_) {
LOGF(INFO) << (enabled ? "Enabling" : "Disabling") << " ZSL";
enabled_ = enabled;
}
}
bool ZslHelper::CanEnableZsl(const internal::ScopedStreams& streams) {
size_t num_input_streams = 0;
bool has_zsl_output_stream = false;
bool has_blob_output_stream = false;
for (auto it = streams.begin(); it != streams.end(); it++) {
camera3_stream_t* stream = it->second.get();
if (stream->stream_type == CAMERA3_STREAM_INPUT ||
stream->stream_type == CAMERA3_STREAM_BIDIRECTIONAL) {
num_input_streams++;
}
if (stream->stream_type == CAMERA3_STREAM_OUTPUT ||
stream->stream_type == CAMERA3_STREAM_BIDIRECTIONAL) {
if (stream->format == HAL_PIXEL_FORMAT_BLOB ||
(stream->usage & GRALLOC_USAGE_STILL_CAPTURE)) {
has_blob_output_stream = true;
}
if ((stream->usage & GRALLOC_USAGE_HW_CAMERA_ZSL) ==
GRALLOC_USAGE_HW_CAMERA_ZSL) {
has_zsl_output_stream = true;
}
}
}
return initialized_ // Initialized means we have an allocated buffer pool.
&& has_blob_output_stream // Has a stream for still capture.
&& num_input_streams < max_num_input_streams_ // Has room for an extra
// input stream for ZSL.
&& !has_zsl_output_stream; // HAL doesn't support multiple raw output
// streams.
}
void ZslHelper::AttachZslStream(camera3_stream_configuration_t* stream_list,
std::vector<camera3_stream_t*>* streams) {
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();
for (size_t i = 0; i < stream_list->num_streams; ++i) {
// GRALLOC_USAGE_STILL_CAPTURE is a private usage from VCD.
// We set the usage flag here to let VCD know ZSL is enabled.
if ((*streams)[i]->usage & GRALLOC_USAGE_STILL_CAPTURE) {
(*streams)[i]->usage |= GRALLOC_USAGE_ZSL_ENABLED;
}
}
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;
}
}
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::IsAttachedZslFrame(uint32_t frame_number) {
base::AutoLock ring_buffer_lock(ring_buffer_lock_);
return buffer_index_map_.find(frame_number) != buffer_index_map_.end();
}
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::ProcessZslCaptureRequest(
uint32_t framework_frame_number,
camera3_capture_request_t* request, // maybe just use *input_buffer?
std::vector<camera3_stream_buffer_t>* output_buffers,
internal::ScopedCameraMetadata* settings,
camera3_capture_request_t* still_request,
std::vector<camera3_stream_buffer_t>* still_output_buffers,
SelectionStrategy strategy) {
if (request->input_buffer != nullptr) {
return;
}
if (IsZslRequested(settings->get())) {
for (auto it = output_buffers->begin(); it != output_buffers->end();) {
if (it->stream->format == HAL_PIXEL_FORMAT_BLOB ||
(it->stream->usage & GRALLOC_USAGE_STILL_CAPTURE)) {
still_output_buffers->push_back(std::move(*it));
it = output_buffers->erase(it);
} else {
it++;
}
}
if (still_output_buffers->empty()) {
LOGF(ERROR) << "ZSL is requested, but we couldn't find any still "
"capture output buffers.";
} else {
camera_metadata_t* zsl_settings;
bool transformed =
TransformRequest(still_request, &zsl_settings, strategy);
if (transformed) {
still_request->frame_number =
frame_number_mapper_->GetHalFrameNumber(framework_frame_number);
still_request->settings = zsl_settings;
} else {
// TODO(lnishan): Implement 3A stabilization mechanism so that we
// would attempt to get a buffer in another time.
// Merging the buffers back for now.
LOGF(ERROR) << "Not splitting this request because we cannot find a "
"suitable ZSL buffer";
for (size_t i = 0; i < still_output_buffers->size(); ++i) {
output_buffers->push_back(std::move((*still_output_buffers)[i]));
}
still_output_buffers->clear();
}
}
still_request->num_output_buffers = still_output_buffers->size();
still_request->output_buffers = const_cast<const camera3_stream_buffer_t*>(
still_output_buffers->data());
}
// We might end up moving all output buffers to the added request. So here we
// unconditionally add a ZSL output buffer. We also need a placeholder request
// so that we can defer a request if a suitable ZSL buffer is not found.
AttachRequest(request, output_buffers);
}
void ZslHelper::AttachRequest(
camera3_capture_request_t* request,
std::vector<camera3_stream_buffer_t>* output_buffers) {
VLOGF_ENTER();
if (!enabled_) {
LOGF(WARNING) << "Trying to attach a request when ZSL is disabled";
return;
}
// Check if the oldest ZSL buffer is filled and free it if it's filled and
// not selected for any transformed ZSL requests.
base::AutoLock l(ring_buffer_lock_);
if (ring_buffer_.IsFilledIndex(0)) {
const ZslBuffer& buf = ring_buffer_.ReadBuffer(0);
if (!buf.selected) {
// We can free the buffer if it's not selected.
if (!zsl_buffer_manager_.ReleaseBuffer(*buf.buffer.buffer)) {
LOGF(ERROR) << "Unable to release the oldest buffer";
}
}
// No need to remember frame-to-index mapping when this buffer is popped.
buffer_index_map_.erase(buf.frame_number);
}
// Attach our ZSL output buffer.
camera3_stream_buffer_t stream_buffer;
stream_buffer.buffer = zsl_buffer_manager_.GetBuffer();
stream_buffer.stream = bi_stream_.get();
stream_buffer.acquire_fence = stream_buffer.release_fence = -1;
buffer_index_map_[request->frame_number] = ring_buffer_.CurrentIndex();
ZslBuffer buffer(request->frame_number, stream_buffer);
ring_buffer_.SaveToBuffer(std::move(buffer));
output_buffers->push_back(std::move(stream_buffer));
request->num_output_buffers++;
}
bool ZslHelper::TransformRequest(camera3_capture_request_t* request,
camera_metadata_t** settings,
SelectionStrategy strategy) {
VLOGF_ENTER();
if (!enabled_) {
LOGF(WARNING) << "Trying to transform a request when ZSL is disabled";
return false;
}
// Select the best buffer.
ZslBuffer* selected_buffer = SelectZslBuffer(strategy);
if (!selected_buffer) {
LOGF(WARNING) << "Unable to find a suitable ZSL buffer. Request will not "
"be transformed.";
return false;
}
LOGF(INFO) << "Transforming request into ZSL reprocessing request";
base::AutoLock ring_buffer_lock(ring_buffer_lock_);
request->input_buffer = &selected_buffer->buffer;
request->input_buffer->stream = bi_stream_.get();
request->input_buffer->acquire_fence = -1;
request->input_buffer->release_fence = -1;
// Note that camera device adapter would take ownership of this pointer.
*settings = selected_buffer->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);
}
if (IsAttachedZslFrame(result->frame_number)) {
base::AutoLock ring_buffer_lock(ring_buffer_lock_);
auto it = buffer_index_map_.find(result->frame_number);
if (it != buffer_index_map_.end()) {
ZslBuffer* buffer = MutableReadBufferByBufferIndex(it->second);
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 the result metadata.
if (buffer) {
buffer->metadata.append(result->result);
if (result->partial_result == partial_result_count_) {
buffer->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 = buffer_index_map_.find(frame_number);
if (it != buffer_index_map_.end()) {
ZslBuffer* buffer = MutableReadBufferByBufferIndex(it->second);
if (buffer) {
buffer->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) {
VLOGF_ENTER();
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;
}
*bi_width = 0;
*bi_height = 0;
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;
}
}
}
return *bi_width > 0 && *bi_height > 0;
}
ZslBuffer* ZslHelper::SelectZslBuffer(SelectionStrategy strategy) {
// Select the best ZSL buffer based on time and statistics.
auto 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);
};
base::AutoLock ring_buffer_lock(ring_buffer_lock_);
if (strategy == LAST_SUBMITTED) {
for (int i = kZslBufferSize - 1; i >= 0; --i) {
if (!ring_buffer_.IsFilledIndex(i)) {
continue;
}
ZslBuffer* buffer = ring_buffer_.MutableReadBuffer(i);
if (buffer->metadata_ready && buffer->buffer_ready && !buffer->selected) {
buffer->selected = true;
return buffer;
}
}
LOGF(WARNING) << "Failed to find a unselected submitted ZSL buffer";
return nullptr;
}
// For CLOSEST or CLOSEST_3A strategies.
int64_t cur_timestamp = GetCurrentTimestamp();
LOGF(INFO) << "Current timestamp = " << cur_timestamp;
ZslBuffer* selected_buffer = nullptr;
int64_t min_diff = kZslLookbackNs;
int64_t ideal_timestamp = cur_timestamp - kZslLookbackNs;
for (int i = kZslBufferSize - 1; i >= 0; --i) {
if (!ring_buffer_.IsFilledIndex(i)) {
continue;
}
ZslBuffer* buffer = ring_buffer_.MutableReadBuffer(i);
if (!buffer->metadata_ready || !buffer->buffer_ready || buffer->selected) {
continue;
}
int64_t timestamp = GetTimestamp(buffer->metadata);
bool satisfy_3a = strategy == CLOSEST || (strategy == CLOSEST_3A &&
Is3AConverged(buffer->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 = buffer;
} else {
// Not possible to find a better buffer
break;
}
}
}
if (selected_buffer == nullptr) {
LOGF(WARNING)
<< "Failed to a find suitable ZSL buffer with the given strategy";
return nullptr;
}
LOGF(INFO) << "Timestamp of the selected buffer = "
<< GetTimestamp(selected_buffer->metadata);
selected_buffer->selected = true;
return selected_buffer;
}
int64_t ZslHelper::GetCurrentTimestamp() {
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;
}
ZslBuffer* ZslHelper::MutableReadBufferByBufferIndex(size_t buffer_index) {
size_t current_index = ring_buffer_.CurrentIndex();
DCHECK(current_index > buffer_index);
// The DCHECK fails if the caller is attempting to update a buffer that's no
// longer in the ring buffer. This means a capture result is returned after
// |kZslBufferSize| frames, which shouldn't happen and likely indicates
// something is wrong.
DCHECK(current_index - buffer_index <= ZslHelper::kZslBufferSize);
if (current_index - buffer_index <= ZslHelper::kZslBufferSize) {
size_t rel_index =
ZslHelper::kZslBufferSize - (current_index - buffer_index);
return ring_buffer_.MutableReadBuffer(rel_index);
}
return nullptr;
}
} // namespace cros