发现835手机外接1080p@60摄像头时,帧率不稳定(burst)。现象是如果统计一千帧,帧率是60fps,但是如果打印两帧之间的间隔,发现有时候间隔是3毫秒,有时是9ms。这样导致UI处理不过来,而Android GraphicBuffer在queueBuffer时,最多只能缓存一帧,而丢弃前面的帧

status_t BufferQueueProducer::queueBuffer(int slot,
        const QueueBufferInput &input, QueueBufferOutput *output) {
    ATRACE_CALL();
    ATRACE_BUFFER_INDEX(slot);

    ................................................

    sp<IConsumerListener> frameAvailableListener;
    sp<IConsumerListener> frameReplacedListener;
    int callbackTicket = 0;
    uint64_t currentFrameNumber = 0;
    BufferItem item;
    { // Autolock scope
        Mutex::Autolock lock(mCore->mMutex);

        .........................................

        output->bufferReplaced = false;
        if (mCore->mQueue.empty()) {
            // When the queue is empty, we can ignore mDequeueBufferCannotBlock
            // and simply queue this buffer
            mCore->mQueue.push_back(item);
            frameAvailableListener = mCore->mConsumerListener;
        } else {
            // When the queue is not empty, we need to look at the last buffer
            // in the queue to see if we need to replace it
            const BufferItem& last = mCore->mQueue.itemAt(
                    mCore->mQueue.size() - 1);
            if (last.mIsDroppable) {

                if (!last.mIsStale) {
                    mSlots[last.mSlot].mBufferState.freeQueued();

                    // After leaving shared buffer mode, the shared buffer will
                    // still be around. Mark it as no longer shared if this
                    // operation causes it to be free.
                    if (!mCore->mSharedBufferMode &&
                            mSlots[last.mSlot].mBufferState.isFree()) {
                        mSlots[last.mSlot].mBufferState.mShared = false;
                    }
                    // Don't put the shared buffer on the free list.
                    if (!mSlots[last.mSlot].mBufferState.isShared()) {
                        mCore->mActiveBuffers.erase(last.mSlot);
                        mCore->mFreeBuffers.push_back(last.mSlot);
                        output->bufferReplaced = true;
                    }
                }

                // Overwrite the droppable buffer with the incoming one
                mCore->mQueue.editItemAt(mCore->mQueue.size() - 1) = item;
                frameReplacedListener = mCore->mConsumerListener;
            } else {
                mCore->mQueue.push_back(item);
                frameAvailableListener = mCore->mConsumerListener;
            }
        }

        。。。。。。。。。。。。。。。。。。。。。
        VALIDATE_CONSISTENCY();
    } // Autolock scope

    。。。。。。。。。。。。。。。。

    return NO_ERROR;
}

 为了避免这个问题,只好增加延时,在一个队列中先缓存3帧,然后每隔16.66毫秒,送出一帧。这样保证了帧率,但是增加了50毫秒的延时。

Linux提供了一个高精度的定时器timer_create,代码如下。一秒钟打印60次

#include <time.h>
#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>

static int times = 1;
unsigned int lastTime;

unsigned int RealTimeInMilliseconds() {
    struct timespec spec;

    clock_gettime(CLOCK_REALTIME, &spec);

    return spec.tv_sec * 1000 + spec.tv_nsec / 1000000;
}

//Thread function to be invoked when the periodic timer expires
void sighler (union sigval val)
{
    unsigned int now = RealTimeInMilliseconds();
    printf("Time Diff: %u  Count: %d\n", now - lastTime, times++);
    lastTime = now;
}
int main()
{
    int Ret;

    pthread_attr_t attr;
    pthread_attr_init( &attr );

    struct sched_param parm;
    parm.sched_priority = 0;
    pthread_attr_setschedparam(&attr, &parm);

    struct sigevent sig;
    sig.sigev_notify = SIGEV_THREAD;
    sig.sigev_notify_function = sighler;
    sig.sigev_value.sival_int =20;
    sig.sigev_notify_attributes = &attr;

    //create a new timer.
    timer_t timerid;
    Ret = timer_create(CLOCK_REALTIME, &sig, &timerid);
    if (Ret == 0)
    {
        struct itimerspec in, out;
        in.it_value.tv_sec = 0;
        in.it_value.tv_nsec = 16666666;
        in.it_interval.tv_sec = 0;
        in.it_interval.tv_nsec = 16666666;
        //issue the periodic timer request here.
        lastTime = RealTimeInMilliseconds();
        Ret = timer_settime(timerid, 0, &in, &out);
        if(Ret == 0)
            sleep(1);
        else
            printf("timer_settime() failed with %d\n", errno);
        //delete the timer.
        timer_delete(timerid);
    }
    else
        printf("timer_create() failed with %d\n", errno);
    return Ret;
}

打印输出如下:

Time Diff: 17  Count: 1
Time Diff: 16  Count: 2
Time Diff: 17  Count: 3
Time Diff: 17  Count: 4
Time Diff: 16  Count: 5
Time Diff: 17  Count: 6
Time Diff: 17  Count: 7
Time Diff: 16  Count: 8
Time Diff: 17  Count: 9
Time Diff: 17  Count: 10
Time Diff: 16  Count: 11
Time Diff: 17  Count: 12
Time Diff: 17  Count: 13
Time Diff: 16  Count: 14
Time Diff: 17  Count: 15
Time Diff: 17  Count: 16
Time Diff: 16  Count: 17
Time Diff: 17  Count: 18
Time Diff: 17  Count: 19
Time Diff: 16  Count: 20
Time Diff: 17  Count: 21
Time Diff: 17  Count: 22
Time Diff: 16  Count: 23
Time Diff: 17  Count: 24
Time Diff: 17  Count: 25
Time Diff: 16  Count: 26
Time Diff: 17  Count: 27
Time Diff: 17  Count: 28
Time Diff: 16  Count: 29
Time Diff: 17  Count: 30
Time Diff: 17  Count: 31
Time Diff: 16  Count: 32
Time Diff: 17  Count: 33
Time Diff: 17  Count: 34
Time Diff: 16  Count: 35
Time Diff: 17  Count: 36
Time Diff: 17  Count: 37
Time Diff: 16  Count: 38
Time Diff: 17  Count: 39
Time Diff: 17  Count: 40
Time Diff: 16  Count: 41
Time Diff: 17  Count: 42
Time Diff: 17  Count: 43
Time Diff: 16  Count: 44
Time Diff: 17  Count: 45
Time Diff: 17  Count: 46
Time Diff: 16  Count: 47
Time Diff: 17  Count: 48
Time Diff: 17  Count: 49
Time Diff: 16  Count: 50
Time Diff: 17  Count: 51
Time Diff: 17  Count: 52
Time Diff: 16  Count: 53
Time Diff: 17  Count: 54
Time Diff: 17  Count: 55
Time Diff: 16  Count: 56
Time Diff: 17  Count: 57
Time Diff: 17  Count: 58
Time Diff: 16  Count: 59
Time Diff: 17  Count: 60

 


版权声明:本文为wanghuasn911原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/wanghuasn911/article/details/87340603