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