1 /*
2 * Copyright 2015 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_NDEBUG 0
18 #define LOG_TAG "FrameRenderTracker"
19
20 #include <inttypes.h>
21 #include <gui/Surface.h>
22
23 #include <media/stagefright/foundation/ADebug.h>
24 #include <media/stagefright/FrameRenderTracker.h>
25
26 namespace android {
27
FrameRenderTracker()28 FrameRenderTracker::FrameRenderTracker()
29 : mLastRenderTimeNs(-1),
30 mComponentName("unknown component") {
31 }
32
~FrameRenderTracker()33 FrameRenderTracker::~FrameRenderTracker() {
34 }
35
setComponentName(const AString & componentName)36 void FrameRenderTracker::setComponentName(const AString &componentName) {
37 mComponentName = componentName;
38 }
39
clear(nsecs_t lastRenderTimeNs)40 void FrameRenderTracker::clear(nsecs_t lastRenderTimeNs) {
41 mRenderQueue.clear();
42 mLastRenderTimeNs = lastRenderTimeNs;
43 }
44
onFrameQueued(int64_t mediaTimeUs,const sp<GraphicBuffer> & graphicBuffer,const sp<Fence> & fence)45 void FrameRenderTracker::onFrameQueued(
46 int64_t mediaTimeUs, const sp<GraphicBuffer> &graphicBuffer, const sp<Fence> &fence) {
47 mRenderQueue.emplace_back(mediaTimeUs, graphicBuffer, fence);
48 }
49
updateInfoForDequeuedBuffer(ANativeWindowBuffer * buf,int fenceFd,int index)50 FrameRenderTracker::Info *FrameRenderTracker::updateInfoForDequeuedBuffer(
51 ANativeWindowBuffer *buf, int fenceFd, int index) {
52 if (index < 0) {
53 return NULL;
54 }
55
56 // see if this is a buffer that was to be rendered
57 std::list<Info>::iterator renderInfo = mRenderQueue.end();
58 for (std::list<Info>::iterator it = mRenderQueue.begin();
59 it != mRenderQueue.end(); ++it) {
60 if (it->mGraphicBuffer->handle == buf->handle) {
61 renderInfo = it;
62 break;
63 }
64 }
65 if (renderInfo == mRenderQueue.end()) {
66 // could have been canceled after fence has signaled
67 return NULL;
68 }
69
70 if (renderInfo->mIndex >= 0) {
71 // buffer has been dequeued before, so there is nothing to do
72 return NULL;
73 }
74
75 // was this frame dropped (we could also infer this if the fence is invalid or a dup of
76 // the queued fence; however, there is no way to figure that out.)
77 if (fenceFd < 0) {
78 // frame is new or was dropped
79 mRenderQueue.erase(renderInfo);
80 return NULL;
81 }
82
83 // store dequeue fence and buffer index
84 renderInfo->mFence = new Fence(::dup(fenceFd));
85 renderInfo->mIndex = index;
86 return &*renderInfo;
87 }
88
onFrameRendered(int64_t mediaTimeUs,nsecs_t systemNano)89 status_t FrameRenderTracker::onFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano) {
90 // ensure monotonic timestamps
91 if (mLastRenderTimeNs >= systemNano) {
92 ALOGW("[%s] Ignoring out of order/stale system nano %lld for media time %lld from codec.",
93 mComponentName.c_str(), (long long)systemNano, (long long)mediaTimeUs);
94 return BAD_VALUE;
95 }
96
97 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
98 if (systemNano > now) {
99 ALOGW("[%s] Ignoring system nano %lld in the future for media time %lld from codec.",
100 mComponentName.c_str(), (long long)systemNano, (long long)mediaTimeUs);
101 return OK;
102 }
103
104 mRenderQueue.emplace_back(mediaTimeUs, systemNano);
105 mLastRenderTimeNs = systemNano;
106 return OK;
107 }
108
checkFencesAndGetRenderedFrames(const FrameRenderTracker::Info * until,bool dropIncomplete)109 std::list<FrameRenderTracker::Info> FrameRenderTracker::checkFencesAndGetRenderedFrames(
110 const FrameRenderTracker::Info *until, bool dropIncomplete) {
111 std::list<Info> done;
112
113 // complete any frames queued prior to this and drop any incomplete ones if requested
114 for (std::list<Info>::iterator it = mRenderQueue.begin();
115 it != mRenderQueue.end(); ) {
116 bool drop = false; // whether to drop each frame
117 if (it->mIndex < 0) {
118 // frame not yet dequeued (or already rendered on a tunneled surface)
119 drop = dropIncomplete;
120 } else if (it->mFence != NULL) {
121 // check if fence signaled
122 nsecs_t signalTime = it->mFence->getSignalTime();
123 if (signalTime < 0) { // invalid fence
124 drop = true;
125 } else if (signalTime == INT64_MAX) { // unsignaled fence
126 drop = dropIncomplete;
127 } else { // signaled
128 // save render time
129 it->mFence.clear();
130 it->mRenderTimeNs = signalTime;
131 }
132 }
133 bool foundFrame = (Info *)&*it == until;
134
135 // Return frames with signaled fences at the start of the queue, as they are
136 // in submit order, and we don't have to wait for any in-between frames.
137 // Also return any dropped frames.
138 if (drop || (it->mFence == NULL && it == mRenderQueue.begin())) {
139 // (unrendered) dropped frames have their mRenderTimeNs still set to -1
140 done.splice(done.end(), mRenderQueue, it++);
141 } else {
142 ++it;
143 }
144 if (foundFrame) {
145 break;
146 }
147 }
148
149 return done;
150 }
151
untrackFrame(const FrameRenderTracker::Info * info,ssize_t index)152 void FrameRenderTracker::untrackFrame(const FrameRenderTracker::Info *info, ssize_t index) {
153 if (info == NULL && index == SSIZE_MAX) {
154 // nothing to do
155 return;
156 }
157
158 for (std::list<Info>::iterator it = mRenderQueue.begin();
159 it != mRenderQueue.end(); ) {
160 if (&*it == info) {
161 mRenderQueue.erase(it++);
162 } else {
163 if (it->mIndex > index) {
164 --(it->mIndex);
165 }
166 ++it;
167 }
168 }
169 }
170
dumpRenderQueue() const171 void FrameRenderTracker::dumpRenderQueue() const {
172 ALOGI("[%s] Render Queue: (last render time: %lldns)",
173 mComponentName.c_str(), (long long)mLastRenderTimeNs);
174 for (std::list<Info>::const_iterator it = mRenderQueue.cbegin();
175 it != mRenderQueue.cend(); ++it) {
176 if (it->mFence == NULL) {
177 ALOGI(" RENDERED: handle: %p, media time: %lldus, index: %zd, render time: %lldns",
178 it->mGraphicBuffer == NULL ? NULL : it->mGraphicBuffer->handle,
179 (long long)it->mMediaTimeUs, it->mIndex, (long long)it->mRenderTimeNs);
180 } else if (it->mIndex < 0) {
181 ALOGI(" QUEUED: handle: %p, media time: %lldus, fence: %s",
182 it->mGraphicBuffer->handle, (long long)it->mMediaTimeUs,
183 it->mFence->isValid() ? "YES" : "NO");
184 } else {
185 ALOGI(" DEQUEUED: handle: %p, media time: %lldus, index: %zd",
186 it->mGraphicBuffer->handle, (long long)it->mMediaTimeUs, it->mIndex);
187 }
188 }
189 }
190
191 } // namespace android
192