blob: d1ec763ada07818103884b6622020e32c32e126f [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"
45#include "aidl/android/hardware/camera/device/CaptureRequest.h"
46#include "aidl/android/hardware/camera/device/HalStream.h"
47#include "aidl/android/hardware/camera/device/NotifyMsg.h"
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +010048#include "aidl/android/hardware/camera/device/RequestTemplate.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010049#include "aidl/android/hardware/camera/device/ShutterMsg.h"
50#include "aidl/android/hardware/camera/device/StreamBuffer.h"
51#include "aidl/android/hardware/camera/device/StreamConfiguration.h"
52#include "aidl/android/hardware/camera/device/StreamRotation.h"
53#include "aidl/android/hardware/graphics/common/BufferUsage.h"
54#include "aidl/android/hardware/graphics/common/PixelFormat.h"
55#include "android/hardware_buffer.h"
56#include "android/native_window_aidl.h"
57#include "fmq/AidlMessageQueue.h"
58#include "system/camera_metadata.h"
59#include "ui/GraphicBuffer.h"
60#include "util/EglDisplayContext.h"
61#include "util/EglFramebuffer.h"
62#include "util/EglProgram.h"
63#include "util/JpegUtil.h"
64#include "util/MetadataBuilder.h"
65#include "util/TestPatternHelper.h"
66#include "util/Util.h"
67
68namespace android {
69namespace companion {
70namespace virtualcamera {
71
72using ::aidl::android::companion::virtualcamera::Format;
73using ::aidl::android::companion::virtualcamera::IVirtualCameraCallback;
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +010074using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010075using ::aidl::android::hardware::camera::common::Status;
76using ::aidl::android::hardware::camera::device::BufferCache;
77using ::aidl::android::hardware::camera::device::CameraMetadata;
78using ::aidl::android::hardware::camera::device::CameraOfflineSessionInfo;
79using ::aidl::android::hardware::camera::device::CaptureRequest;
80using ::aidl::android::hardware::camera::device::HalStream;
81using ::aidl::android::hardware::camera::device::ICameraDeviceCallback;
82using ::aidl::android::hardware::camera::device::ICameraOfflineSession;
83using ::aidl::android::hardware::camera::device::RequestTemplate;
84using ::aidl::android::hardware::camera::device::Stream;
85using ::aidl::android::hardware::camera::device::StreamBuffer;
86using ::aidl::android::hardware::camera::device::StreamConfiguration;
87using ::aidl::android::hardware::camera::device::StreamRotation;
88using ::aidl::android::hardware::common::fmq::MQDescriptor;
89using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
90using ::aidl::android::hardware::graphics::common::BufferUsage;
91using ::aidl::android::hardware::graphics::common::PixelFormat;
92using ::android::base::unique_fd;
93
94namespace {
95
96using metadata_ptr =
97 std::unique_ptr<camera_metadata_t, void (*)(camera_metadata_t*)>;
98
99using namespace std::chrono_literals;
100
101// Size of request/result metadata fast message queue.
102// Setting to 0 to always disables FMQ.
103static constexpr size_t kMetadataMsgQueueSize = 0;
104
105// Maximum number of buffers to use per single stream.
106static constexpr size_t kMaxStreamBuffers = 2;
107
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100108camera_metadata_enum_android_control_capture_intent_t requestTemplateToIntent(
109 const RequestTemplate type) {
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100110 switch (type) {
111 case RequestTemplate::PREVIEW:
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100112 return ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100113 case RequestTemplate::STILL_CAPTURE:
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100114 return ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100115 case RequestTemplate::VIDEO_RECORD:
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100116 return ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100117 case RequestTemplate::VIDEO_SNAPSHOT:
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100118 return ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100119 default:
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100120 // Return PREVIEW by default
121 return ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100122 }
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100123}
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100124
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100125int getMaxFps(const std::vector<SupportedStreamConfiguration>& configs) {
126 return std::transform_reduce(
127 configs.begin(), configs.end(), 0,
128 [](const int a, const int b) { return std::max(a, b); },
129 [](const SupportedStreamConfiguration& config) { return config.maxFps; });
130}
131
132CameraMetadata createDefaultRequestSettings(
133 const RequestTemplate type,
134 const std::vector<SupportedStreamConfiguration>& inputConfigs) {
135 int maxFps = getMaxFps(inputConfigs);
136 auto metadata =
137 MetadataBuilder()
138 .setControlCaptureIntent(requestTemplateToIntent(type))
139 .setControlMode(ANDROID_CONTROL_MODE_AUTO)
140 .setControlAeMode(ANDROID_CONTROL_AE_MODE_ON)
141 .setControlAeExposureCompensation(0)
142 .setControlAeTargetFpsRange(maxFps, maxFps)
143 .setControlAeAntibandingMode(ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO)
144 .setControlAePrecaptureTrigger(
145 ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE)
146 .setControlAfTrigger(ANDROID_CONTROL_AF_TRIGGER_IDLE)
Jan Sebechlebskybb01c1d2024-02-12 11:41:37 +0100147 .setControlAfMode(ANDROID_CONTROL_AF_MODE_OFF)
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100148 .setControlAwbMode(ANDROID_CONTROL_AWB_MODE_AUTO)
Jan Sebechlebskybb01c1d2024-02-12 11:41:37 +0100149 .setControlEffectMode(ANDROID_CONTROL_EFFECT_MODE_OFF)
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100150 .setFaceDetectMode(ANDROID_STATISTICS_FACE_DETECT_MODE_OFF)
151 .setFlashMode(ANDROID_FLASH_MODE_OFF)
Jan Sebechlebskybb01c1d2024-02-12 11:41:37 +0100152 .setFlashState(ANDROID_FLASH_STATE_UNAVAILABLE)
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100153 .build();
154 if (metadata == nullptr) {
155 ALOGE("%s: Failed to construct metadata for default request type %s",
156 __func__, toString(type).c_str());
157 return CameraMetadata();
158 } else {
159 ALOGV("%s: Successfully created metadata for request type %s", __func__,
160 toString(type).c_str());
161 }
162 return *metadata;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100163}
164
165HalStream getHalStream(const Stream& stream) {
166 HalStream halStream;
167 halStream.id = stream.id;
168 halStream.physicalCameraId = stream.physicalCameraId;
169 halStream.maxBuffers = kMaxStreamBuffers;
170
171 if (stream.format == PixelFormat::IMPLEMENTATION_DEFINED) {
172 // If format is implementation defined we need it to override
173 // it with actual format.
174 // TODO(b/301023410) Override with the format based on the
175 // camera configuration, once we support more formats.
176 halStream.overrideFormat = PixelFormat::YCBCR_420_888;
177 } else {
178 halStream.overrideFormat = stream.format;
179 }
180 halStream.overrideDataSpace = stream.dataSpace;
181
182 halStream.producerUsage = BufferUsage::GPU_RENDER_TARGET;
183 halStream.supportOffline = false;
184 return halStream;
185}
186
Jan Sebechlebsky39129f82024-01-19 16:42:11 +0100187Stream getHighestResolutionStream(const std::vector<Stream>& streams) {
188 return *(std::max_element(streams.begin(), streams.end(),
189 [](const Stream& a, const Stream& b) {
190 return a.width * a.height < b.width * b.height;
191 }));
192}
193
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100194} // namespace
195
196VirtualCameraSession::VirtualCameraSession(
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100197 std::shared_ptr<VirtualCameraDevice> cameraDevice,
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100198 std::shared_ptr<ICameraDeviceCallback> cameraDeviceCallback,
199 std::shared_ptr<IVirtualCameraCallback> virtualCameraClientCallback)
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100200 : mCameraDevice(cameraDevice),
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100201 mCameraDeviceCallback(cameraDeviceCallback),
202 mVirtualCameraClientCallback(virtualCameraClientCallback) {
203 mRequestMetadataQueue = std::make_unique<RequestMetadataQueue>(
204 kMetadataMsgQueueSize, false /* non blocking */);
205 if (!mRequestMetadataQueue->isValid()) {
206 ALOGE("%s: invalid request fmq", __func__);
207 }
208
209 mResultMetadataQueue = std::make_shared<ResultMetadataQueue>(
210 kMetadataMsgQueueSize, false /* non blocking */);
211 if (!mResultMetadataQueue->isValid()) {
212 ALOGE("%s: invalid result fmq", __func__);
213 }
214}
215
216ndk::ScopedAStatus VirtualCameraSession::close() {
217 ALOGV("%s", __func__);
218
219 if (mVirtualCameraClientCallback != nullptr) {
220 mVirtualCameraClientCallback->onStreamClosed(/*streamId=*/0);
221 }
222
Jan Sebechlebskyb0d8cab2023-11-28 10:55:04 +0100223 {
224 std::lock_guard<std::mutex> lock(mLock);
225 if (mRenderThread != nullptr) {
226 mRenderThread->stop();
227 mRenderThread = nullptr;
228 }
229 }
230
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100231 mSessionContext.closeAllStreams();
232 return ndk::ScopedAStatus::ok();
233}
234
235ndk::ScopedAStatus VirtualCameraSession::configureStreams(
236 const StreamConfiguration& in_requestedConfiguration,
237 std::vector<HalStream>* _aidl_return) {
238 ALOGV("%s: requestedConfiguration: %s", __func__,
239 in_requestedConfiguration.toString().c_str());
240
241 if (_aidl_return == nullptr) {
242 return cameraStatus(Status::ILLEGAL_ARGUMENT);
243 }
244
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100245 std::shared_ptr<VirtualCameraDevice> virtualCamera = mCameraDevice.lock();
246 if (virtualCamera == nullptr) {
247 ALOGW("%s: configure called on already unregistered camera", __func__);
248 return cameraStatus(Status::CAMERA_DISCONNECTED);
249 }
250
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100251 mSessionContext.removeStreamsNotInStreamConfiguration(
252 in_requestedConfiguration);
253
254 auto& streams = in_requestedConfiguration.streams;
255 auto& halStreams = *_aidl_return;
256 halStreams.clear();
257 halStreams.resize(in_requestedConfiguration.streams.size());
258
259 sp<Surface> inputSurface = nullptr;
260 int inputWidth;
261 int inputHeight;
262
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100263 if (!virtualCamera->isStreamCombinationSupported(in_requestedConfiguration)) {
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100264 ALOGE("%s: Requested stream configuration is not supported", __func__);
265 return cameraStatus(Status::ILLEGAL_ARGUMENT);
266 }
267
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100268 {
269 std::lock_guard<std::mutex> lock(mLock);
270 for (int i = 0; i < in_requestedConfiguration.streams.size(); ++i) {
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100271 halStreams[i] = getHalStream(streams[i]);
272 if (mSessionContext.initializeStream(streams[i])) {
273 ALOGV("Configured new stream: %s", streams[i].toString().c_str());
274 }
275 }
276
Jan Sebechlebsky39129f82024-01-19 16:42:11 +0100277 Stream maxResStream = getHighestResolutionStream(streams);
278 inputWidth = maxResStream.width;
279 inputHeight = maxResStream.height;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100280 if (mRenderThread == nullptr) {
281 // If there's no client callback, start camera in test mode.
282 const bool testMode = mVirtualCameraClientCallback == nullptr;
283 mRenderThread = std::make_unique<VirtualCameraRenderThread>(
Jan Sebechlebskybb01c1d2024-02-12 11:41:37 +0100284 mSessionContext, Resolution(inputWidth, inputHeight),
285 virtualCamera->getMaxInputResolution(), mCameraDeviceCallback,
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100286 testMode);
287 mRenderThread->start();
288 inputSurface = mRenderThread->getInputSurface();
289 }
290 }
291
292 if (mVirtualCameraClientCallback != nullptr && inputSurface != nullptr) {
293 // TODO(b/301023410) Pass streamId based on client input stream id once
294 // support for multiple input streams is implemented. For now we always
295 // create single texture.
296 mVirtualCameraClientCallback->onStreamConfigured(
297 /*streamId=*/0, aidl::android::view::Surface(inputSurface.get()),
298 inputWidth, inputHeight, Format::YUV_420_888);
299 }
300
301 mFirstRequest.store(true);
302 return ndk::ScopedAStatus::ok();
303}
304
305ndk::ScopedAStatus VirtualCameraSession::constructDefaultRequestSettings(
306 RequestTemplate in_type, CameraMetadata* _aidl_return) {
307 ALOGV("%s: type %d", __func__, static_cast<int32_t>(in_type));
308
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100309 std::shared_ptr<VirtualCameraDevice> camera = mCameraDevice.lock();
310 if (camera == nullptr) {
311 ALOGW(
312 "%s: constructDefaultRequestSettings called on already unregistered "
313 "camera",
314 __func__);
315 return cameraStatus(Status::CAMERA_DISCONNECTED);
316 }
317
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100318 switch (in_type) {
319 case RequestTemplate::PREVIEW:
320 case RequestTemplate::STILL_CAPTURE:
Jan Sebechlebskyb0119fa2023-12-04 10:29:06 +0100321 case RequestTemplate::VIDEO_RECORD:
322 case RequestTemplate::VIDEO_SNAPSHOT: {
Jan Sebechlebskyc3e1a632024-02-06 14:19:05 +0100323 *_aidl_return =
324 createDefaultRequestSettings(in_type, camera->getInputConfigs());
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100325 return ndk::ScopedAStatus::ok();
326 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100327 case RequestTemplate::MANUAL:
328 case RequestTemplate::ZERO_SHUTTER_LAG:
329 // Don't support VIDEO_SNAPSHOT, MANUAL, ZSL templates
330 return ndk::ScopedAStatus::fromServiceSpecificError(
331 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
332 ;
333 default:
334 ALOGE("%s: unknown request template type %d", __FUNCTION__,
335 static_cast<int>(in_type));
336 return ndk::ScopedAStatus::fromServiceSpecificError(
337 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
338 ;
339 }
340}
341
342ndk::ScopedAStatus VirtualCameraSession::flush() {
343 ALOGV("%s", __func__);
344 std::lock_guard<std::mutex> lock(mLock);
Jan Sebechlebskyb0d8cab2023-11-28 10:55:04 +0100345 if (mRenderThread != nullptr) {
346 mRenderThread->flush();
347 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100348 return ndk::ScopedAStatus::ok();
349}
350
351ndk::ScopedAStatus VirtualCameraSession::getCaptureRequestMetadataQueue(
352 MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) {
353 ALOGV("%s", __func__);
354 *_aidl_return = mRequestMetadataQueue->dupeDesc();
355 return ndk::ScopedAStatus::ok();
356}
357
358ndk::ScopedAStatus VirtualCameraSession::getCaptureResultMetadataQueue(
359 MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) {
360 ALOGV("%s", __func__);
361 *_aidl_return = mResultMetadataQueue->dupeDesc();
362 return ndk::ScopedAStatus::ok();
363}
364
365ndk::ScopedAStatus VirtualCameraSession::isReconfigurationRequired(
366 const CameraMetadata& in_oldSessionParams,
367 const CameraMetadata& in_newSessionParams, bool* _aidl_return) {
368 ALOGV("%s: oldSessionParams: %s newSessionParams: %s", __func__,
369 in_newSessionParams.toString().c_str(),
370 in_oldSessionParams.toString().c_str());
371
372 if (_aidl_return == nullptr) {
373 return ndk::ScopedAStatus::fromServiceSpecificError(
374 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
375 }
376
377 *_aidl_return = true;
378 return ndk::ScopedAStatus::ok();
379}
380
381ndk::ScopedAStatus VirtualCameraSession::processCaptureRequest(
382 const std::vector<CaptureRequest>& in_requests,
383 const std::vector<BufferCache>& in_cachesToRemove, int32_t* _aidl_return) {
384 ALOGV("%s", __func__);
385
386 if (!in_cachesToRemove.empty()) {
387 mSessionContext.removeBufferCaches(in_cachesToRemove);
388 }
389
390 for (const auto& captureRequest : in_requests) {
391 auto status = processCaptureRequest(captureRequest);
392 if (!status.isOk()) {
393 return status;
394 }
395 }
396 *_aidl_return = in_requests.size();
397 return ndk::ScopedAStatus::ok();
398}
399
400ndk::ScopedAStatus VirtualCameraSession::signalStreamFlush(
401 const std::vector<int32_t>& in_streamIds, int32_t in_streamConfigCounter) {
402 ALOGV("%s", __func__);
403
404 (void)in_streamIds;
405 (void)in_streamConfigCounter;
406 return ndk::ScopedAStatus::ok();
407}
408
409ndk::ScopedAStatus VirtualCameraSession::switchToOffline(
410 const std::vector<int32_t>& in_streamsToKeep,
411 CameraOfflineSessionInfo* out_offlineSessionInfo,
412 std::shared_ptr<ICameraOfflineSession>* _aidl_return) {
413 ALOGV("%s", __func__);
414
415 (void)in_streamsToKeep;
416 (void)out_offlineSessionInfo;
417
418 if (_aidl_return == nullptr) {
419 return ndk::ScopedAStatus::fromServiceSpecificError(
420 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
421 }
422
423 *_aidl_return = nullptr;
424 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
425}
426
427ndk::ScopedAStatus VirtualCameraSession::repeatingRequestEnd(
428 int32_t in_frameNumber, const std::vector<int32_t>& in_streamIds) {
429 ALOGV("%s", __func__);
430 (void)in_frameNumber;
431 (void)in_streamIds;
432 return ndk::ScopedAStatus::ok();
433}
434
435std::set<int> VirtualCameraSession::getStreamIds() const {
436 return mSessionContext.getStreamIds();
437}
438
439ndk::ScopedAStatus VirtualCameraSession::processCaptureRequest(
440 const CaptureRequest& request) {
441 ALOGD("%s: request: %s", __func__, request.toString().c_str());
442
443 if (mFirstRequest.exchange(false) && request.settings.metadata.empty()) {
444 return cameraStatus(Status::ILLEGAL_ARGUMENT);
445 }
446
447 std::shared_ptr<ICameraDeviceCallback> cameraCallback = nullptr;
448 {
449 std::lock_guard<std::mutex> lock(mLock);
450 cameraCallback = mCameraDeviceCallback;
451 }
452
453 if (cameraCallback == nullptr) {
454 ALOGE(
455 "%s: processCaptureRequest called, but there's no camera callback "
456 "configured",
457 __func__);
458 return cameraStatus(Status::INTERNAL_ERROR);
459 }
460
461 if (!mSessionContext.importBuffersFromCaptureRequest(request)) {
462 ALOGE("Failed to import buffers from capture request.");
463 return cameraStatus(Status::INTERNAL_ERROR);
464 }
465
466 std::vector<CaptureRequestBuffer> taskBuffers;
467 taskBuffers.reserve(request.outputBuffers.size());
468 for (const StreamBuffer& streamBuffer : request.outputBuffers) {
469 taskBuffers.emplace_back(streamBuffer.streamId, streamBuffer.bufferId,
470 importFence(streamBuffer.acquireFence));
471 }
472
473 {
474 std::lock_guard<std::mutex> lock(mLock);
475 if (mRenderThread == nullptr) {
476 ALOGE(
477 "%s: processCaptureRequest (frameNumber %d)called before configure "
478 "(render thread not initialized)",
479 __func__, request.frameNumber);
480 return cameraStatus(Status::INTERNAL_ERROR);
481 }
482 mRenderThread->enqueueTask(std::make_unique<ProcessCaptureRequestTask>(
483 request.frameNumber, taskBuffers));
484 }
485
486 if (mVirtualCameraClientCallback != nullptr) {
487 auto status = mVirtualCameraClientCallback->onProcessCaptureRequest(
488 /*streamId=*/0, request.frameNumber);
489 if (!status.isOk()) {
490 ALOGE(
491 "Failed to invoke onProcessCaptureRequest client callback for frame "
492 "%d",
493 request.frameNumber);
494 }
495 }
496
497 return ndk::ScopedAStatus::ok();
498}
499
500} // namespace virtualcamera
501} // namespace companion
502} // namespace android