blob: 84f721bec944736b783b9e0eab4da4620949c8da [file] [log] [blame]
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +01001/*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
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"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010031#include "aidl/android/hardware/camera/common/Status.h"
32#include "aidl/android/hardware/camera/device/CameraMetadata.h"
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010033#include "aidl/android/hardware/camera/device/StreamConfiguration.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010034#include "android/binder_auto_utils.h"
35#include "android/binder_status.h"
36#include "log/log.h"
37#include "system/camera_metadata.h"
38#include "util/MetadataBuilder.h"
39#include "util/Util.h"
40
41namespace android {
42namespace companion {
43namespace virtualcamera {
44
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010045using ::aidl::android::companion::virtualcamera::Format;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010046using ::aidl::android::companion::virtualcamera::IVirtualCameraCallback;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010047using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010048using ::aidl::android::hardware::camera::common::CameraResourceCost;
49using ::aidl::android::hardware::camera::common::Status;
50using ::aidl::android::hardware::camera::device::CameraMetadata;
51using ::aidl::android::hardware::camera::device::ICameraDeviceCallback;
52using ::aidl::android::hardware::camera::device::ICameraDeviceSession;
53using ::aidl::android::hardware::camera::device::ICameraInjectionSession;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010054using ::aidl::android::hardware::camera::device::Stream;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010055using ::aidl::android::hardware::camera::device::StreamConfiguration;
56using ::aidl::android::hardware::camera::device::StreamRotation;
57using ::aidl::android::hardware::camera::device::StreamType;
58using ::aidl::android::hardware::graphics::common::PixelFormat;
59
60namespace {
61
62using namespace std::chrono_literals;
63
64// Prefix of camera name - "device@1.1/virtual/{numerical_id}"
65const char* kDevicePathPrefix = "device@1.1/virtual/";
66
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010067constexpr std::chrono::nanoseconds kMinFrameDuration30Fps = 1s / 30;
68constexpr int32_t kMaxJpegSize = 3 * 1024 * 1024 /*3MiB*/;
69
70constexpr MetadataBuilder::ControlRegion kDefaultEmptyControlRegion{};
71
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010072struct Resolution {
73 Resolution(const int w, const int h) : width(w), height(h) {
74 }
75
76 bool operator<(const Resolution& other) const {
77 return width * height < other.width * other.height;
78 }
79
80 bool operator==(const Resolution& other) const {
81 return width == other.width && height == other.height;
82 }
83
84 const int width;
85 const int height;
86};
87
88std::optional<Resolution> getMaxResolution(
89 const std::vector<SupportedStreamConfiguration>& configs) {
90 auto itMax = std::max_element(configs.begin(), configs.end(),
91 [](const SupportedStreamConfiguration& a,
92 const SupportedStreamConfiguration& b) {
93 return a.width * b.height < a.width * b.height;
94 });
95 if (itMax == configs.end()) {
96 ALOGE(
97 "%s: empty vector of supported configurations, cannot find largest "
98 "resolution.",
99 __func__);
100 return std::nullopt;
101 }
102
103 return Resolution(itMax->width, itMax->height);
104}
105
106std::set<Resolution> getUniqueResolutions(
107 const std::vector<SupportedStreamConfiguration>& configs) {
108 std::set<Resolution> uniqueResolutions;
109 std::transform(configs.begin(), configs.end(),
110 std::inserter(uniqueResolutions, uniqueResolutions.begin()),
111 [](const SupportedStreamConfiguration& config) {
112 return Resolution(config.width, config.height);
113 });
114 return uniqueResolutions;
115}
116
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100117// TODO(b/301023410) - Populate camera characteristics according to camera configuration.
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100118std::optional<CameraMetadata> initCameraCharacteristics(
119 const std::vector<SupportedStreamConfiguration>& supportedInputConfig) {
120 if (!std::all_of(supportedInputConfig.begin(), supportedInputConfig.end(),
121 [](const SupportedStreamConfiguration& config) {
Jan Sebechlebsky042d1fb2023-12-12 16:37:00 +0100122 return isFormatSupportedForInput(
123 config.width, config.height, config.pixelFormat);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100124 })) {
Jan Sebechlebsky042d1fb2023-12-12 16:37:00 +0100125 ALOGE("%s: input configuration contains unsupported format", __func__);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100126 return std::nullopt;
127 }
128
129 MetadataBuilder builder =
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100130 MetadataBuilder()
131 .setSupportedHardwareLevel(
132 ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL)
133 .setFlashAvailable(false)
134 .setLensFacing(ANDROID_LENS_FACING_EXTERNAL)
135 .setSensorOrientation(0)
136 .setAvailableFaceDetectModes({ANDROID_STATISTICS_FACE_DETECT_MODE_OFF})
Jan Sebechlebskyb0119fa2023-12-04 10:29:06 +0100137 .setAvailableMaxDigitalZoom(1.0)
138 .setControlAvailableModes({ANDROID_CONTROL_MODE_AUTO})
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100139 .setControlAfAvailableModes({ANDROID_CONTROL_AF_MODE_OFF})
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100140 .setControlAeAvailableFpsRange(10, 30)
141 .setControlMaxRegions(0, 0, 0)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100142 .setControlAfRegions({kDefaultEmptyControlRegion})
143 .setControlAeRegions({kDefaultEmptyControlRegion})
144 .setControlAwbRegions({kDefaultEmptyControlRegion})
145 .setControlAeCompensationRange(0, 1)
146 .setControlAeCompensationStep(camera_metadata_rational_t{0, 1})
Jan Sebechlebsky6ab07fe2023-12-05 15:23:34 +0100147 .setControlZoomRatioRange(/*min=*/1.0, /*max=*/1.0)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100148 .setMaxJpegSize(kMaxJpegSize)
149 .setAvailableRequestKeys({ANDROID_CONTROL_AF_MODE})
150 .setAvailableResultKeys({ANDROID_CONTROL_AF_MODE})
151 .setAvailableCapabilities(
152 {ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE})
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100153 .setAvailableCharacteristicKeys();
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100154
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100155 // Active array size must correspond to largest supported input resolution.
156 std::optional<Resolution> maxResolution =
157 getMaxResolution(supportedInputConfig);
158 if (!maxResolution.has_value()) {
159 return std::nullopt;
160 }
161 builder.setSensorActiveArraySize(0, 0, maxResolution->width,
162 maxResolution->height);
163
164 std::vector<MetadataBuilder::StreamConfiguration> outputConfigurations;
165
166 // TODO(b/301023410) Add also all "standard" resolutions we can rescale the
167 // streams to (all standard resolutions with same aspect ratio).
168
169 // Add IMPLEMENTATION_DEFINED format for all supported input resolutions.
170 std::set<Resolution> uniqueResolutions =
171 getUniqueResolutions(supportedInputConfig);
172 std::transform(
173 uniqueResolutions.begin(), uniqueResolutions.end(),
174 std::back_inserter(outputConfigurations),
175 [](const Resolution& resolution) {
176 return MetadataBuilder::StreamConfiguration{
177 .width = resolution.width,
178 .height = resolution.height,
179 .format = ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,
180 .minFrameDuration = kMinFrameDuration30Fps,
181 .minStallDuration = 0s};
182 });
183
184 // Add all supported configuration with explicit pixel format.
185 std::transform(supportedInputConfig.begin(), supportedInputConfig.end(),
186 std::back_inserter(outputConfigurations),
187 [](const SupportedStreamConfiguration& config) {
188 return MetadataBuilder::StreamConfiguration{
189 .width = config.width,
190 .height = config.height,
191 .format = static_cast<int>(config.pixelFormat),
192 .minFrameDuration = kMinFrameDuration30Fps,
193 .minStallDuration = 0s};
194 });
195
196 // TODO(b/301023410) We currently don't support rescaling for still capture,
197 // so only announce BLOB support for formats exactly matching the input.
198 std::transform(uniqueResolutions.begin(), uniqueResolutions.end(),
199 std::back_inserter(outputConfigurations),
200 [](const Resolution& resolution) {
201 return MetadataBuilder::StreamConfiguration{
202 .width = resolution.width,
203 .height = resolution.height,
204 .format = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB,
205 .minFrameDuration = kMinFrameDuration30Fps,
206 .minStallDuration = 0s};
207 });
208
209 ALOGV("Adding %zu output configurations", outputConfigurations.size());
210 builder.setAvailableOutputStreamConfigurations(outputConfigurations);
211
212 auto metadata = builder.build();
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100213 if (metadata == nullptr) {
214 ALOGE("Failed to build metadata!");
215 return CameraMetadata();
216 }
217
218 return std::move(*metadata);
219}
220
221} // namespace
222
223VirtualCameraDevice::VirtualCameraDevice(
224 const uint32_t cameraId,
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100225 const std::vector<SupportedStreamConfiguration>& supportedInputConfig,
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100226 std::shared_ptr<IVirtualCameraCallback> virtualCameraClientCallback)
227 : mCameraId(cameraId),
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100228 mVirtualCameraClientCallback(virtualCameraClientCallback),
229 mSupportedInputConfigurations(supportedInputConfig) {
230 std::optional<CameraMetadata> metadata =
231 initCameraCharacteristics(mSupportedInputConfigurations);
232 if (metadata.has_value()) {
233 mCameraCharacteristics = *metadata;
234 } else {
235 ALOGE(
236 "%s: Failed to initialize camera characteristic based on provided "
237 "configuration.",
238 __func__);
239 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100240}
241
242ndk::ScopedAStatus VirtualCameraDevice::getCameraCharacteristics(
243 CameraMetadata* _aidl_return) {
244 ALOGV("%s", __func__);
245 if (_aidl_return == nullptr) {
246 return cameraStatus(Status::ILLEGAL_ARGUMENT);
247 }
248
249 *_aidl_return = mCameraCharacteristics;
250 return ndk::ScopedAStatus::ok();
251}
252
253ndk::ScopedAStatus VirtualCameraDevice::getPhysicalCameraCharacteristics(
254 const std::string& in_physicalCameraId, CameraMetadata* _aidl_return) {
255 ALOGV("%s: physicalCameraId %s", __func__, in_physicalCameraId.c_str());
256 (void)_aidl_return;
257
258 // VTS tests expect this call to fail with illegal argument status for
259 // all publicly advertised camera ids.
260 // Because we don't support physical camera ids, we just always
261 // fail with illegal argument (there's no valid argument to provide).
262 return cameraStatus(Status::ILLEGAL_ARGUMENT);
263}
264
265ndk::ScopedAStatus VirtualCameraDevice::getResourceCost(
266 CameraResourceCost* _aidl_return) {
267 ALOGV("%s", __func__);
268 if (_aidl_return == nullptr) {
269 return cameraStatus(Status::ILLEGAL_ARGUMENT);
270 }
271 _aidl_return->resourceCost = 100; // ¯\_(ツ)_/¯
272 return ndk::ScopedAStatus::ok();
273}
274
275ndk::ScopedAStatus VirtualCameraDevice::isStreamCombinationSupported(
276 const StreamConfiguration& in_streams, bool* _aidl_return) {
277 ALOGV("%s", __func__);
278
279 if (_aidl_return == nullptr) {
280 return cameraStatus(Status::ILLEGAL_ARGUMENT);
281 }
282
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100283 *_aidl_return = isStreamCombinationSupported(in_streams);
284 return ndk::ScopedAStatus::ok();
285};
286
287bool VirtualCameraDevice::isStreamCombinationSupported(
288 const StreamConfiguration& streamConfiguration) const {
289 for (const Stream& stream : streamConfiguration.streams) {
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100290 ALOGV("%s: Configuration queried: %s", __func__, stream.toString().c_str());
291
292 if (stream.streamType == StreamType::INPUT) {
293 ALOGW("%s: Input stream type is not supported", __func__);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100294 return false;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100295 }
296
297 // TODO(b/301023410) remove hardcoded format checks, verify against configuration.
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100298 if (stream.rotation != StreamRotation::ROTATION_0 ||
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100299 (stream.format != PixelFormat::IMPLEMENTATION_DEFINED &&
300 stream.format != PixelFormat::YCBCR_420_888 &&
301 stream.format != PixelFormat::BLOB)) {
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100302 ALOGV("Unsupported output stream type");
303 return false;
304 }
305
306 auto matchesSupportedInputConfig =
307 [&stream](const SupportedStreamConfiguration& config) {
308 return stream.width == config.width && stream.height == config.height;
309 };
310 if (std::none_of(mSupportedInputConfigurations.begin(),
311 mSupportedInputConfigurations.end(),
312 matchesSupportedInputConfig)) {
313 ALOGV("Requested config doesn't match any supported input config");
314 return false;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100315 }
316 }
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100317 return true;
318}
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100319
320ndk::ScopedAStatus VirtualCameraDevice::open(
321 const std::shared_ptr<ICameraDeviceCallback>& in_callback,
322 std::shared_ptr<ICameraDeviceSession>* _aidl_return) {
323 ALOGV("%s", __func__);
324
325 *_aidl_return = ndk::SharedRefBase::make<VirtualCameraSession>(
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100326 sharedFromThis(), in_callback, mVirtualCameraClientCallback);
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100327
328 return ndk::ScopedAStatus::ok();
329};
330
331ndk::ScopedAStatus VirtualCameraDevice::openInjectionSession(
332 const std::shared_ptr<ICameraDeviceCallback>& in_callback,
333 std::shared_ptr<ICameraInjectionSession>* _aidl_return) {
334 ALOGV("%s", __func__);
335
336 (void)in_callback;
337 (void)_aidl_return;
338 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
339}
340
341ndk::ScopedAStatus VirtualCameraDevice::setTorchMode(bool in_on) {
342 ALOGV("%s: on = %s", __func__, in_on ? "on" : "off");
343 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
344}
345
346ndk::ScopedAStatus VirtualCameraDevice::turnOnTorchWithStrengthLevel(
347 int32_t in_torchStrength) {
348 ALOGV("%s: torchStrength = %d", __func__, in_torchStrength);
349 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
350}
351
352ndk::ScopedAStatus VirtualCameraDevice::getTorchStrengthLevel(
353 int32_t* _aidl_return) {
354 (void)_aidl_return;
355 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
356}
357
358binder_status_t VirtualCameraDevice::dump(int fd, const char** args,
359 uint32_t numArgs) {
360 // TODO(b/301023410) Implement.
361 (void)fd;
362 (void)args;
363 (void)numArgs;
364 return STATUS_OK;
365}
366
367std::string VirtualCameraDevice::getCameraName() const {
368 return std::string(kDevicePathPrefix) + std::to_string(mCameraId);
369}
370
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100371std::shared_ptr<VirtualCameraDevice> VirtualCameraDevice::sharedFromThis() {
372 // SharedRefBase which BnCameraDevice inherits from breaks
373 // std::enable_shared_from_this. This is recommended replacement for
374 // shared_from_this() per documentation in binder_interface_utils.h.
375 return ref<VirtualCameraDevice>();
376}
377
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100378} // namespace virtualcamera
379} // namespace companion
380} // namespace android