xref: /aosp_15_r20/frameworks/av/services/camera/virtualcamera/VirtualCameraRenderThread.cc (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker  * Copyright (C) 2023 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker  *
4*ec779b8eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker  *
8*ec779b8eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker  *
10*ec779b8eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker  * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker  */
16*ec779b8eSAndroid Build Coastguard Worker 
17*ec779b8eSAndroid Build Coastguard Worker // #define LOG_NDEBUG 0
18*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "VirtualCameraRenderThread"
19*ec779b8eSAndroid Build Coastguard Worker #include "VirtualCameraRenderThread.h"
20*ec779b8eSAndroid Build Coastguard Worker 
21*ec779b8eSAndroid Build Coastguard Worker #include <android_companion_virtualdevice_flags.h>
22*ec779b8eSAndroid Build Coastguard Worker 
23*ec779b8eSAndroid Build Coastguard Worker #include <chrono>
24*ec779b8eSAndroid Build Coastguard Worker #include <cstdint>
25*ec779b8eSAndroid Build Coastguard Worker #include <cstring>
26*ec779b8eSAndroid Build Coastguard Worker #include <future>
27*ec779b8eSAndroid Build Coastguard Worker #include <memory>
28*ec779b8eSAndroid Build Coastguard Worker #include <mutex>
29*ec779b8eSAndroid Build Coastguard Worker #include <thread>
30*ec779b8eSAndroid Build Coastguard Worker #include <utility>
31*ec779b8eSAndroid Build Coastguard Worker #include <vector>
32*ec779b8eSAndroid Build Coastguard Worker 
33*ec779b8eSAndroid Build Coastguard Worker #include "Exif.h"
34*ec779b8eSAndroid Build Coastguard Worker #include "GLES/gl.h"
35*ec779b8eSAndroid Build Coastguard Worker #include "VirtualCameraCaptureResult.h"
36*ec779b8eSAndroid Build Coastguard Worker #include "VirtualCameraDevice.h"
37*ec779b8eSAndroid Build Coastguard Worker #include "VirtualCameraSessionContext.h"
38*ec779b8eSAndroid Build Coastguard Worker #include "aidl/android/hardware/camera/common/Status.h"
39*ec779b8eSAndroid Build Coastguard Worker #include "aidl/android/hardware/camera/device/BufferStatus.h"
40*ec779b8eSAndroid Build Coastguard Worker #include "aidl/android/hardware/camera/device/CameraBlob.h"
41*ec779b8eSAndroid Build Coastguard Worker #include "aidl/android/hardware/camera/device/CameraBlobId.h"
42*ec779b8eSAndroid Build Coastguard Worker #include "aidl/android/hardware/camera/device/CameraMetadata.h"
43*ec779b8eSAndroid Build Coastguard Worker #include "aidl/android/hardware/camera/device/CaptureResult.h"
44*ec779b8eSAndroid Build Coastguard Worker #include "aidl/android/hardware/camera/device/ErrorCode.h"
45*ec779b8eSAndroid Build Coastguard Worker #include "aidl/android/hardware/camera/device/ICameraDeviceCallback.h"
46*ec779b8eSAndroid Build Coastguard Worker #include "aidl/android/hardware/camera/device/NotifyMsg.h"
47*ec779b8eSAndroid Build Coastguard Worker #include "aidl/android/hardware/camera/device/ShutterMsg.h"
48*ec779b8eSAndroid Build Coastguard Worker #include "aidl/android/hardware/camera/device/StreamBuffer.h"
49*ec779b8eSAndroid Build Coastguard Worker #include "android-base/thread_annotations.h"
50*ec779b8eSAndroid Build Coastguard Worker #include "android/binder_auto_utils.h"
51*ec779b8eSAndroid Build Coastguard Worker #include "android/hardware_buffer.h"
52*ec779b8eSAndroid Build Coastguard Worker #include "system/camera_metadata.h"
53*ec779b8eSAndroid Build Coastguard Worker #include "ui/GraphicBuffer.h"
54*ec779b8eSAndroid Build Coastguard Worker #include "ui/Rect.h"
55*ec779b8eSAndroid Build Coastguard Worker #include "util/EglFramebuffer.h"
56*ec779b8eSAndroid Build Coastguard Worker #include "util/JpegUtil.h"
57*ec779b8eSAndroid Build Coastguard Worker #include "util/Util.h"
58*ec779b8eSAndroid Build Coastguard Worker #include "utils/Errors.h"
59*ec779b8eSAndroid Build Coastguard Worker 
60*ec779b8eSAndroid Build Coastguard Worker namespace android {
61*ec779b8eSAndroid Build Coastguard Worker namespace companion {
62*ec779b8eSAndroid Build Coastguard Worker namespace virtualcamera {
63*ec779b8eSAndroid Build Coastguard Worker 
64*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::hardware::camera::common::Status;
65*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::hardware::camera::device::BufferStatus;
66*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::hardware::camera::device::CameraBlob;
67*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::hardware::camera::device::CameraBlobId;
68*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::hardware::camera::device::CameraMetadata;
69*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::hardware::camera::device::CaptureResult;
70*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::hardware::camera::device::ErrorCode;
71*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::hardware::camera::device::ErrorMsg;
72*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::hardware::camera::device::ICameraDeviceCallback;
73*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::hardware::camera::device::NotifyMsg;
74*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::hardware::camera::device::ShutterMsg;
75*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::hardware::camera::device::Stream;
76*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::hardware::camera::device::StreamBuffer;
77*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::hardware::graphics::common::PixelFormat;
78*ec779b8eSAndroid Build Coastguard Worker using ::android::base::ScopedLockAssertion;
79*ec779b8eSAndroid Build Coastguard Worker 
80*ec779b8eSAndroid Build Coastguard Worker using ::android::hardware::camera::common::helper::ExifUtils;
81*ec779b8eSAndroid Build Coastguard Worker 
82*ec779b8eSAndroid Build Coastguard Worker namespace {
83*ec779b8eSAndroid Build Coastguard Worker 
84*ec779b8eSAndroid Build Coastguard Worker // helper type for the visitor
85*ec779b8eSAndroid Build Coastguard Worker template <class... Ts>
86*ec779b8eSAndroid Build Coastguard Worker struct overloaded : Ts... {
87*ec779b8eSAndroid Build Coastguard Worker   using Ts::operator()...;
88*ec779b8eSAndroid Build Coastguard Worker };
89*ec779b8eSAndroid Build Coastguard Worker // explicit deduction guide (not needed as of C++20)
90*ec779b8eSAndroid Build Coastguard Worker template <class... Ts>
91*ec779b8eSAndroid Build Coastguard Worker overloaded(Ts...) -> overloaded<Ts...>;
92*ec779b8eSAndroid Build Coastguard Worker 
93*ec779b8eSAndroid Build Coastguard Worker using namespace std::chrono_literals;
94*ec779b8eSAndroid Build Coastguard Worker 
95*ec779b8eSAndroid Build Coastguard Worker namespace flags = ::android::companion::virtualdevice::flags;
96*ec779b8eSAndroid Build Coastguard Worker 
97*ec779b8eSAndroid Build Coastguard Worker static constexpr std::chrono::milliseconds kAcquireFenceTimeout = 500ms;
98*ec779b8eSAndroid Build Coastguard Worker 
99*ec779b8eSAndroid Build Coastguard Worker static constexpr size_t kJpegThumbnailBufferSize = 32 * 1024;  // 32 KiB
100*ec779b8eSAndroid Build Coastguard Worker 
101*ec779b8eSAndroid Build Coastguard Worker static constexpr UpdateTextureTask kUpdateTextureTask;
102*ec779b8eSAndroid Build Coastguard Worker 
103*ec779b8eSAndroid Build Coastguard Worker // The number of nanosecond to wait for the first frame to be drawn on the input surface
104*ec779b8eSAndroid Build Coastguard Worker static constexpr std::chrono::nanoseconds kMaxWaitFirstFrame = 3s;
105*ec779b8eSAndroid Build Coastguard Worker 
createShutterNotifyMsg(int frameNumber,std::chrono::nanoseconds timestamp)106*ec779b8eSAndroid Build Coastguard Worker NotifyMsg createShutterNotifyMsg(int frameNumber,
107*ec779b8eSAndroid Build Coastguard Worker                                  std::chrono::nanoseconds timestamp) {
108*ec779b8eSAndroid Build Coastguard Worker   NotifyMsg msg;
109*ec779b8eSAndroid Build Coastguard Worker   msg.set<NotifyMsg::Tag::shutter>(ShutterMsg{
110*ec779b8eSAndroid Build Coastguard Worker       .frameNumber = frameNumber,
111*ec779b8eSAndroid Build Coastguard Worker       .timestamp = timestamp.count(),
112*ec779b8eSAndroid Build Coastguard Worker   });
113*ec779b8eSAndroid Build Coastguard Worker   return msg;
114*ec779b8eSAndroid Build Coastguard Worker }
115*ec779b8eSAndroid Build Coastguard Worker 
116*ec779b8eSAndroid Build Coastguard Worker // Create a NotifyMsg for an error case. The default error is ERROR_BUFFER.
createErrorNotifyMsg(int frameNumber,int streamId,ErrorCode errorCode=ErrorCode::ERROR_BUFFER)117*ec779b8eSAndroid Build Coastguard Worker NotifyMsg createErrorNotifyMsg(int frameNumber, int streamId,
118*ec779b8eSAndroid Build Coastguard Worker                                ErrorCode errorCode = ErrorCode::ERROR_BUFFER) {
119*ec779b8eSAndroid Build Coastguard Worker   NotifyMsg msg;
120*ec779b8eSAndroid Build Coastguard Worker   msg.set<NotifyMsg::Tag::error>(ErrorMsg{.frameNumber = frameNumber,
121*ec779b8eSAndroid Build Coastguard Worker                                           .errorStreamId = streamId,
122*ec779b8eSAndroid Build Coastguard Worker                                           .errorCode = errorCode});
123*ec779b8eSAndroid Build Coastguard Worker   return msg;
124*ec779b8eSAndroid Build Coastguard Worker }
125*ec779b8eSAndroid Build Coastguard Worker 
createRequestErrorNotifyMsg(int frameNumber)126*ec779b8eSAndroid Build Coastguard Worker NotifyMsg createRequestErrorNotifyMsg(int frameNumber) {
127*ec779b8eSAndroid Build Coastguard Worker   NotifyMsg msg;
128*ec779b8eSAndroid Build Coastguard Worker   msg.set<NotifyMsg::Tag::error>(
129*ec779b8eSAndroid Build Coastguard Worker       ErrorMsg{.frameNumber = frameNumber,
130*ec779b8eSAndroid Build Coastguard Worker                // errorStreamId needs to be set to -1 for ERROR_REQUEST
131*ec779b8eSAndroid Build Coastguard Worker                // (not tied to specific stream).
132*ec779b8eSAndroid Build Coastguard Worker                .errorStreamId = -1,
133*ec779b8eSAndroid Build Coastguard Worker                .errorCode = ErrorCode::ERROR_REQUEST});
134*ec779b8eSAndroid Build Coastguard Worker   return msg;
135*ec779b8eSAndroid Build Coastguard Worker }
136*ec779b8eSAndroid Build Coastguard Worker 
allocateTemporaryFramebuffer(EGLDisplay eglDisplay,const uint width,const int height)137*ec779b8eSAndroid Build Coastguard Worker std::shared_ptr<EglFrameBuffer> allocateTemporaryFramebuffer(
138*ec779b8eSAndroid Build Coastguard Worker     EGLDisplay eglDisplay, const uint width, const int height) {
139*ec779b8eSAndroid Build Coastguard Worker   const AHardwareBuffer_Desc desc{
140*ec779b8eSAndroid Build Coastguard Worker       .width = static_cast<uint32_t>(width),
141*ec779b8eSAndroid Build Coastguard Worker       .height = static_cast<uint32_t>(height),
142*ec779b8eSAndroid Build Coastguard Worker       .layers = 1,
143*ec779b8eSAndroid Build Coastguard Worker       .format = AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420,
144*ec779b8eSAndroid Build Coastguard Worker       .usage = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER |
145*ec779b8eSAndroid Build Coastguard Worker                AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
146*ec779b8eSAndroid Build Coastguard Worker       .rfu0 = 0,
147*ec779b8eSAndroid Build Coastguard Worker       .rfu1 = 0};
148*ec779b8eSAndroid Build Coastguard Worker 
149*ec779b8eSAndroid Build Coastguard Worker   AHardwareBuffer* hwBufferPtr;
150*ec779b8eSAndroid Build Coastguard Worker   int status = AHardwareBuffer_allocate(&desc, &hwBufferPtr);
151*ec779b8eSAndroid Build Coastguard Worker   if (status != NO_ERROR) {
152*ec779b8eSAndroid Build Coastguard Worker     ALOGE(
153*ec779b8eSAndroid Build Coastguard Worker         "%s: Failed to allocate hardware buffer for temporary framebuffer: %d",
154*ec779b8eSAndroid Build Coastguard Worker         __func__, status);
155*ec779b8eSAndroid Build Coastguard Worker     return nullptr;
156*ec779b8eSAndroid Build Coastguard Worker   }
157*ec779b8eSAndroid Build Coastguard Worker 
158*ec779b8eSAndroid Build Coastguard Worker   return std::make_shared<EglFrameBuffer>(
159*ec779b8eSAndroid Build Coastguard Worker       eglDisplay,
160*ec779b8eSAndroid Build Coastguard Worker       std::shared_ptr<AHardwareBuffer>(hwBufferPtr, AHardwareBuffer_release));
161*ec779b8eSAndroid Build Coastguard Worker }
162*ec779b8eSAndroid Build Coastguard Worker 
isYuvFormat(const PixelFormat pixelFormat)163*ec779b8eSAndroid Build Coastguard Worker bool isYuvFormat(const PixelFormat pixelFormat) {
164*ec779b8eSAndroid Build Coastguard Worker   switch (static_cast<android_pixel_format_t>(pixelFormat)) {
165*ec779b8eSAndroid Build Coastguard Worker     case HAL_PIXEL_FORMAT_YCBCR_422_I:
166*ec779b8eSAndroid Build Coastguard Worker     case HAL_PIXEL_FORMAT_YCBCR_422_SP:
167*ec779b8eSAndroid Build Coastguard Worker     case HAL_PIXEL_FORMAT_Y16:
168*ec779b8eSAndroid Build Coastguard Worker     case HAL_PIXEL_FORMAT_YV12:
169*ec779b8eSAndroid Build Coastguard Worker     case HAL_PIXEL_FORMAT_YCBCR_420_888:
170*ec779b8eSAndroid Build Coastguard Worker       return true;
171*ec779b8eSAndroid Build Coastguard Worker     default:
172*ec779b8eSAndroid Build Coastguard Worker       return false;
173*ec779b8eSAndroid Build Coastguard Worker   }
174*ec779b8eSAndroid Build Coastguard Worker }
175*ec779b8eSAndroid Build Coastguard Worker 
createExif(Resolution imageSize,const CameraMetadata resultMetadata,const std::vector<uint8_t> & compressedThumbnail={})176*ec779b8eSAndroid Build Coastguard Worker std::vector<uint8_t> createExif(
177*ec779b8eSAndroid Build Coastguard Worker     Resolution imageSize, const CameraMetadata resultMetadata,
178*ec779b8eSAndroid Build Coastguard Worker     const std::vector<uint8_t>& compressedThumbnail = {}) {
179*ec779b8eSAndroid Build Coastguard Worker   std::unique_ptr<ExifUtils> exifUtils(ExifUtils::create());
180*ec779b8eSAndroid Build Coastguard Worker   exifUtils->initialize();
181*ec779b8eSAndroid Build Coastguard Worker 
182*ec779b8eSAndroid Build Coastguard Worker   // Make a copy of the metadata in order to converting it the HAL metadata
183*ec779b8eSAndroid Build Coastguard Worker   // format (as opposed to the AIDL class) and use the setFromMetadata method
184*ec779b8eSAndroid Build Coastguard Worker   // from ExifUtil
185*ec779b8eSAndroid Build Coastguard Worker   camera_metadata_t* rawSettings =
186*ec779b8eSAndroid Build Coastguard Worker       clone_camera_metadata((camera_metadata_t*)resultMetadata.metadata.data());
187*ec779b8eSAndroid Build Coastguard Worker   if (rawSettings != nullptr) {
188*ec779b8eSAndroid Build Coastguard Worker     android::hardware::camera::common::helper::CameraMetadata halMetadata(
189*ec779b8eSAndroid Build Coastguard Worker         rawSettings);
190*ec779b8eSAndroid Build Coastguard Worker     exifUtils->setFromMetadata(halMetadata, imageSize.width, imageSize.height);
191*ec779b8eSAndroid Build Coastguard Worker   }
192*ec779b8eSAndroid Build Coastguard Worker   exifUtils->setMake(VirtualCameraDevice::kDefaultMakeAndModel);
193*ec779b8eSAndroid Build Coastguard Worker   exifUtils->setModel(VirtualCameraDevice::kDefaultMakeAndModel);
194*ec779b8eSAndroid Build Coastguard Worker   exifUtils->setFlash(0);
195*ec779b8eSAndroid Build Coastguard Worker 
196*ec779b8eSAndroid Build Coastguard Worker   std::vector<uint8_t> app1Data;
197*ec779b8eSAndroid Build Coastguard Worker 
198*ec779b8eSAndroid Build Coastguard Worker   size_t thumbnailDataSize = compressedThumbnail.size();
199*ec779b8eSAndroid Build Coastguard Worker   const void* thumbnailData =
200*ec779b8eSAndroid Build Coastguard Worker       thumbnailDataSize > 0
201*ec779b8eSAndroid Build Coastguard Worker           ? reinterpret_cast<const void*>(compressedThumbnail.data())
202*ec779b8eSAndroid Build Coastguard Worker           : nullptr;
203*ec779b8eSAndroid Build Coastguard Worker 
204*ec779b8eSAndroid Build Coastguard Worker   if (!exifUtils->generateApp1(thumbnailData, thumbnailDataSize)) {
205*ec779b8eSAndroid Build Coastguard Worker     ALOGE("%s: Failed to generate APP1 segment for EXIF metadata", __func__);
206*ec779b8eSAndroid Build Coastguard Worker     return app1Data;
207*ec779b8eSAndroid Build Coastguard Worker   }
208*ec779b8eSAndroid Build Coastguard Worker 
209*ec779b8eSAndroid Build Coastguard Worker   const uint8_t* data = exifUtils->getApp1Buffer();
210*ec779b8eSAndroid Build Coastguard Worker   const size_t size = exifUtils->getApp1Length();
211*ec779b8eSAndroid Build Coastguard Worker 
212*ec779b8eSAndroid Build Coastguard Worker   app1Data.insert(app1Data.end(), data, data + size);
213*ec779b8eSAndroid Build Coastguard Worker   return app1Data;
214*ec779b8eSAndroid Build Coastguard Worker }
215*ec779b8eSAndroid Build Coastguard Worker 
getMaxFrameDuration(const RequestSettings & requestSettings)216*ec779b8eSAndroid Build Coastguard Worker std::chrono::nanoseconds getMaxFrameDuration(
217*ec779b8eSAndroid Build Coastguard Worker     const RequestSettings& requestSettings) {
218*ec779b8eSAndroid Build Coastguard Worker   if (requestSettings.fpsRange.has_value()) {
219*ec779b8eSAndroid Build Coastguard Worker     return std::chrono::nanoseconds(static_cast<uint64_t>(
220*ec779b8eSAndroid Build Coastguard Worker         1e9 / std::max(1, requestSettings.fpsRange->minFps)));
221*ec779b8eSAndroid Build Coastguard Worker   }
222*ec779b8eSAndroid Build Coastguard Worker   return std::chrono::nanoseconds(
223*ec779b8eSAndroid Build Coastguard Worker       static_cast<uint64_t>(1e9 / VirtualCameraDevice::kMinFps));
224*ec779b8eSAndroid Build Coastguard Worker }
225*ec779b8eSAndroid Build Coastguard Worker 
226*ec779b8eSAndroid Build Coastguard Worker }  // namespace
227*ec779b8eSAndroid Build Coastguard Worker 
CaptureRequestBuffer(int streamId,int bufferId,sp<Fence> fence)228*ec779b8eSAndroid Build Coastguard Worker CaptureRequestBuffer::CaptureRequestBuffer(int streamId, int bufferId,
229*ec779b8eSAndroid Build Coastguard Worker                                            sp<Fence> fence)
230*ec779b8eSAndroid Build Coastguard Worker     : mStreamId(streamId), mBufferId(bufferId), mFence(fence) {
231*ec779b8eSAndroid Build Coastguard Worker }
232*ec779b8eSAndroid Build Coastguard Worker 
getStreamId() const233*ec779b8eSAndroid Build Coastguard Worker int CaptureRequestBuffer::getStreamId() const {
234*ec779b8eSAndroid Build Coastguard Worker   return mStreamId;
235*ec779b8eSAndroid Build Coastguard Worker }
236*ec779b8eSAndroid Build Coastguard Worker 
getBufferId() const237*ec779b8eSAndroid Build Coastguard Worker int CaptureRequestBuffer::getBufferId() const {
238*ec779b8eSAndroid Build Coastguard Worker   return mBufferId;
239*ec779b8eSAndroid Build Coastguard Worker }
240*ec779b8eSAndroid Build Coastguard Worker 
getFence() const241*ec779b8eSAndroid Build Coastguard Worker sp<Fence> CaptureRequestBuffer::getFence() const {
242*ec779b8eSAndroid Build Coastguard Worker   return mFence;
243*ec779b8eSAndroid Build Coastguard Worker }
244*ec779b8eSAndroid Build Coastguard Worker 
VirtualCameraRenderThread(VirtualCameraSessionContext & sessionContext,const Resolution inputSurfaceSize,const Resolution reportedSensorSize,std::shared_ptr<ICameraDeviceCallback> cameraDeviceCallback)245*ec779b8eSAndroid Build Coastguard Worker VirtualCameraRenderThread::VirtualCameraRenderThread(
246*ec779b8eSAndroid Build Coastguard Worker     VirtualCameraSessionContext& sessionContext,
247*ec779b8eSAndroid Build Coastguard Worker     const Resolution inputSurfaceSize, const Resolution reportedSensorSize,
248*ec779b8eSAndroid Build Coastguard Worker     std::shared_ptr<ICameraDeviceCallback> cameraDeviceCallback)
249*ec779b8eSAndroid Build Coastguard Worker     : mCameraDeviceCallback(cameraDeviceCallback),
250*ec779b8eSAndroid Build Coastguard Worker       mInputSurfaceSize(inputSurfaceSize),
251*ec779b8eSAndroid Build Coastguard Worker       mReportedSensorSize(reportedSensorSize),
252*ec779b8eSAndroid Build Coastguard Worker       mSessionContext(sessionContext),
253*ec779b8eSAndroid Build Coastguard Worker       mInputSurfaceFuture(mInputSurfacePromise.get_future()) {
254*ec779b8eSAndroid Build Coastguard Worker }
255*ec779b8eSAndroid Build Coastguard Worker 
~VirtualCameraRenderThread()256*ec779b8eSAndroid Build Coastguard Worker VirtualCameraRenderThread::~VirtualCameraRenderThread() {
257*ec779b8eSAndroid Build Coastguard Worker   stop();
258*ec779b8eSAndroid Build Coastguard Worker   if (mThread.joinable()) {
259*ec779b8eSAndroid Build Coastguard Worker     mThread.join();
260*ec779b8eSAndroid Build Coastguard Worker   }
261*ec779b8eSAndroid Build Coastguard Worker }
262*ec779b8eSAndroid Build Coastguard Worker 
ProcessCaptureRequestTask(int frameNumber,const std::vector<CaptureRequestBuffer> & requestBuffers,const RequestSettings & requestSettings)263*ec779b8eSAndroid Build Coastguard Worker ProcessCaptureRequestTask::ProcessCaptureRequestTask(
264*ec779b8eSAndroid Build Coastguard Worker     int frameNumber, const std::vector<CaptureRequestBuffer>& requestBuffers,
265*ec779b8eSAndroid Build Coastguard Worker     const RequestSettings& requestSettings)
266*ec779b8eSAndroid Build Coastguard Worker     : mFrameNumber(frameNumber),
267*ec779b8eSAndroid Build Coastguard Worker       mBuffers(requestBuffers),
268*ec779b8eSAndroid Build Coastguard Worker       mRequestSettings(requestSettings) {
269*ec779b8eSAndroid Build Coastguard Worker }
270*ec779b8eSAndroid Build Coastguard Worker 
getFrameNumber() const271*ec779b8eSAndroid Build Coastguard Worker int ProcessCaptureRequestTask::getFrameNumber() const {
272*ec779b8eSAndroid Build Coastguard Worker   return mFrameNumber;
273*ec779b8eSAndroid Build Coastguard Worker }
274*ec779b8eSAndroid Build Coastguard Worker 
getBuffers() const275*ec779b8eSAndroid Build Coastguard Worker const std::vector<CaptureRequestBuffer>& ProcessCaptureRequestTask::getBuffers()
276*ec779b8eSAndroid Build Coastguard Worker     const {
277*ec779b8eSAndroid Build Coastguard Worker   return mBuffers;
278*ec779b8eSAndroid Build Coastguard Worker }
279*ec779b8eSAndroid Build Coastguard Worker 
getRequestSettings() const280*ec779b8eSAndroid Build Coastguard Worker const RequestSettings& ProcessCaptureRequestTask::getRequestSettings() const {
281*ec779b8eSAndroid Build Coastguard Worker   return mRequestSettings;
282*ec779b8eSAndroid Build Coastguard Worker }
283*ec779b8eSAndroid Build Coastguard Worker 
requestTextureUpdate()284*ec779b8eSAndroid Build Coastguard Worker void VirtualCameraRenderThread::requestTextureUpdate() {
285*ec779b8eSAndroid Build Coastguard Worker   std::lock_guard<std::mutex> lock(mLock);
286*ec779b8eSAndroid Build Coastguard Worker   // If queue is not empty, we don't need to set the mTextureUpdateRequested
287*ec779b8eSAndroid Build Coastguard Worker   // flag, since the texture will be updated during ProcessCaptureRequestTask
288*ec779b8eSAndroid Build Coastguard Worker   // processing anyway.
289*ec779b8eSAndroid Build Coastguard Worker   if (mQueue.empty()) {
290*ec779b8eSAndroid Build Coastguard Worker     mTextureUpdateRequested = true;
291*ec779b8eSAndroid Build Coastguard Worker     mCondVar.notify_one();
292*ec779b8eSAndroid Build Coastguard Worker   }
293*ec779b8eSAndroid Build Coastguard Worker }
294*ec779b8eSAndroid Build Coastguard Worker 
enqueueTask(std::unique_ptr<ProcessCaptureRequestTask> task)295*ec779b8eSAndroid Build Coastguard Worker void VirtualCameraRenderThread::enqueueTask(
296*ec779b8eSAndroid Build Coastguard Worker     std::unique_ptr<ProcessCaptureRequestTask> task) {
297*ec779b8eSAndroid Build Coastguard Worker   std::lock_guard<std::mutex> lock(mLock);
298*ec779b8eSAndroid Build Coastguard Worker   // When enqueving process capture request task, clear the
299*ec779b8eSAndroid Build Coastguard Worker   // mTextureUpdateRequested flag. If this flag is set, the texture was not yet
300*ec779b8eSAndroid Build Coastguard Worker   // updated and it will be updated when processing ProcessCaptureRequestTask
301*ec779b8eSAndroid Build Coastguard Worker   // anyway.
302*ec779b8eSAndroid Build Coastguard Worker   mTextureUpdateRequested = false;
303*ec779b8eSAndroid Build Coastguard Worker   mQueue.emplace_back(std::move(task));
304*ec779b8eSAndroid Build Coastguard Worker   mCondVar.notify_one();
305*ec779b8eSAndroid Build Coastguard Worker }
306*ec779b8eSAndroid Build Coastguard Worker 
flush()307*ec779b8eSAndroid Build Coastguard Worker void VirtualCameraRenderThread::flush() {
308*ec779b8eSAndroid Build Coastguard Worker   std::lock_guard<std::mutex> lock(mLock);
309*ec779b8eSAndroid Build Coastguard Worker   while (!mQueue.empty()) {
310*ec779b8eSAndroid Build Coastguard Worker     std::unique_ptr<ProcessCaptureRequestTask> task = std::move(mQueue.front());
311*ec779b8eSAndroid Build Coastguard Worker     mQueue.pop_front();
312*ec779b8eSAndroid Build Coastguard Worker     flushCaptureRequest(*task);
313*ec779b8eSAndroid Build Coastguard Worker   }
314*ec779b8eSAndroid Build Coastguard Worker }
315*ec779b8eSAndroid Build Coastguard Worker 
start()316*ec779b8eSAndroid Build Coastguard Worker void VirtualCameraRenderThread::start() {
317*ec779b8eSAndroid Build Coastguard Worker   mThread = std::thread(&VirtualCameraRenderThread::threadLoop, this);
318*ec779b8eSAndroid Build Coastguard Worker }
319*ec779b8eSAndroid Build Coastguard Worker 
stop()320*ec779b8eSAndroid Build Coastguard Worker void VirtualCameraRenderThread::stop() {
321*ec779b8eSAndroid Build Coastguard Worker   {
322*ec779b8eSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mLock);
323*ec779b8eSAndroid Build Coastguard Worker     mPendingExit = true;
324*ec779b8eSAndroid Build Coastguard Worker     mCondVar.notify_one();
325*ec779b8eSAndroid Build Coastguard Worker   }
326*ec779b8eSAndroid Build Coastguard Worker }
327*ec779b8eSAndroid Build Coastguard Worker 
getInputSurface()328*ec779b8eSAndroid Build Coastguard Worker sp<Surface> VirtualCameraRenderThread::getInputSurface() {
329*ec779b8eSAndroid Build Coastguard Worker   return mInputSurfaceFuture.get();
330*ec779b8eSAndroid Build Coastguard Worker }
331*ec779b8eSAndroid Build Coastguard Worker 
dequeueTask()332*ec779b8eSAndroid Build Coastguard Worker RenderThreadTask VirtualCameraRenderThread::dequeueTask() {
333*ec779b8eSAndroid Build Coastguard Worker   std::unique_lock<std::mutex> lock(mLock);
334*ec779b8eSAndroid Build Coastguard Worker   // Clang's thread safety analysis doesn't perform alias analysis,
335*ec779b8eSAndroid Build Coastguard Worker   // so it doesn't support moveable std::unique_lock.
336*ec779b8eSAndroid Build Coastguard Worker   //
337*ec779b8eSAndroid Build Coastguard Worker   // Lock assertion below is basically explicit declaration that
338*ec779b8eSAndroid Build Coastguard Worker   // the lock is held in this scope, which is true, since it's only
339*ec779b8eSAndroid Build Coastguard Worker   // released during waiting inside mCondVar.wait calls.
340*ec779b8eSAndroid Build Coastguard Worker   ScopedLockAssertion lockAssertion(mLock);
341*ec779b8eSAndroid Build Coastguard Worker 
342*ec779b8eSAndroid Build Coastguard Worker   mCondVar.wait(lock, [this]() REQUIRES(mLock) {
343*ec779b8eSAndroid Build Coastguard Worker     return mPendingExit || mTextureUpdateRequested || !mQueue.empty();
344*ec779b8eSAndroid Build Coastguard Worker   });
345*ec779b8eSAndroid Build Coastguard Worker   if (mPendingExit) {
346*ec779b8eSAndroid Build Coastguard Worker     // Render thread task with null task signals render thread to terminate.
347*ec779b8eSAndroid Build Coastguard Worker     return RenderThreadTask(nullptr);
348*ec779b8eSAndroid Build Coastguard Worker   }
349*ec779b8eSAndroid Build Coastguard Worker   if (mTextureUpdateRequested) {
350*ec779b8eSAndroid Build Coastguard Worker     // If mTextureUpdateRequested, it's guaranteed the queue is empty, return
351*ec779b8eSAndroid Build Coastguard Worker     // kUpdateTextureTask to signal we want render thread to update the texture
352*ec779b8eSAndroid Build Coastguard Worker     // (consume buffer from the queue).
353*ec779b8eSAndroid Build Coastguard Worker     mTextureUpdateRequested = false;
354*ec779b8eSAndroid Build Coastguard Worker     return RenderThreadTask(kUpdateTextureTask);
355*ec779b8eSAndroid Build Coastguard Worker   }
356*ec779b8eSAndroid Build Coastguard Worker   RenderThreadTask task(std::move(mQueue.front()));
357*ec779b8eSAndroid Build Coastguard Worker   mQueue.pop_front();
358*ec779b8eSAndroid Build Coastguard Worker   return task;
359*ec779b8eSAndroid Build Coastguard Worker }
360*ec779b8eSAndroid Build Coastguard Worker 
threadLoop()361*ec779b8eSAndroid Build Coastguard Worker void VirtualCameraRenderThread::threadLoop() {
362*ec779b8eSAndroid Build Coastguard Worker   ALOGV("Render thread starting");
363*ec779b8eSAndroid Build Coastguard Worker 
364*ec779b8eSAndroid Build Coastguard Worker   mEglDisplayContext = std::make_unique<EglDisplayContext>();
365*ec779b8eSAndroid Build Coastguard Worker   mEglTextureYuvProgram =
366*ec779b8eSAndroid Build Coastguard Worker       std::make_unique<EglTextureProgram>(EglTextureProgram::TextureFormat::YUV);
367*ec779b8eSAndroid Build Coastguard Worker   mEglTextureRgbProgram = std::make_unique<EglTextureProgram>(
368*ec779b8eSAndroid Build Coastguard Worker       EglTextureProgram::TextureFormat::RGBA);
369*ec779b8eSAndroid Build Coastguard Worker   mEglSurfaceTexture = std::make_unique<EglSurfaceTexture>(
370*ec779b8eSAndroid Build Coastguard Worker       mInputSurfaceSize.width, mInputSurfaceSize.height);
371*ec779b8eSAndroid Build Coastguard Worker   mEglSurfaceTexture->setFrameAvailableListener(
372*ec779b8eSAndroid Build Coastguard Worker       [this]() { requestTextureUpdate(); });
373*ec779b8eSAndroid Build Coastguard Worker 
374*ec779b8eSAndroid Build Coastguard Worker   mInputSurfacePromise.set_value(mEglSurfaceTexture->getSurface());
375*ec779b8eSAndroid Build Coastguard Worker 
376*ec779b8eSAndroid Build Coastguard Worker   while (RenderThreadTask task = dequeueTask()) {
377*ec779b8eSAndroid Build Coastguard Worker     std::visit(
378*ec779b8eSAndroid Build Coastguard Worker         overloaded{[this](const std::unique_ptr<ProcessCaptureRequestTask>& t) {
379*ec779b8eSAndroid Build Coastguard Worker                      processTask(*t);
380*ec779b8eSAndroid Build Coastguard Worker                    },
381*ec779b8eSAndroid Build Coastguard Worker                    [this](const UpdateTextureTask&) {
382*ec779b8eSAndroid Build Coastguard Worker                      ALOGV("Idle update of the texture");
383*ec779b8eSAndroid Build Coastguard Worker                      mEglSurfaceTexture->updateTexture();
384*ec779b8eSAndroid Build Coastguard Worker                    }},
385*ec779b8eSAndroid Build Coastguard Worker         task);
386*ec779b8eSAndroid Build Coastguard Worker   }
387*ec779b8eSAndroid Build Coastguard Worker 
388*ec779b8eSAndroid Build Coastguard Worker   // Destroy EGL utilities still on the render thread.
389*ec779b8eSAndroid Build Coastguard Worker   mEglSurfaceTexture.reset();
390*ec779b8eSAndroid Build Coastguard Worker   mEglTextureRgbProgram.reset();
391*ec779b8eSAndroid Build Coastguard Worker   mEglTextureYuvProgram.reset();
392*ec779b8eSAndroid Build Coastguard Worker   mEglDisplayContext.reset();
393*ec779b8eSAndroid Build Coastguard Worker 
394*ec779b8eSAndroid Build Coastguard Worker   ALOGV("Render thread exiting");
395*ec779b8eSAndroid Build Coastguard Worker }
396*ec779b8eSAndroid Build Coastguard Worker 
processTask(const ProcessCaptureRequestTask & request)397*ec779b8eSAndroid Build Coastguard Worker void VirtualCameraRenderThread::processTask(
398*ec779b8eSAndroid Build Coastguard Worker     const ProcessCaptureRequestTask& request) {
399*ec779b8eSAndroid Build Coastguard Worker   std::chrono::nanoseconds timestamp =
400*ec779b8eSAndroid Build Coastguard Worker       std::chrono::duration_cast<std::chrono::nanoseconds>(
401*ec779b8eSAndroid Build Coastguard Worker           std::chrono::steady_clock::now().time_since_epoch());
402*ec779b8eSAndroid Build Coastguard Worker   const std::chrono::nanoseconds lastAcquisitionTimestamp(
403*ec779b8eSAndroid Build Coastguard Worker       mLastAcquisitionTimestampNanoseconds.exchange(timestamp.count(),
404*ec779b8eSAndroid Build Coastguard Worker                                                     std::memory_order_relaxed));
405*ec779b8eSAndroid Build Coastguard Worker 
406*ec779b8eSAndroid Build Coastguard Worker   if (request.getRequestSettings().fpsRange) {
407*ec779b8eSAndroid Build Coastguard Worker     int maxFps = std::max(1, request.getRequestSettings().fpsRange->maxFps);
408*ec779b8eSAndroid Build Coastguard Worker     timestamp = throttleRendering(maxFps, lastAcquisitionTimestamp, timestamp);
409*ec779b8eSAndroid Build Coastguard Worker   }
410*ec779b8eSAndroid Build Coastguard Worker 
411*ec779b8eSAndroid Build Coastguard Worker   // Calculate the maximal amount of time we can afford to wait for next frame.
412*ec779b8eSAndroid Build Coastguard Worker   const bool isFirstFrameDrawn = mEglSurfaceTexture->isFirstFrameDrawn();
413*ec779b8eSAndroid Build Coastguard Worker   ALOGV("First Frame Drawn: %s", isFirstFrameDrawn ? "Yes" : "No");
414*ec779b8eSAndroid Build Coastguard Worker 
415*ec779b8eSAndroid Build Coastguard Worker   const std::chrono::nanoseconds maxFrameDuration =
416*ec779b8eSAndroid Build Coastguard Worker       isFirstFrameDrawn ? getMaxFrameDuration(request.getRequestSettings())
417*ec779b8eSAndroid Build Coastguard Worker                         : kMaxWaitFirstFrame;
418*ec779b8eSAndroid Build Coastguard Worker   const std::chrono::nanoseconds elapsedDuration =
419*ec779b8eSAndroid Build Coastguard Worker       isFirstFrameDrawn ? timestamp - lastAcquisitionTimestamp : 0ns;
420*ec779b8eSAndroid Build Coastguard Worker 
421*ec779b8eSAndroid Build Coastguard Worker   if (elapsedDuration < maxFrameDuration) {
422*ec779b8eSAndroid Build Coastguard Worker     // We can afford to wait for next frame.
423*ec779b8eSAndroid Build Coastguard Worker     // Note that if there's already new frame in the input Surface, the call
424*ec779b8eSAndroid Build Coastguard Worker     // below returns immediatelly.
425*ec779b8eSAndroid Build Coastguard Worker     bool gotNewFrame = mEglSurfaceTexture->waitForNextFrame(maxFrameDuration -
426*ec779b8eSAndroid Build Coastguard Worker                                                             elapsedDuration);
427*ec779b8eSAndroid Build Coastguard Worker     timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
428*ec779b8eSAndroid Build Coastguard Worker         std::chrono::steady_clock::now().time_since_epoch());
429*ec779b8eSAndroid Build Coastguard Worker     if (!gotNewFrame) {
430*ec779b8eSAndroid Build Coastguard Worker       if (!mEglSurfaceTexture->isFirstFrameDrawn()) {
431*ec779b8eSAndroid Build Coastguard Worker         // We don't have any input ever drawn. This is considered as an error
432*ec779b8eSAndroid Build Coastguard Worker         // case. Notify the framework of the failure and return early.
433*ec779b8eSAndroid Build Coastguard Worker         ALOGW("Timed out waiting for first frame to be drawn.");
434*ec779b8eSAndroid Build Coastguard Worker         std::unique_ptr<CaptureResult> captureResult = createCaptureResult(
435*ec779b8eSAndroid Build Coastguard Worker             request.getFrameNumber(), /* metadata = */ nullptr);
436*ec779b8eSAndroid Build Coastguard Worker         notifyTimeout(request, *captureResult);
437*ec779b8eSAndroid Build Coastguard Worker         submitCaptureResult(std::move(captureResult));
438*ec779b8eSAndroid Build Coastguard Worker         return;
439*ec779b8eSAndroid Build Coastguard Worker       }
440*ec779b8eSAndroid Build Coastguard Worker 
441*ec779b8eSAndroid Build Coastguard Worker       ALOGV(
442*ec779b8eSAndroid Build Coastguard Worker           "%s: No new frame received on input surface after waiting for "
443*ec779b8eSAndroid Build Coastguard Worker           "%" PRIu64 "ns, repeating last frame.",
444*ec779b8eSAndroid Build Coastguard Worker           __func__,
445*ec779b8eSAndroid Build Coastguard Worker           static_cast<uint64_t>((timestamp - lastAcquisitionTimestamp).count()));
446*ec779b8eSAndroid Build Coastguard Worker     }
447*ec779b8eSAndroid Build Coastguard Worker     mLastAcquisitionTimestampNanoseconds.store(timestamp.count(),
448*ec779b8eSAndroid Build Coastguard Worker                                                std::memory_order_relaxed);
449*ec779b8eSAndroid Build Coastguard Worker   }
450*ec779b8eSAndroid Build Coastguard Worker   // Acquire new (most recent) image from the Surface.
451*ec779b8eSAndroid Build Coastguard Worker   mEglSurfaceTexture->updateTexture();
452*ec779b8eSAndroid Build Coastguard Worker   std::chrono::nanoseconds captureTimestamp = timestamp;
453*ec779b8eSAndroid Build Coastguard Worker 
454*ec779b8eSAndroid Build Coastguard Worker   if (flags::camera_timestamp_from_surface()) {
455*ec779b8eSAndroid Build Coastguard Worker     std::chrono::nanoseconds surfaceTimestamp =
456*ec779b8eSAndroid Build Coastguard Worker         getSurfaceTimestamp(elapsedDuration);
457*ec779b8eSAndroid Build Coastguard Worker     if (surfaceTimestamp.count() > 0) {
458*ec779b8eSAndroid Build Coastguard Worker       captureTimestamp = surfaceTimestamp;
459*ec779b8eSAndroid Build Coastguard Worker     }
460*ec779b8eSAndroid Build Coastguard Worker     ALOGV("%s captureTimestamp:%lld timestamp:%lld", __func__,
461*ec779b8eSAndroid Build Coastguard Worker           captureTimestamp.count(), timestamp.count());
462*ec779b8eSAndroid Build Coastguard Worker   }
463*ec779b8eSAndroid Build Coastguard Worker 
464*ec779b8eSAndroid Build Coastguard Worker   std::unique_ptr<CaptureResult> captureResult = createCaptureResult(
465*ec779b8eSAndroid Build Coastguard Worker       request.getFrameNumber(),
466*ec779b8eSAndroid Build Coastguard Worker       createCaptureResultMetadata(
467*ec779b8eSAndroid Build Coastguard Worker           captureTimestamp, request.getRequestSettings(), mReportedSensorSize));
468*ec779b8eSAndroid Build Coastguard Worker   renderOutputBuffers(request, *captureResult);
469*ec779b8eSAndroid Build Coastguard Worker 
470*ec779b8eSAndroid Build Coastguard Worker   auto status = notifyShutter(request, *captureResult, captureTimestamp);
471*ec779b8eSAndroid Build Coastguard Worker   if (!status.isOk()) {
472*ec779b8eSAndroid Build Coastguard Worker     ALOGE("%s: notify call failed: %s", __func__,
473*ec779b8eSAndroid Build Coastguard Worker           status.getDescription().c_str());
474*ec779b8eSAndroid Build Coastguard Worker     return;
475*ec779b8eSAndroid Build Coastguard Worker   }
476*ec779b8eSAndroid Build Coastguard Worker 
477*ec779b8eSAndroid Build Coastguard Worker   submitCaptureResult(std::move(captureResult));
478*ec779b8eSAndroid Build Coastguard Worker }
479*ec779b8eSAndroid Build Coastguard Worker 
throttleRendering(int maxFps,std::chrono::nanoseconds lastAcquisitionTimestamp,std::chrono::nanoseconds timestamp)480*ec779b8eSAndroid Build Coastguard Worker std::chrono::nanoseconds VirtualCameraRenderThread::throttleRendering(
481*ec779b8eSAndroid Build Coastguard Worker     int maxFps, std::chrono::nanoseconds lastAcquisitionTimestamp,
482*ec779b8eSAndroid Build Coastguard Worker     std::chrono::nanoseconds timestamp) {
483*ec779b8eSAndroid Build Coastguard Worker   const std::chrono::nanoseconds minFrameDuration(
484*ec779b8eSAndroid Build Coastguard Worker       static_cast<uint64_t>(1e9 / maxFps));
485*ec779b8eSAndroid Build Coastguard Worker   const std::chrono::nanoseconds frameDuration =
486*ec779b8eSAndroid Build Coastguard Worker       timestamp - lastAcquisitionTimestamp;
487*ec779b8eSAndroid Build Coastguard Worker   if (frameDuration < minFrameDuration) {
488*ec779b8eSAndroid Build Coastguard Worker     // We're too fast for the configured maxFps, let's wait a bit.
489*ec779b8eSAndroid Build Coastguard Worker     const std::chrono::nanoseconds sleepTime = minFrameDuration - frameDuration;
490*ec779b8eSAndroid Build Coastguard Worker     ALOGV("Current frame duration would  be %" PRIu64
491*ec779b8eSAndroid Build Coastguard Worker           " ns corresponding to, "
492*ec779b8eSAndroid Build Coastguard Worker           "sleeping for %" PRIu64
493*ec779b8eSAndroid Build Coastguard Worker           " ns before updating texture to match maxFps %d",
494*ec779b8eSAndroid Build Coastguard Worker           static_cast<uint64_t>(frameDuration.count()),
495*ec779b8eSAndroid Build Coastguard Worker           static_cast<uint64_t>(sleepTime.count()), maxFps);
496*ec779b8eSAndroid Build Coastguard Worker 
497*ec779b8eSAndroid Build Coastguard Worker     std::this_thread::sleep_for(sleepTime);
498*ec779b8eSAndroid Build Coastguard Worker     timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
499*ec779b8eSAndroid Build Coastguard Worker         std::chrono::steady_clock::now().time_since_epoch());
500*ec779b8eSAndroid Build Coastguard Worker     mLastAcquisitionTimestampNanoseconds.store(timestamp.count(),
501*ec779b8eSAndroid Build Coastguard Worker                                                std::memory_order_relaxed);
502*ec779b8eSAndroid Build Coastguard Worker   }
503*ec779b8eSAndroid Build Coastguard Worker   return timestamp;
504*ec779b8eSAndroid Build Coastguard Worker }
505*ec779b8eSAndroid Build Coastguard Worker 
getSurfaceTimestamp(std::chrono::nanoseconds timeSinceLastFrame)506*ec779b8eSAndroid Build Coastguard Worker std::chrono::nanoseconds VirtualCameraRenderThread::getSurfaceTimestamp(
507*ec779b8eSAndroid Build Coastguard Worker     std::chrono::nanoseconds timeSinceLastFrame) {
508*ec779b8eSAndroid Build Coastguard Worker   std::chrono::nanoseconds surfaceTimestamp = mEglSurfaceTexture->getTimestamp();
509*ec779b8eSAndroid Build Coastguard Worker   uint64_t lastSurfaceTimestamp = mLastSurfaceTimestampNanoseconds.load();
510*ec779b8eSAndroid Build Coastguard Worker   if (lastSurfaceTimestamp > 0 &&
511*ec779b8eSAndroid Build Coastguard Worker       surfaceTimestamp.count() <= lastSurfaceTimestamp) {
512*ec779b8eSAndroid Build Coastguard Worker     // The timestamps were provided by the producer but we are
513*ec779b8eSAndroid Build Coastguard Worker     // repeating the last frame, so we increase the previous timestamp by
514*ec779b8eSAndroid Build Coastguard Worker     // the elapsed time sinced its capture, otherwise the camera framework
515*ec779b8eSAndroid Build Coastguard Worker     // will discard the frame.
516*ec779b8eSAndroid Build Coastguard Worker     surfaceTimestamp = std::chrono::nanoseconds(lastSurfaceTimestamp +
517*ec779b8eSAndroid Build Coastguard Worker                                                 timeSinceLastFrame.count());
518*ec779b8eSAndroid Build Coastguard Worker     ALOGI(
519*ec779b8eSAndroid Build Coastguard Worker         "Surface's timestamp is stall. Artificially increasing the surface "
520*ec779b8eSAndroid Build Coastguard Worker         "timestamp by %lld",
521*ec779b8eSAndroid Build Coastguard Worker         timeSinceLastFrame.count());
522*ec779b8eSAndroid Build Coastguard Worker   }
523*ec779b8eSAndroid Build Coastguard Worker   mLastSurfaceTimestampNanoseconds.store(surfaceTimestamp.count(),
524*ec779b8eSAndroid Build Coastguard Worker                                          std::memory_order_relaxed);
525*ec779b8eSAndroid Build Coastguard Worker   return surfaceTimestamp;
526*ec779b8eSAndroid Build Coastguard Worker }
527*ec779b8eSAndroid Build Coastguard Worker 
createCaptureResult(int frameNumber,std::unique_ptr<CameraMetadata> metadata)528*ec779b8eSAndroid Build Coastguard Worker std::unique_ptr<CaptureResult> VirtualCameraRenderThread::createCaptureResult(
529*ec779b8eSAndroid Build Coastguard Worker     int frameNumber, std::unique_ptr<CameraMetadata> metadata) {
530*ec779b8eSAndroid Build Coastguard Worker   std::unique_ptr<CaptureResult> captureResult =
531*ec779b8eSAndroid Build Coastguard Worker       std::make_unique<CaptureResult>();
532*ec779b8eSAndroid Build Coastguard Worker   captureResult->fmqResultSize = 0;
533*ec779b8eSAndroid Build Coastguard Worker   captureResult->frameNumber = frameNumber;
534*ec779b8eSAndroid Build Coastguard Worker   // Partial result needs to be set to 1 when metadata are present.
535*ec779b8eSAndroid Build Coastguard Worker   captureResult->partialResult = 1;
536*ec779b8eSAndroid Build Coastguard Worker   captureResult->inputBuffer.streamId = -1;
537*ec779b8eSAndroid Build Coastguard Worker   captureResult->physicalCameraMetadata.resize(0);
538*ec779b8eSAndroid Build Coastguard Worker   captureResult->result = metadata != nullptr ? *metadata : CameraMetadata();
539*ec779b8eSAndroid Build Coastguard Worker   return captureResult;
540*ec779b8eSAndroid Build Coastguard Worker }
541*ec779b8eSAndroid Build Coastguard Worker 
renderOutputBuffers(const ProcessCaptureRequestTask & request,CaptureResult & captureResult)542*ec779b8eSAndroid Build Coastguard Worker void VirtualCameraRenderThread::renderOutputBuffers(
543*ec779b8eSAndroid Build Coastguard Worker     const ProcessCaptureRequestTask& request, CaptureResult& captureResult) {
544*ec779b8eSAndroid Build Coastguard Worker   const std::vector<CaptureRequestBuffer>& buffers = request.getBuffers();
545*ec779b8eSAndroid Build Coastguard Worker   captureResult.outputBuffers.resize(buffers.size());
546*ec779b8eSAndroid Build Coastguard Worker 
547*ec779b8eSAndroid Build Coastguard Worker   for (int i = 0; i < buffers.size(); ++i) {
548*ec779b8eSAndroid Build Coastguard Worker     const CaptureRequestBuffer& reqBuffer = buffers[i];
549*ec779b8eSAndroid Build Coastguard Worker     StreamBuffer& resBuffer = captureResult.outputBuffers[i];
550*ec779b8eSAndroid Build Coastguard Worker     resBuffer.streamId = reqBuffer.getStreamId();
551*ec779b8eSAndroid Build Coastguard Worker     resBuffer.bufferId = reqBuffer.getBufferId();
552*ec779b8eSAndroid Build Coastguard Worker     resBuffer.status = BufferStatus::OK;
553*ec779b8eSAndroid Build Coastguard Worker 
554*ec779b8eSAndroid Build Coastguard Worker     const std::optional<Stream> streamConfig =
555*ec779b8eSAndroid Build Coastguard Worker         mSessionContext.getStreamConfig(reqBuffer.getStreamId());
556*ec779b8eSAndroid Build Coastguard Worker 
557*ec779b8eSAndroid Build Coastguard Worker     if (!streamConfig.has_value()) {
558*ec779b8eSAndroid Build Coastguard Worker       resBuffer.status = BufferStatus::ERROR;
559*ec779b8eSAndroid Build Coastguard Worker       continue;
560*ec779b8eSAndroid Build Coastguard Worker     }
561*ec779b8eSAndroid Build Coastguard Worker 
562*ec779b8eSAndroid Build Coastguard Worker     auto status = streamConfig->format == PixelFormat::BLOB
563*ec779b8eSAndroid Build Coastguard Worker                       ? renderIntoBlobStreamBuffer(
564*ec779b8eSAndroid Build Coastguard Worker                             reqBuffer.getStreamId(), reqBuffer.getBufferId(),
565*ec779b8eSAndroid Build Coastguard Worker                             captureResult.result, request.getRequestSettings(),
566*ec779b8eSAndroid Build Coastguard Worker                             reqBuffer.getFence())
567*ec779b8eSAndroid Build Coastguard Worker                       : renderIntoImageStreamBuffer(reqBuffer.getStreamId(),
568*ec779b8eSAndroid Build Coastguard Worker                                                     reqBuffer.getBufferId(),
569*ec779b8eSAndroid Build Coastguard Worker                                                     reqBuffer.getFence());
570*ec779b8eSAndroid Build Coastguard Worker     if (!status.isOk()) {
571*ec779b8eSAndroid Build Coastguard Worker       resBuffer.status = BufferStatus::ERROR;
572*ec779b8eSAndroid Build Coastguard Worker     }
573*ec779b8eSAndroid Build Coastguard Worker   }
574*ec779b8eSAndroid Build Coastguard Worker }
575*ec779b8eSAndroid Build Coastguard Worker 
notifyTimeout(const ProcessCaptureRequestTask & request,CaptureResult & captureResult)576*ec779b8eSAndroid Build Coastguard Worker ::ndk::ScopedAStatus VirtualCameraRenderThread::notifyTimeout(
577*ec779b8eSAndroid Build Coastguard Worker     const ProcessCaptureRequestTask& request, CaptureResult& captureResult) {
578*ec779b8eSAndroid Build Coastguard Worker   const std::vector<CaptureRequestBuffer>& buffers = request.getBuffers();
579*ec779b8eSAndroid Build Coastguard Worker   captureResult.outputBuffers.resize(buffers.size());
580*ec779b8eSAndroid Build Coastguard Worker 
581*ec779b8eSAndroid Build Coastguard Worker   std::vector<NotifyMsg> notifyMsgs;
582*ec779b8eSAndroid Build Coastguard Worker 
583*ec779b8eSAndroid Build Coastguard Worker   for (int i = 0; i < buffers.size(); ++i) {
584*ec779b8eSAndroid Build Coastguard Worker     const CaptureRequestBuffer& reqBuffer = buffers[i];
585*ec779b8eSAndroid Build Coastguard Worker     StreamBuffer& resBuffer = captureResult.outputBuffers[i];
586*ec779b8eSAndroid Build Coastguard Worker     resBuffer.streamId = reqBuffer.getStreamId();
587*ec779b8eSAndroid Build Coastguard Worker     resBuffer.bufferId = reqBuffer.getBufferId();
588*ec779b8eSAndroid Build Coastguard Worker     resBuffer.status = BufferStatus::ERROR;
589*ec779b8eSAndroid Build Coastguard Worker     notifyMsgs.push_back(createErrorNotifyMsg(
590*ec779b8eSAndroid Build Coastguard Worker         request.getFrameNumber(), resBuffer.streamId, ErrorCode::ERROR_REQUEST));
591*ec779b8eSAndroid Build Coastguard Worker   }
592*ec779b8eSAndroid Build Coastguard Worker   return mCameraDeviceCallback->notify(notifyMsgs);
593*ec779b8eSAndroid Build Coastguard Worker }
594*ec779b8eSAndroid Build Coastguard Worker 
notifyShutter(const ProcessCaptureRequestTask & request,const CaptureResult & captureResult,std::chrono::nanoseconds captureTimestamp)595*ec779b8eSAndroid Build Coastguard Worker ::ndk::ScopedAStatus VirtualCameraRenderThread::notifyShutter(
596*ec779b8eSAndroid Build Coastguard Worker     const ProcessCaptureRequestTask& request, const CaptureResult& captureResult,
597*ec779b8eSAndroid Build Coastguard Worker     std::chrono::nanoseconds captureTimestamp) {
598*ec779b8eSAndroid Build Coastguard Worker   std::vector<NotifyMsg> notifyMsgs{
599*ec779b8eSAndroid Build Coastguard Worker       createShutterNotifyMsg(request.getFrameNumber(), captureTimestamp)};
600*ec779b8eSAndroid Build Coastguard Worker   for (const StreamBuffer& resBuffer : captureResult.outputBuffers) {
601*ec779b8eSAndroid Build Coastguard Worker     if (resBuffer.status != BufferStatus::OK) {
602*ec779b8eSAndroid Build Coastguard Worker       notifyMsgs.push_back(
603*ec779b8eSAndroid Build Coastguard Worker           createErrorNotifyMsg(request.getFrameNumber(), resBuffer.streamId));
604*ec779b8eSAndroid Build Coastguard Worker     }
605*ec779b8eSAndroid Build Coastguard Worker   }
606*ec779b8eSAndroid Build Coastguard Worker 
607*ec779b8eSAndroid Build Coastguard Worker   return mCameraDeviceCallback->notify(notifyMsgs);
608*ec779b8eSAndroid Build Coastguard Worker }
609*ec779b8eSAndroid Build Coastguard Worker 
submitCaptureResult(std::unique_ptr<CaptureResult> captureResult)610*ec779b8eSAndroid Build Coastguard Worker ::ndk::ScopedAStatus VirtualCameraRenderThread::submitCaptureResult(
611*ec779b8eSAndroid Build Coastguard Worker     std::unique_ptr<CaptureResult> captureResult) {
612*ec779b8eSAndroid Build Coastguard Worker   std::vector<::aidl::android::hardware::camera::device::CaptureResult>
613*ec779b8eSAndroid Build Coastguard Worker       captureResults;
614*ec779b8eSAndroid Build Coastguard Worker   captureResults.push_back(std::move(*captureResult));
615*ec779b8eSAndroid Build Coastguard Worker 
616*ec779b8eSAndroid Build Coastguard Worker   ::ndk::ScopedAStatus status =
617*ec779b8eSAndroid Build Coastguard Worker       mCameraDeviceCallback->processCaptureResult(captureResults);
618*ec779b8eSAndroid Build Coastguard Worker   if (!status.isOk()) {
619*ec779b8eSAndroid Build Coastguard Worker     ALOGE("%s: processCaptureResult call failed: %s", __func__,
620*ec779b8eSAndroid Build Coastguard Worker           status.getDescription().c_str());
621*ec779b8eSAndroid Build Coastguard Worker     return status;
622*ec779b8eSAndroid Build Coastguard Worker   }
623*ec779b8eSAndroid Build Coastguard Worker 
624*ec779b8eSAndroid Build Coastguard Worker   ALOGV("%s: Successfully called processCaptureResult", __func__);
625*ec779b8eSAndroid Build Coastguard Worker   return status;
626*ec779b8eSAndroid Build Coastguard Worker }
627*ec779b8eSAndroid Build Coastguard Worker 
flushCaptureRequest(const ProcessCaptureRequestTask & request)628*ec779b8eSAndroid Build Coastguard Worker void VirtualCameraRenderThread::flushCaptureRequest(
629*ec779b8eSAndroid Build Coastguard Worker     const ProcessCaptureRequestTask& request) {
630*ec779b8eSAndroid Build Coastguard Worker   CaptureResult captureResult;
631*ec779b8eSAndroid Build Coastguard Worker   captureResult.fmqResultSize = 0;
632*ec779b8eSAndroid Build Coastguard Worker   captureResult.frameNumber = request.getFrameNumber();
633*ec779b8eSAndroid Build Coastguard Worker   captureResult.inputBuffer.streamId = -1;
634*ec779b8eSAndroid Build Coastguard Worker 
635*ec779b8eSAndroid Build Coastguard Worker   const std::vector<CaptureRequestBuffer>& buffers = request.getBuffers();
636*ec779b8eSAndroid Build Coastguard Worker   captureResult.outputBuffers.resize(buffers.size());
637*ec779b8eSAndroid Build Coastguard Worker 
638*ec779b8eSAndroid Build Coastguard Worker   for (int i = 0; i < buffers.size(); ++i) {
639*ec779b8eSAndroid Build Coastguard Worker     const CaptureRequestBuffer& reqBuffer = buffers[i];
640*ec779b8eSAndroid Build Coastguard Worker     StreamBuffer& resBuffer = captureResult.outputBuffers[i];
641*ec779b8eSAndroid Build Coastguard Worker     resBuffer.streamId = reqBuffer.getStreamId();
642*ec779b8eSAndroid Build Coastguard Worker     resBuffer.bufferId = reqBuffer.getBufferId();
643*ec779b8eSAndroid Build Coastguard Worker     resBuffer.status = BufferStatus::ERROR;
644*ec779b8eSAndroid Build Coastguard Worker     sp<Fence> fence = reqBuffer.getFence();
645*ec779b8eSAndroid Build Coastguard Worker     if (fence != nullptr && fence->isValid()) {
646*ec779b8eSAndroid Build Coastguard Worker       resBuffer.releaseFence.fds.emplace_back(fence->dup());
647*ec779b8eSAndroid Build Coastguard Worker     }
648*ec779b8eSAndroid Build Coastguard Worker   }
649*ec779b8eSAndroid Build Coastguard Worker 
650*ec779b8eSAndroid Build Coastguard Worker   auto status = mCameraDeviceCallback->notify(
651*ec779b8eSAndroid Build Coastguard Worker       {createRequestErrorNotifyMsg(request.getFrameNumber())});
652*ec779b8eSAndroid Build Coastguard Worker   if (!status.isOk()) {
653*ec779b8eSAndroid Build Coastguard Worker     ALOGE("%s: notify call failed: %s", __func__,
654*ec779b8eSAndroid Build Coastguard Worker           status.getDescription().c_str());
655*ec779b8eSAndroid Build Coastguard Worker     return;
656*ec779b8eSAndroid Build Coastguard Worker   }
657*ec779b8eSAndroid Build Coastguard Worker 
658*ec779b8eSAndroid Build Coastguard Worker   std::vector<::aidl::android::hardware::camera::device::CaptureResult>
659*ec779b8eSAndroid Build Coastguard Worker       captureResults(1);
660*ec779b8eSAndroid Build Coastguard Worker   captureResults[0] = std::move(captureResult);
661*ec779b8eSAndroid Build Coastguard Worker 
662*ec779b8eSAndroid Build Coastguard Worker   status = mCameraDeviceCallback->processCaptureResult(captureResults);
663*ec779b8eSAndroid Build Coastguard Worker   if (!status.isOk()) {
664*ec779b8eSAndroid Build Coastguard Worker     ALOGE("%s: processCaptureResult call failed: %s", __func__,
665*ec779b8eSAndroid Build Coastguard Worker           status.getDescription().c_str());
666*ec779b8eSAndroid Build Coastguard Worker   }
667*ec779b8eSAndroid Build Coastguard Worker }
668*ec779b8eSAndroid Build Coastguard Worker 
createThumbnail(const Resolution resolution,const int quality)669*ec779b8eSAndroid Build Coastguard Worker std::vector<uint8_t> VirtualCameraRenderThread::createThumbnail(
670*ec779b8eSAndroid Build Coastguard Worker     const Resolution resolution, const int quality) {
671*ec779b8eSAndroid Build Coastguard Worker   if (resolution.width == 0 || resolution.height == 0) {
672*ec779b8eSAndroid Build Coastguard Worker     ALOGV("%s: Skipping thumbnail creation, zero size requested", __func__);
673*ec779b8eSAndroid Build Coastguard Worker     return {};
674*ec779b8eSAndroid Build Coastguard Worker   }
675*ec779b8eSAndroid Build Coastguard Worker 
676*ec779b8eSAndroid Build Coastguard Worker   ALOGV("%s: Creating thumbnail with size %d x %d, quality %d", __func__,
677*ec779b8eSAndroid Build Coastguard Worker         resolution.width, resolution.height, quality);
678*ec779b8eSAndroid Build Coastguard Worker   Resolution bufferSize = roundTo2DctSize(resolution);
679*ec779b8eSAndroid Build Coastguard Worker   std::shared_ptr<EglFrameBuffer> framebuffer = allocateTemporaryFramebuffer(
680*ec779b8eSAndroid Build Coastguard Worker       mEglDisplayContext->getEglDisplay(), bufferSize.width, bufferSize.height);
681*ec779b8eSAndroid Build Coastguard Worker   if (framebuffer == nullptr) {
682*ec779b8eSAndroid Build Coastguard Worker     ALOGE(
683*ec779b8eSAndroid Build Coastguard Worker         "Failed to allocate temporary framebuffer for JPEG thumbnail "
684*ec779b8eSAndroid Build Coastguard Worker         "compression");
685*ec779b8eSAndroid Build Coastguard Worker     return {};
686*ec779b8eSAndroid Build Coastguard Worker   }
687*ec779b8eSAndroid Build Coastguard Worker 
688*ec779b8eSAndroid Build Coastguard Worker   // TODO(b/324383963) Add support for letterboxing if the thumbnail sizese
689*ec779b8eSAndroid Build Coastguard Worker   // doesn't correspond
690*ec779b8eSAndroid Build Coastguard Worker   //  to input texture aspect ratio.
691*ec779b8eSAndroid Build Coastguard Worker   if (!renderIntoEglFramebuffer(*framebuffer, /*fence=*/nullptr,
692*ec779b8eSAndroid Build Coastguard Worker                                 Rect(resolution.width, resolution.height))
693*ec779b8eSAndroid Build Coastguard Worker            .isOk()) {
694*ec779b8eSAndroid Build Coastguard Worker     ALOGE(
695*ec779b8eSAndroid Build Coastguard Worker         "Failed to render input texture into temporary framebuffer for JPEG "
696*ec779b8eSAndroid Build Coastguard Worker         "thumbnail");
697*ec779b8eSAndroid Build Coastguard Worker     return {};
698*ec779b8eSAndroid Build Coastguard Worker   }
699*ec779b8eSAndroid Build Coastguard Worker 
700*ec779b8eSAndroid Build Coastguard Worker   std::vector<uint8_t> compressedThumbnail;
701*ec779b8eSAndroid Build Coastguard Worker   compressedThumbnail.resize(kJpegThumbnailBufferSize);
702*ec779b8eSAndroid Build Coastguard Worker   ALOGE("%s: Compressing thumbnail %d x %d", __func__, resolution.width,
703*ec779b8eSAndroid Build Coastguard Worker         resolution.height);
704*ec779b8eSAndroid Build Coastguard Worker   std::optional<size_t> compressedSize =
705*ec779b8eSAndroid Build Coastguard Worker       compressJpeg(resolution.width, resolution.height, quality,
706*ec779b8eSAndroid Build Coastguard Worker                    framebuffer->getHardwareBuffer(), {},
707*ec779b8eSAndroid Build Coastguard Worker                    compressedThumbnail.size(), compressedThumbnail.data());
708*ec779b8eSAndroid Build Coastguard Worker   if (!compressedSize.has_value()) {
709*ec779b8eSAndroid Build Coastguard Worker     ALOGE("%s: Failed to compress jpeg thumbnail", __func__);
710*ec779b8eSAndroid Build Coastguard Worker     return {};
711*ec779b8eSAndroid Build Coastguard Worker   }
712*ec779b8eSAndroid Build Coastguard Worker   compressedThumbnail.resize(compressedSize.value());
713*ec779b8eSAndroid Build Coastguard Worker   return compressedThumbnail;
714*ec779b8eSAndroid Build Coastguard Worker }
715*ec779b8eSAndroid Build Coastguard Worker 
renderIntoBlobStreamBuffer(const int streamId,const int bufferId,const CameraMetadata & resultMetadata,const RequestSettings & requestSettings,sp<Fence> fence)716*ec779b8eSAndroid Build Coastguard Worker ndk::ScopedAStatus VirtualCameraRenderThread::renderIntoBlobStreamBuffer(
717*ec779b8eSAndroid Build Coastguard Worker     const int streamId, const int bufferId, const CameraMetadata& resultMetadata,
718*ec779b8eSAndroid Build Coastguard Worker     const RequestSettings& requestSettings, sp<Fence> fence) {
719*ec779b8eSAndroid Build Coastguard Worker   std::shared_ptr<AHardwareBuffer> hwBuffer =
720*ec779b8eSAndroid Build Coastguard Worker       mSessionContext.fetchHardwareBuffer(streamId, bufferId);
721*ec779b8eSAndroid Build Coastguard Worker   if (hwBuffer == nullptr) {
722*ec779b8eSAndroid Build Coastguard Worker     ALOGE("%s: Failed to fetch hardware buffer %d for streamId %d", __func__,
723*ec779b8eSAndroid Build Coastguard Worker           bufferId, streamId);
724*ec779b8eSAndroid Build Coastguard Worker     return cameraStatus(Status::INTERNAL_ERROR);
725*ec779b8eSAndroid Build Coastguard Worker   }
726*ec779b8eSAndroid Build Coastguard Worker 
727*ec779b8eSAndroid Build Coastguard Worker   std::optional<Stream> stream = mSessionContext.getStreamConfig(streamId);
728*ec779b8eSAndroid Build Coastguard Worker   if (!stream.has_value()) {
729*ec779b8eSAndroid Build Coastguard Worker     ALOGE("%s, failed to fetch information about stream %d", __func__, streamId);
730*ec779b8eSAndroid Build Coastguard Worker     return cameraStatus(Status::INTERNAL_ERROR);
731*ec779b8eSAndroid Build Coastguard Worker   }
732*ec779b8eSAndroid Build Coastguard Worker 
733*ec779b8eSAndroid Build Coastguard Worker   ALOGV("%s: Rendering JPEG with size %d x %d, quality %d", __func__,
734*ec779b8eSAndroid Build Coastguard Worker         stream->width, stream->height, requestSettings.jpegQuality);
735*ec779b8eSAndroid Build Coastguard Worker 
736*ec779b8eSAndroid Build Coastguard Worker   // Let's create YUV framebuffer and render the surface into this.
737*ec779b8eSAndroid Build Coastguard Worker   // This will take care about rescaling as well as potential format conversion.
738*ec779b8eSAndroid Build Coastguard Worker   // The buffer dimensions need to be rounded to nearest multiple of JPEG DCT
739*ec779b8eSAndroid Build Coastguard Worker   // size, however we pass the viewport corresponding to size of the stream so
740*ec779b8eSAndroid Build Coastguard Worker   // the image will be only rendered to the area corresponding to the stream
741*ec779b8eSAndroid Build Coastguard Worker   // size.
742*ec779b8eSAndroid Build Coastguard Worker   Resolution bufferSize =
743*ec779b8eSAndroid Build Coastguard Worker       roundTo2DctSize(Resolution(stream->width, stream->height));
744*ec779b8eSAndroid Build Coastguard Worker   std::shared_ptr<EglFrameBuffer> framebuffer = allocateTemporaryFramebuffer(
745*ec779b8eSAndroid Build Coastguard Worker       mEglDisplayContext->getEglDisplay(), bufferSize.width, bufferSize.height);
746*ec779b8eSAndroid Build Coastguard Worker   if (framebuffer == nullptr) {
747*ec779b8eSAndroid Build Coastguard Worker     ALOGE("Failed to allocate temporary framebuffer for JPEG compression");
748*ec779b8eSAndroid Build Coastguard Worker     return cameraStatus(Status::INTERNAL_ERROR);
749*ec779b8eSAndroid Build Coastguard Worker   }
750*ec779b8eSAndroid Build Coastguard Worker 
751*ec779b8eSAndroid Build Coastguard Worker   // Render into temporary framebuffer.
752*ec779b8eSAndroid Build Coastguard Worker   ndk::ScopedAStatus status = renderIntoEglFramebuffer(
753*ec779b8eSAndroid Build Coastguard Worker       *framebuffer, /*fence=*/nullptr, Rect(stream->width, stream->height));
754*ec779b8eSAndroid Build Coastguard Worker   if (!status.isOk()) {
755*ec779b8eSAndroid Build Coastguard Worker     ALOGE("Failed to render input texture into temporary framebuffer");
756*ec779b8eSAndroid Build Coastguard Worker     return status;
757*ec779b8eSAndroid Build Coastguard Worker   }
758*ec779b8eSAndroid Build Coastguard Worker 
759*ec779b8eSAndroid Build Coastguard Worker   PlanesLockGuard planesLock(hwBuffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
760*ec779b8eSAndroid Build Coastguard Worker                              fence);
761*ec779b8eSAndroid Build Coastguard Worker   if (planesLock.getStatus() != OK) {
762*ec779b8eSAndroid Build Coastguard Worker     ALOGE("Failed to lock hwBuffer planes");
763*ec779b8eSAndroid Build Coastguard Worker     return cameraStatus(Status::INTERNAL_ERROR);
764*ec779b8eSAndroid Build Coastguard Worker   }
765*ec779b8eSAndroid Build Coastguard Worker 
766*ec779b8eSAndroid Build Coastguard Worker   std::vector<uint8_t> app1ExifData =
767*ec779b8eSAndroid Build Coastguard Worker       createExif(Resolution(stream->width, stream->height), resultMetadata,
768*ec779b8eSAndroid Build Coastguard Worker                  createThumbnail(requestSettings.thumbnailResolution,
769*ec779b8eSAndroid Build Coastguard Worker                                  requestSettings.thumbnailJpegQuality));
770*ec779b8eSAndroid Build Coastguard Worker 
771*ec779b8eSAndroid Build Coastguard Worker   unsigned long outBufferSize = stream->bufferSize - sizeof(CameraBlob);
772*ec779b8eSAndroid Build Coastguard Worker   void* outBuffer = (*planesLock).planes[0].data;
773*ec779b8eSAndroid Build Coastguard Worker   std::optional<size_t> compressedSize = compressJpeg(
774*ec779b8eSAndroid Build Coastguard Worker       stream->width, stream->height, requestSettings.jpegQuality,
775*ec779b8eSAndroid Build Coastguard Worker       framebuffer->getHardwareBuffer(), app1ExifData, outBufferSize, outBuffer);
776*ec779b8eSAndroid Build Coastguard Worker 
777*ec779b8eSAndroid Build Coastguard Worker   if (!compressedSize.has_value()) {
778*ec779b8eSAndroid Build Coastguard Worker     ALOGE("%s: Failed to compress JPEG image", __func__);
779*ec779b8eSAndroid Build Coastguard Worker     return cameraStatus(Status::INTERNAL_ERROR);
780*ec779b8eSAndroid Build Coastguard Worker   }
781*ec779b8eSAndroid Build Coastguard Worker 
782*ec779b8eSAndroid Build Coastguard Worker   // Add the transport header at the end of the JPEG output buffer.
783*ec779b8eSAndroid Build Coastguard Worker   //
784*ec779b8eSAndroid Build Coastguard Worker   // jpegBlobId must start at byte[buffer_size - sizeof(CameraBlob)],
785*ec779b8eSAndroid Build Coastguard Worker   // where the buffer_size is the size of gralloc buffer.
786*ec779b8eSAndroid Build Coastguard Worker   //
787*ec779b8eSAndroid Build Coastguard Worker   // See
788*ec779b8eSAndroid Build Coastguard Worker   // hardware/interfaces/camera/device/aidl/android/hardware/camera/device/CameraBlobId.aidl
789*ec779b8eSAndroid Build Coastguard Worker   // for the full explanation of the following code.
790*ec779b8eSAndroid Build Coastguard Worker   CameraBlob cameraBlob{
791*ec779b8eSAndroid Build Coastguard Worker       .blobId = CameraBlobId::JPEG,
792*ec779b8eSAndroid Build Coastguard Worker       .blobSizeBytes = static_cast<int32_t>(compressedSize.value())};
793*ec779b8eSAndroid Build Coastguard Worker 
794*ec779b8eSAndroid Build Coastguard Worker   // Copy the cameraBlob to the end of the JPEG buffer.
795*ec779b8eSAndroid Build Coastguard Worker   uint8_t* jpegStreamEndAddress =
796*ec779b8eSAndroid Build Coastguard Worker       reinterpret_cast<uint8_t*>((*planesLock).planes[0].data) +
797*ec779b8eSAndroid Build Coastguard Worker       (stream->bufferSize - sizeof(cameraBlob));
798*ec779b8eSAndroid Build Coastguard Worker   memcpy(jpegStreamEndAddress, &cameraBlob, sizeof(cameraBlob));
799*ec779b8eSAndroid Build Coastguard Worker 
800*ec779b8eSAndroid Build Coastguard Worker   ALOGV("%s: Successfully compressed JPEG image, resulting size %zu B",
801*ec779b8eSAndroid Build Coastguard Worker         __func__, compressedSize.value());
802*ec779b8eSAndroid Build Coastguard Worker 
803*ec779b8eSAndroid Build Coastguard Worker   return ndk::ScopedAStatus::ok();
804*ec779b8eSAndroid Build Coastguard Worker }
805*ec779b8eSAndroid Build Coastguard Worker 
renderIntoImageStreamBuffer(int streamId,int bufferId,sp<Fence> fence)806*ec779b8eSAndroid Build Coastguard Worker ndk::ScopedAStatus VirtualCameraRenderThread::renderIntoImageStreamBuffer(
807*ec779b8eSAndroid Build Coastguard Worker     int streamId, int bufferId, sp<Fence> fence) {
808*ec779b8eSAndroid Build Coastguard Worker   ALOGV("%s", __func__);
809*ec779b8eSAndroid Build Coastguard Worker 
810*ec779b8eSAndroid Build Coastguard Worker   const std::chrono::nanoseconds before =
811*ec779b8eSAndroid Build Coastguard Worker       std::chrono::duration_cast<std::chrono::nanoseconds>(
812*ec779b8eSAndroid Build Coastguard Worker           std::chrono::steady_clock::now().time_since_epoch());
813*ec779b8eSAndroid Build Coastguard Worker 
814*ec779b8eSAndroid Build Coastguard Worker   // Render test pattern using EGL.
815*ec779b8eSAndroid Build Coastguard Worker   std::shared_ptr<EglFrameBuffer> framebuffer =
816*ec779b8eSAndroid Build Coastguard Worker       mSessionContext.fetchOrCreateEglFramebuffer(
817*ec779b8eSAndroid Build Coastguard Worker           mEglDisplayContext->getEglDisplay(), streamId, bufferId);
818*ec779b8eSAndroid Build Coastguard Worker   if (framebuffer == nullptr) {
819*ec779b8eSAndroid Build Coastguard Worker     ALOGE(
820*ec779b8eSAndroid Build Coastguard Worker         "%s: Failed to get EGL framebuffer corresponding to buffer id "
821*ec779b8eSAndroid Build Coastguard Worker         "%d for streamId %d",
822*ec779b8eSAndroid Build Coastguard Worker         __func__, bufferId, streamId);
823*ec779b8eSAndroid Build Coastguard Worker     return cameraStatus(Status::ILLEGAL_ARGUMENT);
824*ec779b8eSAndroid Build Coastguard Worker   }
825*ec779b8eSAndroid Build Coastguard Worker 
826*ec779b8eSAndroid Build Coastguard Worker   ndk::ScopedAStatus status = renderIntoEglFramebuffer(*framebuffer, fence);
827*ec779b8eSAndroid Build Coastguard Worker 
828*ec779b8eSAndroid Build Coastguard Worker   const std::chrono::nanoseconds after =
829*ec779b8eSAndroid Build Coastguard Worker       std::chrono::duration_cast<std::chrono::nanoseconds>(
830*ec779b8eSAndroid Build Coastguard Worker           std::chrono::steady_clock::now().time_since_epoch());
831*ec779b8eSAndroid Build Coastguard Worker 
832*ec779b8eSAndroid Build Coastguard Worker   ALOGV("Rendering to buffer %d, stream %d took %lld ns", bufferId, streamId,
833*ec779b8eSAndroid Build Coastguard Worker         after.count() - before.count());
834*ec779b8eSAndroid Build Coastguard Worker 
835*ec779b8eSAndroid Build Coastguard Worker   return ndk::ScopedAStatus::ok();
836*ec779b8eSAndroid Build Coastguard Worker }
837*ec779b8eSAndroid Build Coastguard Worker 
renderIntoEglFramebuffer(EglFrameBuffer & framebuffer,sp<Fence> fence,std::optional<Rect> viewport)838*ec779b8eSAndroid Build Coastguard Worker ndk::ScopedAStatus VirtualCameraRenderThread::renderIntoEglFramebuffer(
839*ec779b8eSAndroid Build Coastguard Worker     EglFrameBuffer& framebuffer, sp<Fence> fence, std::optional<Rect> viewport) {
840*ec779b8eSAndroid Build Coastguard Worker   ALOGV("%s", __func__);
841*ec779b8eSAndroid Build Coastguard Worker   // Wait for fence to clear.
842*ec779b8eSAndroid Build Coastguard Worker   if (fence != nullptr && fence->isValid()) {
843*ec779b8eSAndroid Build Coastguard Worker     status_t ret = fence->wait(kAcquireFenceTimeout.count());
844*ec779b8eSAndroid Build Coastguard Worker     if (ret != 0) {
845*ec779b8eSAndroid Build Coastguard Worker       ALOGE("Timeout while waiting for the acquire fence for buffer");
846*ec779b8eSAndroid Build Coastguard Worker       return cameraStatus(Status::INTERNAL_ERROR);
847*ec779b8eSAndroid Build Coastguard Worker     }
848*ec779b8eSAndroid Build Coastguard Worker   }
849*ec779b8eSAndroid Build Coastguard Worker 
850*ec779b8eSAndroid Build Coastguard Worker   mEglDisplayContext->makeCurrent();
851*ec779b8eSAndroid Build Coastguard Worker   framebuffer.beforeDraw();
852*ec779b8eSAndroid Build Coastguard Worker 
853*ec779b8eSAndroid Build Coastguard Worker   Rect viewportRect =
854*ec779b8eSAndroid Build Coastguard Worker       viewport.value_or(Rect(framebuffer.getWidth(), framebuffer.getHeight()));
855*ec779b8eSAndroid Build Coastguard Worker   glViewport(viewportRect.left, viewportRect.top, viewportRect.getWidth(),
856*ec779b8eSAndroid Build Coastguard Worker              viewportRect.getHeight());
857*ec779b8eSAndroid Build Coastguard Worker 
858*ec779b8eSAndroid Build Coastguard Worker   sp<GraphicBuffer> textureBuffer = mEglSurfaceTexture->getCurrentBuffer();
859*ec779b8eSAndroid Build Coastguard Worker   if (textureBuffer == nullptr) {
860*ec779b8eSAndroid Build Coastguard Worker     // If there's no current buffer, nothing was written to the surface and
861*ec779b8eSAndroid Build Coastguard Worker     // texture is not initialized yet. Let's render the framebuffer black
862*ec779b8eSAndroid Build Coastguard Worker     // instead of rendering the texture.
863*ec779b8eSAndroid Build Coastguard Worker     glClearColor(0.0f, 0.5f, 0.5f, 0.0f);
864*ec779b8eSAndroid Build Coastguard Worker     glClear(GL_COLOR_BUFFER_BIT);
865*ec779b8eSAndroid Build Coastguard Worker   } else {
866*ec779b8eSAndroid Build Coastguard Worker     const bool renderSuccess =
867*ec779b8eSAndroid Build Coastguard Worker         isYuvFormat(static_cast<PixelFormat>(textureBuffer->getPixelFormat()))
868*ec779b8eSAndroid Build Coastguard Worker             ? mEglTextureYuvProgram->draw(
869*ec779b8eSAndroid Build Coastguard Worker                   mEglSurfaceTexture->getTextureId(),
870*ec779b8eSAndroid Build Coastguard Worker                   mEglSurfaceTexture->getTransformMatrix())
871*ec779b8eSAndroid Build Coastguard Worker             : mEglTextureRgbProgram->draw(
872*ec779b8eSAndroid Build Coastguard Worker                   mEglSurfaceTexture->getTextureId(),
873*ec779b8eSAndroid Build Coastguard Worker                   mEglSurfaceTexture->getTransformMatrix());
874*ec779b8eSAndroid Build Coastguard Worker     if (!renderSuccess) {
875*ec779b8eSAndroid Build Coastguard Worker       ALOGE("%s: Failed to render texture", __func__);
876*ec779b8eSAndroid Build Coastguard Worker       return cameraStatus(Status::INTERNAL_ERROR);
877*ec779b8eSAndroid Build Coastguard Worker     }
878*ec779b8eSAndroid Build Coastguard Worker   }
879*ec779b8eSAndroid Build Coastguard Worker   framebuffer.afterDraw();
880*ec779b8eSAndroid Build Coastguard Worker 
881*ec779b8eSAndroid Build Coastguard Worker   return ndk::ScopedAStatus::ok();
882*ec779b8eSAndroid Build Coastguard Worker }
883*ec779b8eSAndroid Build Coastguard Worker 
884*ec779b8eSAndroid Build Coastguard Worker }  // namespace virtualcamera
885*ec779b8eSAndroid Build Coastguard Worker }  // namespace companion
886*ec779b8eSAndroid Build Coastguard Worker }  // namespace android
887