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