blob: f844cfec6c46d6fe6169b54875a11a0818803238 [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 Pal112458f2023-12-28 19:50:17 +000048using ::aidl::android::companion::virtualcamera::LensFacing;
Biswarup Pal6152a302023-12-19 12:44:09 +000049using ::aidl::android::companion::virtualcamera::SensorOrientation;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010050using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
Biswarup Pal6152a302023-12-19 12:44:09 +000051using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010052using ::aidl::android::hardware::camera::common::CameraResourceCost;
53using ::aidl::android::hardware::camera::common::Status;
54using ::aidl::android::hardware::camera::device::CameraMetadata;
55using ::aidl::android::hardware::camera::device::ICameraDeviceCallback;
56using ::aidl::android::hardware::camera::device::ICameraDeviceSession;
57using ::aidl::android::hardware::camera::device::ICameraInjectionSession;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010058using ::aidl::android::hardware::camera::device::Stream;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010059using ::aidl::android::hardware::camera::device::StreamConfiguration;
60using ::aidl::android::hardware::camera::device::StreamRotation;
61using ::aidl::android::hardware::camera::device::StreamType;
62using ::aidl::android::hardware::graphics::common::PixelFormat;
63
64namespace {
65
66using namespace std::chrono_literals;
67
68// Prefix of camera name - "device@1.1/virtual/{numerical_id}"
69const char* kDevicePathPrefix = "device@1.1/virtual/";
70
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010071constexpr int32_t kMaxJpegSize = 3 * 1024 * 1024 /*3MiB*/;
72
73constexpr MetadataBuilder::ControlRegion kDefaultEmptyControlRegion{};
74
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +010075const std::array<PixelFormat, 3> kOutputFormats{
76 PixelFormat::IMPLEMENTATION_DEFINED, PixelFormat::YCBCR_420_888,
77 PixelFormat::BLOB};
Biswarup Pal6152a302023-12-19 12:44:09 +000078
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
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +010095bool isSupportedOutputFormat(const PixelFormat pixelFormat) {
96 return std::find(kOutputFormats.begin(), kOutputFormats.end(), pixelFormat) !=
97 kOutputFormats.end();
98}
99
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100100std::optional<Resolution> getMaxResolution(
101 const std::vector<SupportedStreamConfiguration>& configs) {
102 auto itMax = std::max_element(configs.begin(), configs.end(),
103 [](const SupportedStreamConfiguration& a,
104 const SupportedStreamConfiguration& b) {
105 return a.width * b.height < a.width * b.height;
106 });
107 if (itMax == configs.end()) {
108 ALOGE(
109 "%s: empty vector of supported configurations, cannot find largest "
110 "resolution.",
111 __func__);
112 return std::nullopt;
113 }
114
115 return Resolution(itMax->width, itMax->height);
116}
117
Biswarup Pal6152a302023-12-19 12:44:09 +0000118// Returns a map of unique resolution to maximum maxFps for all streams with
119// that resolution.
120std::map<Resolution, int> getResolutionToMaxFpsMap(
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100121 const std::vector<SupportedStreamConfiguration>& configs) {
Biswarup Pal6152a302023-12-19 12:44:09 +0000122 std::map<Resolution, int> resolutionToMaxFpsMap;
123
124 for (const SupportedStreamConfiguration& config : configs) {
125 Resolution resolution(config.width, config.height);
126 if (resolutionToMaxFpsMap.find(resolution) == resolutionToMaxFpsMap.end()) {
127 resolutionToMaxFpsMap[resolution] = config.maxFps;
128 } else {
129 int currentMaxFps = resolutionToMaxFpsMap[resolution];
130 resolutionToMaxFpsMap[resolution] = std::max(currentMaxFps, config.maxFps);
131 }
132 }
133
134 return resolutionToMaxFpsMap;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100135}
136
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100137// TODO(b/301023410) - Populate camera characteristics according to camera configuration.
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100138std::optional<CameraMetadata> initCameraCharacteristics(
Biswarup Pal6152a302023-12-19 12:44:09 +0000139 const std::vector<SupportedStreamConfiguration>& supportedInputConfig,
Biswarup Pal112458f2023-12-28 19:50:17 +0000140 const SensorOrientation sensorOrientation, const LensFacing lensFacing) {
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100141 if (!std::all_of(supportedInputConfig.begin(), supportedInputConfig.end(),
142 [](const SupportedStreamConfiguration& config) {
Jan Sebechlebsky042d1fb2023-12-12 16:37:00 +0100143 return isFormatSupportedForInput(
Biswarup Pal6152a302023-12-19 12:44:09 +0000144 config.width, config.height, config.pixelFormat,
145 config.maxFps);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100146 })) {
Jan Sebechlebsky042d1fb2023-12-12 16:37:00 +0100147 ALOGE("%s: input configuration contains unsupported format", __func__);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100148 return std::nullopt;
149 }
150
151 MetadataBuilder builder =
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100152 MetadataBuilder()
153 .setSupportedHardwareLevel(
154 ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL)
155 .setFlashAvailable(false)
Biswarup Pal112458f2023-12-28 19:50:17 +0000156 .setLensFacing(
157 static_cast<camera_metadata_enum_android_lens_facing>(lensFacing))
Biswarup Pal6152a302023-12-19 12:44:09 +0000158 .setSensorOrientation(static_cast<int32_t>(sensorOrientation))
Jan Sebechlebskya984ffb2024-02-01 09:12:37 +0100159 .setSensorReadoutTimestamp(
160 ANDROID_SENSOR_READOUT_TIMESTAMP_NOT_SUPPORTED)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100161 .setAvailableFaceDetectModes({ANDROID_STATISTICS_FACE_DETECT_MODE_OFF})
Jan Sebechlebskyb0119fa2023-12-04 10:29:06 +0100162 .setAvailableMaxDigitalZoom(1.0)
163 .setControlAvailableModes({ANDROID_CONTROL_MODE_AUTO})
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100164 .setControlAfAvailableModes({ANDROID_CONTROL_AF_MODE_OFF})
Jan Sebechlebsky4425a732024-01-31 11:31:54 +0100165 .setControlAvailableSceneModes({ANDROID_CONTROL_SCENE_MODE_DISABLED})
166 .setControlAvailableEffects({ANDROID_CONTROL_EFFECT_MODE_OFF})
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100167 .setControlAeAvailableFpsRange(10, 30)
168 .setControlMaxRegions(0, 0, 0)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100169 .setControlAfRegions({kDefaultEmptyControlRegion})
170 .setControlAeRegions({kDefaultEmptyControlRegion})
171 .setControlAwbRegions({kDefaultEmptyControlRegion})
172 .setControlAeCompensationRange(0, 1)
173 .setControlAeCompensationStep(camera_metadata_rational_t{0, 1})
Jan Sebechlebsky4425a732024-01-31 11:31:54 +0100174 .setControlAwbLockAvailable(false)
175 .setControlAeLockAvailable(false)
176 .setControlAvailableAwbModes({ANDROID_CONTROL_AWB_MODE_AUTO})
Jan Sebechlebsky6ab07fe2023-12-05 15:23:34 +0100177 .setControlZoomRatioRange(/*min=*/1.0, /*max=*/1.0)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100178 .setMaxJpegSize(kMaxJpegSize)
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100179 .setMaxNumberOutputStreams(
180 VirtualCameraDevice::kMaxNumberOfRawStreams,
181 VirtualCameraDevice::kMaxNumberOfProcessedStreams,
182 VirtualCameraDevice::kMaxNumberOfStallStreams)
Jan Sebechlebsky4425a732024-01-31 11:31:54 +0100183 .setSyncMaxLatency(ANDROID_SYNC_MAX_LATENCY_UNKNOWN)
184 .setAvailableRequestKeys({})
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100185 .setAvailableRequestKeys({ANDROID_CONTROL_AF_MODE})
186 .setAvailableResultKeys({ANDROID_CONTROL_AF_MODE})
187 .setAvailableCapabilities(
188 {ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE})
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100189 .setAvailableCharacteristicKeys();
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100190
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100191 // Active array size must correspond to largest supported input resolution.
192 std::optional<Resolution> maxResolution =
193 getMaxResolution(supportedInputConfig);
194 if (!maxResolution.has_value()) {
195 return std::nullopt;
196 }
197 builder.setSensorActiveArraySize(0, 0, maxResolution->width,
198 maxResolution->height);
199
200 std::vector<MetadataBuilder::StreamConfiguration> outputConfigurations;
201
202 // TODO(b/301023410) Add also all "standard" resolutions we can rescale the
203 // streams to (all standard resolutions with same aspect ratio).
204
Biswarup Pal6152a302023-12-19 12:44:09 +0000205 std::map<Resolution, int> resolutionToMaxFpsMap =
206 getResolutionToMaxFpsMap(supportedInputConfig);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100207
Biswarup Pal6152a302023-12-19 12:44:09 +0000208 // Add configurations for all unique input resolutions and output formats.
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100209 for (const PixelFormat format : kOutputFormats) {
Biswarup Pal6152a302023-12-19 12:44:09 +0000210 std::transform(
211 resolutionToMaxFpsMap.begin(), resolutionToMaxFpsMap.end(),
212 std::back_inserter(outputConfigurations), [format](const auto& entry) {
213 Resolution resolution = entry.first;
214 int maxFps = entry.second;
215 return MetadataBuilder::StreamConfiguration{
216 .width = resolution.width,
217 .height = resolution.height,
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100218 .format = static_cast<int32_t>(format),
Biswarup Pal6152a302023-12-19 12:44:09 +0000219 .minFrameDuration = std::chrono::nanoseconds(1s) / maxFps,
220 .minStallDuration = 0s};
221 });
222 }
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100223
224 ALOGV("Adding %zu output configurations", outputConfigurations.size());
225 builder.setAvailableOutputStreamConfigurations(outputConfigurations);
226
227 auto metadata = builder.build();
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100228 if (metadata == nullptr) {
229 ALOGE("Failed to build metadata!");
230 return CameraMetadata();
231 }
232
233 return std::move(*metadata);
234}
235
236} // namespace
237
238VirtualCameraDevice::VirtualCameraDevice(
Biswarup Pal6152a302023-12-19 12:44:09 +0000239 const uint32_t cameraId, const VirtualCameraConfiguration& configuration)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100240 : mCameraId(cameraId),
Biswarup Pal6152a302023-12-19 12:44:09 +0000241 mVirtualCameraClientCallback(configuration.virtualCameraCallback),
242 mSupportedInputConfigurations(configuration.supportedStreamConfigs) {
243 std::optional<CameraMetadata> metadata = initCameraCharacteristics(
Biswarup Pal112458f2023-12-28 19:50:17 +0000244 mSupportedInputConfigurations, configuration.sensorOrientation,
245 configuration.lensFacing);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100246 if (metadata.has_value()) {
247 mCameraCharacteristics = *metadata;
248 } else {
249 ALOGE(
250 "%s: Failed to initialize camera characteristic based on provided "
251 "configuration.",
252 __func__);
253 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100254}
255
256ndk::ScopedAStatus VirtualCameraDevice::getCameraCharacteristics(
257 CameraMetadata* _aidl_return) {
258 ALOGV("%s", __func__);
259 if (_aidl_return == nullptr) {
260 return cameraStatus(Status::ILLEGAL_ARGUMENT);
261 }
262
263 *_aidl_return = mCameraCharacteristics;
264 return ndk::ScopedAStatus::ok();
265}
266
267ndk::ScopedAStatus VirtualCameraDevice::getPhysicalCameraCharacteristics(
268 const std::string& in_physicalCameraId, CameraMetadata* _aidl_return) {
269 ALOGV("%s: physicalCameraId %s", __func__, in_physicalCameraId.c_str());
270 (void)_aidl_return;
271
272 // VTS tests expect this call to fail with illegal argument status for
273 // all publicly advertised camera ids.
274 // Because we don't support physical camera ids, we just always
275 // fail with illegal argument (there's no valid argument to provide).
276 return cameraStatus(Status::ILLEGAL_ARGUMENT);
277}
278
279ndk::ScopedAStatus VirtualCameraDevice::getResourceCost(
280 CameraResourceCost* _aidl_return) {
281 ALOGV("%s", __func__);
282 if (_aidl_return == nullptr) {
283 return cameraStatus(Status::ILLEGAL_ARGUMENT);
284 }
285 _aidl_return->resourceCost = 100; // ¯\_(ツ)_/¯
286 return ndk::ScopedAStatus::ok();
287}
288
289ndk::ScopedAStatus VirtualCameraDevice::isStreamCombinationSupported(
290 const StreamConfiguration& in_streams, bool* _aidl_return) {
291 ALOGV("%s", __func__);
292
293 if (_aidl_return == nullptr) {
294 return cameraStatus(Status::ILLEGAL_ARGUMENT);
295 }
296
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100297 *_aidl_return = isStreamCombinationSupported(in_streams);
298 return ndk::ScopedAStatus::ok();
299};
300
301bool VirtualCameraDevice::isStreamCombinationSupported(
302 const StreamConfiguration& streamConfiguration) const {
Jan Sebechlebsky39129f82024-01-19 16:42:11 +0100303 if (streamConfiguration.streams.empty()) {
304 ALOGE("%s: Querying empty configuration", __func__);
305 return false;
306 }
307
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100308 int numberOfProcessedStreams = 0;
309 int numberOfStallStreams = 0;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100310 for (const Stream& stream : streamConfiguration.streams) {
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100311 ALOGV("%s: Configuration queried: %s", __func__, stream.toString().c_str());
312
313 if (stream.streamType == StreamType::INPUT) {
314 ALOGW("%s: Input stream type is not supported", __func__);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100315 return false;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100316 }
317
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100318 if (stream.rotation != StreamRotation::ROTATION_0 ||
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100319 !isSupportedOutputFormat(stream.format)) {
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100320 ALOGV("Unsupported output stream type");
321 return false;
322 }
323
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100324 if (stream.format == PixelFormat::BLOB) {
325 numberOfStallStreams++;
326 } else {
327 numberOfProcessedStreams++;
328 }
329
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100330 auto matchesSupportedInputConfig =
331 [&stream](const SupportedStreamConfiguration& config) {
332 return stream.width == config.width && stream.height == config.height;
333 };
334 if (std::none_of(mSupportedInputConfigurations.begin(),
335 mSupportedInputConfigurations.end(),
336 matchesSupportedInputConfig)) {
337 ALOGV("Requested config doesn't match any supported input config");
338 return false;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100339 }
340 }
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100341
342 if (numberOfProcessedStreams > kMaxNumberOfProcessedStreams) {
343 ALOGE("%s: %d processed streams exceeds the supported maximum of %d",
344 __func__, numberOfProcessedStreams, kMaxNumberOfProcessedStreams);
345 return false;
346 }
347
348 if (numberOfStallStreams > kMaxNumberOfStallStreams) {
349 ALOGE("%s: %d stall streams exceeds the supported maximum of %d", __func__,
350 numberOfStallStreams, kMaxNumberOfStallStreams);
351 return false;
352 }
353
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100354 return true;
355}
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100356
357ndk::ScopedAStatus VirtualCameraDevice::open(
358 const std::shared_ptr<ICameraDeviceCallback>& in_callback,
359 std::shared_ptr<ICameraDeviceSession>* _aidl_return) {
360 ALOGV("%s", __func__);
361
362 *_aidl_return = ndk::SharedRefBase::make<VirtualCameraSession>(
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100363 sharedFromThis(), in_callback, mVirtualCameraClientCallback);
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100364
365 return ndk::ScopedAStatus::ok();
366};
367
368ndk::ScopedAStatus VirtualCameraDevice::openInjectionSession(
369 const std::shared_ptr<ICameraDeviceCallback>& in_callback,
370 std::shared_ptr<ICameraInjectionSession>* _aidl_return) {
371 ALOGV("%s", __func__);
372
373 (void)in_callback;
374 (void)_aidl_return;
375 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
376}
377
378ndk::ScopedAStatus VirtualCameraDevice::setTorchMode(bool in_on) {
379 ALOGV("%s: on = %s", __func__, in_on ? "on" : "off");
380 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
381}
382
383ndk::ScopedAStatus VirtualCameraDevice::turnOnTorchWithStrengthLevel(
384 int32_t in_torchStrength) {
385 ALOGV("%s: torchStrength = %d", __func__, in_torchStrength);
386 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
387}
388
389ndk::ScopedAStatus VirtualCameraDevice::getTorchStrengthLevel(
390 int32_t* _aidl_return) {
391 (void)_aidl_return;
392 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
393}
394
395binder_status_t VirtualCameraDevice::dump(int fd, const char** args,
396 uint32_t numArgs) {
397 // TODO(b/301023410) Implement.
398 (void)fd;
399 (void)args;
400 (void)numArgs;
401 return STATUS_OK;
402}
403
404std::string VirtualCameraDevice::getCameraName() const {
405 return std::string(kDevicePathPrefix) + std::to_string(mCameraId);
406}
407
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100408std::shared_ptr<VirtualCameraDevice> VirtualCameraDevice::sharedFromThis() {
409 // SharedRefBase which BnCameraDevice inherits from breaks
410 // std::enable_shared_from_this. This is recommended replacement for
411 // shared_from_this() per documentation in binder_interface_utils.h.
412 return ref<VirtualCameraDevice>();
413}
414
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100415} // namespace virtualcamera
416} // namespace companion
417} // namespace android