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 28 FrameRenderTracker::FrameRenderTracker() 29 : mLastRenderTimeNs(-1), 30 mComponentName("unknown component") { 31 } 32 33 FrameRenderTracker::~FrameRenderTracker() { 34 } 35 36 void FrameRenderTracker::setComponentName(const AString &componentName) { 37 mComponentName = componentName; 38 } 39 40 void FrameRenderTracker::clear(nsecs_t lastRenderTimeNs) { 41 mRenderQueue.clear(); 42 mLastRenderTimeNs = lastRenderTimeNs; 43 } 44 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 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 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 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 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 173 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