blob: 80f27ed547d48d6c7732b9a3b0506dd95ec9499d [file] [log] [blame]
Shuzhen Wange4adddb2021-09-21 15:24:44 -07001/*
2 * Copyright (C) 2021 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-PreviewFrameScheduler"
18#define ATRACE_TAG ATRACE_TAG_CAMERA
19//#define LOG_NDEBUG 0
20
21#include <utils/Log.h>
22#include <utils/Trace.h>
23
24#include <android/looper.h>
25#include "PreviewFrameScheduler.h"
26#include "Camera3OutputStream.h"
27
28namespace android {
29
30namespace camera3 {
31
32/**
33 * Internal Choreographer thread implementation for polling and handling callbacks
34 */
35
36// Callback function for Choreographer
37static void frameCallback(const AChoreographerFrameCallbackData* callbackData, void* data) {
38 PreviewFrameScheduler* parent = static_cast<PreviewFrameScheduler*>(data);
39 if (parent == nullptr) {
40 ALOGE("%s: Invalid data for Choreographer callback!", __FUNCTION__);
41 return;
42 }
43
44 size_t length = AChoreographerFrameCallbackData_getFrameTimelinesLength(callbackData);
45 std::vector<nsecs_t> timeline(length);
46 for (size_t i = 0; i < length; i++) {
Rachel Lee1e870792022-02-15 19:03:39 -080047 nsecs_t timestamp = AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos(
Shuzhen Wange4adddb2021-09-21 15:24:44 -070048 callbackData, i);
49 timeline[i] = timestamp;
50 }
51
52 parent->onNewPresentationTime(timeline);
53
Rachel Lee1e870792022-02-15 19:03:39 -080054 AChoreographer_postVsyncCallback(AChoreographer_getInstance(), frameCallback, data);
Shuzhen Wange4adddb2021-09-21 15:24:44 -070055}
56
57struct ChoreographerThread : public Thread {
58 ChoreographerThread();
59 status_t start(PreviewFrameScheduler* parent);
60 virtual status_t readyToRun() override;
61 virtual bool threadLoop() override;
62
63protected:
64 virtual ~ChoreographerThread() {}
65
66private:
67 ChoreographerThread &operator=(const ChoreographerThread &);
68
69 // This only impacts the shutdown time. It won't impact the choreographer
70 // callback frequency.
71 static constexpr nsecs_t kPollingTimeoutMs = 5;
72 PreviewFrameScheduler* mParent = nullptr;
73};
74
75ChoreographerThread::ChoreographerThread() : Thread(false /*canCallJava*/) {
76}
77
78status_t ChoreographerThread::start(PreviewFrameScheduler* parent) {
79 mParent = parent;
80 return run("PreviewChoreographer");
81}
82
83status_t ChoreographerThread::readyToRun() {
84 ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
85 if (AChoreographer_getInstance() == NULL) {
86 return NO_INIT;
87 }
88
Rachel Lee1e870792022-02-15 19:03:39 -080089 AChoreographer_postVsyncCallback(
Shuzhen Wange4adddb2021-09-21 15:24:44 -070090 AChoreographer_getInstance(), frameCallback, mParent);
91 return OK;
92}
93
94bool ChoreographerThread::threadLoop() {
95 if (exitPending()) {
96 return false;
97 }
98 ALooper_pollOnce(kPollingTimeoutMs, nullptr, nullptr, nullptr);
99 return true;
100}
101
102/**
103 * PreviewFrameScheduler implementation
104 */
105
106PreviewFrameScheduler::PreviewFrameScheduler(Camera3OutputStream& parent, sp<Surface> consumer) :
107 mParent(parent),
108 mConsumer(consumer),
109 mChoreographerThread(new ChoreographerThread()) {
110}
111
112PreviewFrameScheduler::~PreviewFrameScheduler() {
113 {
114 Mutex::Autolock l(mLock);
115 mChoreographerThread->requestExit();
116 }
117 mChoreographerThread->join();
118}
119
120status_t PreviewFrameScheduler::queuePreviewBuffer(nsecs_t timestamp, int32_t transform,
121 ANativeWindowBuffer* anwBuffer, int releaseFence) {
122 // Start choreographer thread if it's not already running.
123 if (!mChoreographerThread->isRunning()) {
124 status_t res = mChoreographerThread->start(this);
125 if (res != OK) {
126 ALOGE("%s: Failed to init choreographer thread!", __FUNCTION__);
127 return res;
128 }
129 }
130
131 {
132 Mutex::Autolock l(mLock);
133 mPendingBuffers.emplace(timestamp, transform, anwBuffer, releaseFence);
134
135 // Queue buffer to client right away if pending buffers are more than
136 // the queue depth watermark.
137 if (mPendingBuffers.size() > kQueueDepthWatermark) {
138 auto oldBuffer = mPendingBuffers.front();
139 mPendingBuffers.pop();
140
141 status_t res = queueBufferToClientLocked(oldBuffer, oldBuffer.timestamp);
142 if (res != OK) {
143 return res;
144 }
145
146 // Reset the last capture and presentation time
147 mLastCameraCaptureTime = 0;
148 mLastCameraPresentTime = 0;
149 } else {
150 ATRACE_INT(kPendingBufferTraceName, mPendingBuffers.size());
151 }
152 }
153 return OK;
154}
155
156void PreviewFrameScheduler::onNewPresentationTime(const std::vector<nsecs_t>& timeline) {
157 ATRACE_CALL();
158 Mutex::Autolock l(mLock);
159 if (mPendingBuffers.size() > 0) {
160 auto nextBuffer = mPendingBuffers.front();
161 mPendingBuffers.pop();
162
163 // Find the best presentation time by finding the element in the
164 // choreographer timeline that's closest to the ideal presentation time.
165 // The ideal presentation time is the last presentation time + frame
166 // interval.
167 nsecs_t cameraInterval = nextBuffer.timestamp - mLastCameraCaptureTime;
168 nsecs_t idealPresentTime = (cameraInterval < kSpacingResetIntervalNs) ?
169 (mLastCameraPresentTime + cameraInterval) : nextBuffer.timestamp;
170 nsecs_t presentTime = *std::min_element(timeline.begin(), timeline.end(),
171 [idealPresentTime](nsecs_t p1, nsecs_t p2) {
172 return std::abs(p1 - idealPresentTime) < std::abs(p2 - idealPresentTime);
173 });
174
175 status_t res = queueBufferToClientLocked(nextBuffer, presentTime);
176 ATRACE_INT(kPendingBufferTraceName, mPendingBuffers.size());
177
178 if (mParent.shouldLogError(res)) {
179 ALOGE("%s: Preview Stream: Error queueing buffer to native window:"
180 " %s (%d)", __FUNCTION__, strerror(-res), res);
181 }
182
183 mLastCameraCaptureTime = nextBuffer.timestamp;
184 mLastCameraPresentTime = presentTime;
185 }
186}
187
188status_t PreviewFrameScheduler::queueBufferToClientLocked(
189 const BufferHolder& bufferHolder, nsecs_t timestamp) {
Shuzhen Wang610d7b82022-02-08 14:37:22 -0800190 mParent.setTransform(bufferHolder.transform, true/*mayChangeMirror*/);
Shuzhen Wange4adddb2021-09-21 15:24:44 -0700191
192 status_t res = native_window_set_buffers_timestamp(mConsumer.get(), timestamp);
193 if (res != OK) {
194 ALOGE("%s: Preview Stream: Error setting timestamp: %s (%d)",
195 __FUNCTION__, strerror(-res), res);
196 return res;
197 }
198
Emilian Peev2295df72021-11-12 18:14:10 -0800199 Camera3Stream::queueHDRMetadata(bufferHolder.anwBuffer.get()->handle, mConsumer,
200 mParent.getDynamicRangeProfile());
201
Shuzhen Wange4adddb2021-09-21 15:24:44 -0700202 res = mConsumer->queueBuffer(mConsumer.get(), bufferHolder.anwBuffer.get(),
203 bufferHolder.releaseFence);
204 if (res != OK) {
205 close(bufferHolder.releaseFence);
206 }
207
208 return res;
209}
210
211}; // namespace camera3
212
213}; // namespace android