| // Copyright 2016 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_device_fixture.h" |
| |
| #include <algorithm> |
| |
| namespace camera3_test { |
| |
| int Camera3Device::Initialize(Camera3Module* cam_module, |
| const camera3_callback_ops_t* callback_ops) { |
| if (!cam_module || !hal_thread_.Start()) { |
| return -EINVAL; |
| } |
| |
| // Open camera device |
| cam_device_ = cam_module->OpenDevice(cam_id_); |
| if (!cam_device_) { |
| return -ENODEV; |
| } |
| |
| EXPECT_GE(((const hw_device_t*)cam_device_)->version, |
| (uint16_t)HARDWARE_MODULE_API_VERSION(3, 3)) |
| << "The device must support at least HALv3.3"; |
| |
| // Initialize camera device |
| int result = -EIO; |
| hal_thread_.PostTaskSync(base::Bind(&Camera3Device::InitializeOnHalThread, |
| base::Unretained(this), callback_ops, |
| &result)); |
| EXPECT_EQ(0, result) << "Camera device initialization fails"; |
| |
| EXPECT_NE(nullptr, gralloc_) << "Gralloc initialization fails"; |
| |
| camera_info cam_info; |
| EXPECT_EQ(0, cam_module->GetCameraInfo(cam_id_, &cam_info)); |
| static_info_.reset(new StaticInfo(cam_info)); |
| EXPECT_TRUE(static_info_->IsHardwareLevelAtLeastLimited()) |
| << "The device must support at least LIMITED hardware level"; |
| |
| if (testing::Test::HasFailure()) { |
| return -EINVAL; |
| } |
| |
| initialized_ = true; |
| return 0; |
| } |
| |
| void Camera3Device::Destroy() { |
| // Buffers are expected to be freed in ProcessCaptureResult callback in the |
| // test. |
| EXPECT_TRUE(stream_buffers_.empty()) << "Buffers are not freed correctly"; |
| |
| int result = -EIO; |
| hal_thread_.PostTaskSync(base::Bind(&Camera3Device::CloseOnHalThread, |
| base::Unretained(this), &result)); |
| EXPECT_EQ(0, result) << "Camera device close failed"; |
| hal_thread_.Stop(); |
| } |
| |
| bool Camera3Device::IsTemplateSupported(int32_t type) const { |
| return (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)); |
| } |
| |
| const camera_metadata_t* Camera3Device::ConstructDefaultRequestSettings( |
| int type) { |
| if (!initialized_) { |
| return NULL; |
| } |
| const camera_metadata_t* metadata = nullptr; |
| hal_thread_.PostTaskSync( |
| base::Bind(&Camera3Device::ConstructDefaultRequestSettingsOnHalThread, |
| base::Unretained(this), type, &metadata)); |
| return metadata; |
| } |
| |
| void Camera3Device::AddOutputStream(int format, int width, int height) { |
| camera3_stream_t stream = {}; |
| stream.stream_type = CAMERA3_STREAM_OUTPUT; |
| stream.width = width; |
| stream.height = height; |
| stream.format = format; |
| |
| // Push to the bin that is not used currently |
| { |
| base::AutoLock l(stream_lock_); |
| cam_stream_[!cam_stream_idx_].push_back(stream); |
| } |
| } |
| |
| int Camera3Device::ConfigureStreams() { |
| base::AutoLock l(stream_lock_); |
| |
| // Check whether there are streams |
| if (cam_stream_[!cam_stream_idx_].size() == 0) { |
| return -EINVAL; |
| } |
| |
| // 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; |
| |
| // Configure streams now |
| int ret = -EIO; |
| hal_thread_.PostTaskSync( |
| base::Bind(&Camera3Device::ConfigureStreamsOnHalThread, |
| base::Unretained(this), &cam_stream_config, &ret)); |
| |
| // Swap to the other bin |
| cam_stream_[cam_stream_idx_].clear(); |
| cam_stream_idx_ = !cam_stream_idx_; |
| |
| return ret; |
| } |
| |
| int Camera3Device::AllocateOutputStreamBuffers( |
| std::vector<camera3_stream_buffer_t>* output_buffers) { |
| std::vector<camera3_stream_t> streams; |
| return AllocateOutputStreamBuffersByStreams(streams, output_buffers); |
| } |
| |
| int Camera3Device::AllocateOutputStreamBuffersByStreams( |
| const std::vector<camera3_stream_t>& streams, |
| std::vector<camera3_stream_buffer_t>* output_buffers) { |
| base::AutoLock l1(stream_lock_); |
| |
| int32_t jpeg_max_size = static_info_->GetJpegMaxSize(); |
| if (!output_buffers || |
| (streams.empty() && cam_stream_[cam_stream_idx_].size() == 0) || |
| jpeg_max_size <= 0) { |
| return -EINVAL; |
| } |
| |
| const std::vector<camera3_stream_t>* streams_ptr = |
| streams.empty() ? &cam_stream_[cam_stream_idx_] : &streams; |
| for (const auto& it : *streams_ptr) { |
| BufferHandleUniquePtr 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, |
| GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_CAMERA_WRITE); |
| EXPECT_NE(nullptr, buffer) << "Gralloc allocation fails"; |
| |
| camera3_stream_buffer_t stream_buffer; |
| { |
| base::AutoLock l2(stream_buffers_lock_); |
| 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_buffers_[stream].insert(std::move(buffer)); |
| } |
| output_buffers->push_back(stream_buffer); |
| } |
| |
| return 0; |
| } |
| |
| int Camera3Device::FreeOutputStreamBuffers( |
| const std::vector<camera3_stream_buffer_t>& output_buffers) { |
| base::AutoLock l(stream_buffers_lock_); |
| |
| for (const auto& output_buffer : output_buffers) { |
| if (stream_buffers_.find(output_buffer.stream) == stream_buffers_.end() || |
| !output_buffer.buffer) { |
| LOG(ERROR) << "Failed to find configured stream or buffer is invalid"; |
| return -EINVAL; |
| } |
| |
| bool found = false; |
| for (const auto& it : stream_buffers_[output_buffer.stream]) { |
| if (*it == *output_buffer.buffer) { |
| stream_buffers_[output_buffer.stream].erase(it); |
| if (stream_buffers_[output_buffer.stream].empty()) { |
| stream_buffers_.erase(output_buffer.stream); |
| } |
| found = true; |
| break; |
| } |
| } |
| if (!found) { |
| LOG(ERROR) << "Failed to find output buffer"; |
| return -EINVAL; |
| } |
| } |
| return 0; |
| } |
| |
| void Camera3Device::ClearOutputStreamBuffers() { |
| base::AutoLock l(stream_buffers_lock_); |
| // Free frame buffers |
| stream_buffers_.clear(); |
| } |
| |
| int Camera3Device::ProcessCaptureRequest(camera3_capture_request_t* request) { |
| if (!initialized_) { |
| return -ENODEV; |
| } |
| int ret = -EIO; |
| hal_thread_.PostTaskSync( |
| base::Bind(&Camera3Device::ProcessCaptureRequestOnHalThread, |
| base::Unretained(this), request, &ret)); |
| return ret; |
| } |
| |
| int Camera3Device::Flush() { |
| if (!initialized_) { |
| return -ENODEV; |
| } |
| int ret = -EIO; |
| hal_thread_.PostTaskSync(base::Bind(&Camera3Device::FlushOnHalThread, |
| base::Unretained(this), &ret)); |
| return ret; |
| } |
| |
| const std::string Camera3Device::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); |
| } |
| |
| void Camera3Device::InitializeOnHalThread( |
| const camera3_callback_ops_t* callback_ops, |
| int* result) { |
| *result = cam_device_->ops->initialize(cam_device_, callback_ops); |
| } |
| |
| void Camera3Device::ConstructDefaultRequestSettingsOnHalThread( |
| int type, |
| const camera_metadata_t** result) { |
| *result = |
| cam_device_->ops->construct_default_request_settings(cam_device_, type); |
| } |
| |
| void Camera3Device::ConfigureStreamsOnHalThread( |
| camera3_stream_configuration_t* config, |
| int* result) { |
| *result = cam_device_->ops->configure_streams(cam_device_, config); |
| } |
| |
| void Camera3Device::ProcessCaptureRequestOnHalThread( |
| camera3_capture_request_t* request, |
| int* result) { |
| *result = cam_device_->ops->process_capture_request(cam_device_, request); |
| } |
| |
| void Camera3Device::FlushOnHalThread(int* result) { |
| *result = cam_device_->ops->flush(cam_device_); |
| } |
| |
| void Camera3Device::CloseOnHalThread(int* result) { |
| ASSERT_NE(nullptr, cam_device_->common.close) |
| << "Camera close() is not implemented"; |
| *result = cam_device_->common.close(&cam_device_->common); |
| } |
| |
| const Camera3Device::StaticInfo* Camera3Device::GetStaticInfo() const { |
| return static_info_.get(); |
| } |
| |
| Camera3Device::StaticInfo::StaticInfo(const camera_info& cam_info) |
| : characteristics_(const_cast<camera_metadata_t*>( |
| cam_info.static_camera_characteristics)) {} |
| |
| bool Camera3Device::StaticInfo::IsKeyAvailable(uint32_t tag) const { |
| return AreKeysAvailable(std::vector<uint32_t>(1, tag)); |
| } |
| |
| bool Camera3Device::StaticInfo::AreKeysAvailable( |
| std::vector<uint32_t> tags) const { |
| for (const auto& tag : tags) { |
| camera_metadata_ro_entry_t entry; |
| if (find_camera_metadata_ro_entry(characteristics_, tag, &entry)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| int32_t Camera3Device::StaticInfo::GetHardwareLevel() const { |
| camera_metadata_ro_entry_t entry; |
| if (find_camera_metadata_ro_entry(characteristics_, |
| ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, |
| &entry) != 0) { |
| ADD_FAILURE() |
| << "Cannot find the metadata ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL"; |
| return -EINVAL; |
| } |
| return entry.data.i32[0]; |
| } |
| |
| bool Camera3Device::StaticInfo::IsHardwareLevelAtLeast(int32_t level) const { |
| int32_t dev_level = GetHardwareLevel(); |
| if (dev_level == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) { |
| return dev_level == level; |
| } |
| // Level is not LEGACY, can use numerical sort |
| return dev_level >= level; |
| } |
| |
| bool Camera3Device::StaticInfo::IsHardwareLevelAtLeastFull() const { |
| return IsHardwareLevelAtLeast(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL); |
| } |
| |
| bool Camera3Device::StaticInfo::IsHardwareLevelAtLeastLimited() const { |
| return IsHardwareLevelAtLeast(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED); |
| } |
| |
| bool Camera3Device::StaticInfo::IsCapabilitySupported( |
| int32_t capability) const { |
| EXPECT_GE(capability, 0) << "Capability must be non-negative"; |
| |
| camera_metadata_ro_entry_t entry; |
| if (find_camera_metadata_ro_entry(characteristics_, |
| ANDROID_REQUEST_AVAILABLE_CAPABILITIES, |
| &entry) == 0) { |
| for (size_t i = 0; i < entry.count; i++) { |
| if (entry.data.i32[i] == capability) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| bool Camera3Device::StaticInfo::IsDepthOutputSupported() const { |
| return IsCapabilitySupported( |
| ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT); |
| } |
| |
| bool Camera3Device::StaticInfo::IsColorOutputSupported() const { |
| return IsCapabilitySupported( |
| ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE); |
| } |
| |
| std::set<uint8_t> Camera3Device::StaticInfo::GetAvailableModes( |
| int32_t key, |
| int32_t min_value, |
| int32_t max_value) const { |
| camera_metadata_ro_entry_t entry; |
| if (find_camera_metadata_ro_entry(characteristics_, key, &entry) != 0) { |
| ADD_FAILURE() << "Cannot find the metadata " |
| << get_camera_metadata_tag_name(key); |
| return std::set<uint8_t>(); |
| } |
| std::set<uint8_t> modes; |
| for (size_t i = 0; i < entry.count; i++) { |
| uint8_t mode = entry.data.u8[i]; |
| // Each element must be distinct |
| EXPECT_TRUE(modes.find(mode) == modes.end()) |
| << "Duplicate modes " << mode << " for the metadata " |
| << get_camera_metadata_tag_name(key); |
| EXPECT_TRUE(mode >= min_value && mode <= max_value) |
| << "Mode " << mode << " is outside of [" << min_value << "," |
| << max_value << "] for the metadata " |
| << get_camera_metadata_tag_name(key); |
| modes.insert(mode); |
| } |
| return modes; |
| } |
| |
| std::set<uint8_t> Camera3Device::StaticInfo::GetAvailableEdgeModes() const { |
| std::set<uint8_t> modes = GetAvailableModes( |
| ANDROID_EDGE_AVAILABLE_EDGE_MODES, ANDROID_EDGE_MODE_OFF, |
| ANDROID_EDGE_MODE_ZERO_SHUTTER_LAG); |
| |
| // Full device should always include OFF and FAST |
| if (IsHardwareLevelAtLeastFull()) { |
| EXPECT_TRUE((modes.find(ANDROID_EDGE_MODE_OFF) != modes.end()) && |
| (modes.find(ANDROID_EDGE_MODE_FAST) != modes.end())) |
| << "Full device must contain OFF and FAST edge modes"; |
| } |
| |
| // FAST and HIGH_QUALITY mode must be both present or both not present |
| EXPECT_TRUE((modes.find(ANDROID_EDGE_MODE_FAST) != modes.end()) == |
| (modes.find(ANDROID_EDGE_MODE_HIGH_QUALITY) != modes.end())) |
| << "FAST and HIGH_QUALITY mode must both present or both not present"; |
| |
| return modes; |
| } |
| |
| std::set<uint8_t> Camera3Device::StaticInfo::GetAvailableNoiseReductionModes() |
| const { |
| std::set<uint8_t> modes = |
| GetAvailableModes(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES, |
| ANDROID_NOISE_REDUCTION_MODE_OFF, |
| ANDROID_NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG); |
| |
| // Full device should always include OFF and FAST |
| if (IsHardwareLevelAtLeastFull()) { |
| EXPECT_TRUE((modes.find(ANDROID_NOISE_REDUCTION_MODE_OFF) != modes.end()) && |
| (modes.find(ANDROID_NOISE_REDUCTION_MODE_FAST) != modes.end())) |
| << "Full device must contain OFF and FAST noise reduction modes"; |
| } |
| |
| // FAST and HIGH_QUALITY mode must be both present or both not present |
| EXPECT_TRUE( |
| (modes.find(ANDROID_NOISE_REDUCTION_MODE_FAST) != modes.end()) == |
| (modes.find(ANDROID_NOISE_REDUCTION_MODE_HIGH_QUALITY) != modes.end())) |
| << "FAST and HIGH_QUALITY mode must both present or both not present"; |
| |
| return modes; |
| } |
| |
| std::set<uint8_t> Camera3Device::StaticInfo::GetAvailableColorAberrationModes() |
| const { |
| std::set<uint8_t> modes = |
| GetAvailableModes(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES, |
| ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF, |
| ANDROID_COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY); |
| |
| EXPECT_TRUE((modes.find(ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF) != |
| modes.end()) || |
| (modes.find(ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST) != |
| modes.end())) |
| << "Camera devices must always support either OFF or FAST mode"; |
| |
| // FAST and HIGH_QUALITY mode must be both present or both not present |
| EXPECT_TRUE( |
| (modes.find(ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST) != |
| modes.end()) == |
| (modes.find(ANDROID_COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY) != |
| modes.end())) |
| << "FAST and HIGH_QUALITY mode must both present or both not present"; |
| |
| return modes; |
| } |
| |
| std::set<uint8_t> Camera3Device::StaticInfo::GetAvailableToneMapModes() const { |
| std::set<uint8_t> modes = GetAvailableModes( |
| ANDROID_TONEMAP_AVAILABLE_TONE_MAP_MODES, |
| ANDROID_TONEMAP_MODE_CONTRAST_CURVE, ANDROID_TONEMAP_MODE_PRESET_CURVE); |
| |
| EXPECT_TRUE(modes.find(ANDROID_TONEMAP_MODE_FAST) != modes.end()) |
| << "Camera devices must always support FAST mode"; |
| |
| // FAST and HIGH_QUALITY mode must be both present |
| EXPECT_TRUE(modes.find(ANDROID_TONEMAP_MODE_HIGH_QUALITY) != modes.end()) |
| << "FAST and HIGH_QUALITY mode must both present"; |
| |
| return modes; |
| } |
| |
| void Camera3Device::StaticInfo::GetStreamConfigEntry( |
| camera_metadata_ro_entry_t* entry) const { |
| entry->count = 0; |
| |
| camera_metadata_ro_entry_t local_entry = {}; |
| ASSERT_EQ( |
| 0, find_camera_metadata_ro_entry( |
| characteristics_, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, |
| &local_entry)) |
| << "Fail to find metadata key " |
| "ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS"; |
| ASSERT_NE(0u, local_entry.count) << "Camera stream configuration is empty"; |
| ASSERT_EQ(0u, local_entry.count % kNumOfElementsInStreamConfigEntry) |
| << "Camera stream configuration parsing error"; |
| *entry = local_entry; |
| } |
| |
| std::set<int32_t> Camera3Device::StaticInfo::GetAvailableFormats( |
| int32_t direction) const { |
| camera_metadata_ro_entry_t available_config = {}; |
| GetStreamConfigEntry(&available_config); |
| std::set<int32_t> formats; |
| for (size_t i = 0; i < available_config.count; |
| i += kNumOfElementsInStreamConfigEntry) { |
| int32_t format = available_config.data.i32[i + STREAM_CONFIG_FORMAT_INDEX]; |
| int32_t in_or_out = |
| available_config.data.i32[i + STREAM_CONFIG_DIRECTION_INDEX]; |
| if (in_or_out == direction) { |
| formats.insert(format); |
| } |
| } |
| return formats; |
| } |
| |
| bool Camera3Device::StaticInfo::IsFormatAvailable(int format) const { |
| camera_metadata_ro_entry_t available_config = {}; |
| GetStreamConfigEntry(&available_config); |
| for (uint32_t i = 0; i < available_config.count; |
| i += kNumOfElementsInStreamConfigEntry) { |
| if (available_config.data.i32[i + STREAM_CONFIG_FORMAT_INDEX] == format) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| std::vector<ResolutionInfo> |
| Camera3Device::StaticInfo::GetSortedOutputResolutions(int32_t format) const { |
| camera_metadata_ro_entry_t available_config = {}; |
| GetStreamConfigEntry(&available_config); |
| std::vector<ResolutionInfo> available_resolutions; |
| for (uint32_t i = 0; i < available_config.count; |
| i += kNumOfElementsInStreamConfigEntry) { |
| int32_t fmt = available_config.data.i32[i + STREAM_CONFIG_FORMAT_INDEX]; |
| int32_t width = available_config.data.i32[i + STREAM_CONFIG_WIDTH_INDEX]; |
| int32_t height = available_config.data.i32[i + STREAM_CONFIG_HEIGHT_INDEX]; |
| int32_t in_or_out = |
| available_config.data.i32[i + STREAM_CONFIG_DIRECTION_INDEX]; |
| if ((fmt == format) && |
| (in_or_out == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT)) { |
| available_resolutions.emplace_back(width, height); |
| } |
| } |
| std::sort(available_resolutions.begin(), available_resolutions.end()); |
| return available_resolutions; |
| } |
| |
| bool Camera3Device::StaticInfo::IsAELockSupported() const { |
| camera_metadata_ro_entry_t entry; |
| if (find_camera_metadata_ro_entry( |
| characteristics_, ANDROID_CONTROL_AE_LOCK_AVAILABLE, &entry) != 0) { |
| ADD_FAILURE() |
| << "Cannot find the metadata ANDROID_CONTROL_AE_LOCK_AVAILABLE"; |
| return false; |
| } |
| return entry.data.i32[0] == ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE; |
| } |
| |
| bool Camera3Device::StaticInfo::IsAWBLockSupported() const { |
| camera_metadata_ro_entry_t entry; |
| if (find_camera_metadata_ro_entry( |
| characteristics_, ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &entry) != 0) { |
| ADD_FAILURE() |
| << "Cannot find the metadata ANDROID_CONTROL_AWB_LOCK_AVAILABLE"; |
| return false; |
| } |
| return entry.data.i32[0] == ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE; |
| } |
| |
| int32_t Camera3Device::StaticInfo::GetPartialResultCount() const { |
| camera_metadata_ro_entry_t entry; |
| if (find_camera_metadata_ro_entry(characteristics_, |
| ANDROID_REQUEST_PARTIAL_RESULT_COUNT, |
| &entry) != 0) { |
| // Optional key. Default value is 1 if key is missing. |
| return 1; |
| } |
| return entry.data.i32[0]; |
| } |
| |
| int32_t Camera3Device::StaticInfo::GetJpegMaxSize() const { |
| camera_metadata_ro_entry_t entry; |
| if (find_camera_metadata_ro_entry(characteristics_, ANDROID_JPEG_MAX_SIZE, |
| &entry) != 0) { |
| ADD_FAILURE() << "Cannot find the metadata ANDROID_JPEG_MAX_SIZE"; |
| return -EINVAL; |
| } |
| return entry.data.i32[0]; |
| } |
| |
| int32_t Camera3Device::StaticInfo::GetSensorOrientation() const { |
| camera_metadata_ro_entry_t entry; |
| if (find_camera_metadata_ro_entry(characteristics_, |
| ANDROID_SENSOR_ORIENTATION, &entry) != 0) { |
| ADD_FAILURE() << "Cannot find the metadata ANDROID_SENSOR_ORIENTATION"; |
| return -EINVAL; |
| } |
| return entry.data.i32[0]; |
| } |
| |
| // Test fixture |
| |
| void Camera3DeviceFixture::SetUp() { |
| ASSERT_EQ(0, cam_module_.Initialize()) |
| << "Camera module initialization fails"; |
| |
| // Prepare callback functions for camera device |
| Camera3DeviceFixture::notify = Camera3DeviceFixture::NotifyCallback; |
| Camera3DeviceFixture::process_capture_result = |
| Camera3DeviceFixture::ProcessCaptureResultCallback; |
| |
| ASSERT_EQ(0, cam_device_.Initialize(&cam_module_, this)) |
| << "Camera device initialization fails"; |
| } |
| |
| void Camera3DeviceFixture::TearDown() { |
| cam_device_.Destroy(); |
| } |
| |
| void Camera3DeviceFixture::ProcessCaptureResult( |
| const camera3_capture_result* result) { |
| // Do nothing in this callback |
| } |
| |
| void Camera3DeviceFixture::Notify(const camera3_notify_msg* msg) { |
| // Do nothing in this callback |
| } |
| |
| void Camera3DeviceFixture::ProcessCaptureResultCallback( |
| const camera3_callback_ops* cb, |
| const camera3_capture_result* result) { |
| // Forward to callback of instance |
| Camera3DeviceFixture* d = const_cast<Camera3DeviceFixture*>( |
| static_cast<const Camera3DeviceFixture*>(cb)); |
| d->ProcessCaptureResult(result); |
| } |
| |
| void Camera3DeviceFixture::NotifyCallback(const camera3_callback_ops* cb, |
| const camera3_notify_msg* msg) { |
| // Forward to callback of instance |
| Camera3DeviceFixture* d = const_cast<Camera3DeviceFixture*>( |
| static_cast<const Camera3DeviceFixture*>(cb)); |
| d->Notify(msg); |
| } |
| |
| // Test cases |
| |
| // Test spec: |
| // - Camera ID |
| class Camera3DeviceSimpleTest : public Camera3DeviceFixture, |
| public ::testing::WithParamInterface<int> { |
| public: |
| Camera3DeviceSimpleTest() : Camera3DeviceFixture(GetParam()) {} |
| }; |
| |
| TEST_P(Camera3DeviceSimpleTest, SensorOrientationTest) { |
| // Chromebook has a hardware requirement that the top of the camera should |
| // match the top of the display in tablet mode. |
| ASSERT_EQ(0, cam_device_.GetStaticInfo()->GetSensorOrientation()) |
| << "Invalid camera sensor orientation"; |
| } |
| |
| // Test spec: |
| // - Camera ID |
| // - Capture type |
| class Camera3DeviceDefaultSettings |
| : public Camera3DeviceFixture, |
| public ::testing::WithParamInterface<std::tuple<int, int>> { |
| public: |
| Camera3DeviceDefaultSettings() |
| : Camera3DeviceFixture(std::get<0>(GetParam())) {} |
| }; |
| |
| static bool IsMetadataKeyAvailable(const camera_metadata_t* settings, |
| int32_t key) { |
| camera_metadata_ro_entry_t entry; |
| return find_camera_metadata_ro_entry(settings, key, &entry) == 0; |
| } |
| |
| static void ExpectKeyValue(const camera_metadata_t* settings, |
| int32_t key, |
| const char* key_name, |
| int32_t value, |
| int32_t compare_type) { |
| camera_metadata_ro_entry_t entry; |
| ASSERT_EQ(0, find_camera_metadata_ro_entry(settings, key, &entry)) |
| << "Cannot find the metadata " << key_name; |
| if (compare_type == 0) { |
| ASSERT_EQ(value, entry.data.i32[0]) << "Wrong value of metadata " |
| << key_name; |
| } else { |
| ASSERT_NE(value, entry.data.i32[0]) << "Wrong value of metadata " |
| << key_name; |
| } |
| } |
| #define EXPECT_KEY_VALUE_EQ(settings, key, value) \ |
| ExpectKeyValue(settings, key, #key, value, 0) |
| #define EXPECT_KEY_VALUE_NE(settings, key, value) \ |
| ExpectKeyValue(settings, key, #key, value, 1) |
| |
| static void ExpectKeyValueNotEqualsI64(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_NE(value, entry.data.i64[0]) << "Wrong value of metadata " << key_name; |
| } |
| #define EXPECT_KEY_VALUE_NE_I64(settings, key, value) \ |
| ExpectKeyValueNotEqualsI64(settings, key, #key, value) |
| |
| TEST_P(Camera3DeviceDefaultSettings, ConstructDefaultSettings) { |
| int type = std::get<1>(GetParam()); |
| |
| const camera_metadata_t* default_settings; |
| default_settings = cam_device_.ConstructDefaultRequestSettings(type); |
| ASSERT_NE(nullptr, default_settings) << "Camera default settings are NULL"; |
| |
| auto static_info = cam_device_.GetStaticInfo(); |
| |
| // Reference: camera2/cts/CameraDeviceTest.java#captureTemplateTestByCamera |
| if (!cam_device_.IsTemplateSupported(type)) { |
| return; |
| } else if (type != CAMERA3_TEMPLATE_PREVIEW && |
| static_info->IsDepthOutputSupported() && |
| !static_info->IsColorOutputSupported()) { |
| // Depth-only devices need only support PREVIEW template |
| return; |
| } |
| |
| // Reference: camera2/cts/CameraDeviceTest.java#checkRequestForTemplate |
| // 3A settings--control mode |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_CONTROL_AE_MODE, |
| ANDROID_CONTROL_AE_MODE_ON); |
| |
| EXPECT_KEY_VALUE_EQ(default_settings, |
| ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION, 0); |
| |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, |
| ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); |
| |
| // if AE lock is not supported, expect the control key to be non-existent or |
| // false |
| if (static_info->IsAELockSupported() || |
| IsMetadataKeyAvailable(default_settings, ANDROID_CONTROL_AE_LOCK)) { |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_CONTROL_AE_LOCK, |
| ANDROID_CONTROL_AE_LOCK_OFF); |
| } |
| |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_CONTROL_AF_TRIGGER, |
| ANDROID_CONTROL_AF_TRIGGER_IDLE); |
| |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_CONTROL_AWB_MODE, |
| ANDROID_CONTROL_AWB_MODE_AUTO); |
| |
| // if AWB lock is not supported, expect the control key to be non-existent or |
| // false |
| if (static_info->IsAWBLockSupported() || |
| IsMetadataKeyAvailable(default_settings, ANDROID_CONTROL_AWB_LOCK)) { |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_CONTROL_AWB_LOCK, |
| ANDROID_CONTROL_AWB_LOCK_OFF); |
| } |
| |
| // Check 3A regions |
| // TODO: CONTROL_AE_REGIONS, CONTROL_AWB_REGIONS, CONTROL_AF_REGIONS? |
| |
| // Sensor settings |
| // TODO: LENS_APERTURE, LENS_FILTER_DENSITY, LENS_FOCAL_LENGTH, |
| // LENS_OPTICAL_STABILIZATION_MODE? |
| // BLACK_LEVEL_LOCK? |
| |
| if (static_info->IsKeyAvailable(ANDROID_BLACK_LEVEL_LOCK)) { |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_BLACK_LEVEL_LOCK, |
| ANDROID_BLACK_LEVEL_LOCK_OFF); |
| } |
| |
| if (static_info->IsKeyAvailable(ANDROID_SENSOR_FRAME_DURATION)) { |
| EXPECT_KEY_VALUE_NE_I64(default_settings, ANDROID_SENSOR_FRAME_DURATION, 0); |
| } |
| |
| if (static_info->IsKeyAvailable(ANDROID_SENSOR_EXPOSURE_TIME)) { |
| EXPECT_KEY_VALUE_NE_I64(default_settings, ANDROID_SENSOR_EXPOSURE_TIME, 0); |
| } |
| |
| if (static_info->IsKeyAvailable(ANDROID_SENSOR_SENSITIVITY)) { |
| EXPECT_KEY_VALUE_NE(default_settings, ANDROID_SENSOR_SENSITIVITY, 0); |
| } |
| |
| // ISP-processing settings |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_STATISTICS_FACE_DETECT_MODE, |
| ANDROID_STATISTICS_FACE_DETECT_MODE_OFF); |
| |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_FLASH_MODE, |
| ANDROID_FLASH_MODE_OFF); |
| |
| if (static_info->IsKeyAvailable(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE)) { |
| // If the device doesn't support RAW, all template should have OFF as |
| // default |
| if (!static_info->IsCapabilitySupported( |
| ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW)) { |
| EXPECT_KEY_VALUE_EQ(default_settings, |
| ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, |
| ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF); |
| } |
| } |
| |
| bool support_reprocessing = |
| static_info->IsCapabilitySupported( |
| ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING) || |
| static_info->IsCapabilitySupported( |
| ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING); |
| |
| if (type == CAMERA3_TEMPLATE_STILL_CAPTURE) { |
| // Not enforce high quality here, as some devices may not effectively have |
| // high quality mode |
| if (static_info->IsKeyAvailable(ANDROID_COLOR_CORRECTION_MODE)) { |
| EXPECT_KEY_VALUE_NE(default_settings, ANDROID_COLOR_CORRECTION_MODE, |
| ANDROID_COLOR_CORRECTION_MODE_TRANSFORM_MATRIX); |
| } |
| |
| // Edge enhancement, noise reduction and aberration correction modes. |
| EXPECT_EQ(static_info->IsKeyAvailable(ANDROID_EDGE_MODE), |
| static_info->IsKeyAvailable(ANDROID_EDGE_AVAILABLE_EDGE_MODES)) |
| << "Edge mode must be present in request if available edge modes are " |
| "present in metadata, and vice-versa"; |
| if (static_info->IsKeyAvailable(ANDROID_EDGE_MODE)) { |
| std::set<uint8_t> edge_modes = static_info->GetAvailableEdgeModes(); |
| // Don't need check fast as fast or high quality must be both present or |
| // both not. |
| if (edge_modes.find(ANDROID_EDGE_MODE_HIGH_QUALITY) != edge_modes.end()) { |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_EDGE_MODE, |
| ANDROID_EDGE_MODE_HIGH_QUALITY); |
| } else { |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_EDGE_MODE, |
| ANDROID_EDGE_MODE_OFF); |
| } |
| } |
| |
| EXPECT_EQ(static_info->IsKeyAvailable(ANDROID_NOISE_REDUCTION_MODE), |
| static_info->IsKeyAvailable( |
| ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES)) |
| << "Noise reduction mode must be present in request if available noise " |
| "reductions are present in metadata, and vice-versa"; |
| if (static_info->IsKeyAvailable( |
| ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES)) { |
| std::set<uint8_t> nr_modes = |
| static_info->GetAvailableNoiseReductionModes(); |
| // Don't need check fast as fast or high quality must be both present or |
| // both not |
| if (nr_modes.find(ANDROID_NOISE_REDUCTION_MODE_HIGH_QUALITY) != |
| nr_modes.end()) { |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_NOISE_REDUCTION_MODE, |
| ANDROID_NOISE_REDUCTION_MODE_HIGH_QUALITY); |
| } else { |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_NOISE_REDUCTION_MODE, |
| ANDROID_NOISE_REDUCTION_MODE_OFF); |
| } |
| } |
| |
| EXPECT_EQ( |
| static_info->IsKeyAvailable(ANDROID_COLOR_CORRECTION_ABERRATION_MODE), |
| static_info->IsKeyAvailable( |
| ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES)) |
| << "Aberration correction mode must be present in request if available " |
| "aberration correction reductions are present in metadata, and " |
| "vice-versa"; |
| if (static_info->IsKeyAvailable(ANDROID_COLOR_CORRECTION_ABERRATION_MODE)) { |
| std::set<uint8_t> aberration_modes = |
| static_info->GetAvailableColorAberrationModes(); |
| // Don't need check fast as fast or high quality must be both present or |
| // both not |
| if (aberration_modes.find( |
| ANDROID_COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY) != |
| aberration_modes.end()) { |
| EXPECT_KEY_VALUE_EQ( |
| default_settings, ANDROID_COLOR_CORRECTION_ABERRATION_MODE, |
| ANDROID_COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY); |
| } else { |
| EXPECT_KEY_VALUE_EQ(default_settings, |
| ANDROID_COLOR_CORRECTION_ABERRATION_MODE, |
| ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF); |
| } |
| } |
| } else if (type == CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG && |
| support_reprocessing) { |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_EDGE_MODE, |
| ANDROID_EDGE_MODE_ZERO_SHUTTER_LAG); |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_NOISE_REDUCTION_MODE, |
| ANDROID_NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG); |
| } else if (type == CAMERA3_TEMPLATE_PREVIEW || |
| type == CAMERA3_TEMPLATE_VIDEO_RECORD) { |
| if (static_info->IsKeyAvailable(ANDROID_EDGE_MODE)) { |
| std::set<uint8_t> edge_modes = static_info->GetAvailableEdgeModes(); |
| if (edge_modes.find(ANDROID_EDGE_MODE_FAST) != edge_modes.end()) { |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_EDGE_MODE, |
| ANDROID_EDGE_MODE_FAST); |
| } else { |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_EDGE_MODE, |
| ANDROID_EDGE_MODE_OFF); |
| } |
| } |
| |
| if (static_info->IsKeyAvailable(ANDROID_NOISE_REDUCTION_MODE)) { |
| std::set<uint8_t> nr_modes = |
| static_info->GetAvailableNoiseReductionModes(); |
| if (nr_modes.find(ANDROID_NOISE_REDUCTION_MODE_FAST) != nr_modes.end()) { |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_NOISE_REDUCTION_MODE, |
| ANDROID_NOISE_REDUCTION_MODE_FAST); |
| } else { |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_NOISE_REDUCTION_MODE, |
| ANDROID_NOISE_REDUCTION_MODE_OFF); |
| } |
| } |
| |
| if (static_info->IsKeyAvailable(ANDROID_COLOR_CORRECTION_ABERRATION_MODE)) { |
| std::set<uint8_t> aberration_modes = |
| static_info->GetAvailableColorAberrationModes(); |
| if (aberration_modes.find( |
| ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST) != |
| aberration_modes.end()) { |
| EXPECT_KEY_VALUE_EQ(default_settings, |
| ANDROID_COLOR_CORRECTION_ABERRATION_MODE, |
| ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST); |
| } else { |
| EXPECT_KEY_VALUE_EQ(default_settings, |
| ANDROID_COLOR_CORRECTION_ABERRATION_MODE, |
| ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF); |
| } |
| } |
| } else { |
| if (static_info->IsKeyAvailable(ANDROID_EDGE_MODE)) { |
| EXPECT_KEY_VALUE_NE(default_settings, ANDROID_EDGE_MODE, 0); |
| } |
| |
| if (static_info->IsKeyAvailable(ANDROID_NOISE_REDUCTION_MODE)) { |
| EXPECT_KEY_VALUE_NE(default_settings, ANDROID_NOISE_REDUCTION_MODE, 0); |
| } |
| |
| if (static_info->IsKeyAvailable(ANDROID_COLOR_CORRECTION_ABERRATION_MODE)) { |
| EXPECT_KEY_VALUE_NE(default_settings, |
| ANDROID_COLOR_CORRECTION_ABERRATION_MODE, 0); |
| } |
| } |
| |
| // Tone map and lens shading modes. |
| if (type == CAMERA3_TEMPLATE_STILL_CAPTURE) { |
| EXPECT_EQ( |
| static_info->IsKeyAvailable(ANDROID_TONEMAP_MODE), |
| static_info->IsKeyAvailable(ANDROID_TONEMAP_AVAILABLE_TONE_MAP_MODES)) |
| << "Tonemap mode must be present in request if available tonemap modes " |
| "are present in metadata, and vice-versa"; |
| if (static_info->IsKeyAvailable(ANDROID_TONEMAP_AVAILABLE_TONE_MAP_MODES)) { |
| std::set<uint8_t> tone_map_modes = |
| static_info->GetAvailableToneMapModes(); |
| if (tone_map_modes.find(ANDROID_TONEMAP_MODE_HIGH_QUALITY) != |
| tone_map_modes.end()) { |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_TONEMAP_MODE, |
| ANDROID_TONEMAP_MODE_HIGH_QUALITY); |
| } else { |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_TONEMAP_MODE, |
| ANDROID_TONEMAP_MODE_FAST); |
| } |
| } |
| |
| // Still capture template should have android.statistics.lensShadingMapMode |
| // ON when RAW capability is supported. |
| if (static_info->IsKeyAvailable(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE) && |
| static_info->IsCapabilitySupported( |
| ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW)) { |
| EXPECT_KEY_VALUE_EQ(default_settings, |
| ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, |
| ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_ON); |
| } |
| } else { |
| if (static_info->IsKeyAvailable(ANDROID_TONEMAP_MODE)) { |
| EXPECT_KEY_VALUE_NE(default_settings, ANDROID_TONEMAP_MODE, |
| ANDROID_TONEMAP_MODE_CONTRAST_CURVE); |
| EXPECT_KEY_VALUE_NE(default_settings, ANDROID_TONEMAP_MODE, |
| ANDROID_TONEMAP_MODE_GAMMA_VALUE); |
| EXPECT_KEY_VALUE_NE(default_settings, ANDROID_TONEMAP_MODE, |
| ANDROID_TONEMAP_MODE_PRESET_CURVE); |
| } |
| if (static_info->IsKeyAvailable(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE)) { |
| EXPECT_KEY_VALUE_NE(default_settings, |
| ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, 0); |
| } |
| } |
| |
| EXPECT_KEY_VALUE_EQ(default_settings, ANDROID_CONTROL_CAPTURE_INTENT, type); |
| } |
| |
| // Test spec: |
| // - Camera ID |
| // - Capture type |
| class CreateInvalidTemplate |
| : public Camera3DeviceFixture, |
| public ::testing::WithParamInterface<std::tuple<int, int>> { |
| public: |
| CreateInvalidTemplate() : Camera3DeviceFixture(std::get<0>(GetParam())) {} |
| }; |
| |
| TEST_P(CreateInvalidTemplate, ConstructDefaultSettings) { |
| // Reference: |
| // camera2/cts/CameraDeviceTest.java#testCameraDeviceCreateCaptureBuilder |
| int type = std::get<1>(GetParam()); |
| LOG(ERROR) << type; |
| ASSERT_EQ(nullptr, cam_device_.ConstructDefaultRequestSettings(type)) |
| << "Should get error due to an invalid template ID"; |
| } |
| |
| INSTANTIATE_TEST_CASE_P(Camera3DeviceTest, |
| Camera3DeviceSimpleTest, |
| ::testing::ValuesIn(Camera3Module().GetCameraIds())); |
| |
| INSTANTIATE_TEST_CASE_P( |
| Camera3DeviceTest, |
| Camera3DeviceDefaultSettings, |
| ::testing::Combine(::testing::ValuesIn(Camera3Module().GetCameraIds()), |
| ::testing::Values(CAMERA3_TEMPLATE_PREVIEW, |
| CAMERA3_TEMPLATE_STILL_CAPTURE, |
| CAMERA3_TEMPLATE_VIDEO_RECORD, |
| CAMERA3_TEMPLATE_VIDEO_SNAPSHOT, |
| CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG, |
| CAMERA3_TEMPLATE_MANUAL))); |
| |
| INSTANTIATE_TEST_CASE_P( |
| Camera3DeviceTest, |
| CreateInvalidTemplate, |
| ::testing::Combine(::testing::ValuesIn(Camera3Module().GetCameraIds()), |
| ::testing::Values(CAMERA3_TEMPLATE_PREVIEW - 1, |
| CAMERA3_TEMPLATE_MANUAL + 1))); |
| |
| } // namespace camera3_test |