blob: 28fa495bd9d7b36701328f84956c6e2bc9fc9ba2 [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 "VirtualCameraSession"
19#include "VirtualCameraSession.h"
20
Jan Sebechlebsky39129f82024-01-19 16:42:11 +010021#include <algorithm>
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010022#include <atomic>
23#include <chrono>
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +010024#include <cmath>
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010025#include <cstddef>
26#include <cstdint>
27#include <cstring>
28#include <map>
29#include <memory>
30#include <mutex>
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +010031#include <numeric>
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010032#include <optional>
33#include <tuple>
34#include <unordered_set>
35#include <utility>
36#include <vector>
37
38#include "CameraMetadata.h"
39#include "EGL/egl.h"
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010040#include "VirtualCameraDevice.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010041#include "VirtualCameraRenderThread.h"
42#include "VirtualCameraStream.h"
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +010043#include "aidl/android/companion/virtualcamera/SupportedStreamConfiguration.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010044#include "aidl/android/hardware/camera/common/Status.h"
45#include "aidl/android/hardware/camera/device/BufferCache.h"
46#include "aidl/android/hardware/camera/device/BufferStatus.h"
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +010047#include "aidl/android/hardware/camera/device/CameraMetadata.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010048#include "aidl/android/hardware/camera/device/CaptureRequest.h"
49#include "aidl/android/hardware/camera/device/HalStream.h"
50#include "aidl/android/hardware/camera/device/NotifyMsg.h"
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +010051#include "aidl/android/hardware/camera/device/RequestTemplate.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010052#include "aidl/android/hardware/camera/device/ShutterMsg.h"
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +010053#include "aidl/android/hardware/camera/device/Stream.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010054#include "aidl/android/hardware/camera/device/StreamBuffer.h"
55#include "aidl/android/hardware/camera/device/StreamConfiguration.h"
56#include "aidl/android/hardware/camera/device/StreamRotation.h"
57#include "aidl/android/hardware/graphics/common/BufferUsage.h"
58#include "aidl/android/hardware/graphics/common/PixelFormat.h"
59#include "android/hardware_buffer.h"
60#include "android/native_window_aidl.h"
61#include "fmq/AidlMessageQueue.h"
62#include "system/camera_metadata.h"
63#include "ui/GraphicBuffer.h"
64#include "util/EglDisplayContext.h"
65#include "util/EglFramebuffer.h"
66#include "util/EglProgram.h"
67#include "util/JpegUtil.h"
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +010068#include "util/MetadataUtil.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010069#include "util/TestPatternHelper.h"
70#include "util/Util.h"
71
72namespace android {
73namespace companion {
74namespace virtualcamera {
75
76using ::aidl::android::companion::virtualcamera::Format;
77using ::aidl::android::companion::virtualcamera::IVirtualCameraCallback;
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +010078using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010079using ::aidl::android::hardware::camera::common::Status;
80using ::aidl::android::hardware::camera::device::BufferCache;
81using ::aidl::android::hardware::camera::device::CameraMetadata;
82using ::aidl::android::hardware::camera::device::CameraOfflineSessionInfo;
83using ::aidl::android::hardware::camera::device::CaptureRequest;
84using ::aidl::android::hardware::camera::device::HalStream;
85using ::aidl::android::hardware::camera::device::ICameraDeviceCallback;
86using ::aidl::android::hardware::camera::device::ICameraOfflineSession;
87using ::aidl::android::hardware::camera::device::RequestTemplate;
88using ::aidl::android::hardware::camera::device::Stream;
89using ::aidl::android::hardware::camera::device::StreamBuffer;
90using ::aidl::android::hardware::camera::device::StreamConfiguration;
91using ::aidl::android::hardware::camera::device::StreamRotation;
92using ::aidl::android::hardware::common::fmq::MQDescriptor;
93using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
94using ::aidl::android::hardware::graphics::common::BufferUsage;
95using ::aidl::android::hardware::graphics::common::PixelFormat;
96using ::android::base::unique_fd;
97
98namespace {
99
100using metadata_ptr =
101 std::unique_ptr<camera_metadata_t, void (*)(camera_metadata_t*)>;
102
103using namespace std::chrono_literals;
104
105// Size of request/result metadata fast message queue.
106// Setting to 0 to always disables FMQ.
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +0100107constexpr size_t kMetadataMsgQueueSize = 0;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100108
109// Maximum number of buffers to use per single stream.
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +0100110constexpr size_t kMaxStreamBuffers = 2;
111
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +0100112// Thumbnail size (0,0) correspods to disabling thumbnail.
113const Resolution kDefaultJpegThumbnailSize(0, 0);
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100114
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100115camera_metadata_enum_android_control_capture_intent_t requestTemplateToIntent(
116 const RequestTemplate type) {
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100117 switch (type) {
118 case RequestTemplate::PREVIEW:
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100119 return ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100120 case RequestTemplate::STILL_CAPTURE:
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100121 return ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100122 case RequestTemplate::VIDEO_RECORD:
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100123 return ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100124 case RequestTemplate::VIDEO_SNAPSHOT:
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100125 return ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100126 default:
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100127 // Return PREVIEW by default
128 return ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100129 }
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100130}
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100131
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100132int getMaxFps(const std::vector<SupportedStreamConfiguration>& configs) {
133 return std::transform_reduce(
134 configs.begin(), configs.end(), 0,
135 [](const int a, const int b) { return std::max(a, b); },
136 [](const SupportedStreamConfiguration& config) { return config.maxFps; });
137}
138
139CameraMetadata createDefaultRequestSettings(
140 const RequestTemplate type,
141 const std::vector<SupportedStreamConfiguration>& inputConfigs) {
142 int maxFps = getMaxFps(inputConfigs);
143 auto metadata =
144 MetadataBuilder()
Jan Sebechlebsky4be2bd02024-02-26 18:35:18 +0100145 .setAberrationCorrectionMode(
146 ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF)
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100147 .setControlCaptureIntent(requestTemplateToIntent(type))
148 .setControlMode(ANDROID_CONTROL_MODE_AUTO)
149 .setControlAeMode(ANDROID_CONTROL_AE_MODE_ON)
150 .setControlAeExposureCompensation(0)
Vadim Caen11dfd932024-03-05 09:57:20 +0100151 .setControlAeTargetFpsRange(FpsRange{maxFps, maxFps})
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100152 .setControlAeAntibandingMode(ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO)
153 .setControlAePrecaptureTrigger(
154 ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE)
155 .setControlAfTrigger(ANDROID_CONTROL_AF_TRIGGER_IDLE)
Jan Sebechlebskybb01c1d2024-02-12 11:41:37 +0100156 .setControlAfMode(ANDROID_CONTROL_AF_MODE_OFF)
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100157 .setControlAwbMode(ANDROID_CONTROL_AWB_MODE_AUTO)
Jan Sebechlebskybb01c1d2024-02-12 11:41:37 +0100158 .setControlEffectMode(ANDROID_CONTROL_EFFECT_MODE_OFF)
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100159 .setFaceDetectMode(ANDROID_STATISTICS_FACE_DETECT_MODE_OFF)
160 .setFlashMode(ANDROID_FLASH_MODE_OFF)
Jan Sebechlebskybb01c1d2024-02-12 11:41:37 +0100161 .setFlashState(ANDROID_FLASH_STATE_UNAVAILABLE)
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +0100162 .setJpegQuality(VirtualCameraDevice::kDefaultJpegQuality)
163 .setJpegThumbnailQuality(VirtualCameraDevice::kDefaultJpegQuality)
164 .setJpegThumbnailSize(0, 0)
Jan Sebechlebsky4be2bd02024-02-26 18:35:18 +0100165 .setNoiseReductionMode(ANDROID_NOISE_REDUCTION_MODE_OFF)
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100166 .build();
167 if (metadata == nullptr) {
168 ALOGE("%s: Failed to construct metadata for default request type %s",
169 __func__, toString(type).c_str());
170 return CameraMetadata();
171 } else {
172 ALOGV("%s: Successfully created metadata for request type %s", __func__,
173 toString(type).c_str());
174 }
175 return *metadata;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100176}
177
178HalStream getHalStream(const Stream& stream) {
179 HalStream halStream;
180 halStream.id = stream.id;
181 halStream.physicalCameraId = stream.physicalCameraId;
182 halStream.maxBuffers = kMaxStreamBuffers;
183
184 if (stream.format == PixelFormat::IMPLEMENTATION_DEFINED) {
185 // If format is implementation defined we need it to override
186 // it with actual format.
187 // TODO(b/301023410) Override with the format based on the
188 // camera configuration, once we support more formats.
189 halStream.overrideFormat = PixelFormat::YCBCR_420_888;
190 } else {
191 halStream.overrideFormat = stream.format;
192 }
193 halStream.overrideDataSpace = stream.dataSpace;
194
195 halStream.producerUsage = BufferUsage::GPU_RENDER_TARGET;
196 halStream.supportOffline = false;
197 return halStream;
198}
199
Jan Sebechlebsky39129f82024-01-19 16:42:11 +0100200Stream getHighestResolutionStream(const std::vector<Stream>& streams) {
201 return *(std::max_element(streams.begin(), streams.end(),
202 [](const Stream& a, const Stream& b) {
203 return a.width * a.height < b.width * b.height;
204 }));
205}
206
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +0100207Resolution resolutionFromStream(const Stream& stream) {
208 return Resolution(stream.width, stream.height);
209}
210
211Resolution resolutionFromInputConfig(
212 const SupportedStreamConfiguration& inputConfig) {
213 return Resolution(inputConfig.width, inputConfig.height);
214}
215
216std::optional<SupportedStreamConfiguration> pickInputConfigurationForStreams(
217 const std::vector<Stream>& requestedStreams,
218 const std::vector<SupportedStreamConfiguration>& supportedInputConfigs) {
219 Stream maxResolutionStream = getHighestResolutionStream(requestedStreams);
220 Resolution maxResolution = resolutionFromStream(maxResolutionStream);
221
222 // Find best fitting stream to satisfy all requested streams:
223 // Best fitting => same or higher resolution as input with lowest pixel count
224 // difference and same aspect ratio.
225 auto isBetterInputConfig = [maxResolution](
226 const SupportedStreamConfiguration& configA,
227 const SupportedStreamConfiguration& configB) {
228 int maxResPixelCount = maxResolution.width * maxResolution.height;
229 int pixelCountDiffA =
230 std::abs((configA.width * configA.height) - maxResPixelCount);
231 int pixelCountDiffB =
232 std::abs((configB.width * configB.height) - maxResPixelCount);
233
234 return pixelCountDiffA < pixelCountDiffB;
235 };
236
237 std::optional<SupportedStreamConfiguration> bestConfig;
238 for (const SupportedStreamConfiguration& inputConfig : supportedInputConfigs) {
239 Resolution inputConfigResolution = resolutionFromInputConfig(inputConfig);
240 if (inputConfigResolution < maxResolution ||
241 !isApproximatellySameAspectRatio(inputConfigResolution, maxResolution)) {
242 // We don't want to upscale from lower resolution, or use different aspect
243 // ratio, skip.
244 continue;
245 }
246
247 if (!bestConfig.has_value() ||
248 isBetterInputConfig(inputConfig, bestConfig.value())) {
249 bestConfig = inputConfig;
250 }
251 }
252
253 return bestConfig;
254}
255
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +0100256RequestSettings createSettingsFromMetadata(const CameraMetadata& metadata) {
257 return RequestSettings{
258 .jpegQuality = getJpegQuality(metadata).value_or(
259 VirtualCameraDevice::kDefaultJpegQuality),
Vadim Caenc0aff132024-03-12 17:20:07 +0100260 .jpegOrientation = getJpegOrientation(metadata),
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +0100261 .thumbnailResolution =
262 getJpegThumbnailSize(metadata).value_or(Resolution(0, 0)),
263 .thumbnailJpegQuality = getJpegThumbnailQuality(metadata).value_or(
Vadim Caen11dfd932024-03-05 09:57:20 +0100264 VirtualCameraDevice::kDefaultJpegQuality),
265 .fpsRange = getFpsRange(metadata),
266 .captureIntent = getCaptureIntent(metadata).value_or(
Vadim Caenc0aff132024-03-12 17:20:07 +0100267 ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW),
Vadim Caen6a43beb2024-04-12 15:06:42 +0200268 .gpsCoordinates = getGpsCoordinates(metadata),
269 .aePrecaptureTrigger = getPrecaptureTrigger(metadata)};
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +0100270}
271
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100272} // namespace
273
274VirtualCameraSession::VirtualCameraSession(
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100275 std::shared_ptr<VirtualCameraDevice> cameraDevice,
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100276 std::shared_ptr<ICameraDeviceCallback> cameraDeviceCallback,
277 std::shared_ptr<IVirtualCameraCallback> virtualCameraClientCallback)
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100278 : mCameraDevice(cameraDevice),
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100279 mCameraDeviceCallback(cameraDeviceCallback),
280 mVirtualCameraClientCallback(virtualCameraClientCallback) {
281 mRequestMetadataQueue = std::make_unique<RequestMetadataQueue>(
282 kMetadataMsgQueueSize, false /* non blocking */);
283 if (!mRequestMetadataQueue->isValid()) {
284 ALOGE("%s: invalid request fmq", __func__);
285 }
286
287 mResultMetadataQueue = std::make_shared<ResultMetadataQueue>(
288 kMetadataMsgQueueSize, false /* non blocking */);
289 if (!mResultMetadataQueue->isValid()) {
290 ALOGE("%s: invalid result fmq", __func__);
291 }
292}
293
294ndk::ScopedAStatus VirtualCameraSession::close() {
295 ALOGV("%s", __func__);
296
297 if (mVirtualCameraClientCallback != nullptr) {
298 mVirtualCameraClientCallback->onStreamClosed(/*streamId=*/0);
299 }
300
Jan Sebechlebskyb0d8cab2023-11-28 10:55:04 +0100301 {
302 std::lock_guard<std::mutex> lock(mLock);
303 if (mRenderThread != nullptr) {
304 mRenderThread->stop();
305 mRenderThread = nullptr;
306 }
307 }
308
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100309 mSessionContext.closeAllStreams();
310 return ndk::ScopedAStatus::ok();
311}
312
313ndk::ScopedAStatus VirtualCameraSession::configureStreams(
314 const StreamConfiguration& in_requestedConfiguration,
315 std::vector<HalStream>* _aidl_return) {
316 ALOGV("%s: requestedConfiguration: %s", __func__,
317 in_requestedConfiguration.toString().c_str());
318
319 if (_aidl_return == nullptr) {
320 return cameraStatus(Status::ILLEGAL_ARGUMENT);
321 }
322
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100323 std::shared_ptr<VirtualCameraDevice> virtualCamera = mCameraDevice.lock();
324 if (virtualCamera == nullptr) {
325 ALOGW("%s: configure called on already unregistered camera", __func__);
326 return cameraStatus(Status::CAMERA_DISCONNECTED);
327 }
328
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100329 mSessionContext.removeStreamsNotInStreamConfiguration(
330 in_requestedConfiguration);
331
332 auto& streams = in_requestedConfiguration.streams;
333 auto& halStreams = *_aidl_return;
334 halStreams.clear();
335 halStreams.resize(in_requestedConfiguration.streams.size());
336
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100337 if (!virtualCamera->isStreamCombinationSupported(in_requestedConfiguration)) {
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100338 ALOGE("%s: Requested stream configuration is not supported", __func__);
339 return cameraStatus(Status::ILLEGAL_ARGUMENT);
340 }
341
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +0100342 sp<Surface> inputSurface = nullptr;
343 std::optional<SupportedStreamConfiguration> inputConfig;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100344 {
345 std::lock_guard<std::mutex> lock(mLock);
346 for (int i = 0; i < in_requestedConfiguration.streams.size(); ++i) {
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100347 halStreams[i] = getHalStream(streams[i]);
348 if (mSessionContext.initializeStream(streams[i])) {
349 ALOGV("Configured new stream: %s", streams[i].toString().c_str());
350 }
351 }
352
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +0100353 inputConfig = pickInputConfigurationForStreams(
354 streams, virtualCamera->getInputConfigs());
355 if (!inputConfig.has_value()) {
356 ALOGE(
357 "%s: Failed to pick any input configuration for stream configuration "
358 "request: %s",
359 __func__, in_requestedConfiguration.toString().c_str());
360 return cameraStatus(Status::ILLEGAL_ARGUMENT);
361 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100362 if (mRenderThread == nullptr) {
363 // If there's no client callback, start camera in test mode.
364 const bool testMode = mVirtualCameraClientCallback == nullptr;
365 mRenderThread = std::make_unique<VirtualCameraRenderThread>(
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +0100366 mSessionContext, resolutionFromInputConfig(*inputConfig),
Jan Sebechlebskybb01c1d2024-02-12 11:41:37 +0100367 virtualCamera->getMaxInputResolution(), mCameraDeviceCallback,
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100368 testMode);
369 mRenderThread->start();
370 inputSurface = mRenderThread->getInputSurface();
371 }
372 }
373
374 if (mVirtualCameraClientCallback != nullptr && inputSurface != nullptr) {
375 // TODO(b/301023410) Pass streamId based on client input stream id once
376 // support for multiple input streams is implemented. For now we always
377 // create single texture.
378 mVirtualCameraClientCallback->onStreamConfigured(
379 /*streamId=*/0, aidl::android::view::Surface(inputSurface.get()),
Jan Sebechlebsky4c9bb1e2024-02-28 16:32:39 +0100380 inputConfig->width, inputConfig->height, inputConfig->pixelFormat);
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100381 }
382
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100383 return ndk::ScopedAStatus::ok();
384}
385
386ndk::ScopedAStatus VirtualCameraSession::constructDefaultRequestSettings(
387 RequestTemplate in_type, CameraMetadata* _aidl_return) {
388 ALOGV("%s: type %d", __func__, static_cast<int32_t>(in_type));
389
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100390 std::shared_ptr<VirtualCameraDevice> camera = mCameraDevice.lock();
391 if (camera == nullptr) {
392 ALOGW(
393 "%s: constructDefaultRequestSettings called on already unregistered "
394 "camera",
395 __func__);
396 return cameraStatus(Status::CAMERA_DISCONNECTED);
397 }
398
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100399 switch (in_type) {
400 case RequestTemplate::PREVIEW:
401 case RequestTemplate::STILL_CAPTURE:
Jan Sebechlebskyb0119fa2023-12-04 10:29:06 +0100402 case RequestTemplate::VIDEO_RECORD:
403 case RequestTemplate::VIDEO_SNAPSHOT: {
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100404 *_aidl_return =
405 createDefaultRequestSettings(in_type, camera->getInputConfigs());
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100406 return ndk::ScopedAStatus::ok();
407 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100408 case RequestTemplate::MANUAL:
409 case RequestTemplate::ZERO_SHUTTER_LAG:
410 // Don't support VIDEO_SNAPSHOT, MANUAL, ZSL templates
411 return ndk::ScopedAStatus::fromServiceSpecificError(
412 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
413 ;
414 default:
415 ALOGE("%s: unknown request template type %d", __FUNCTION__,
416 static_cast<int>(in_type));
417 return ndk::ScopedAStatus::fromServiceSpecificError(
418 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
419 ;
420 }
421}
422
423ndk::ScopedAStatus VirtualCameraSession::flush() {
424 ALOGV("%s", __func__);
425 std::lock_guard<std::mutex> lock(mLock);
Jan Sebechlebskyb0d8cab2023-11-28 10:55:04 +0100426 if (mRenderThread != nullptr) {
427 mRenderThread->flush();
428 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100429 return ndk::ScopedAStatus::ok();
430}
431
432ndk::ScopedAStatus VirtualCameraSession::getCaptureRequestMetadataQueue(
433 MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) {
434 ALOGV("%s", __func__);
435 *_aidl_return = mRequestMetadataQueue->dupeDesc();
436 return ndk::ScopedAStatus::ok();
437}
438
439ndk::ScopedAStatus VirtualCameraSession::getCaptureResultMetadataQueue(
440 MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) {
441 ALOGV("%s", __func__);
442 *_aidl_return = mResultMetadataQueue->dupeDesc();
443 return ndk::ScopedAStatus::ok();
444}
445
446ndk::ScopedAStatus VirtualCameraSession::isReconfigurationRequired(
447 const CameraMetadata& in_oldSessionParams,
448 const CameraMetadata& in_newSessionParams, bool* _aidl_return) {
449 ALOGV("%s: oldSessionParams: %s newSessionParams: %s", __func__,
450 in_newSessionParams.toString().c_str(),
451 in_oldSessionParams.toString().c_str());
452
453 if (_aidl_return == nullptr) {
454 return ndk::ScopedAStatus::fromServiceSpecificError(
455 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
456 }
457
458 *_aidl_return = true;
459 return ndk::ScopedAStatus::ok();
460}
461
462ndk::ScopedAStatus VirtualCameraSession::processCaptureRequest(
463 const std::vector<CaptureRequest>& in_requests,
464 const std::vector<BufferCache>& in_cachesToRemove, int32_t* _aidl_return) {
465 ALOGV("%s", __func__);
466
467 if (!in_cachesToRemove.empty()) {
468 mSessionContext.removeBufferCaches(in_cachesToRemove);
469 }
470
471 for (const auto& captureRequest : in_requests) {
472 auto status = processCaptureRequest(captureRequest);
473 if (!status.isOk()) {
474 return status;
475 }
476 }
477 *_aidl_return = in_requests.size();
478 return ndk::ScopedAStatus::ok();
479}
480
481ndk::ScopedAStatus VirtualCameraSession::signalStreamFlush(
482 const std::vector<int32_t>& in_streamIds, int32_t in_streamConfigCounter) {
483 ALOGV("%s", __func__);
484
485 (void)in_streamIds;
486 (void)in_streamConfigCounter;
487 return ndk::ScopedAStatus::ok();
488}
489
490ndk::ScopedAStatus VirtualCameraSession::switchToOffline(
491 const std::vector<int32_t>& in_streamsToKeep,
492 CameraOfflineSessionInfo* out_offlineSessionInfo,
493 std::shared_ptr<ICameraOfflineSession>* _aidl_return) {
494 ALOGV("%s", __func__);
495
496 (void)in_streamsToKeep;
497 (void)out_offlineSessionInfo;
498
499 if (_aidl_return == nullptr) {
500 return ndk::ScopedAStatus::fromServiceSpecificError(
501 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
502 }
503
504 *_aidl_return = nullptr;
505 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
506}
507
508ndk::ScopedAStatus VirtualCameraSession::repeatingRequestEnd(
509 int32_t in_frameNumber, const std::vector<int32_t>& in_streamIds) {
510 ALOGV("%s", __func__);
511 (void)in_frameNumber;
512 (void)in_streamIds;
513 return ndk::ScopedAStatus::ok();
514}
515
516std::set<int> VirtualCameraSession::getStreamIds() const {
517 return mSessionContext.getStreamIds();
518}
519
520ndk::ScopedAStatus VirtualCameraSession::processCaptureRequest(
521 const CaptureRequest& request) {
Vadim Caen324fcfb2024-03-21 16:49:08 +0100522 ALOGV("%s: request: %s", __func__, request.toString().c_str());
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100523
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100524 std::shared_ptr<ICameraDeviceCallback> cameraCallback = nullptr;
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +0100525 RequestSettings requestSettings;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100526 {
527 std::lock_guard<std::mutex> lock(mLock);
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +0100528
529 // If metadata it empty, last received metadata applies, if it's non-empty
530 // update it.
531 if (!request.settings.metadata.empty()) {
532 mCurrentRequestMetadata = request.settings;
533 }
534
535 // We don't have any metadata for this request - this means we received none
536 // in first request, this is an error state.
537 if (mCurrentRequestMetadata.metadata.empty()) {
538 return cameraStatus(Status::ILLEGAL_ARGUMENT);
539 }
540
541 requestSettings = createSettingsFromMetadata(mCurrentRequestMetadata);
542
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100543 cameraCallback = mCameraDeviceCallback;
544 }
545
546 if (cameraCallback == nullptr) {
547 ALOGE(
548 "%s: processCaptureRequest called, but there's no camera callback "
549 "configured",
550 __func__);
551 return cameraStatus(Status::INTERNAL_ERROR);
552 }
553
554 if (!mSessionContext.importBuffersFromCaptureRequest(request)) {
555 ALOGE("Failed to import buffers from capture request.");
556 return cameraStatus(Status::INTERNAL_ERROR);
557 }
558
559 std::vector<CaptureRequestBuffer> taskBuffers;
560 taskBuffers.reserve(request.outputBuffers.size());
561 for (const StreamBuffer& streamBuffer : request.outputBuffers) {
562 taskBuffers.emplace_back(streamBuffer.streamId, streamBuffer.bufferId,
563 importFence(streamBuffer.acquireFence));
564 }
565
566 {
567 std::lock_guard<std::mutex> lock(mLock);
568 if (mRenderThread == nullptr) {
569 ALOGE(
570 "%s: processCaptureRequest (frameNumber %d)called before configure "
571 "(render thread not initialized)",
572 __func__, request.frameNumber);
573 return cameraStatus(Status::INTERNAL_ERROR);
574 }
575 mRenderThread->enqueueTask(std::make_unique<ProcessCaptureRequestTask>(
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +0100576 request.frameNumber, taskBuffers, requestSettings));
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100577 }
578
579 if (mVirtualCameraClientCallback != nullptr) {
580 auto status = mVirtualCameraClientCallback->onProcessCaptureRequest(
581 /*streamId=*/0, request.frameNumber);
582 if (!status.isOk()) {
583 ALOGE(
584 "Failed to invoke onProcessCaptureRequest client callback for frame "
585 "%d",
586 request.frameNumber);
587 }
588 }
589
590 return ndk::ScopedAStatus::ok();
591}
592
593} // namespace virtualcamera
594} // namespace companion
595} // namespace android