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