blob: ea5f924b2256da1d61058ac8ffe9376bee750ba1 [file] [log] [blame]
// Copyright 2017 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 "camera3_test/camera3_device_impl.h"
#include <utility>
#include <base/check.h>
#include <base/numerics/safe_conversions.h>
#include <sync/sync.h>
#include "camera3_test/camera3_perf_log.h"
#include "cros-camera/common.h"
namespace camera3_test {
static void ExpectKeyValueGreaterThanI64(const camera_metadata_t* settings,
int32_t key,
const char* key_name,
int64_t value) {
camera_metadata_ro_entry_t entry;
ASSERT_EQ(0, find_camera_metadata_ro_entry(settings, key, &entry))
<< "Cannot find the metadata " << key_name;
ASSERT_GT(entry.data.i64[0], value) << "Wrong value of metadata " << key_name;
}
#define EXPECT_KEY_VALUE_GT_I64(settings, key, value) \
ExpectKeyValueGreaterThanI64(settings, key, #key, value)
Camera3DeviceImpl::Camera3DeviceImpl(int cam_id)
: cam_id_(cam_id),
hal_thread_(GetThreadName(cam_id).c_str()),
initialized_(false),
cam_stream_idx_(0),
gralloc_(Camera3TestGralloc::GetInstance()),
request_frame_number_(kInitialFrameNumber) {
DETACH_FROM_THREAD(thread_checker_);
}
int Camera3DeviceImpl::Initialize(Camera3Module* cam_module) {
VLOGF_ENTER();
if (!cam_module || !hal_thread_.Start()) {
return -EINVAL;
}
int result = -EIO;
hal_thread_.PostTaskSync(
FROM_HERE, base::Bind(&Camera3DeviceImpl::InitializeOnThread,
base::Unretained(this), cam_module, &result));
return result;
}
void Camera3DeviceImpl::Destroy() {
VLOGF_ENTER();
int result = -EIO;
hal_thread_.PostTaskSync(FROM_HERE,
base::Bind(&Camera3DeviceImpl::DestroyOnThread,
base::Unretained(this), &result));
EXPECT_EQ(0, result) << "Camera device close failed";
hal_thread_.Stop();
DETACH_FROM_THREAD(thread_checker_);
}
void Camera3DeviceImpl::RegisterProcessCaptureResultCallback(
Camera3Device::ProcessCaptureResultCallback cb) {
hal_thread_.PostTaskSync(
FROM_HERE,
base::Bind(
&Camera3DeviceImpl::RegisterProcessCaptureResultCallbackOnThread,
base::Unretained(this), cb));
}
void Camera3DeviceImpl::RegisterNotifyCallback(
Camera3Device::NotifyCallback cb) {
hal_thread_.PostTaskSync(
FROM_HERE, base::Bind(&Camera3DeviceImpl::RegisterNotifyCallbackOnThread,
base::Unretained(this), cb));
}
void Camera3DeviceImpl::RegisterResultMetadataOutputBufferCallback(
Camera3Device::ProcessResultMetadataOutputBuffersCallback cb) {
hal_thread_.PostTaskSync(
FROM_HERE,
base::Bind(&Camera3DeviceImpl::
RegisterResultMetadataOutputBufferCallbackOnThread,
base::Unretained(this), cb));
}
void Camera3DeviceImpl::RegisterPartialMetadataCallback(
Camera3Device::ProcessPartialMetadataCallback cb) {
hal_thread_.PostTaskSync(
FROM_HERE,
base::Bind(&Camera3DeviceImpl::RegisterPartialMetadataCallbackOnThread,
base::Unretained(this), cb));
}
bool Camera3DeviceImpl::IsTemplateSupported(int32_t type) {
bool result = false;
hal_thread_.PostTaskSync(
FROM_HERE, base::Bind(&Camera3DeviceImpl::IsTemplateSupportedOnThread,
base::Unretained(this), type, &result));
return result;
}
const camera_metadata_t* Camera3DeviceImpl::ConstructDefaultRequestSettings(
int type) {
const camera_metadata_t* metadata = nullptr;
hal_thread_.PostTaskSync(
FROM_HERE,
base::Bind(&Camera3DeviceImpl::ConstructDefaultRequestSettingsOnThread,
base::Unretained(this), type, &metadata));
return metadata;
}
void Camera3DeviceImpl::AddStream(int format,
int width,
int height,
int crop_rotate_scale_degrees,
camera3_stream_type_t type) {
VLOGF_ENTER();
hal_thread_.PostTaskSync(
FROM_HERE,
base::Bind(&Camera3DeviceImpl::AddStreamOnThread, base::Unretained(this),
format, width, height, crop_rotate_scale_degrees, type));
}
int Camera3DeviceImpl::ConfigureStreams(
std::vector<const camera3_stream_t*>* streams) {
VLOGF_ENTER();
int32_t result = -EIO;
hal_thread_.PostTaskSync(
FROM_HERE, base::Bind(&Camera3DeviceImpl::ConfigureStreamsOnThread,
base::Unretained(this), streams, &result));
return result;
}
int Camera3DeviceImpl::AllocateOutputStreamBuffers(
std::vector<camera3_stream_buffer_t>* output_buffers) {
VLOGF_ENTER();
int32_t result = -EIO;
hal_thread_.PostTaskSync(
FROM_HERE,
base::Bind(&Camera3DeviceImpl::AllocateOutputStreamBuffersOnThread,
base::Unretained(this), output_buffers, &result));
return result;
}
int Camera3DeviceImpl::AllocateOutputBuffersByStreams(
const std::vector<const camera3_stream_t*>& streams,
std::vector<camera3_stream_buffer_t>* output_buffers) {
VLOGF_ENTER();
int32_t result = -EIO;
hal_thread_.PostTaskSync(
FROM_HERE,
base::Bind(&Camera3DeviceImpl::AllocateOutputBuffersByStreamsOnThread,
base::Unretained(this), &streams, output_buffers, &result));
return result;
}
int Camera3DeviceImpl::RegisterOutputBuffer(
const camera3_stream_t& stream, cros::ScopedBufferHandle unique_buffer) {
VLOGF_ENTER();
int32_t result = -EIO;
hal_thread_.PostTaskSync(
FROM_HERE, base::Bind(&Camera3DeviceImpl::RegisterOutputBufferOnThread,
base::Unretained(this), &stream,
base::Passed(&unique_buffer), &result));
return result;
}
int Camera3DeviceImpl::ProcessCaptureRequest(
camera3_capture_request_t* capture_request) {
VLOGF_ENTER();
int32_t result = -EIO;
hal_thread_.PostTaskSync(
FROM_HERE, base::Bind(&Camera3DeviceImpl::ProcessCaptureRequestOnThread,
base::Unretained(this), capture_request, &result));
return result;
}
int Camera3DeviceImpl::WaitShutter(const struct timespec& timeout) {
if (!initialized_) {
return -ENODEV;
}
if (!process_capture_result_cb_.is_null()) {
LOGF(ERROR)
<< "Test has registered its own process_capture_result callback "
"function and thus must provide its own "
<< __func__;
return -EINVAL;
}
return sem_timedwait(&shutter_sem_, &timeout);
}
int Camera3DeviceImpl::WaitCaptureResult(const struct timespec& timeout) {
if (!initialized_) {
return -ENODEV;
}
if (!process_capture_result_cb_.is_null()) {
LOGF(ERROR)
<< "Test has registered its own process_capture_result callback "
"function and thus must provide its own "
<< __func__;
return -EINVAL;
}
return sem_timedwait(&capture_result_sem_, &timeout);
}
int Camera3DeviceImpl::Flush() {
DCHECK(dev_connector_);
VLOGF_ENTER();
return dev_connector_->Flush();
}
void Camera3DeviceImpl::InitializeOnThread(Camera3Module* cam_module,
int* result) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (initialized_) {
LOGF(ERROR) << "Device " << cam_id_ << " is already initialized";
*result = -EINVAL;
return;
}
// Open camera device
Camera3PerfLog::GetInstance()->UpdateDeviceEvent(
cam_id_, DeviceEvent::OPENING, base::TimeTicks::Now());
*result = -ENODEV;
dev_connector_ = cam_module->OpenDevice(cam_id_);
if (!dev_connector_) {
return;
}
*result = -EINVAL;
ASSERT_NE(nullptr, gralloc_) << "Gralloc initialization fails";
camera_info cam_info;
ASSERT_EQ(0, cam_module->GetCameraInfo(cam_id_, &cam_info));
device_api_version_ = cam_info.device_version;
static_info_.reset(new Camera3Device::StaticInfo(cam_info));
ASSERT_TRUE(static_info_->IsHardwareLevelAtLeastExternal())
<< "The device must support at least EXTERNAL hardware level";
// Initialize camera device
Camera3DeviceImpl::notify = Camera3DeviceImpl::NotifyForwarder;
Camera3DeviceImpl::process_capture_result =
Camera3DeviceImpl::ProcessCaptureResultForwarder;
*result = dev_connector_->Initialize(this, cam_info.device_version);
if (*result) {
return;
}
Camera3PerfLog::GetInstance()->UpdateDeviceEvent(cam_id_, DeviceEvent::OPENED,
base::TimeTicks::Now());
sem_init(&shutter_sem_, 0, 0);
sem_init(&capture_result_sem_, 0, 0);
initialized_ = true;
}
void Camera3DeviceImpl::RegisterProcessCaptureResultCallbackOnThread(
Camera3Device::ProcessCaptureResultCallback cb) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
process_capture_result_cb_ = cb;
}
void Camera3DeviceImpl::RegisterNotifyCallbackOnThread(
Camera3Device::NotifyCallback cb) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
notify_cb_ = cb;
}
void Camera3DeviceImpl::RegisterResultMetadataOutputBufferCallbackOnThread(
Camera3Device::ProcessResultMetadataOutputBuffersCallback cb) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
process_result_metadata_output_buffers_cb_ = cb;
}
void Camera3DeviceImpl::RegisterPartialMetadataCallbackOnThread(
Camera3Device::ProcessPartialMetadataCallback cb) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
process_partial_metadata_cb_ = cb;
}
void Camera3DeviceImpl::IsTemplateSupportedOnThread(int32_t type,
bool* result) {
if (initialized_) {
*result =
(type != CAMERA3_TEMPLATE_MANUAL ||
static_info_->IsCapabilitySupported(
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) &&
(type != CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG ||
static_info_->IsCapabilitySupported(
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING));
}
}
void Camera3DeviceImpl::ConstructDefaultRequestSettingsOnThread(
int type, const camera_metadata_t** result) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (initialized_) {
*result = dev_connector_->ConstructDefaultRequestSettings(type);
}
}
void Camera3DeviceImpl::AddStreamOnThread(int format,
int width,
int height,
int crop_rotate_scale_degrees,
camera3_stream_type_t type) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (initialized_) {
auto& cur_stream = cam_stream_[!cam_stream_idx_];
// Push to the bin that is not used currently
cros::internal::camera3_stream_aux_t stream = {};
stream.stream_type = type;
stream.width = width;
stream.height = height;
stream.format = format;
if (type == CAMERA3_STREAM_OUTPUT &&
format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
// This is a preview stream. Add the usage flag for preview.
stream.usage |= GRALLOC_USAGE_HW_COMPOSER;
}
if (device_api_version_ >= CAMERA_DEVICE_API_VERSION_3_5) {
stream.physical_camera_id = "";
}
stream.crop_rotate_scale_degrees = crop_rotate_scale_degrees;
cur_stream.push_back(stream);
}
}
void Camera3DeviceImpl::ConfigureStreamsOnThread(
std::vector<const camera3_stream_t*>* streams, int* result) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
*result = -EINVAL;
if (!initialized_) {
*result = -ENODEV;
return;
}
// Check whether there are streams
if (cam_stream_[!cam_stream_idx_].size() == 0) {
return;
}
// Prepare stream configuration
std::vector<camera3_stream_t*> cam_streams;
camera3_stream_configuration_t cam_stream_config = {};
for (size_t i = 0; i < cam_stream_[!cam_stream_idx_].size(); i++) {
cam_streams.push_back(&cam_stream_[!cam_stream_idx_][i]);
}
cam_stream_config.num_streams = cam_streams.size();
cam_stream_config.streams = cam_streams.data();
cam_stream_config.operation_mode = CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE;
if (device_api_version_ >= CAMERA_DEVICE_API_VERSION_3_5) {
cam_stream_config.session_parameters = nullptr;
}
// Configure streams now
*result = dev_connector_->ConfigureStreams(&cam_stream_config);
if (*result == 0) {
for (const auto& it : cam_stream_[!cam_stream_idx_]) {
if (it.max_buffers == 0) {
LOGF(ERROR) << "Max number of buffers equal to zero is invalid";
*result = -EINVAL;
return;
}
}
}
// Swap to the other bin
cam_stream_[cam_stream_idx_].clear();
cam_stream_idx_ = !cam_stream_idx_;
if (*result == 0 && streams) {
streams->clear();
for (auto const& it : cam_stream_[cam_stream_idx_]) {
streams->push_back(&it);
}
}
}
void Camera3DeviceImpl::AllocateOutputStreamBuffersOnThread(
std::vector<camera3_stream_buffer_t>* output_buffers, int32_t* result) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
std::vector<const camera3_stream_t*> streams;
for (const auto& it : cam_stream_[cam_stream_idx_]) {
if (it.stream_type == CAMERA3_STREAM_OUTPUT ||
it.stream_type == CAMERA3_STREAM_BIDIRECTIONAL) {
streams.push_back(&it);
}
}
AllocateOutputBuffersByStreamsOnThread(&streams, output_buffers, result);
}
void Camera3DeviceImpl::AllocateOutputBuffersByStreamsOnThread(
const std::vector<const camera3_stream_t*>* streams,
std::vector<camera3_stream_buffer_t>* output_buffers,
int32_t* result) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
*result = -EINVAL;
if (!initialized_) {
*result = -ENODEV;
return;
}
if (!output_buffers || streams->empty()) {
return;
}
int32_t jpeg_max_size = 0;
if (std::find_if(streams->begin(), streams->end(),
[](const camera3_stream_t* stream) {
return stream->format == HAL_PIXEL_FORMAT_BLOB;
}) != streams->end()) {
jpeg_max_size = static_info_->GetJpegMaxSize();
if (jpeg_max_size <= 0) {
return;
}
}
for (const auto& it : *streams) {
cros::ScopedBufferHandle buffer = gralloc_->Allocate(
(it->format == HAL_PIXEL_FORMAT_BLOB) ? jpeg_max_size : it->width,
(it->format == HAL_PIXEL_FORMAT_BLOB) ? 1 : it->height, it->format,
it->usage);
if (!buffer) {
LOGF(ERROR) << "Gralloc allocation fails";
*result = -ENOMEM;
return;
}
camera3_stream_buffer_t stream_buffer;
camera3_stream_t* stream = const_cast<camera3_stream_t*>(it);
stream_buffer = {.stream = stream,
.buffer = buffer.get(),
.status = CAMERA3_BUFFER_STATUS_OK,
.acquire_fence = -1,
.release_fence = -1};
stream_buffer_map_[stream].push_back(std::move(buffer));
output_buffers->push_back(stream_buffer);
}
*result = 0;
}
void Camera3DeviceImpl::RegisterOutputBufferOnThread(
const camera3_stream_t* stream,
cros::ScopedBufferHandle unique_buffer,
int32_t* result) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
VLOGF_ENTER();
if (!initialized_) {
*result = -ENODEV;
return;
}
if (!unique_buffer) {
*result = -EINVAL;
return;
}
stream_buffer_map_[stream].emplace_back(std::move(unique_buffer));
*result = 0;
}
void Camera3DeviceImpl::ProcessCaptureRequestOnThread(
camera3_capture_request_t* request, int* result) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
VLOGF_ENTER();
if (!initialized_) {
*result = -ENODEV;
return;
}
if (request) {
capture_request_map_[request_frame_number_] = *request;
capture_request_map_[request_frame_number_].frame_number =
request_frame_number_;
for (uint32_t i = 0; i < request->num_output_buffers; i++) {
stream_output_buffer_map_[request->output_buffers[i].stream].push_back(
*request->output_buffers[i].buffer);
}
}
*result = dev_connector_->ProcessCaptureRequest(
request ? &capture_request_map_[request_frame_number_] : request);
if (*result == 0) {
request->frame_number = request_frame_number_;
request_frame_number_++;
}
}
Camera3DeviceImpl::StreamBuffer::StreamBuffer(
const camera3_stream_buffer_t& stream_buffer)
: camera3_stream_buffer_t(stream_buffer) {
buffer_handle = *stream_buffer.buffer;
}
Camera3DeviceImpl::CaptureResult::CaptureResult(
const camera3_capture_result_t& result)
: camera3_capture_result_t(result) {
if (result.result) {
metadata_result.reset(clone_camera_metadata(result.result));
}
for (uint32_t i = 0; i < result.num_output_buffers; i++) {
stream_buffers.emplace_back(result.output_buffers[i]);
}
}
void Camera3DeviceImpl::ProcessCaptureResultOnThread(
std::unique_ptr<CaptureResult> result) {
VLOGF_ENTER();
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
ASSERT_NE(nullptr, result) << "Capture result is null";
// At least one of metadata or output buffers or input buffer should be
// returned
ASSERT_TRUE((result->metadata_result != nullptr) ||
(result->num_output_buffers != 0) ||
(result->input_buffer != NULL))
<< "No result data provided by HAL for frame " << result->frame_number;
if (result->num_output_buffers) {
ASSERT_NE(nullptr, result->output_buffers)
<< "No output buffer is returned while " << result->num_output_buffers
<< " are expected";
}
ASSERT_NE(capture_request_map_.end(),
capture_request_map_.find(result->frame_number))
<< "A result is received for nonexistent request (frame number "
<< result->frame_number << ")";
// For HAL3.2 or above, If HAL doesn't support partial, it must always set
// partial_result to 1 when metadata is included in this result.
ASSERT_TRUE(UsePartialResult() || !result->metadata_result ||
result->partial_result == 1)
<< "Result is malformed: partial_result must be 1 if partial result is "
"not supported";
// If partial_result > 0, there should be metadata returned in this result;
// otherwise, there should be none.
ASSERT_TRUE((result->partial_result > 0) ==
(result->metadata_result != nullptr));
if (result->metadata_result) {
ProcessPartialResult(result.get());
}
for (const auto& stream_buffer : result->stream_buffers) {
ASSERT_NE(nullptr, stream_buffer.buffer)
<< "Capture result output buffer is null";
// An error may be expected while flushing
EXPECT_EQ(CAMERA3_BUFFER_STATUS_OK, stream_buffer.status)
<< "Capture result buffer status error";
ASSERT_EQ(-1, stream_buffer.acquire_fence)
<< "Capture result buffer fence error";
// Check buffers for a given streams are returned in order
ASSERT_FALSE(stream_output_buffer_map_[stream_buffer.stream].empty());
ASSERT_EQ(stream_output_buffer_map_[stream_buffer.stream].front(),
stream_buffer.buffer_handle)
<< "Buffers of the same stream are delivered out of order";
stream_output_buffer_map_[stream_buffer.stream].pop_front();
if (stream_buffer.release_fence != -1) {
ASSERT_EQ(0, sync_wait(stream_buffer.release_fence, 1000))
<< "Error waiting on buffer acquire fence";
close(stream_buffer.release_fence);
}
}
capture_result_info_map_[result->frame_number].output_buffers_.insert(
capture_result_info_map_[result->frame_number].output_buffers_.end(),
result->stream_buffers.begin(), result->stream_buffers.end());
capture_result_info_map_[result->frame_number].num_output_buffers_ +=
result->num_output_buffers;
if (result->input_buffer != nullptr) {
capture_result_info_map_[result->frame_number].have_input_buffer_ = true;
}
ASSERT_LE(capture_result_info_map_[result->frame_number].num_output_buffers_,
capture_request_map_[result->frame_number].num_output_buffers);
if (capture_result_info_map_[result->frame_number].num_output_buffers_ ==
capture_request_map_[result->frame_number].num_output_buffers &&
capture_result_info_map_[result->frame_number].have_input_buffer_ ==
(capture_request_map_[result->frame_number].input_buffer !=
nullptr) &&
capture_result_info_map_[result->frame_number].have_result_metadata_) {
ASSERT_EQ(completed_request_set_.end(),
completed_request_set_.find(result->frame_number))
<< "Multiple results are received for the same request";
completed_request_set_.insert(result->frame_number);
// Process all received metadata and output buffers
std::vector<cros::ScopedBufferHandle> unique_buffers;
if (GetOutputStreamBufferHandles(
capture_result_info_map_[result->frame_number].output_buffers_,
&unique_buffers)) {
ADD_FAILURE() << "Failed to get output buffers";
}
ScopedCameraMetadata final_metadata(
capture_result_info_map_[result->frame_number].MergePartialMetadata());
EXPECT_KEY_VALUE_GT_I64(final_metadata.get(), ANDROID_SENSOR_TIMESTAMP, 0);
if (!process_result_metadata_output_buffers_cb_.is_null()) {
process_result_metadata_output_buffers_cb_.Run(result->frame_number,
std::move(final_metadata),
std::move(unique_buffers));
}
std::vector<ScopedCameraMetadata> partial_metadata;
partial_metadata.swap(
capture_result_info_map_[result->frame_number].partial_metadata_);
if (!process_partial_metadata_cb_.is_null()) {
process_partial_metadata_cb_.Run(&partial_metadata);
}
capture_request_map_.erase(result->frame_number);
capture_result_info_map_.erase(result->frame_number);
// Everything looks fine. Post it now.
sem_post(&capture_result_sem_);
}
}
void Camera3DeviceImpl::NotifyOnThread(camera3_notify_msg_t msg) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
EXPECT_EQ(CAMERA3_MSG_SHUTTER, msg.type)
<< "Shutter error = " << msg.message.error.error_code;
// Use the timestamp reported from camera instead of base::TimeTicks::Now()
// since HAL may not notify() shutter messages in time.
const int64_t timestamp_ns =
base::checked_cast<int64_t>(msg.message.shutter.timestamp / 1000LL);
Camera3PerfLog::GetInstance()->UpdateFrameEvent(
cam_id_, msg.message.shutter.frame_number, FrameEvent::SHUTTER,
base::TimeTicks() + base::TimeDelta::FromMicroseconds(timestamp_ns));
if (msg.type == CAMERA3_MSG_SHUTTER) {
sem_post(&shutter_sem_);
}
}
void Camera3DeviceImpl::DestroyOnThread(int* result) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
*result = -EINVAL;
if (!initialized_) {
*result = -ENODEV;
return;
}
dev_connector_.reset();
sem_destroy(&shutter_sem_);
sem_destroy(&capture_result_sem_);
initialized_ = false;
*result = 0;
}
const Camera3Device::StaticInfo* Camera3DeviceImpl::GetStaticInfo() const {
return static_info_.get();
}
void Camera3DeviceImpl::ProcessCaptureResultForwarder(
const camera3_callback_ops* cb, const camera3_capture_result_t* result) {
// Forward to callback of instance
Camera3DeviceImpl* d =
const_cast<Camera3DeviceImpl*>(static_cast<const Camera3DeviceImpl*>(cb));
d->ProcessCaptureResult(result);
}
void Camera3DeviceImpl::NotifyForwarder(const camera3_callback_ops* cb,
const camera3_notify_msg_t* msg) {
// Forward to callback of instance
Camera3DeviceImpl* d =
const_cast<Camera3DeviceImpl*>(static_cast<const Camera3DeviceImpl*>(cb));
d->Notify(msg);
}
void Camera3DeviceImpl::ProcessCaptureResult(
const camera3_capture_result_t* result) {
VLOGF_ENTER();
if (!process_capture_result_cb_.is_null()) {
process_capture_result_cb_.Run(result);
return;
}
std::unique_ptr<CaptureResult> unique_result(new CaptureResult(*result));
hal_thread_.PostTaskAsync(
FROM_HERE,
base::Bind(&Camera3DeviceImpl::ProcessCaptureResultOnThread,
base::Unretained(this), base::Passed(&unique_result)));
}
void Camera3DeviceImpl::Notify(const camera3_notify_msg_t* msg) {
VLOGF_ENTER();
if (!notify_cb_.is_null()) {
notify_cb_.Run(msg);
return;
}
hal_thread_.PostTaskAsync(FROM_HERE,
base::Bind(&Camera3DeviceImpl::NotifyOnThread,
base::Unretained(this), *msg));
}
int Camera3DeviceImpl::GetOutputStreamBufferHandles(
const std::vector<StreamBuffer>& output_buffers,
std::vector<cros::ScopedBufferHandle>* unique_buffers) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
VLOGF_ENTER();
for (const auto& output_buffer : output_buffers) {
if (!output_buffer.buffer ||
stream_buffer_map_.find(output_buffer.stream) ==
stream_buffer_map_.end()) {
LOGF(ERROR) << "Failed to find configured stream or buffer is invalid";
return -EINVAL;
}
auto stream_buffers = &stream_buffer_map_[output_buffer.stream];
auto it = std::find_if(stream_buffers->begin(), stream_buffers->end(),
[=](const cros::ScopedBufferHandle& buffer) {
return *buffer == output_buffer.buffer_handle;
});
if (it != stream_buffers->end()) {
unique_buffers->push_back(std::move(*it));
stream_buffers->erase(it);
} else {
LOGF(ERROR) << "Failed to find output buffer";
return -EINVAL;
}
}
return 0;
}
bool Camera3DeviceImpl::UsePartialResult() const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return static_info_->GetPartialResultCount() > 1;
}
void Camera3DeviceImpl::ProcessPartialResult(CaptureResult* result) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// True if this partial result is the final one. If HAL does not use partial
// result, the value is True by default.
bool is_final_partial_result = !UsePartialResult();
// Check if this result carries only partial metadata
if (UsePartialResult() && result->metadata_result != nullptr) {
EXPECT_LE(result->partial_result, static_info_->GetPartialResultCount());
EXPECT_GE(result->partial_result, 1);
is_final_partial_result =
(result->partial_result == static_info_->GetPartialResultCount());
}
// Did we get the (final) result metadata for this capture?
if (result->metadata_result != nullptr && is_final_partial_result) {
EXPECT_FALSE(
capture_result_info_map_[result->frame_number].have_result_metadata_)
<< "Called multiple times with final metadata";
capture_result_info_map_[result->frame_number].have_result_metadata_ = true;
}
capture_result_info_map_[result->frame_number].partial_metadata_.push_back(
std::move(result->metadata_result));
}
Camera3DeviceImpl::CaptureResultInfo::CaptureResultInfo()
: have_input_buffer_(false),
num_output_buffers_(0),
have_result_metadata_(false) {
DETACH_FROM_THREAD(thread_checker_);
}
bool Camera3DeviceImpl::CaptureResultInfo::IsMetadataKeyAvailable(
int32_t key) const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return GetMetadataKeyEntry(key, nullptr);
}
int32_t Camera3DeviceImpl::CaptureResultInfo::GetMetadataKeyValue(
int32_t key) const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
camera_metadata_ro_entry_t entry;
return GetMetadataKeyEntry(key, &entry) ? entry.data.i32[0] : -EINVAL;
}
int64_t Camera3DeviceImpl::CaptureResultInfo::GetMetadataKeyValue64(
int32_t key) const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
camera_metadata_ro_entry_t entry;
return GetMetadataKeyEntry(key, &entry) ? entry.data.i64[0] : -EINVAL;
}
ScopedCameraMetadata
Camera3DeviceImpl::CaptureResultInfo::MergePartialMetadata() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
size_t entry_count = 0;
size_t data_count = 0;
for (const auto& it : partial_metadata_) {
entry_count += get_camera_metadata_entry_count(it.get());
data_count += get_camera_metadata_data_count(it.get());
}
camera_metadata_t* metadata =
allocate_camera_metadata(entry_count, data_count);
if (!metadata) {
ADD_FAILURE() << "Can't allocate larger metadata buffer";
return nullptr;
}
for (const auto& it : partial_metadata_) {
append_camera_metadata(metadata, it.get());
}
return ScopedCameraMetadata(metadata);
}
bool Camera3DeviceImpl::CaptureResultInfo::GetMetadataKeyEntry(
int32_t key, camera_metadata_ro_entry_t* entry) const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
camera_metadata_ro_entry_t local_entry;
entry = entry ? entry : &local_entry;
for (const auto& it : partial_metadata_) {
if (find_camera_metadata_ro_entry(it.get(), key, entry) == 0) {
return true;
}
}
return false;
}
const std::string Camera3DeviceImpl::GetThreadName(int cam_id) {
const size_t kThreadNameLength = 30;
char thread_name[kThreadNameLength];
snprintf(thread_name, kThreadNameLength, "Camera3 Test Device %d Thread",
cam_id);
return std::string(thread_name);
}
} // namespace camera3_test