blob: 47780d84fdcc2bbc22f7d315d1c511cb94d7288b [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
21#include <atomic>
22#include <chrono>
23#include <cstddef>
24#include <cstdint>
25#include <cstring>
26#include <map>
27#include <memory>
28#include <mutex>
29#include <optional>
30#include <tuple>
31#include <unordered_set>
32#include <utility>
33#include <vector>
34
35#include "CameraMetadata.h"
36#include "EGL/egl.h"
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010037#include "VirtualCameraDevice.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010038#include "VirtualCameraRenderThread.h"
39#include "VirtualCameraStream.h"
40#include "aidl/android/hardware/camera/common/Status.h"
41#include "aidl/android/hardware/camera/device/BufferCache.h"
42#include "aidl/android/hardware/camera/device/BufferStatus.h"
43#include "aidl/android/hardware/camera/device/CaptureRequest.h"
44#include "aidl/android/hardware/camera/device/HalStream.h"
45#include "aidl/android/hardware/camera/device/NotifyMsg.h"
46#include "aidl/android/hardware/camera/device/ShutterMsg.h"
47#include "aidl/android/hardware/camera/device/StreamBuffer.h"
48#include "aidl/android/hardware/camera/device/StreamConfiguration.h"
49#include "aidl/android/hardware/camera/device/StreamRotation.h"
50#include "aidl/android/hardware/graphics/common/BufferUsage.h"
51#include "aidl/android/hardware/graphics/common/PixelFormat.h"
52#include "android/hardware_buffer.h"
53#include "android/native_window_aidl.h"
54#include "fmq/AidlMessageQueue.h"
55#include "system/camera_metadata.h"
56#include "ui/GraphicBuffer.h"
57#include "util/EglDisplayContext.h"
58#include "util/EglFramebuffer.h"
59#include "util/EglProgram.h"
60#include "util/JpegUtil.h"
61#include "util/MetadataBuilder.h"
62#include "util/TestPatternHelper.h"
63#include "util/Util.h"
64
65namespace android {
66namespace companion {
67namespace virtualcamera {
68
69using ::aidl::android::companion::virtualcamera::Format;
70using ::aidl::android::companion::virtualcamera::IVirtualCameraCallback;
71using ::aidl::android::hardware::camera::common::Status;
72using ::aidl::android::hardware::camera::device::BufferCache;
73using ::aidl::android::hardware::camera::device::CameraMetadata;
74using ::aidl::android::hardware::camera::device::CameraOfflineSessionInfo;
75using ::aidl::android::hardware::camera::device::CaptureRequest;
76using ::aidl::android::hardware::camera::device::HalStream;
77using ::aidl::android::hardware::camera::device::ICameraDeviceCallback;
78using ::aidl::android::hardware::camera::device::ICameraOfflineSession;
79using ::aidl::android::hardware::camera::device::RequestTemplate;
80using ::aidl::android::hardware::camera::device::Stream;
81using ::aidl::android::hardware::camera::device::StreamBuffer;
82using ::aidl::android::hardware::camera::device::StreamConfiguration;
83using ::aidl::android::hardware::camera::device::StreamRotation;
84using ::aidl::android::hardware::common::fmq::MQDescriptor;
85using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
86using ::aidl::android::hardware::graphics::common::BufferUsage;
87using ::aidl::android::hardware::graphics::common::PixelFormat;
88using ::android::base::unique_fd;
89
90namespace {
91
92using metadata_ptr =
93 std::unique_ptr<camera_metadata_t, void (*)(camera_metadata_t*)>;
94
95using namespace std::chrono_literals;
96
97// Size of request/result metadata fast message queue.
98// Setting to 0 to always disables FMQ.
99static constexpr size_t kMetadataMsgQueueSize = 0;
100
101// Maximum number of buffers to use per single stream.
102static constexpr size_t kMaxStreamBuffers = 2;
103
104CameraMetadata createDefaultRequestSettings(RequestTemplate type) {
105 hardware::camera::common::V1_0::helper::CameraMetadata metadataHelper;
106
107 camera_metadata_enum_android_control_capture_intent_t intent =
108 ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
109 switch (type) {
110 case RequestTemplate::PREVIEW:
111 intent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
112 break;
113 case RequestTemplate::STILL_CAPTURE:
114 intent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;
115 break;
116 case RequestTemplate::VIDEO_RECORD:
117 intent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;
118 break;
119 case RequestTemplate::VIDEO_SNAPSHOT:
120 intent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;
121 break;
122 default:
123 // Leave default.
124 break;
125 }
126
127 auto metadata = MetadataBuilder().setControlCaptureIntent(intent).build();
128 return (metadata != nullptr) ? std::move(*metadata) : CameraMetadata();
129}
130
131HalStream getHalStream(const Stream& stream) {
132 HalStream halStream;
133 halStream.id = stream.id;
134 halStream.physicalCameraId = stream.physicalCameraId;
135 halStream.maxBuffers = kMaxStreamBuffers;
136
137 if (stream.format == PixelFormat::IMPLEMENTATION_DEFINED) {
138 // If format is implementation defined we need it to override
139 // it with actual format.
140 // TODO(b/301023410) Override with the format based on the
141 // camera configuration, once we support more formats.
142 halStream.overrideFormat = PixelFormat::YCBCR_420_888;
143 } else {
144 halStream.overrideFormat = stream.format;
145 }
146 halStream.overrideDataSpace = stream.dataSpace;
147
148 halStream.producerUsage = BufferUsage::GPU_RENDER_TARGET;
149 halStream.supportOffline = false;
150 return halStream;
151}
152
153} // namespace
154
155VirtualCameraSession::VirtualCameraSession(
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100156 std::shared_ptr<VirtualCameraDevice> cameraDevice,
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100157 std::shared_ptr<ICameraDeviceCallback> cameraDeviceCallback,
158 std::shared_ptr<IVirtualCameraCallback> virtualCameraClientCallback)
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100159 : mCameraDevice(cameraDevice),
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100160 mCameraDeviceCallback(cameraDeviceCallback),
161 mVirtualCameraClientCallback(virtualCameraClientCallback) {
162 mRequestMetadataQueue = std::make_unique<RequestMetadataQueue>(
163 kMetadataMsgQueueSize, false /* non blocking */);
164 if (!mRequestMetadataQueue->isValid()) {
165 ALOGE("%s: invalid request fmq", __func__);
166 }
167
168 mResultMetadataQueue = std::make_shared<ResultMetadataQueue>(
169 kMetadataMsgQueueSize, false /* non blocking */);
170 if (!mResultMetadataQueue->isValid()) {
171 ALOGE("%s: invalid result fmq", __func__);
172 }
173}
174
175ndk::ScopedAStatus VirtualCameraSession::close() {
176 ALOGV("%s", __func__);
177
178 if (mVirtualCameraClientCallback != nullptr) {
179 mVirtualCameraClientCallback->onStreamClosed(/*streamId=*/0);
180 }
181
Jan Sebechlebskyb0d8cab2023-11-28 10:55:04 +0100182 {
183 std::lock_guard<std::mutex> lock(mLock);
184 if (mRenderThread != nullptr) {
185 mRenderThread->stop();
186 mRenderThread = nullptr;
187 }
188 }
189
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100190 mSessionContext.closeAllStreams();
191 return ndk::ScopedAStatus::ok();
192}
193
194ndk::ScopedAStatus VirtualCameraSession::configureStreams(
195 const StreamConfiguration& in_requestedConfiguration,
196 std::vector<HalStream>* _aidl_return) {
197 ALOGV("%s: requestedConfiguration: %s", __func__,
198 in_requestedConfiguration.toString().c_str());
199
200 if (_aidl_return == nullptr) {
201 return cameraStatus(Status::ILLEGAL_ARGUMENT);
202 }
203
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100204 std::shared_ptr<VirtualCameraDevice> virtualCamera = mCameraDevice.lock();
205 if (virtualCamera == nullptr) {
206 ALOGW("%s: configure called on already unregistered camera", __func__);
207 return cameraStatus(Status::CAMERA_DISCONNECTED);
208 }
209
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100210 mSessionContext.removeStreamsNotInStreamConfiguration(
211 in_requestedConfiguration);
212
213 auto& streams = in_requestedConfiguration.streams;
214 auto& halStreams = *_aidl_return;
215 halStreams.clear();
216 halStreams.resize(in_requestedConfiguration.streams.size());
217
218 sp<Surface> inputSurface = nullptr;
219 int inputWidth;
220 int inputHeight;
221
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100222 if (!virtualCamera->isStreamCombinationSupported(in_requestedConfiguration)) {
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100223 ALOGE("%s: Requested stream configuration is not supported", __func__);
224 return cameraStatus(Status::ILLEGAL_ARGUMENT);
225 }
226
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100227 {
228 std::lock_guard<std::mutex> lock(mLock);
229 for (int i = 0; i < in_requestedConfiguration.streams.size(); ++i) {
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100230 halStreams[i] = getHalStream(streams[i]);
231 if (mSessionContext.initializeStream(streams[i])) {
232 ALOGV("Configured new stream: %s", streams[i].toString().c_str());
233 }
234 }
235
236 inputWidth = streams[0].width;
237 inputHeight = streams[0].height;
238 if (mRenderThread == nullptr) {
239 // If there's no client callback, start camera in test mode.
240 const bool testMode = mVirtualCameraClientCallback == nullptr;
241 mRenderThread = std::make_unique<VirtualCameraRenderThread>(
242 mSessionContext, inputWidth, inputHeight, mCameraDeviceCallback,
243 testMode);
244 mRenderThread->start();
245 inputSurface = mRenderThread->getInputSurface();
246 }
247 }
248
249 if (mVirtualCameraClientCallback != nullptr && inputSurface != nullptr) {
250 // TODO(b/301023410) Pass streamId based on client input stream id once
251 // support for multiple input streams is implemented. For now we always
252 // create single texture.
253 mVirtualCameraClientCallback->onStreamConfigured(
254 /*streamId=*/0, aidl::android::view::Surface(inputSurface.get()),
255 inputWidth, inputHeight, Format::YUV_420_888);
256 }
257
258 mFirstRequest.store(true);
259 return ndk::ScopedAStatus::ok();
260}
261
262ndk::ScopedAStatus VirtualCameraSession::constructDefaultRequestSettings(
263 RequestTemplate in_type, CameraMetadata* _aidl_return) {
264 ALOGV("%s: type %d", __func__, static_cast<int32_t>(in_type));
265
266 switch (in_type) {
267 case RequestTemplate::PREVIEW:
268 case RequestTemplate::STILL_CAPTURE:
Jan Sebechlebskyb0119fa2023-12-04 10:29:06 +0100269 case RequestTemplate::VIDEO_RECORD:
270 case RequestTemplate::VIDEO_SNAPSHOT: {
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100271 *_aidl_return = createDefaultRequestSettings(in_type);
272 return ndk::ScopedAStatus::ok();
273 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100274 case RequestTemplate::MANUAL:
275 case RequestTemplate::ZERO_SHUTTER_LAG:
276 // Don't support VIDEO_SNAPSHOT, MANUAL, ZSL templates
277 return ndk::ScopedAStatus::fromServiceSpecificError(
278 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
279 ;
280 default:
281 ALOGE("%s: unknown request template type %d", __FUNCTION__,
282 static_cast<int>(in_type));
283 return ndk::ScopedAStatus::fromServiceSpecificError(
284 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
285 ;
286 }
287}
288
289ndk::ScopedAStatus VirtualCameraSession::flush() {
290 ALOGV("%s", __func__);
291 std::lock_guard<std::mutex> lock(mLock);
Jan Sebechlebskyb0d8cab2023-11-28 10:55:04 +0100292 if (mRenderThread != nullptr) {
293 mRenderThread->flush();
294 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100295 return ndk::ScopedAStatus::ok();
296}
297
298ndk::ScopedAStatus VirtualCameraSession::getCaptureRequestMetadataQueue(
299 MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) {
300 ALOGV("%s", __func__);
301 *_aidl_return = mRequestMetadataQueue->dupeDesc();
302 return ndk::ScopedAStatus::ok();
303}
304
305ndk::ScopedAStatus VirtualCameraSession::getCaptureResultMetadataQueue(
306 MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) {
307 ALOGV("%s", __func__);
308 *_aidl_return = mResultMetadataQueue->dupeDesc();
309 return ndk::ScopedAStatus::ok();
310}
311
312ndk::ScopedAStatus VirtualCameraSession::isReconfigurationRequired(
313 const CameraMetadata& in_oldSessionParams,
314 const CameraMetadata& in_newSessionParams, bool* _aidl_return) {
315 ALOGV("%s: oldSessionParams: %s newSessionParams: %s", __func__,
316 in_newSessionParams.toString().c_str(),
317 in_oldSessionParams.toString().c_str());
318
319 if (_aidl_return == nullptr) {
320 return ndk::ScopedAStatus::fromServiceSpecificError(
321 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
322 }
323
324 *_aidl_return = true;
325 return ndk::ScopedAStatus::ok();
326}
327
328ndk::ScopedAStatus VirtualCameraSession::processCaptureRequest(
329 const std::vector<CaptureRequest>& in_requests,
330 const std::vector<BufferCache>& in_cachesToRemove, int32_t* _aidl_return) {
331 ALOGV("%s", __func__);
332
333 if (!in_cachesToRemove.empty()) {
334 mSessionContext.removeBufferCaches(in_cachesToRemove);
335 }
336
337 for (const auto& captureRequest : in_requests) {
338 auto status = processCaptureRequest(captureRequest);
339 if (!status.isOk()) {
340 return status;
341 }
342 }
343 *_aidl_return = in_requests.size();
344 return ndk::ScopedAStatus::ok();
345}
346
347ndk::ScopedAStatus VirtualCameraSession::signalStreamFlush(
348 const std::vector<int32_t>& in_streamIds, int32_t in_streamConfigCounter) {
349 ALOGV("%s", __func__);
350
351 (void)in_streamIds;
352 (void)in_streamConfigCounter;
353 return ndk::ScopedAStatus::ok();
354}
355
356ndk::ScopedAStatus VirtualCameraSession::switchToOffline(
357 const std::vector<int32_t>& in_streamsToKeep,
358 CameraOfflineSessionInfo* out_offlineSessionInfo,
359 std::shared_ptr<ICameraOfflineSession>* _aidl_return) {
360 ALOGV("%s", __func__);
361
362 (void)in_streamsToKeep;
363 (void)out_offlineSessionInfo;
364
365 if (_aidl_return == nullptr) {
366 return ndk::ScopedAStatus::fromServiceSpecificError(
367 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
368 }
369
370 *_aidl_return = nullptr;
371 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
372}
373
374ndk::ScopedAStatus VirtualCameraSession::repeatingRequestEnd(
375 int32_t in_frameNumber, const std::vector<int32_t>& in_streamIds) {
376 ALOGV("%s", __func__);
377 (void)in_frameNumber;
378 (void)in_streamIds;
379 return ndk::ScopedAStatus::ok();
380}
381
382std::set<int> VirtualCameraSession::getStreamIds() const {
383 return mSessionContext.getStreamIds();
384}
385
386ndk::ScopedAStatus VirtualCameraSession::processCaptureRequest(
387 const CaptureRequest& request) {
388 ALOGD("%s: request: %s", __func__, request.toString().c_str());
389
390 if (mFirstRequest.exchange(false) && request.settings.metadata.empty()) {
391 return cameraStatus(Status::ILLEGAL_ARGUMENT);
392 }
393
394 std::shared_ptr<ICameraDeviceCallback> cameraCallback = nullptr;
395 {
396 std::lock_guard<std::mutex> lock(mLock);
397 cameraCallback = mCameraDeviceCallback;
398 }
399
400 if (cameraCallback == nullptr) {
401 ALOGE(
402 "%s: processCaptureRequest called, but there's no camera callback "
403 "configured",
404 __func__);
405 return cameraStatus(Status::INTERNAL_ERROR);
406 }
407
408 if (!mSessionContext.importBuffersFromCaptureRequest(request)) {
409 ALOGE("Failed to import buffers from capture request.");
410 return cameraStatus(Status::INTERNAL_ERROR);
411 }
412
413 std::vector<CaptureRequestBuffer> taskBuffers;
414 taskBuffers.reserve(request.outputBuffers.size());
415 for (const StreamBuffer& streamBuffer : request.outputBuffers) {
416 taskBuffers.emplace_back(streamBuffer.streamId, streamBuffer.bufferId,
417 importFence(streamBuffer.acquireFence));
418 }
419
420 {
421 std::lock_guard<std::mutex> lock(mLock);
422 if (mRenderThread == nullptr) {
423 ALOGE(
424 "%s: processCaptureRequest (frameNumber %d)called before configure "
425 "(render thread not initialized)",
426 __func__, request.frameNumber);
427 return cameraStatus(Status::INTERNAL_ERROR);
428 }
429 mRenderThread->enqueueTask(std::make_unique<ProcessCaptureRequestTask>(
430 request.frameNumber, taskBuffers));
431 }
432
433 if (mVirtualCameraClientCallback != nullptr) {
434 auto status = mVirtualCameraClientCallback->onProcessCaptureRequest(
435 /*streamId=*/0, request.frameNumber);
436 if (!status.isOk()) {
437 ALOGE(
438 "Failed to invoke onProcessCaptureRequest client callback for frame "
439 "%d",
440 request.frameNumber);
441 }
442 }
443
444 return ndk::ScopedAStatus::ok();
445}
446
447} // namespace virtualcamera
448} // namespace companion
449} // namespace android