blob: 9e15871519821cbc773bd0c26c21f040420b20d7 [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 Sebechlebsky3b478c42023-11-23 13:15:56 +0100156 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
204 mSessionContext.removeStreamsNotInStreamConfiguration(
205 in_requestedConfiguration);
206
207 auto& streams = in_requestedConfiguration.streams;
208 auto& halStreams = *_aidl_return;
209 halStreams.clear();
210 halStreams.resize(in_requestedConfiguration.streams.size());
211
212 sp<Surface> inputSurface = nullptr;
213 int inputWidth;
214 int inputHeight;
215
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100216 if (!mCameraDevice.isStreamCombinationSupported(in_requestedConfiguration)) {
217 ALOGE("%s: Requested stream configuration is not supported", __func__);
218 return cameraStatus(Status::ILLEGAL_ARGUMENT);
219 }
220
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100221 {
222 std::lock_guard<std::mutex> lock(mLock);
223 for (int i = 0; i < in_requestedConfiguration.streams.size(); ++i) {
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100224 halStreams[i] = getHalStream(streams[i]);
225 if (mSessionContext.initializeStream(streams[i])) {
226 ALOGV("Configured new stream: %s", streams[i].toString().c_str());
227 }
228 }
229
230 inputWidth = streams[0].width;
231 inputHeight = streams[0].height;
232 if (mRenderThread == nullptr) {
233 // If there's no client callback, start camera in test mode.
234 const bool testMode = mVirtualCameraClientCallback == nullptr;
235 mRenderThread = std::make_unique<VirtualCameraRenderThread>(
236 mSessionContext, inputWidth, inputHeight, mCameraDeviceCallback,
237 testMode);
238 mRenderThread->start();
239 inputSurface = mRenderThread->getInputSurface();
240 }
241 }
242
243 if (mVirtualCameraClientCallback != nullptr && inputSurface != nullptr) {
244 // TODO(b/301023410) Pass streamId based on client input stream id once
245 // support for multiple input streams is implemented. For now we always
246 // create single texture.
247 mVirtualCameraClientCallback->onStreamConfigured(
248 /*streamId=*/0, aidl::android::view::Surface(inputSurface.get()),
249 inputWidth, inputHeight, Format::YUV_420_888);
250 }
251
252 mFirstRequest.store(true);
253 return ndk::ScopedAStatus::ok();
254}
255
256ndk::ScopedAStatus VirtualCameraSession::constructDefaultRequestSettings(
257 RequestTemplate in_type, CameraMetadata* _aidl_return) {
258 ALOGV("%s: type %d", __func__, static_cast<int32_t>(in_type));
259
260 switch (in_type) {
261 case RequestTemplate::PREVIEW:
262 case RequestTemplate::STILL_CAPTURE:
Jan Sebechlebskyb0119fa2023-12-04 10:29:06 +0100263 case RequestTemplate::VIDEO_RECORD:
264 case RequestTemplate::VIDEO_SNAPSHOT: {
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100265 *_aidl_return = createDefaultRequestSettings(in_type);
266 return ndk::ScopedAStatus::ok();
267 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100268 case RequestTemplate::MANUAL:
269 case RequestTemplate::ZERO_SHUTTER_LAG:
270 // Don't support VIDEO_SNAPSHOT, MANUAL, ZSL templates
271 return ndk::ScopedAStatus::fromServiceSpecificError(
272 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
273 ;
274 default:
275 ALOGE("%s: unknown request template type %d", __FUNCTION__,
276 static_cast<int>(in_type));
277 return ndk::ScopedAStatus::fromServiceSpecificError(
278 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
279 ;
280 }
281}
282
283ndk::ScopedAStatus VirtualCameraSession::flush() {
284 ALOGV("%s", __func__);
285 std::lock_guard<std::mutex> lock(mLock);
Jan Sebechlebskyb0d8cab2023-11-28 10:55:04 +0100286 if (mRenderThread != nullptr) {
287 mRenderThread->flush();
288 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100289 return ndk::ScopedAStatus::ok();
290}
291
292ndk::ScopedAStatus VirtualCameraSession::getCaptureRequestMetadataQueue(
293 MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) {
294 ALOGV("%s", __func__);
295 *_aidl_return = mRequestMetadataQueue->dupeDesc();
296 return ndk::ScopedAStatus::ok();
297}
298
299ndk::ScopedAStatus VirtualCameraSession::getCaptureResultMetadataQueue(
300 MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) {
301 ALOGV("%s", __func__);
302 *_aidl_return = mResultMetadataQueue->dupeDesc();
303 return ndk::ScopedAStatus::ok();
304}
305
306ndk::ScopedAStatus VirtualCameraSession::isReconfigurationRequired(
307 const CameraMetadata& in_oldSessionParams,
308 const CameraMetadata& in_newSessionParams, bool* _aidl_return) {
309 ALOGV("%s: oldSessionParams: %s newSessionParams: %s", __func__,
310 in_newSessionParams.toString().c_str(),
311 in_oldSessionParams.toString().c_str());
312
313 if (_aidl_return == nullptr) {
314 return ndk::ScopedAStatus::fromServiceSpecificError(
315 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
316 }
317
318 *_aidl_return = true;
319 return ndk::ScopedAStatus::ok();
320}
321
322ndk::ScopedAStatus VirtualCameraSession::processCaptureRequest(
323 const std::vector<CaptureRequest>& in_requests,
324 const std::vector<BufferCache>& in_cachesToRemove, int32_t* _aidl_return) {
325 ALOGV("%s", __func__);
326
327 if (!in_cachesToRemove.empty()) {
328 mSessionContext.removeBufferCaches(in_cachesToRemove);
329 }
330
331 for (const auto& captureRequest : in_requests) {
332 auto status = processCaptureRequest(captureRequest);
333 if (!status.isOk()) {
334 return status;
335 }
336 }
337 *_aidl_return = in_requests.size();
338 return ndk::ScopedAStatus::ok();
339}
340
341ndk::ScopedAStatus VirtualCameraSession::signalStreamFlush(
342 const std::vector<int32_t>& in_streamIds, int32_t in_streamConfigCounter) {
343 ALOGV("%s", __func__);
344
345 (void)in_streamIds;
346 (void)in_streamConfigCounter;
347 return ndk::ScopedAStatus::ok();
348}
349
350ndk::ScopedAStatus VirtualCameraSession::switchToOffline(
351 const std::vector<int32_t>& in_streamsToKeep,
352 CameraOfflineSessionInfo* out_offlineSessionInfo,
353 std::shared_ptr<ICameraOfflineSession>* _aidl_return) {
354 ALOGV("%s", __func__);
355
356 (void)in_streamsToKeep;
357 (void)out_offlineSessionInfo;
358
359 if (_aidl_return == nullptr) {
360 return ndk::ScopedAStatus::fromServiceSpecificError(
361 static_cast<int32_t>(Status::ILLEGAL_ARGUMENT));
362 }
363
364 *_aidl_return = nullptr;
365 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
366}
367
368ndk::ScopedAStatus VirtualCameraSession::repeatingRequestEnd(
369 int32_t in_frameNumber, const std::vector<int32_t>& in_streamIds) {
370 ALOGV("%s", __func__);
371 (void)in_frameNumber;
372 (void)in_streamIds;
373 return ndk::ScopedAStatus::ok();
374}
375
376std::set<int> VirtualCameraSession::getStreamIds() const {
377 return mSessionContext.getStreamIds();
378}
379
380ndk::ScopedAStatus VirtualCameraSession::processCaptureRequest(
381 const CaptureRequest& request) {
382 ALOGD("%s: request: %s", __func__, request.toString().c_str());
383
384 if (mFirstRequest.exchange(false) && request.settings.metadata.empty()) {
385 return cameraStatus(Status::ILLEGAL_ARGUMENT);
386 }
387
388 std::shared_ptr<ICameraDeviceCallback> cameraCallback = nullptr;
389 {
390 std::lock_guard<std::mutex> lock(mLock);
391 cameraCallback = mCameraDeviceCallback;
392 }
393
394 if (cameraCallback == nullptr) {
395 ALOGE(
396 "%s: processCaptureRequest called, but there's no camera callback "
397 "configured",
398 __func__);
399 return cameraStatus(Status::INTERNAL_ERROR);
400 }
401
402 if (!mSessionContext.importBuffersFromCaptureRequest(request)) {
403 ALOGE("Failed to import buffers from capture request.");
404 return cameraStatus(Status::INTERNAL_ERROR);
405 }
406
407 std::vector<CaptureRequestBuffer> taskBuffers;
408 taskBuffers.reserve(request.outputBuffers.size());
409 for (const StreamBuffer& streamBuffer : request.outputBuffers) {
410 taskBuffers.emplace_back(streamBuffer.streamId, streamBuffer.bufferId,
411 importFence(streamBuffer.acquireFence));
412 }
413
414 {
415 std::lock_guard<std::mutex> lock(mLock);
416 if (mRenderThread == nullptr) {
417 ALOGE(
418 "%s: processCaptureRequest (frameNumber %d)called before configure "
419 "(render thread not initialized)",
420 __func__, request.frameNumber);
421 return cameraStatus(Status::INTERNAL_ERROR);
422 }
423 mRenderThread->enqueueTask(std::make_unique<ProcessCaptureRequestTask>(
424 request.frameNumber, taskBuffers));
425 }
426
427 if (mVirtualCameraClientCallback != nullptr) {
428 auto status = mVirtualCameraClientCallback->onProcessCaptureRequest(
429 /*streamId=*/0, request.frameNumber);
430 if (!status.isOk()) {
431 ALOGE(
432 "Failed to invoke onProcessCaptureRequest client callback for frame "
433 "%d",
434 request.frameNumber);
435 }
436 }
437
438 return ndk::ScopedAStatus::ok();
439}
440
441} // namespace virtualcamera
442} // namespace companion
443} // namespace android