xref: /aosp_15_r20/frameworks/av/services/camera/libcameraservice/device3/PreviewFrameSpacer.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "Camera3-PreviewFrameSpacer"
18 #define ATRACE_TAG ATRACE_TAG_CAMERA
19 //#define LOG_NDEBUG 0
20 
21 #include <com_android_internal_camera_flags.h>
22 
23 #include <utils/Log.h>
24 
25 #include "PreviewFrameSpacer.h"
26 #include "Camera3OutputStream.h"
27 #include "utils/SchedulingPolicyUtils.h"
28 #include "utils/Utils.h"
29 
30 namespace flags = com::android::internal::camera::flags;
31 
32 namespace android {
33 
34 namespace camera3 {
35 
PreviewFrameSpacer(wp<Camera3OutputStream> parent,sp<Surface> consumer)36 PreviewFrameSpacer::PreviewFrameSpacer(wp<Camera3OutputStream> parent, sp<Surface> consumer) :
37         mParent(parent),
38         mConsumer(consumer) {
39 }
40 
~PreviewFrameSpacer()41 PreviewFrameSpacer::~PreviewFrameSpacer() {
42 }
43 
queuePreviewBuffer(nsecs_t timestamp,nsecs_t readoutTimestamp,int32_t transform,ANativeWindowBuffer * anwBuffer,int releaseFence)44 status_t PreviewFrameSpacer::queuePreviewBuffer(nsecs_t timestamp, nsecs_t readoutTimestamp,
45         int32_t transform, ANativeWindowBuffer* anwBuffer, int releaseFence) {
46     Mutex::Autolock l(mLock);
47     mPendingBuffers.emplace(timestamp, readoutTimestamp, transform, anwBuffer, releaseFence);
48     ALOGV("%s: mPendingBuffers size %zu, timestamp %" PRId64 ", readoutTime %" PRId64,
49             __FUNCTION__, mPendingBuffers.size(), timestamp, readoutTimestamp);
50 
51     mBufferCond.signal();
52     return OK;
53 }
54 
threadLoop()55 bool PreviewFrameSpacer::threadLoop() {
56     Mutex::Autolock l(mLock);
57     if (mPendingBuffers.size() == 0) {
58         mBufferCond.waitRelative(mLock, kWaitDuration);
59         if (exitPending()) {
60             return false;
61         } else {
62             return true;
63         }
64     }
65 
66     nsecs_t currentTime = systemTime();
67     auto buffer = mPendingBuffers.front();
68     nsecs_t readoutInterval = buffer.readoutTimestamp - mLastCameraReadoutTime;
69     // If the readout interval exceeds threshold, directly queue
70     // cached buffer.
71     if (readoutInterval >= kFrameIntervalThreshold) {
72         mPendingBuffers.pop();
73         queueBufferToClientLocked(buffer, currentTime);
74         return true;
75     }
76 
77     // Cache the frame to match readout time interval, for up to kMaxFrameWaitTime
78     // Because the code between here and queueBuffer() takes time to execute, make sure the
79     // presentationInterval is slightly shorter than readoutInterval.
80     nsecs_t expectedQueueTime = mLastCameraPresentTime + readoutInterval - kFrameAdjustThreshold;
81     nsecs_t frameWaitTime = std::min(kMaxFrameWaitTime, expectedQueueTime - currentTime);
82     if (frameWaitTime > 0 && mPendingBuffers.size() < 2) {
83         mBufferCond.waitRelative(mLock, frameWaitTime);
84         if (exitPending()) {
85             return false;
86         }
87         currentTime = systemTime();
88     }
89     ALOGV("%s: readoutInterval %" PRId64 ", waited for %" PRId64
90             ", timestamp %" PRId64, __FUNCTION__, readoutInterval,
91             mPendingBuffers.size() < 2 ? frameWaitTime : 0, buffer.timestamp);
92     mPendingBuffers.pop();
93     queueBufferToClientLocked(buffer, currentTime);
94     return true;
95 }
96 
requestExit()97 void PreviewFrameSpacer::requestExit() {
98     // Call parent to set up shutdown
99     Thread::requestExit();
100     // Exit from other possible wait
101     mBufferCond.signal();
102 }
103 
queueBufferToClientLocked(const BufferHolder & bufferHolder,nsecs_t currentTime)104 void PreviewFrameSpacer::queueBufferToClientLocked(
105         const BufferHolder& bufferHolder, nsecs_t currentTime) {
106     sp<Camera3OutputStream> parent = mParent.promote();
107     if (parent == nullptr) {
108         ALOGV("%s: Parent camera3 output stream was destroyed", __FUNCTION__);
109         return;
110     }
111 
112     parent->setTransform(bufferHolder.transform, true/*mayChangeMirror*/);
113 
114     status_t res = native_window_set_buffers_timestamp(mConsumer.get(), bufferHolder.timestamp);
115     if (res != OK) {
116         ALOGE("%s: Preview Stream: Error setting timestamp: %s (%d)",
117                 __FUNCTION__, strerror(-res), res);
118     }
119 
120     Camera3Stream::queueHDRMetadata(bufferHolder.anwBuffer.get()->handle, mConsumer,
121             parent->getDynamicRangeProfile());
122 
123     res = mConsumer->queueBuffer(mConsumer.get(), bufferHolder.anwBuffer.get(),
124             bufferHolder.releaseFence);
125     if (res != OK) {
126         close(bufferHolder.releaseFence);
127         if (parent->shouldLogError(res)) {
128             ALOGE("%s: Failed to queue buffer to client: %s(%d)", __FUNCTION__,
129                     strerror(-res), res);
130         }
131     }
132 
133     parent->onCachedBufferQueued();
134     mLastCameraPresentTime = currentTime;
135     mLastCameraReadoutTime = bufferHolder.readoutTimestamp;
136 }
137 
run(const char * name,int32_t priority,size_t stack)138 status_t PreviewFrameSpacer::run(const char* name, int32_t priority, size_t stack) {
139     auto ret = Thread::run(name, priority, stack);
140     if (flags::bump_preview_frame_space_priority()) {
141         // Boost priority of the preview frame spacer thread to SCHED_FIFO.
142         pid_t previewFrameSpacerTid = getTid();
143         auto res = SchedulingPolicyUtils::requestPriorityDirect(getpid(), previewFrameSpacerTid,
144                 RunThreadWithRealtimePriority::kRequestThreadPriority);
145         if (res != OK) {
146             ALOGW("Can't set realtime priority for preview frame spacer thread: %s (%d)",
147                     strerror(-res), res);
148         } else {
149             ALOGV("Set real time priority for preview frame spacer thread (tid %d)",
150                     previewFrameSpacerTid);
151         }
152     }
153     return ret;
154 }
155 
156 }; // namespace camera3
157 
158 }; // namespace android
159