blob: 9dbe09442c531d8ecbbae1abaa04838b399a5814 [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// #define LOG_NDEBUG 0
#define LOG_TAG "VirtualCameraDevice"
#include "VirtualCameraDevice.h"
#include <array>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <string>
#include "CameraMetadata.h"
#include "VirtualCameraSession.h"
#include "aidl/android/hardware/camera/common/Status.h"
#include "aidl/android/hardware/camera/device/CameraMetadata.h"
#include "android/binder_auto_utils.h"
#include "android/binder_status.h"
#include "log/log.h"
#include "system/camera_metadata.h"
#include "util/MetadataBuilder.h"
#include "util/Util.h"
namespace android {
namespace services {
namespace virtualcamera {
using ::aidl::android::hardware::camera::common::CameraResourceCost;
using ::aidl::android::hardware::camera::common::Status;
using ::aidl::android::hardware::camera::device::CameraMetadata;
using ::aidl::android::hardware::camera::device::ICameraDeviceCallback;
using ::aidl::android::hardware::camera::device::ICameraDeviceSession;
using ::aidl::android::hardware::camera::device::ICameraInjectionSession;
using ::aidl::android::hardware::camera::device::StreamConfiguration;
using ::aidl::android::hardware::camera::device::StreamRotation;
using ::aidl::android::hardware::camera::device::StreamType;
using ::aidl::android::hardware::graphics::common::PixelFormat;
namespace {
using namespace std::chrono_literals;
// Prefix of camera name - "device@1.1/virtual/{numerical_id}"
const char* kDevicePathPrefix = "device@1.1/virtual/";
constexpr int32_t kVgaWidth = 640;
constexpr int32_t kVgaHeight = 480;
constexpr std::chrono::nanoseconds kMinFrameDuration30Fps = 1s / 30;
constexpr int32_t kMaxJpegSize = 3 * 1024 * 1024 /*3MiB*/;
constexpr MetadataBuilder::ControlRegion kDefaultEmptyControlRegion{};
// TODO(b/301023410) - Populate camera characteristics according to camera configuration.
CameraMetadata initCameraCharacteristics() {
auto metadata =
MetadataBuilder()
.setSupportedHardwareLevel(
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL)
.setFlashAvailable(false)
.setLensFacing(ANDROID_LENS_FACING_EXTERNAL)
.setSensorOrientation(0)
.setAvailableFaceDetectModes({ANDROID_STATISTICS_FACE_DETECT_MODE_OFF})
.setControlAfAvailableModes({ANDROID_CONTROL_AF_MODE_OFF})
.setAvailableOutputStreamConfigurations(
{MetadataBuilder::StreamConfiguration{
.width = kVgaWidth,
.height = kVgaHeight,
.format =
ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,
.minFrameDuration = kMinFrameDuration30Fps,
.minStallDuration = 0s},
{MetadataBuilder::StreamConfiguration{
.width = kVgaWidth,
.height = kVgaHeight,
.format = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB,
.minFrameDuration = kMinFrameDuration30Fps,
.minStallDuration = 0s}}})
.setControlAeAvailableFpsRange(10, 30)
.setControlMaxRegions(0, 0, 0)
.setSensorActiveArraySize(0, 0, kVgaWidth, kVgaHeight)
.setControlAfRegions({kDefaultEmptyControlRegion})
.setControlAeRegions({kDefaultEmptyControlRegion})
.setControlAwbRegions({kDefaultEmptyControlRegion})
.setControlAeCompensationRange(0, 1)
.setControlAeCompensationStep(camera_metadata_rational_t{0, 1})
.setMaxJpegSize(kMaxJpegSize)
.setAvailableRequestKeys({ANDROID_CONTROL_AF_MODE})
.setAvailableResultKeys({ANDROID_CONTROL_AF_MODE})
.setAvailableCapabilities(
{ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE})
.setAvailableCharacteristicKeys()
.build();
if (metadata == nullptr) {
ALOGE("Failed to build metadata!");
return CameraMetadata();
}
return std::move(*metadata);
}
} // namespace
VirtualCameraDevice::VirtualCameraDevice(const uint32_t cameraId)
: mCameraId(cameraId) {
mCameraCharacteristics = initCameraCharacteristics();
}
ndk::ScopedAStatus VirtualCameraDevice::getCameraCharacteristics(
CameraMetadata* _aidl_return) {
ALOGV("%s", __func__);
if (_aidl_return == nullptr) {
return cameraStatus(Status::ILLEGAL_ARGUMENT);
}
*_aidl_return = mCameraCharacteristics;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus VirtualCameraDevice::getPhysicalCameraCharacteristics(
const std::string& in_physicalCameraId, CameraMetadata* _aidl_return) {
ALOGV("%s: physicalCameraId %s", __func__, in_physicalCameraId.c_str());
(void)_aidl_return;
// VTS tests expect this call to fail with illegal argument status for
// all publicly advertised camera ids.
// Because we don't support physical camera ids, we just always
// fail with illegal argument (there's no valid argument to provide).
return cameraStatus(Status::ILLEGAL_ARGUMENT);
}
ndk::ScopedAStatus VirtualCameraDevice::getResourceCost(
CameraResourceCost* _aidl_return) {
ALOGV("%s", __func__);
if (_aidl_return == nullptr) {
return cameraStatus(Status::ILLEGAL_ARGUMENT);
}
_aidl_return->resourceCost = 100; // ¯\_(ツ)_/¯
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus VirtualCameraDevice::isStreamCombinationSupported(
const StreamConfiguration& in_streams, bool* _aidl_return) {
ALOGV("%s", __func__);
if (_aidl_return == nullptr) {
return cameraStatus(Status::ILLEGAL_ARGUMENT);
}
for (const auto& stream : in_streams.streams) {
ALOGV("%s: Configuration queried: %s", __func__, stream.toString().c_str());
if (stream.streamType == StreamType::INPUT) {
ALOGW("%s: Input stream type is not supported", __func__);
*_aidl_return = false;
return ndk::ScopedAStatus::ok();
}
// TODO(b/301023410) remove hardcoded format checks, verify against configuration.
if (stream.width != 640 || stream.height != 480 ||
stream.rotation != StreamRotation::ROTATION_0 ||
(stream.format != PixelFormat::IMPLEMENTATION_DEFINED &&
stream.format != PixelFormat::YCBCR_420_888 &&
stream.format != PixelFormat::BLOB)) {
*_aidl_return = false;
return ndk::ScopedAStatus::ok();
}
}
*_aidl_return = true;
return ndk::ScopedAStatus::ok();
};
ndk::ScopedAStatus VirtualCameraDevice::open(
const std::shared_ptr<ICameraDeviceCallback>& in_callback,
std::shared_ptr<ICameraDeviceSession>* _aidl_return) {
ALOGV("%s", __func__);
*_aidl_return = ndk::SharedRefBase::make<VirtualCameraSession>(
in_callback, std::to_string(mCameraId));
return ndk::ScopedAStatus::ok();
};
ndk::ScopedAStatus VirtualCameraDevice::openInjectionSession(
const std::shared_ptr<ICameraDeviceCallback>& in_callback,
std::shared_ptr<ICameraInjectionSession>* _aidl_return) {
ALOGV("%s", __func__);
(void)in_callback;
(void)_aidl_return;
return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
}
ndk::ScopedAStatus VirtualCameraDevice::setTorchMode(bool in_on) {
ALOGV("%s: on = %s", __func__, in_on ? "on" : "off");
return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
}
ndk::ScopedAStatus VirtualCameraDevice::turnOnTorchWithStrengthLevel(
int32_t in_torchStrength) {
ALOGV("%s: torchStrength = %d", __func__, in_torchStrength);
return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
}
ndk::ScopedAStatus VirtualCameraDevice::getTorchStrengthLevel(
int32_t* _aidl_return) {
(void)_aidl_return;
return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
}
binder_status_t VirtualCameraDevice::dump(int fd, const char** args,
uint32_t numArgs) {
// TODO(b/301023410) Implement.
(void)fd;
(void)args;
(void)numArgs;
return STATUS_OK;
}
std::string VirtualCameraDevice::getCameraName() const {
return std::string(kDevicePathPrefix) + std::to_string(mCameraId);
}
} // namespace virtualcamera
} // namespace services
} // namespace android