blob: f39e4370a45ab42c771a05dabfaa501627ea1314 [file] [log] [blame]
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +01001/*
Biswarup Pal6152a302023-12-19 12:44:09 +00002 * Copyright 2023 The Android Open Source Project
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +01003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// #define LOG_NDEBUG 0
18#define LOG_TAG "VirtualCameraDevice"
19#include "VirtualCameraDevice.h"
20
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010021#include <algorithm>
22#include <array>
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010023#include <chrono>
24#include <cstdint>
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010025#include <iterator>
26#include <optional>
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010027#include <string>
28
29#include "VirtualCameraSession.h"
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010030#include "aidl/android/companion/virtualcamera/SupportedStreamConfiguration.h"
Biswarup Pal6152a302023-12-19 12:44:09 +000031#include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010032#include "aidl/android/hardware/camera/common/Status.h"
33#include "aidl/android/hardware/camera/device/CameraMetadata.h"
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010034#include "aidl/android/hardware/camera/device/StreamConfiguration.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010035#include "android/binder_auto_utils.h"
36#include "android/binder_status.h"
37#include "log/log.h"
38#include "system/camera_metadata.h"
39#include "util/MetadataBuilder.h"
40#include "util/Util.h"
41
42namespace android {
43namespace companion {
44namespace virtualcamera {
45
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010046using ::aidl::android::companion::virtualcamera::Format;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010047using ::aidl::android::companion::virtualcamera::IVirtualCameraCallback;
Biswarup Pal6152a302023-12-19 12:44:09 +000048using ::aidl::android::companion::virtualcamera::SensorOrientation;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010049using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
Biswarup Pal6152a302023-12-19 12:44:09 +000050using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010051using ::aidl::android::hardware::camera::common::CameraResourceCost;
52using ::aidl::android::hardware::camera::common::Status;
53using ::aidl::android::hardware::camera::device::CameraMetadata;
54using ::aidl::android::hardware::camera::device::ICameraDeviceCallback;
55using ::aidl::android::hardware::camera::device::ICameraDeviceSession;
56using ::aidl::android::hardware::camera::device::ICameraInjectionSession;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010057using ::aidl::android::hardware::camera::device::Stream;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010058using ::aidl::android::hardware::camera::device::StreamConfiguration;
59using ::aidl::android::hardware::camera::device::StreamRotation;
60using ::aidl::android::hardware::camera::device::StreamType;
61using ::aidl::android::hardware::graphics::common::PixelFormat;
62
63namespace {
64
65using namespace std::chrono_literals;
66
67// Prefix of camera name - "device@1.1/virtual/{numerical_id}"
68const char* kDevicePathPrefix = "device@1.1/virtual/";
69
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010070constexpr int32_t kMaxJpegSize = 3 * 1024 * 1024 /*3MiB*/;
71
72constexpr MetadataBuilder::ControlRegion kDefaultEmptyControlRegion{};
73
Biswarup Pal6152a302023-12-19 12:44:09 +000074const std::array<int32_t, 3> kOutputFormats{
75 ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,
76 ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888,
77 ANDROID_SCALER_AVAILABLE_FORMATS_BLOB};
78
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010079struct Resolution {
80 Resolution(const int w, const int h) : width(w), height(h) {
81 }
82
83 bool operator<(const Resolution& other) const {
84 return width * height < other.width * other.height;
85 }
86
87 bool operator==(const Resolution& other) const {
88 return width == other.width && height == other.height;
89 }
90
91 const int width;
92 const int height;
93};
94
95std::optional<Resolution> getMaxResolution(
96 const std::vector<SupportedStreamConfiguration>& configs) {
97 auto itMax = std::max_element(configs.begin(), configs.end(),
98 [](const SupportedStreamConfiguration& a,
99 const SupportedStreamConfiguration& b) {
100 return a.width * b.height < a.width * b.height;
101 });
102 if (itMax == configs.end()) {
103 ALOGE(
104 "%s: empty vector of supported configurations, cannot find largest "
105 "resolution.",
106 __func__);
107 return std::nullopt;
108 }
109
110 return Resolution(itMax->width, itMax->height);
111}
112
Biswarup Pal6152a302023-12-19 12:44:09 +0000113// Returns a map of unique resolution to maximum maxFps for all streams with
114// that resolution.
115std::map<Resolution, int> getResolutionToMaxFpsMap(
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100116 const std::vector<SupportedStreamConfiguration>& configs) {
Biswarup Pal6152a302023-12-19 12:44:09 +0000117 std::map<Resolution, int> resolutionToMaxFpsMap;
118
119 for (const SupportedStreamConfiguration& config : configs) {
120 Resolution resolution(config.width, config.height);
121 if (resolutionToMaxFpsMap.find(resolution) == resolutionToMaxFpsMap.end()) {
122 resolutionToMaxFpsMap[resolution] = config.maxFps;
123 } else {
124 int currentMaxFps = resolutionToMaxFpsMap[resolution];
125 resolutionToMaxFpsMap[resolution] = std::max(currentMaxFps, config.maxFps);
126 }
127 }
128
129 return resolutionToMaxFpsMap;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100130}
131
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100132// TODO(b/301023410) - Populate camera characteristics according to camera configuration.
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100133std::optional<CameraMetadata> initCameraCharacteristics(
Biswarup Pal6152a302023-12-19 12:44:09 +0000134 const std::vector<SupportedStreamConfiguration>& supportedInputConfig,
135 const SensorOrientation sensorOrientation) {
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100136 if (!std::all_of(supportedInputConfig.begin(), supportedInputConfig.end(),
137 [](const SupportedStreamConfiguration& config) {
Jan Sebechlebsky042d1fb2023-12-12 16:37:00 +0100138 return isFormatSupportedForInput(
Biswarup Pal6152a302023-12-19 12:44:09 +0000139 config.width, config.height, config.pixelFormat,
140 config.maxFps);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100141 })) {
Jan Sebechlebsky042d1fb2023-12-12 16:37:00 +0100142 ALOGE("%s: input configuration contains unsupported format", __func__);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100143 return std::nullopt;
144 }
145
146 MetadataBuilder builder =
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100147 MetadataBuilder()
148 .setSupportedHardwareLevel(
149 ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL)
150 .setFlashAvailable(false)
151 .setLensFacing(ANDROID_LENS_FACING_EXTERNAL)
Biswarup Pal6152a302023-12-19 12:44:09 +0000152 .setSensorOrientation(static_cast<int32_t>(sensorOrientation))
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100153 .setAvailableFaceDetectModes({ANDROID_STATISTICS_FACE_DETECT_MODE_OFF})
Jan Sebechlebskyb0119fa2023-12-04 10:29:06 +0100154 .setAvailableMaxDigitalZoom(1.0)
155 .setControlAvailableModes({ANDROID_CONTROL_MODE_AUTO})
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100156 .setControlAfAvailableModes({ANDROID_CONTROL_AF_MODE_OFF})
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100157 .setControlAeAvailableFpsRange(10, 30)
158 .setControlMaxRegions(0, 0, 0)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100159 .setControlAfRegions({kDefaultEmptyControlRegion})
160 .setControlAeRegions({kDefaultEmptyControlRegion})
161 .setControlAwbRegions({kDefaultEmptyControlRegion})
162 .setControlAeCompensationRange(0, 1)
163 .setControlAeCompensationStep(camera_metadata_rational_t{0, 1})
Jan Sebechlebsky6ab07fe2023-12-05 15:23:34 +0100164 .setControlZoomRatioRange(/*min=*/1.0, /*max=*/1.0)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100165 .setMaxJpegSize(kMaxJpegSize)
166 .setAvailableRequestKeys({ANDROID_CONTROL_AF_MODE})
167 .setAvailableResultKeys({ANDROID_CONTROL_AF_MODE})
168 .setAvailableCapabilities(
169 {ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE})
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100170 .setAvailableCharacteristicKeys();
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100171
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100172 // Active array size must correspond to largest supported input resolution.
173 std::optional<Resolution> maxResolution =
174 getMaxResolution(supportedInputConfig);
175 if (!maxResolution.has_value()) {
176 return std::nullopt;
177 }
178 builder.setSensorActiveArraySize(0, 0, maxResolution->width,
179 maxResolution->height);
180
181 std::vector<MetadataBuilder::StreamConfiguration> outputConfigurations;
182
183 // TODO(b/301023410) Add also all "standard" resolutions we can rescale the
184 // streams to (all standard resolutions with same aspect ratio).
185
Biswarup Pal6152a302023-12-19 12:44:09 +0000186 std::map<Resolution, int> resolutionToMaxFpsMap =
187 getResolutionToMaxFpsMap(supportedInputConfig);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100188
Biswarup Pal6152a302023-12-19 12:44:09 +0000189 // Add configurations for all unique input resolutions and output formats.
190 for (int32_t format : kOutputFormats) {
191 std::transform(
192 resolutionToMaxFpsMap.begin(), resolutionToMaxFpsMap.end(),
193 std::back_inserter(outputConfigurations), [format](const auto& entry) {
194 Resolution resolution = entry.first;
195 int maxFps = entry.second;
196 return MetadataBuilder::StreamConfiguration{
197 .width = resolution.width,
198 .height = resolution.height,
199 .format = format,
200 .minFrameDuration = std::chrono::nanoseconds(1s) / maxFps,
201 .minStallDuration = 0s};
202 });
203 }
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100204
205 ALOGV("Adding %zu output configurations", outputConfigurations.size());
206 builder.setAvailableOutputStreamConfigurations(outputConfigurations);
207
208 auto metadata = builder.build();
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100209 if (metadata == nullptr) {
210 ALOGE("Failed to build metadata!");
211 return CameraMetadata();
212 }
213
214 return std::move(*metadata);
215}
216
217} // namespace
218
219VirtualCameraDevice::VirtualCameraDevice(
Biswarup Pal6152a302023-12-19 12:44:09 +0000220 const uint32_t cameraId, const VirtualCameraConfiguration& configuration)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100221 : mCameraId(cameraId),
Biswarup Pal6152a302023-12-19 12:44:09 +0000222 mVirtualCameraClientCallback(configuration.virtualCameraCallback),
223 mSupportedInputConfigurations(configuration.supportedStreamConfigs) {
224 std::optional<CameraMetadata> metadata = initCameraCharacteristics(
225 mSupportedInputConfigurations, configuration.sensorOrientation);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100226 if (metadata.has_value()) {
227 mCameraCharacteristics = *metadata;
228 } else {
229 ALOGE(
230 "%s: Failed to initialize camera characteristic based on provided "
231 "configuration.",
232 __func__);
233 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100234}
235
236ndk::ScopedAStatus VirtualCameraDevice::getCameraCharacteristics(
237 CameraMetadata* _aidl_return) {
238 ALOGV("%s", __func__);
239 if (_aidl_return == nullptr) {
240 return cameraStatus(Status::ILLEGAL_ARGUMENT);
241 }
242
243 *_aidl_return = mCameraCharacteristics;
244 return ndk::ScopedAStatus::ok();
245}
246
247ndk::ScopedAStatus VirtualCameraDevice::getPhysicalCameraCharacteristics(
248 const std::string& in_physicalCameraId, CameraMetadata* _aidl_return) {
249 ALOGV("%s: physicalCameraId %s", __func__, in_physicalCameraId.c_str());
250 (void)_aidl_return;
251
252 // VTS tests expect this call to fail with illegal argument status for
253 // all publicly advertised camera ids.
254 // Because we don't support physical camera ids, we just always
255 // fail with illegal argument (there's no valid argument to provide).
256 return cameraStatus(Status::ILLEGAL_ARGUMENT);
257}
258
259ndk::ScopedAStatus VirtualCameraDevice::getResourceCost(
260 CameraResourceCost* _aidl_return) {
261 ALOGV("%s", __func__);
262 if (_aidl_return == nullptr) {
263 return cameraStatus(Status::ILLEGAL_ARGUMENT);
264 }
265 _aidl_return->resourceCost = 100; // ¯\_(ツ)_/¯
266 return ndk::ScopedAStatus::ok();
267}
268
269ndk::ScopedAStatus VirtualCameraDevice::isStreamCombinationSupported(
270 const StreamConfiguration& in_streams, bool* _aidl_return) {
271 ALOGV("%s", __func__);
272
273 if (_aidl_return == nullptr) {
274 return cameraStatus(Status::ILLEGAL_ARGUMENT);
275 }
276
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100277 *_aidl_return = isStreamCombinationSupported(in_streams);
278 return ndk::ScopedAStatus::ok();
279};
280
281bool VirtualCameraDevice::isStreamCombinationSupported(
282 const StreamConfiguration& streamConfiguration) const {
283 for (const Stream& stream : streamConfiguration.streams) {
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100284 ALOGV("%s: Configuration queried: %s", __func__, stream.toString().c_str());
285
286 if (stream.streamType == StreamType::INPUT) {
287 ALOGW("%s: Input stream type is not supported", __func__);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100288 return false;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100289 }
290
291 // TODO(b/301023410) remove hardcoded format checks, verify against configuration.
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100292 if (stream.rotation != StreamRotation::ROTATION_0 ||
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100293 (stream.format != PixelFormat::IMPLEMENTATION_DEFINED &&
294 stream.format != PixelFormat::YCBCR_420_888 &&
295 stream.format != PixelFormat::BLOB)) {
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100296 ALOGV("Unsupported output stream type");
297 return false;
298 }
299
300 auto matchesSupportedInputConfig =
301 [&stream](const SupportedStreamConfiguration& config) {
302 return stream.width == config.width && stream.height == config.height;
303 };
304 if (std::none_of(mSupportedInputConfigurations.begin(),
305 mSupportedInputConfigurations.end(),
306 matchesSupportedInputConfig)) {
307 ALOGV("Requested config doesn't match any supported input config");
308 return false;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100309 }
310 }
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100311 return true;
312}
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100313
314ndk::ScopedAStatus VirtualCameraDevice::open(
315 const std::shared_ptr<ICameraDeviceCallback>& in_callback,
316 std::shared_ptr<ICameraDeviceSession>* _aidl_return) {
317 ALOGV("%s", __func__);
318
319 *_aidl_return = ndk::SharedRefBase::make<VirtualCameraSession>(
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100320 sharedFromThis(), in_callback, mVirtualCameraClientCallback);
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100321
322 return ndk::ScopedAStatus::ok();
323};
324
325ndk::ScopedAStatus VirtualCameraDevice::openInjectionSession(
326 const std::shared_ptr<ICameraDeviceCallback>& in_callback,
327 std::shared_ptr<ICameraInjectionSession>* _aidl_return) {
328 ALOGV("%s", __func__);
329
330 (void)in_callback;
331 (void)_aidl_return;
332 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
333}
334
335ndk::ScopedAStatus VirtualCameraDevice::setTorchMode(bool in_on) {
336 ALOGV("%s: on = %s", __func__, in_on ? "on" : "off");
337 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
338}
339
340ndk::ScopedAStatus VirtualCameraDevice::turnOnTorchWithStrengthLevel(
341 int32_t in_torchStrength) {
342 ALOGV("%s: torchStrength = %d", __func__, in_torchStrength);
343 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
344}
345
346ndk::ScopedAStatus VirtualCameraDevice::getTorchStrengthLevel(
347 int32_t* _aidl_return) {
348 (void)_aidl_return;
349 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
350}
351
352binder_status_t VirtualCameraDevice::dump(int fd, const char** args,
353 uint32_t numArgs) {
354 // TODO(b/301023410) Implement.
355 (void)fd;
356 (void)args;
357 (void)numArgs;
358 return STATUS_OK;
359}
360
361std::string VirtualCameraDevice::getCameraName() const {
362 return std::string(kDevicePathPrefix) + std::to_string(mCameraId);
363}
364
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100365std::shared_ptr<VirtualCameraDevice> VirtualCameraDevice::sharedFromThis() {
366 // SharedRefBase which BnCameraDevice inherits from breaks
367 // std::enable_shared_from_this. This is recommended replacement for
368 // shared_from_this() per documentation in binder_interface_utils.h.
369 return ref<VirtualCameraDevice>();
370}
371
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100372} // namespace virtualcamera
373} // namespace companion
374} // namespace android