blob: dfa71f33a80fffd67c653837c05cfcd36cf7f8e9 [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>
24#include <cstddef>
25#include <cstdint>
26#include <cstring>
27#include <map>
28#include <memory>
29#include <mutex>
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +010030#include <numeric>
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010031#include <optional>
32#include <tuple>
33#include <unordered_set>
34#include <utility>
35#include <vector>
36
37#include "CameraMetadata.h"
38#include "EGL/egl.h"
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010039#include "VirtualCameraDevice.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010040#include "VirtualCameraRenderThread.h"
41#include "VirtualCameraStream.h"
42#include "aidl/android/hardware/camera/common/Status.h"
43#include "aidl/android/hardware/camera/device/BufferCache.h"
44#include "aidl/android/hardware/camera/device/BufferStatus.h"
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +010045#include "aidl/android/hardware/camera/device/CameraMetadata.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010046#include "aidl/android/hardware/camera/device/CaptureRequest.h"
47#include "aidl/android/hardware/camera/device/HalStream.h"
48#include "aidl/android/hardware/camera/device/NotifyMsg.h"
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +010049#include "aidl/android/hardware/camera/device/RequestTemplate.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010050#include "aidl/android/hardware/camera/device/ShutterMsg.h"
51#include "aidl/android/hardware/camera/device/StreamBuffer.h"
52#include "aidl/android/hardware/camera/device/StreamConfiguration.h"
53#include "aidl/android/hardware/camera/device/StreamRotation.h"
54#include "aidl/android/hardware/graphics/common/BufferUsage.h"
55#include "aidl/android/hardware/graphics/common/PixelFormat.h"
56#include "android/hardware_buffer.h"
57#include "android/native_window_aidl.h"
58#include "fmq/AidlMessageQueue.h"
59#include "system/camera_metadata.h"
60#include "ui/GraphicBuffer.h"
61#include "util/EglDisplayContext.h"
62#include "util/EglFramebuffer.h"
63#include "util/EglProgram.h"
64#include "util/JpegUtil.h"
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +010065#include "util/MetadataUtil.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010066#include "util/TestPatternHelper.h"
67#include "util/Util.h"
68
69namespace android {
70namespace companion {
71namespace virtualcamera {
72
73using ::aidl::android::companion::virtualcamera::Format;
74using ::aidl::android::companion::virtualcamera::IVirtualCameraCallback;
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +010075using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010076using ::aidl::android::hardware::camera::common::Status;
77using ::aidl::android::hardware::camera::device::BufferCache;
78using ::aidl::android::hardware::camera::device::CameraMetadata;
79using ::aidl::android::hardware::camera::device::CameraOfflineSessionInfo;
80using ::aidl::android::hardware::camera::device::CaptureRequest;
81using ::aidl::android::hardware::camera::device::HalStream;
82using ::aidl::android::hardware::camera::device::ICameraDeviceCallback;
83using ::aidl::android::hardware::camera::device::ICameraOfflineSession;
84using ::aidl::android::hardware::camera::device::RequestTemplate;
85using ::aidl::android::hardware::camera::device::Stream;
86using ::aidl::android::hardware::camera::device::StreamBuffer;
87using ::aidl::android::hardware::camera::device::StreamConfiguration;
88using ::aidl::android::hardware::camera::device::StreamRotation;
89using ::aidl::android::hardware::common::fmq::MQDescriptor;
90using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
91using ::aidl::android::hardware::graphics::common::BufferUsage;
92using ::aidl::android::hardware::graphics::common::PixelFormat;
93using ::android::base::unique_fd;
94
95namespace {
96
97using metadata_ptr =
98 std::unique_ptr<camera_metadata_t, void (*)(camera_metadata_t*)>;
99
100using namespace std::chrono_literals;
101
102// Size of request/result metadata fast message queue.
103// Setting to 0 to always disables FMQ.
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +0100104constexpr size_t kMetadataMsgQueueSize = 0;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100105
106// Maximum number of buffers to use per single stream.
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +0100107constexpr size_t kMaxStreamBuffers = 2;
108
109constexpr int32_t kDefaultJpegQuality = 80;
110constexpr int32_t kDefaultJpegThumbnailQuality = 70;
111
112// 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()
145 .setControlCaptureIntent(requestTemplateToIntent(type))
146 .setControlMode(ANDROID_CONTROL_MODE_AUTO)
147 .setControlAeMode(ANDROID_CONTROL_AE_MODE_ON)
148 .setControlAeExposureCompensation(0)
149 .setControlAeTargetFpsRange(maxFps, maxFps)
150 .setControlAeAntibandingMode(ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO)
151 .setControlAePrecaptureTrigger(
152 ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE)
153 .setControlAfTrigger(ANDROID_CONTROL_AF_TRIGGER_IDLE)
Jan Sebechlebskybb01c1d2024-02-12 11:41:37 +0100154 .setControlAfMode(ANDROID_CONTROL_AF_MODE_OFF)
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100155 .setControlAwbMode(ANDROID_CONTROL_AWB_MODE_AUTO)
Jan Sebechlebskybb01c1d2024-02-12 11:41:37 +0100156 .setControlEffectMode(ANDROID_CONTROL_EFFECT_MODE_OFF)
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100157 .setFaceDetectMode(ANDROID_STATISTICS_FACE_DETECT_MODE_OFF)
158 .setFlashMode(ANDROID_FLASH_MODE_OFF)
Jan Sebechlebskybb01c1d2024-02-12 11:41:37 +0100159 .setFlashState(ANDROID_FLASH_STATE_UNAVAILABLE)
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +0100160 .setJpegQuality(VirtualCameraDevice::kDefaultJpegQuality)
161 .setJpegThumbnailQuality(VirtualCameraDevice::kDefaultJpegQuality)
162 .setJpegThumbnailSize(0, 0)
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100163 .build();
164 if (metadata == nullptr) {
165 ALOGE("%s: Failed to construct metadata for default request type %s",
166 __func__, toString(type).c_str());
167 return CameraMetadata();
168 } else {
169 ALOGV("%s: Successfully created metadata for request type %s", __func__,
170 toString(type).c_str());
171 }
172 return *metadata;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100173}
174
175HalStream getHalStream(const Stream& stream) {
176 HalStream halStream;
177 halStream.id = stream.id;
178 halStream.physicalCameraId = stream.physicalCameraId;
179 halStream.maxBuffers = kMaxStreamBuffers;
180
181 if (stream.format == PixelFormat::IMPLEMENTATION_DEFINED) {
182 // If format is implementation defined we need it to override
183 // it with actual format.
184 // TODO(b/301023410) Override with the format based on the
185 // camera configuration, once we support more formats.
186 halStream.overrideFormat = PixelFormat::YCBCR_420_888;
187 } else {
188 halStream.overrideFormat = stream.format;
189 }
190 halStream.overrideDataSpace = stream.dataSpace;
191
192 halStream.producerUsage = BufferUsage::GPU_RENDER_TARGET;
193 halStream.supportOffline = false;
194 return halStream;
195}
196
Jan Sebechlebsky39129f82024-01-19 16:42:11 +0100197Stream getHighestResolutionStream(const std::vector<Stream>& streams) {
198 return *(std::max_element(streams.begin(), streams.end(),
199 [](const Stream& a, const Stream& b) {
200 return a.width * a.height < b.width * b.height;
201 }));
202}
203
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +0100204RequestSettings createSettingsFromMetadata(const CameraMetadata& metadata) {
205 return RequestSettings{
206 .jpegQuality = getJpegQuality(metadata).value_or(
207 VirtualCameraDevice::kDefaultJpegQuality),
208 .thumbnailResolution =
209 getJpegThumbnailSize(metadata).value_or(Resolution(0, 0)),
210 .thumbnailJpegQuality = getJpegThumbnailQuality(metadata).value_or(
211 VirtualCameraDevice::kDefaultJpegQuality)};
212}
213
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100214} // namespace
215
216VirtualCameraSession::VirtualCameraSession(
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100217 std::shared_ptr<VirtualCameraDevice> cameraDevice,
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100218 std::shared_ptr<ICameraDeviceCallback> cameraDeviceCallback,
219 std::shared_ptr<IVirtualCameraCallback> virtualCameraClientCallback)
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100220 : mCameraDevice(cameraDevice),
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100221 mCameraDeviceCallback(cameraDeviceCallback),
222 mVirtualCameraClientCallback(virtualCameraClientCallback) {
223 mRequestMetadataQueue = std::make_unique<RequestMetadataQueue>(
224 kMetadataMsgQueueSize, false /* non blocking */);
225 if (!mRequestMetadataQueue->isValid()) {
226 ALOGE("%s: invalid request fmq", __func__);
227 }
228
229 mResultMetadataQueue = std::make_shared<ResultMetadataQueue>(
230 kMetadataMsgQueueSize, false /* non blocking */);
231 if (!mResultMetadataQueue->isValid()) {
232 ALOGE("%s: invalid result fmq", __func__);
233 }
234}
235
236ndk::ScopedAStatus VirtualCameraSession::close() {
237 ALOGV("%s", __func__);
238
239 if (mVirtualCameraClientCallback != nullptr) {
240 mVirtualCameraClientCallback->onStreamClosed(/*streamId=*/0);
241 }
242
Jan Sebechlebskyb0d8cab2023-11-28 10:55:04 +0100243 {
244 std::lock_guard<std::mutex> lock(mLock);
245 if (mRenderThread != nullptr) {
246 mRenderThread->stop();
247 mRenderThread = nullptr;
248 }
249 }
250
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100251 mSessionContext.closeAllStreams();
252 return ndk::ScopedAStatus::ok();
253}
254
255ndk::ScopedAStatus VirtualCameraSession::configureStreams(
256 const StreamConfiguration& in_requestedConfiguration,
257 std::vector<HalStream>* _aidl_return) {
258 ALOGV("%s: requestedConfiguration: %s", __func__,
259 in_requestedConfiguration.toString().c_str());
260
261 if (_aidl_return == nullptr) {
262 return cameraStatus(Status::ILLEGAL_ARGUMENT);
263 }
264
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100265 std::shared_ptr<VirtualCameraDevice> virtualCamera = mCameraDevice.lock();
266 if (virtualCamera == nullptr) {
267 ALOGW("%s: configure called on already unregistered camera", __func__);
268 return cameraStatus(Status::CAMERA_DISCONNECTED);
269 }
270
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100271 mSessionContext.removeStreamsNotInStreamConfiguration(
272 in_requestedConfiguration);
273
274 auto& streams = in_requestedConfiguration.streams;
275 auto& halStreams = *_aidl_return;
276 halStreams.clear();
277 halStreams.resize(in_requestedConfiguration.streams.size());
278
279 sp<Surface> inputSurface = nullptr;
280 int inputWidth;
281 int inputHeight;
282
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100283 if (!virtualCamera->isStreamCombinationSupported(in_requestedConfiguration)) {
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100284 ALOGE("%s: Requested stream configuration is not supported", __func__);
285 return cameraStatus(Status::ILLEGAL_ARGUMENT);
286 }
287
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100288 {
289 std::lock_guard<std::mutex> lock(mLock);
290 for (int i = 0; i < in_requestedConfiguration.streams.size(); ++i) {
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100291 halStreams[i] = getHalStream(streams[i]);
292 if (mSessionContext.initializeStream(streams[i])) {
293 ALOGV("Configured new stream: %s", streams[i].toString().c_str());
294 }
295 }
296
Jan Sebechlebsky39129f82024-01-19 16:42:11 +0100297 Stream maxResStream = getHighestResolutionStream(streams);
298 inputWidth = maxResStream.width;
299 inputHeight = maxResStream.height;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100300 if (mRenderThread == nullptr) {
301 // If there's no client callback, start camera in test mode.
302 const bool testMode = mVirtualCameraClientCallback == nullptr;
303 mRenderThread = std::make_unique<VirtualCameraRenderThread>(
Jan Sebechlebskybb01c1d2024-02-12 11:41:37 +0100304 mSessionContext, Resolution(inputWidth, inputHeight),
305 virtualCamera->getMaxInputResolution(), mCameraDeviceCallback,
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100306 testMode);
307 mRenderThread->start();
308 inputSurface = mRenderThread->getInputSurface();
309 }
310 }
311
312 if (mVirtualCameraClientCallback != nullptr && inputSurface != nullptr) {
313 // TODO(b/301023410) Pass streamId based on client input stream id once
314 // support for multiple input streams is implemented. For now we always
315 // create single texture.
316 mVirtualCameraClientCallback->onStreamConfigured(
317 /*streamId=*/0, aidl::android::view::Surface(inputSurface.get()),
318 inputWidth, inputHeight, Format::YUV_420_888);
319 }
320
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100321 return ndk::ScopedAStatus::ok();
322}
323
324ndk::ScopedAStatus VirtualCameraSession::constructDefaultRequestSettings(
325 RequestTemplate in_type, CameraMetadata* _aidl_return) {
326 ALOGV("%s: type %d", __func__, static_cast<int32_t>(in_type));
327
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100328 std::shared_ptr<VirtualCameraDevice> camera = mCameraDevice.lock();
329 if (camera == nullptr) {
330 ALOGW(
331 "%s: constructDefaultRequestSettings called on already unregistered "
332 "camera",
333 __func__);
334 return cameraStatus(Status::CAMERA_DISCONNECTED);
335 }
336
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100337 switch (in_type) {
338 case RequestTemplate::PREVIEW:
339 case RequestTemplate::STILL_CAPTURE:
Jan Sebechlebskyb0119fa2023-12-04 10:29:06 +0100340 case RequestTemplate::VIDEO_RECORD:
341 case RequestTemplate::VIDEO_SNAPSHOT: {
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100342 *_aidl_return =
343 createDefaultRequestSettings(in_type, camera->getInputConfigs());
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100344 return ndk::ScopedAStatus::ok();
345 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100346 case RequestTemplate::MANUAL:
347 case RequestTemplate::ZERO_SHUTTER_LAG:
348 // Don't support VIDEO_SNAPSHOT, MANUAL, ZSL templates
349 return ndk::ScopedAStatus::fromServiceSpecificError(
350 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
351 ;
352 default:
353 ALOGE("%s: unknown request template type %d", __FUNCTION__,
354 static_cast<int>(in_type));
355 return ndk::ScopedAStatus::fromServiceSpecificError(
356 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
357 ;
358 }
359}
360
361ndk::ScopedAStatus VirtualCameraSession::flush() {
362 ALOGV("%s", __func__);
363 std::lock_guard<std::mutex> lock(mLock);
Jan Sebechlebskyb0d8cab2023-11-28 10:55:04 +0100364 if (mRenderThread != nullptr) {
365 mRenderThread->flush();
366 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100367 return ndk::ScopedAStatus::ok();
368}
369
370ndk::ScopedAStatus VirtualCameraSession::getCaptureRequestMetadataQueue(
371 MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) {
372 ALOGV("%s", __func__);
373 *_aidl_return = mRequestMetadataQueue->dupeDesc();
374 return ndk::ScopedAStatus::ok();
375}
376
377ndk::ScopedAStatus VirtualCameraSession::getCaptureResultMetadataQueue(
378 MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) {
379 ALOGV("%s", __func__);
380 *_aidl_return = mResultMetadataQueue->dupeDesc();
381 return ndk::ScopedAStatus::ok();
382}
383
384ndk::ScopedAStatus VirtualCameraSession::isReconfigurationRequired(
385 const CameraMetadata& in_oldSessionParams,
386 const CameraMetadata& in_newSessionParams, bool* _aidl_return) {
387 ALOGV("%s: oldSessionParams: %s newSessionParams: %s", __func__,
388 in_newSessionParams.toString().c_str(),
389 in_oldSessionParams.toString().c_str());
390
391 if (_aidl_return == nullptr) {
392 return ndk::ScopedAStatus::fromServiceSpecificError(
393 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
394 }
395
396 *_aidl_return = true;
397 return ndk::ScopedAStatus::ok();
398}
399
400ndk::ScopedAStatus VirtualCameraSession::processCaptureRequest(
401 const std::vector<CaptureRequest>& in_requests,
402 const std::vector<BufferCache>& in_cachesToRemove, int32_t* _aidl_return) {
403 ALOGV("%s", __func__);
404
405 if (!in_cachesToRemove.empty()) {
406 mSessionContext.removeBufferCaches(in_cachesToRemove);
407 }
408
409 for (const auto& captureRequest : in_requests) {
410 auto status = processCaptureRequest(captureRequest);
411 if (!status.isOk()) {
412 return status;
413 }
414 }
415 *_aidl_return = in_requests.size();
416 return ndk::ScopedAStatus::ok();
417}
418
419ndk::ScopedAStatus VirtualCameraSession::signalStreamFlush(
420 const std::vector<int32_t>& in_streamIds, int32_t in_streamConfigCounter) {
421 ALOGV("%s", __func__);
422
423 (void)in_streamIds;
424 (void)in_streamConfigCounter;
425 return ndk::ScopedAStatus::ok();
426}
427
428ndk::ScopedAStatus VirtualCameraSession::switchToOffline(
429 const std::vector<int32_t>& in_streamsToKeep,
430 CameraOfflineSessionInfo* out_offlineSessionInfo,
431 std::shared_ptr<ICameraOfflineSession>* _aidl_return) {
432 ALOGV("%s", __func__);
433
434 (void)in_streamsToKeep;
435 (void)out_offlineSessionInfo;
436
437 if (_aidl_return == nullptr) {
438 return ndk::ScopedAStatus::fromServiceSpecificError(
439 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
440 }
441
442 *_aidl_return = nullptr;
443 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
444}
445
446ndk::ScopedAStatus VirtualCameraSession::repeatingRequestEnd(
447 int32_t in_frameNumber, const std::vector<int32_t>& in_streamIds) {
448 ALOGV("%s", __func__);
449 (void)in_frameNumber;
450 (void)in_streamIds;
451 return ndk::ScopedAStatus::ok();
452}
453
454std::set<int> VirtualCameraSession::getStreamIds() const {
455 return mSessionContext.getStreamIds();
456}
457
458ndk::ScopedAStatus VirtualCameraSession::processCaptureRequest(
459 const CaptureRequest& request) {
460 ALOGD("%s: request: %s", __func__, request.toString().c_str());
461
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100462 std::shared_ptr<ICameraDeviceCallback> cameraCallback = nullptr;
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +0100463 RequestSettings requestSettings;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100464 {
465 std::lock_guard<std::mutex> lock(mLock);
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +0100466
467 // If metadata it empty, last received metadata applies, if it's non-empty
468 // update it.
469 if (!request.settings.metadata.empty()) {
470 mCurrentRequestMetadata = request.settings;
471 }
472
473 // We don't have any metadata for this request - this means we received none
474 // in first request, this is an error state.
475 if (mCurrentRequestMetadata.metadata.empty()) {
476 return cameraStatus(Status::ILLEGAL_ARGUMENT);
477 }
478
479 requestSettings = createSettingsFromMetadata(mCurrentRequestMetadata);
480
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100481 cameraCallback = mCameraDeviceCallback;
482 }
483
484 if (cameraCallback == nullptr) {
485 ALOGE(
486 "%s: processCaptureRequest called, but there's no camera callback "
487 "configured",
488 __func__);
489 return cameraStatus(Status::INTERNAL_ERROR);
490 }
491
492 if (!mSessionContext.importBuffersFromCaptureRequest(request)) {
493 ALOGE("Failed to import buffers from capture request.");
494 return cameraStatus(Status::INTERNAL_ERROR);
495 }
496
497 std::vector<CaptureRequestBuffer> taskBuffers;
498 taskBuffers.reserve(request.outputBuffers.size());
499 for (const StreamBuffer& streamBuffer : request.outputBuffers) {
500 taskBuffers.emplace_back(streamBuffer.streamId, streamBuffer.bufferId,
501 importFence(streamBuffer.acquireFence));
502 }
503
504 {
505 std::lock_guard<std::mutex> lock(mLock);
506 if (mRenderThread == nullptr) {
507 ALOGE(
508 "%s: processCaptureRequest (frameNumber %d)called before configure "
509 "(render thread not initialized)",
510 __func__, request.frameNumber);
511 return cameraStatus(Status::INTERNAL_ERROR);
512 }
513 mRenderThread->enqueueTask(std::make_unique<ProcessCaptureRequestTask>(
Jan Sebechlebsky4ce32082024-02-14 16:02:11 +0100514 request.frameNumber, taskBuffers, requestSettings));
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100515 }
516
517 if (mVirtualCameraClientCallback != nullptr) {
518 auto status = mVirtualCameraClientCallback->onProcessCaptureRequest(
519 /*streamId=*/0, request.frameNumber);
520 if (!status.isOk()) {
521 ALOGE(
522 "Failed to invoke onProcessCaptureRequest client callback for frame "
523 "%d",
524 request.frameNumber);
525 }
526 }
527
528 return ndk::ScopedAStatus::ok();
529}
530
531} // namespace virtualcamera
532} // namespace companion
533} // namespace android