Home | History | Annotate | Download | only in libstagefright
      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