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         // EOS is normally marked on the last frame
93         (mLastRenderTimeNs == systemNano && mediaTimeUs != INT64_MAX)) {
94         ALOGW("[%s] Ignoring out of order/stale system nano %lld for media time %lld from codec.",
95                 mComponentName.c_str(), (long long)systemNano, (long long)mediaTimeUs);
96         return BAD_VALUE;
97     }
98 
99     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
100     if (systemNano > now) {
101         ALOGW("[%s] Ignoring system nano %lld in the future for media time %lld from codec.",
102                 mComponentName.c_str(), (long long)systemNano, (long long)mediaTimeUs);
103         return OK;
104     }
105 
106     mRenderQueue.emplace_back(mediaTimeUs, systemNano);
107     mLastRenderTimeNs = systemNano;
108     return OK;
109 }
110 
checkFencesAndGetRenderedFrames(const FrameRenderTracker::Info * until,bool dropIncomplete)111 std::list<FrameRenderTracker::Info> FrameRenderTracker::checkFencesAndGetRenderedFrames(
112         const FrameRenderTracker::Info *until, bool dropIncomplete) {
113     std::list<Info> done;
114 
115     // complete any frames queued prior to this and drop any incomplete ones if requested
116     for (std::list<Info>::iterator it = mRenderQueue.begin();
117             it != mRenderQueue.end(); ) {
118         bool drop = false; // whether to drop each frame
119         if (it->mIndex < 0) {
120             // frame not yet dequeued (or already rendered on a tunneled surface)
121             drop = dropIncomplete;
122         } else if (it->mFence != NULL) {
123             // check if fence signaled
124             nsecs_t signalTime = it->mFence->getSignalTime();
125             if (signalTime < 0) { // invalid fence
126                 drop = true;
127             } else if (signalTime == INT64_MAX) { // unsignaled fence
128                 drop = dropIncomplete;
129             } else { // signaled
130                 // save render time
131                 it->mFence.clear();
132                 it->mRenderTimeNs = signalTime;
133             }
134         }
135         bool foundFrame = (Info *)&*it == until;
136 
137         // Return frames with signaled fences at the start of the queue, as they are
138         // in submit order, and we don't have to wait for any in-between frames.
139         // Also return any dropped frames.
140         if (drop || (it->mFence == NULL && it == mRenderQueue.begin())) {
141             // (unrendered) dropped frames have their mRenderTimeNs still set to -1
142             done.splice(done.end(), mRenderQueue, it++);
143         } else {
144             ++it;
145         }
146         if (foundFrame) {
147             break;
148         }
149     }
150 
151     return done;
152 }
153 
untrackFrame(const FrameRenderTracker::Info * info,ssize_t index)154 void FrameRenderTracker::untrackFrame(const FrameRenderTracker::Info *info, ssize_t index) {
155     if (info == NULL && index == SSIZE_MAX) {
156         // nothing to do
157         return;
158     }
159 
160     for (std::list<Info>::iterator it = mRenderQueue.begin();
161             it != mRenderQueue.end(); ) {
162         if (&*it == info) {
163             mRenderQueue.erase(it++);
164         } else {
165             if (it->mIndex > index) {
166                 --(it->mIndex);
167             }
168             ++it;
169         }
170     }
171 }
172 
dumpRenderQueue() const173 void FrameRenderTracker::dumpRenderQueue() const {
174     ALOGI("[%s] Render Queue: (last render time: %lldns)",
175             mComponentName.c_str(), (long long)mLastRenderTimeNs);
176     for (std::list<Info>::const_iterator it = mRenderQueue.cbegin();
177             it != mRenderQueue.cend(); ++it) {
178         if (it->mFence == NULL) {
179             ALOGI("  RENDERED: handle: %p, media time: %lldus, index: %zd, render time: %lldns",
180                     it->mGraphicBuffer == NULL ? NULL : it->mGraphicBuffer->handle,
181                     (long long)it->mMediaTimeUs, it->mIndex, (long long)it->mRenderTimeNs);
182         } else if (it->mIndex < 0) {
183             ALOGI("    QUEUED: handle: %p, media time: %lldus, fence: %s",
184                     it->mGraphicBuffer->handle, (long long)it->mMediaTimeUs,
185                     it->mFence->isValid() ? "YES" : "NO");
186         } else {
187             ALOGI("  DEQUEUED: handle: %p, media time: %lldus, index: %zd",
188                     it->mGraphicBuffer->handle, (long long)it->mMediaTimeUs, it->mIndex);
189         }
190     }
191 }
192 
193 }  // namespace android
194