• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <utils/Log.h>
22 
23 #include "PreviewFrameSpacer.h"
24 #include "Camera3OutputStream.h"
25 
26 namespace android {
27 
28 namespace camera3 {
29 
PreviewFrameSpacer(wp<Camera3OutputStream> parent,sp<Surface> consumer)30 PreviewFrameSpacer::PreviewFrameSpacer(wp<Camera3OutputStream> parent, sp<Surface> consumer) :
31         mParent(parent),
32         mConsumer(consumer) {
33 }
34 
~PreviewFrameSpacer()35 PreviewFrameSpacer::~PreviewFrameSpacer() {
36 }
37 
queuePreviewBuffer(nsecs_t timestamp,nsecs_t readoutTimestamp,int32_t transform,ANativeWindowBuffer * anwBuffer,int releaseFence)38 status_t PreviewFrameSpacer::queuePreviewBuffer(nsecs_t timestamp, nsecs_t readoutTimestamp,
39         int32_t transform, ANativeWindowBuffer* anwBuffer, int releaseFence) {
40     Mutex::Autolock l(mLock);
41     mPendingBuffers.emplace(timestamp, readoutTimestamp, transform, anwBuffer, releaseFence);
42     ALOGV("%s: mPendingBuffers size %zu, timestamp %" PRId64 ", readoutTime %" PRId64,
43             __FUNCTION__, mPendingBuffers.size(), timestamp, readoutTimestamp);
44 
45     mBufferCond.signal();
46     return OK;
47 }
48 
threadLoop()49 bool PreviewFrameSpacer::threadLoop() {
50     Mutex::Autolock l(mLock);
51     if (mPendingBuffers.size() == 0) {
52         mBufferCond.waitRelative(mLock, kWaitDuration);
53         if (exitPending()) {
54             return false;
55         } else {
56             return true;
57         }
58     }
59 
60     nsecs_t currentTime = systemTime();
61     auto buffer = mPendingBuffers.front();
62     nsecs_t readoutInterval = buffer.readoutTimestamp - mLastCameraReadoutTime;
63     // If the readout interval exceeds threshold, directly queue
64     // cached buffer.
65     if (readoutInterval >= kFrameIntervalThreshold) {
66         mPendingBuffers.pop();
67         queueBufferToClientLocked(buffer, currentTime);
68         return true;
69     }
70 
71     // Cache the frame to match readout time interval, for up to kMaxFrameWaitTime
72     // Because the code between here and queueBuffer() takes time to execute, make sure the
73     // presentationInterval is slightly shorter than readoutInterval.
74     nsecs_t expectedQueueTime = mLastCameraPresentTime + readoutInterval - kFrameAdjustThreshold;
75     nsecs_t frameWaitTime = std::min(kMaxFrameWaitTime, expectedQueueTime - currentTime);
76     if (frameWaitTime > 0 && mPendingBuffers.size() < 2) {
77         mBufferCond.waitRelative(mLock, frameWaitTime);
78         if (exitPending()) {
79             return false;
80         }
81         currentTime = systemTime();
82     }
83     ALOGV("%s: readoutInterval %" PRId64 ", waited for %" PRId64
84             ", timestamp %" PRId64, __FUNCTION__, readoutInterval,
85             mPendingBuffers.size() < 2 ? frameWaitTime : 0, buffer.timestamp);
86     mPendingBuffers.pop();
87     queueBufferToClientLocked(buffer, currentTime);
88     return true;
89 }
90 
requestExit()91 void PreviewFrameSpacer::requestExit() {
92     // Call parent to set up shutdown
93     Thread::requestExit();
94     // Exit from other possible wait
95     mBufferCond.signal();
96 }
97 
queueBufferToClientLocked(const BufferHolder & bufferHolder,nsecs_t currentTime)98 void PreviewFrameSpacer::queueBufferToClientLocked(
99         const BufferHolder& bufferHolder, nsecs_t currentTime) {
100     sp<Camera3OutputStream> parent = mParent.promote();
101     if (parent == nullptr) {
102         ALOGV("%s: Parent camera3 output stream was destroyed", __FUNCTION__);
103         return;
104     }
105 
106     parent->setTransform(bufferHolder.transform, true/*mayChangeMirror*/);
107 
108     status_t res = native_window_set_buffers_timestamp(mConsumer.get(), bufferHolder.timestamp);
109     if (res != OK) {
110         ALOGE("%s: Preview Stream: Error setting timestamp: %s (%d)",
111                 __FUNCTION__, strerror(-res), res);
112     }
113 
114     Camera3Stream::queueHDRMetadata(bufferHolder.anwBuffer.get()->handle, mConsumer,
115             parent->getDynamicRangeProfile());
116 
117     res = mConsumer->queueBuffer(mConsumer.get(), bufferHolder.anwBuffer.get(),
118             bufferHolder.releaseFence);
119     if (res != OK) {
120         close(bufferHolder.releaseFence);
121         if (parent->shouldLogError(res)) {
122             ALOGE("%s: Failed to queue buffer to client: %s(%d)", __FUNCTION__,
123                     strerror(-res), res);
124         }
125     }
126 
127     parent->onCachedBufferQueued();
128     mLastCameraPresentTime = currentTime;
129     mLastCameraReadoutTime = bufferHolder.readoutTimestamp;
130 }
131 
132 }; // namespace camera3
133 
134 }; // namespace android
135