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
26namespace android {
27
28FrameRenderTracker::FrameRenderTracker()
29    : mLastRenderTimeNs(-1),
30      mComponentName("unknown component") {
31}
32
33FrameRenderTracker::~FrameRenderTracker() {
34}
35
36void FrameRenderTracker::setComponentName(const AString &componentName) {
37    mComponentName = componentName;
38}
39
40void FrameRenderTracker::clear(nsecs_t lastRenderTimeNs) {
41    mRenderQueue.clear();
42    mLastRenderTimeNs = lastRenderTimeNs;
43}
44
45void FrameRenderTracker::onFrameQueued(
46        int64_t mediaTimeUs, const sp<GraphicBuffer> &graphicBuffer, const sp<Fence> &fence) {
47    mRenderQueue.emplace_back(mediaTimeUs, graphicBuffer, fence);
48}
49
50FrameRenderTracker::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
89status_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
111std::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
154void 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
173void 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