GraphicBufferSource.cpp revision db43b34c3428e480f8c4c66e7e88f4001f37f91e
1/*
2 * Copyright (C) 2013 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#include <inttypes.h>
18
19#define LOG_TAG "GraphicBufferSource"
20//#define LOG_NDEBUG 0
21#include <utils/Log.h>
22
23#include "GraphicBufferSource.h"
24
25#include <OMX_Core.h>
26#include <media/stagefright/foundation/ADebug.h>
27#include <media/stagefright/foundation/AMessage.h>
28
29#include <media/hardware/MetadataBufferType.h>
30#include <ui/GraphicBuffer.h>
31
32namespace android {
33
34static const bool EXTRA_CHECK = true;
35
36
37GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance,
38        uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bufferCount) :
39    mInitCheck(UNKNOWN_ERROR),
40    mNodeInstance(nodeInstance),
41    mExecuting(false),
42    mSuspended(false),
43    mNumFramesAvailable(0),
44    mEndOfStream(false),
45    mEndOfStreamSent(false),
46    mRepeatAfterUs(-1ll),
47    mRepeatLastFrameGeneration(0),
48    mLatestSubmittedBufferId(-1),
49    mLatestSubmittedBufferFrameNum(0),
50    mLatestSubmittedBufferUseCount(0),
51    mRepeatBufferDeferred(false) {
52
53    ALOGV("GraphicBufferSource w=%u h=%u c=%u",
54            bufferWidth, bufferHeight, bufferCount);
55
56    if (bufferWidth == 0 || bufferHeight == 0) {
57        ALOGE("Invalid dimensions %ux%u", bufferWidth, bufferHeight);
58        mInitCheck = BAD_VALUE;
59        return;
60    }
61
62    String8 name("GraphicBufferSource");
63
64    mBufferQueue = new BufferQueue();
65    mBufferQueue->setConsumerName(name);
66    mBufferQueue->setDefaultBufferSize(bufferWidth, bufferHeight);
67    mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER |
68            GRALLOC_USAGE_HW_TEXTURE);
69
70    mInitCheck = mBufferQueue->setMaxAcquiredBufferCount(bufferCount);
71    if (mInitCheck != NO_ERROR) {
72        ALOGE("Unable to set BQ max acquired buffer count to %u: %d",
73                bufferCount, mInitCheck);
74        return;
75    }
76
77    // Note that we can't create an sp<...>(this) in a ctor that will not keep a
78    // reference once the ctor ends, as that would cause the refcount of 'this'
79    // dropping to 0 at the end of the ctor.  Since all we need is a wp<...>
80    // that's what we create.
81    wp<BufferQueue::ConsumerListener> listener = static_cast<BufferQueue::ConsumerListener*>(this);
82    sp<BufferQueue::ProxyConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener);
83
84    mInitCheck = mBufferQueue->consumerConnect(proxy, false);
85    if (mInitCheck != NO_ERROR) {
86        ALOGE("Error connecting to BufferQueue: %s (%d)",
87                strerror(-mInitCheck), mInitCheck);
88        return;
89    }
90
91    CHECK(mInitCheck == NO_ERROR);
92}
93
94GraphicBufferSource::~GraphicBufferSource() {
95    ALOGV("~GraphicBufferSource");
96    if (mBufferQueue != NULL) {
97        status_t err = mBufferQueue->consumerDisconnect();
98        if (err != NO_ERROR) {
99            ALOGW("consumerDisconnect failed: %d", err);
100        }
101    }
102}
103
104void GraphicBufferSource::omxExecuting() {
105    Mutex::Autolock autoLock(mMutex);
106    ALOGV("--> executing; avail=%d, codec vec size=%zd",
107            mNumFramesAvailable, mCodecBuffers.size());
108    CHECK(!mExecuting);
109    mExecuting = true;
110
111    // Start by loading up as many buffers as possible.  We want to do this,
112    // rather than just submit the first buffer, to avoid a degenerate case:
113    // if all BQ buffers arrive before we start executing, and we only submit
114    // one here, the other BQ buffers will just sit until we get notified
115    // that the codec buffer has been released.  We'd then acquire and
116    // submit a single additional buffer, repeatedly, never using more than
117    // one codec buffer simultaneously.  (We could instead try to submit
118    // all BQ buffers whenever any codec buffer is freed, but if we get the
119    // initial conditions right that will never be useful.)
120    while (mNumFramesAvailable) {
121        if (!fillCodecBuffer_l()) {
122            ALOGV("stop load with frames available (codecAvail=%d)",
123                    isCodecBufferAvailable_l());
124            break;
125        }
126    }
127
128    ALOGV("done loading initial frames, avail=%d", mNumFramesAvailable);
129
130    // If EOS has already been signaled, and there are no more frames to
131    // submit, try to send EOS now as well.
132    if (mEndOfStream && mNumFramesAvailable == 0) {
133        submitEndOfInputStream_l();
134    }
135
136    if (mRepeatAfterUs > 0ll && mLooper == NULL) {
137        mReflector = new AHandlerReflector<GraphicBufferSource>(this);
138
139        mLooper = new ALooper;
140        mLooper->registerHandler(mReflector);
141        mLooper->start();
142
143        if (mLatestSubmittedBufferId >= 0) {
144            sp<AMessage> msg =
145                new AMessage(kWhatRepeatLastFrame, mReflector->id());
146
147            msg->setInt32("generation", ++mRepeatLastFrameGeneration);
148            msg->post(mRepeatAfterUs);
149        }
150    }
151}
152
153void GraphicBufferSource::omxIdle() {
154    ALOGV("omxIdle");
155
156    Mutex::Autolock autoLock(mMutex);
157
158    if (mExecuting) {
159        // We are only interested in the transition from executing->idle,
160        // not loaded->idle.
161        mExecuting = false;
162    }
163}
164
165void GraphicBufferSource::omxLoaded(){
166    Mutex::Autolock autoLock(mMutex);
167    if (!mExecuting) {
168        // This can happen if something failed very early.
169        ALOGW("Dropped back down to Loaded without Executing");
170    }
171
172    if (mLooper != NULL) {
173        mLooper->unregisterHandler(mReflector->id());
174        mReflector.clear();
175
176        mLooper->stop();
177        mLooper.clear();
178    }
179
180    ALOGV("--> loaded; avail=%d eos=%d eosSent=%d",
181            mNumFramesAvailable, mEndOfStream, mEndOfStreamSent);
182
183    // Codec is no longer executing.  Discard all codec-related state.
184    mCodecBuffers.clear();
185    // TODO: scan mCodecBuffers to verify that all mGraphicBuffer entries
186    //       are null; complain if not
187
188    mExecuting = false;
189}
190
191void GraphicBufferSource::addCodecBuffer(OMX_BUFFERHEADERTYPE* header) {
192    Mutex::Autolock autoLock(mMutex);
193
194    if (mExecuting) {
195        // This should never happen -- buffers can only be allocated when
196        // transitioning from "loaded" to "idle".
197        ALOGE("addCodecBuffer: buffer added while executing");
198        return;
199    }
200
201    ALOGV("addCodecBuffer h=%p size=%" PRIu32 " p=%p",
202            header, header->nAllocLen, header->pBuffer);
203    CodecBuffer codecBuffer;
204    codecBuffer.mHeader = header;
205    mCodecBuffers.add(codecBuffer);
206}
207
208void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) {
209    Mutex::Autolock autoLock(mMutex);
210
211    if (!mExecuting) {
212        return;
213    }
214
215    int cbi = findMatchingCodecBuffer_l(header);
216    if (cbi < 0) {
217        // This should never happen.
218        ALOGE("codecBufferEmptied: buffer not recognized (h=%p)", header);
219        return;
220    }
221
222    ALOGV("codecBufferEmptied h=%p size=%" PRIu32 " filled=%" PRIu32 " p=%p",
223            header, header->nAllocLen, header->nFilledLen,
224            header->pBuffer);
225    CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi));
226
227    // header->nFilledLen may not be the original value, so we can't compare
228    // that to zero to see of this was the EOS buffer.  Instead we just
229    // see if the GraphicBuffer reference was null, which should only ever
230    // happen for EOS.
231    if (codecBuffer.mGraphicBuffer == NULL) {
232        if (!(mEndOfStream && mEndOfStreamSent)) {
233            // This can happen when broken code sends us the same buffer
234            // twice in a row.
235            ALOGE("ERROR: codecBufferEmptied on non-EOS null buffer "
236                    "(buffer emptied twice?)");
237        }
238        // No GraphicBuffer to deal with, no additional input or output is
239        // expected, so just return.
240        return;
241    }
242
243    if (EXTRA_CHECK) {
244        // Pull the graphic buffer handle back out of the buffer, and confirm
245        // that it matches expectations.
246        OMX_U8* data = header->pBuffer;
247        buffer_handle_t bufferHandle;
248        memcpy(&bufferHandle, data + 4, sizeof(buffer_handle_t));
249        if (bufferHandle != codecBuffer.mGraphicBuffer->handle) {
250            // should never happen
251            ALOGE("codecBufferEmptied: buffer's handle is %p, expected %p",
252                    bufferHandle, codecBuffer.mGraphicBuffer->handle);
253            CHECK(!"codecBufferEmptied: mismatched buffer");
254        }
255    }
256
257    // Find matching entry in our cached copy of the BufferQueue slots.
258    // If we find a match, release that slot.  If we don't, the BufferQueue
259    // has dropped that GraphicBuffer, and there's nothing for us to release.
260    int id = codecBuffer.mBuf;
261    if (mBufferSlot[id] != NULL &&
262        mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) {
263        ALOGV("cbi %d matches bq slot %d, handle=%p",
264                cbi, id, mBufferSlot[id]->handle);
265
266        if (id == mLatestSubmittedBufferId) {
267            CHECK_GT(mLatestSubmittedBufferUseCount--, 0);
268        } else {
269            mBufferQueue->releaseBuffer(id, codecBuffer.mFrameNumber,
270                    EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
271        }
272    } else {
273        ALOGV("codecBufferEmptied: no match for emptied buffer in cbi %d",
274                cbi);
275    }
276
277    // Mark the codec buffer as available by clearing the GraphicBuffer ref.
278    codecBuffer.mGraphicBuffer = NULL;
279
280    if (mNumFramesAvailable) {
281        // Fill this codec buffer.
282        CHECK(!mEndOfStreamSent);
283        ALOGV("buffer freed, %d frames avail (eos=%d)",
284                mNumFramesAvailable, mEndOfStream);
285        fillCodecBuffer_l();
286    } else if (mEndOfStream) {
287        // No frames available, but EOS is pending, so use this buffer to
288        // send that.
289        ALOGV("buffer freed, EOS pending");
290        submitEndOfInputStream_l();
291    } else if (mRepeatBufferDeferred) {
292        bool success = repeatLatestSubmittedBuffer_l();
293        if (success) {
294            ALOGV("deferred repeatLatestSubmittedBuffer_l SUCCESS");
295        } else {
296            ALOGV("deferred repeatLatestSubmittedBuffer_l FAILURE");
297        }
298        mRepeatBufferDeferred = false;
299    }
300
301    return;
302}
303
304void GraphicBufferSource::suspend(bool suspend) {
305    Mutex::Autolock autoLock(mMutex);
306
307    if (suspend) {
308        mSuspended = true;
309
310        while (mNumFramesAvailable > 0) {
311            BufferQueue::BufferItem item;
312            status_t err = mBufferQueue->acquireBuffer(&item, 0);
313
314            if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
315                // shouldn't happen.
316                ALOGW("suspend: frame was not available");
317                break;
318            } else if (err != OK) {
319                ALOGW("suspend: acquireBuffer returned err=%d", err);
320                break;
321            }
322
323            --mNumFramesAvailable;
324
325            mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber,
326                    EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence);
327        }
328        return;
329    }
330
331    mSuspended = false;
332
333    if (mExecuting && mNumFramesAvailable == 0 && mRepeatBufferDeferred) {
334        if (repeatLatestSubmittedBuffer_l()) {
335            ALOGV("suspend/deferred repeatLatestSubmittedBuffer_l SUCCESS");
336
337            mRepeatBufferDeferred = false;
338        } else {
339            ALOGV("suspend/deferred repeatLatestSubmittedBuffer_l FAILURE");
340        }
341    }
342}
343
344bool GraphicBufferSource::fillCodecBuffer_l() {
345    CHECK(mExecuting && mNumFramesAvailable > 0);
346
347    if (mSuspended) {
348        return false;
349    }
350
351    int cbi = findAvailableCodecBuffer_l();
352    if (cbi < 0) {
353        // No buffers available, bail.
354        ALOGV("fillCodecBuffer_l: no codec buffers, avail now %d",
355                mNumFramesAvailable);
356        return false;
357    }
358
359    ALOGV("fillCodecBuffer_l: acquiring buffer, avail=%d",
360            mNumFramesAvailable);
361    BufferQueue::BufferItem item;
362    status_t err = mBufferQueue->acquireBuffer(&item, 0);
363    if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
364        // shouldn't happen
365        ALOGW("fillCodecBuffer_l: frame was not available");
366        return false;
367    } else if (err != OK) {
368        // now what? fake end-of-stream?
369        ALOGW("fillCodecBuffer_l: acquireBuffer returned err=%d", err);
370        return false;
371    }
372
373    mNumFramesAvailable--;
374
375    // Wait for it to become available.
376    err = item.mFence->waitForever("GraphicBufferSource::fillCodecBuffer_l");
377    if (err != OK) {
378        ALOGW("failed to wait for buffer fence: %d", err);
379        // keep going
380    }
381
382    // If this is the first time we're seeing this buffer, add it to our
383    // slot table.
384    if (item.mGraphicBuffer != NULL) {
385        ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mBuf);
386        mBufferSlot[item.mBuf] = item.mGraphicBuffer;
387    }
388
389    err = submitBuffer_l(item, cbi);
390    if (err != OK) {
391        ALOGV("submitBuffer_l failed, releasing bq buf %d", item.mBuf);
392        mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber,
393                EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
394    } else {
395        ALOGV("buffer submitted (bq %d, cbi %d)", item.mBuf, cbi);
396        setLatestSubmittedBuffer_l(item);
397    }
398
399    return true;
400}
401
402bool GraphicBufferSource::repeatLatestSubmittedBuffer_l() {
403    CHECK(mExecuting && mNumFramesAvailable == 0);
404
405    if (mLatestSubmittedBufferId < 0 || mSuspended) {
406        return false;
407    }
408    if (mBufferSlot[mLatestSubmittedBufferId] == NULL) {
409        // This can happen if the remote side disconnects, causing
410        // onBuffersReleased() to NULL out our copy of the slots.  The
411        // buffer is gone, so we have nothing to show.
412        //
413        // To be on the safe side we try to release the buffer.
414        ALOGD("repeatLatestSubmittedBuffer_l: slot was NULL");
415        mBufferQueue->releaseBuffer(
416                mLatestSubmittedBufferId,
417                mLatestSubmittedBufferFrameNum,
418                EGL_NO_DISPLAY,
419                EGL_NO_SYNC_KHR,
420                Fence::NO_FENCE);
421        mLatestSubmittedBufferId = -1;
422        mLatestSubmittedBufferFrameNum = 0;
423        return false;
424    }
425
426    int cbi = findAvailableCodecBuffer_l();
427    if (cbi < 0) {
428        // No buffers available, bail.
429        ALOGV("repeatLatestSubmittedBuffer_l: no codec buffers.");
430        return false;
431    }
432
433    BufferQueue::BufferItem item;
434    item.mBuf = mLatestSubmittedBufferId;
435    item.mFrameNumber = mLatestSubmittedBufferFrameNum;
436
437    status_t err = submitBuffer_l(item, cbi);
438
439    if (err != OK) {
440        return false;
441    }
442
443    ++mLatestSubmittedBufferUseCount;
444
445    return true;
446}
447
448void GraphicBufferSource::setLatestSubmittedBuffer_l(
449        const BufferQueue::BufferItem &item) {
450    ALOGV("setLatestSubmittedBuffer_l");
451
452    if (mLatestSubmittedBufferId >= 0) {
453        if (mLatestSubmittedBufferUseCount == 0) {
454            mBufferQueue->releaseBuffer(
455                    mLatestSubmittedBufferId,
456                    mLatestSubmittedBufferFrameNum,
457                    EGL_NO_DISPLAY,
458                    EGL_NO_SYNC_KHR,
459                    Fence::NO_FENCE);
460        }
461    }
462
463    mLatestSubmittedBufferId = item.mBuf;
464    mLatestSubmittedBufferFrameNum = item.mFrameNumber;
465    mLatestSubmittedBufferUseCount = 1;
466    mRepeatBufferDeferred = false;
467
468    if (mReflector != NULL) {
469        sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector->id());
470        msg->setInt32("generation", ++mRepeatLastFrameGeneration);
471        msg->post(mRepeatAfterUs);
472    }
473}
474
475status_t GraphicBufferSource::signalEndOfInputStream() {
476    Mutex::Autolock autoLock(mMutex);
477    ALOGV("signalEndOfInputStream: exec=%d avail=%d eos=%d",
478            mExecuting, mNumFramesAvailable, mEndOfStream);
479
480    if (mEndOfStream) {
481        ALOGE("EOS was already signaled");
482        return INVALID_OPERATION;
483    }
484
485    // Set the end-of-stream flag.  If no frames are pending from the
486    // BufferQueue, and a codec buffer is available, and we're executing,
487    // we initiate the EOS from here.  Otherwise, we'll let
488    // codecBufferEmptied() (or omxExecuting) do it.
489    //
490    // Note: if there are no pending frames and all codec buffers are
491    // available, we *must* submit the EOS from here or we'll just
492    // stall since no future events are expected.
493    mEndOfStream = true;
494
495    if (mExecuting && mNumFramesAvailable == 0) {
496        submitEndOfInputStream_l();
497    }
498
499    return OK;
500}
501
502status_t GraphicBufferSource::submitBuffer_l(
503        const BufferQueue::BufferItem &item, int cbi) {
504    ALOGV("submitBuffer_l cbi=%d", cbi);
505    CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi));
506    codecBuffer.mGraphicBuffer = mBufferSlot[item.mBuf];
507    codecBuffer.mBuf = item.mBuf;
508    codecBuffer.mFrameNumber = item.mFrameNumber;
509
510    OMX_BUFFERHEADERTYPE* header = codecBuffer.mHeader;
511    CHECK(header->nAllocLen >= 4 + sizeof(buffer_handle_t));
512    OMX_U8* data = header->pBuffer;
513    const OMX_U32 type = kMetadataBufferTypeGrallocSource;
514    buffer_handle_t handle = codecBuffer.mGraphicBuffer->handle;
515    memcpy(data, &type, 4);
516    memcpy(data + 4, &handle, sizeof(buffer_handle_t));
517
518    status_t err = mNodeInstance->emptyDirectBuffer(header, 0,
519            4 + sizeof(buffer_handle_t), OMX_BUFFERFLAG_ENDOFFRAME,
520            item.mTimestamp / 1000);
521    if (err != OK) {
522        ALOGW("WARNING: emptyDirectBuffer failed: 0x%x", err);
523        codecBuffer.mGraphicBuffer = NULL;
524        return err;
525    }
526
527    ALOGV("emptyDirectBuffer succeeded, h=%p p=%p bufhandle=%p",
528            header, header->pBuffer, handle);
529    return OK;
530}
531
532void GraphicBufferSource::submitEndOfInputStream_l() {
533    CHECK(mEndOfStream);
534    if (mEndOfStreamSent) {
535        ALOGV("EOS already sent");
536        return;
537    }
538
539    int cbi = findAvailableCodecBuffer_l();
540    if (cbi < 0) {
541        ALOGV("submitEndOfInputStream_l: no codec buffers available");
542        return;
543    }
544
545    // We reject any additional incoming graphic buffers, so there's no need
546    // to stick a placeholder into codecBuffer.mGraphicBuffer to mark it as
547    // in-use.
548    CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi));
549
550    OMX_BUFFERHEADERTYPE* header = codecBuffer.mHeader;
551    if (EXTRA_CHECK) {
552        // Guard against implementations that don't check nFilledLen.
553        size_t fillLen = 4 + sizeof(buffer_handle_t);
554        CHECK(header->nAllocLen >= fillLen);
555        OMX_U8* data = header->pBuffer;
556        memset(data, 0xcd, fillLen);
557    }
558
559    uint64_t timestamp = 0; // does this matter?
560
561    status_t err = mNodeInstance->emptyDirectBuffer(header, /*offset*/ 0,
562            /*length*/ 0, OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS,
563            timestamp);
564    if (err != OK) {
565        ALOGW("emptyDirectBuffer EOS failed: 0x%x", err);
566    } else {
567        ALOGV("submitEndOfInputStream_l: buffer submitted, header=%p cbi=%d",
568                header, cbi);
569        mEndOfStreamSent = true;
570    }
571}
572
573int GraphicBufferSource::findAvailableCodecBuffer_l() {
574    CHECK(mCodecBuffers.size() > 0);
575
576    for (int i = (int)mCodecBuffers.size() - 1; i>= 0; --i) {
577        if (mCodecBuffers[i].mGraphicBuffer == NULL) {
578            return i;
579        }
580    }
581    return -1;
582}
583
584int GraphicBufferSource::findMatchingCodecBuffer_l(
585        const OMX_BUFFERHEADERTYPE* header) {
586    for (int i = (int)mCodecBuffers.size() - 1; i>= 0; --i) {
587        if (mCodecBuffers[i].mHeader == header) {
588            return i;
589        }
590    }
591    return -1;
592}
593
594// BufferQueue::ConsumerListener callback
595void GraphicBufferSource::onFrameAvailable() {
596    Mutex::Autolock autoLock(mMutex);
597
598    ALOGV("onFrameAvailable exec=%d avail=%d",
599            mExecuting, mNumFramesAvailable);
600
601    if (mEndOfStream || mSuspended) {
602        if (mEndOfStream) {
603            // This should only be possible if a new buffer was queued after
604            // EOS was signaled, i.e. the app is misbehaving.
605
606            ALOGW("onFrameAvailable: EOS is set, ignoring frame");
607        } else {
608            ALOGV("onFrameAvailable: suspended, ignoring frame");
609        }
610
611        BufferQueue::BufferItem item;
612        status_t err = mBufferQueue->acquireBuffer(&item, 0);
613        if (err == OK) {
614            mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber,
615                    EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence);
616        }
617        return;
618    }
619
620    mNumFramesAvailable++;
621
622    mRepeatBufferDeferred = false;
623    ++mRepeatLastFrameGeneration;
624
625    if (mExecuting) {
626        fillCodecBuffer_l();
627    }
628}
629
630// BufferQueue::ConsumerListener callback
631void GraphicBufferSource::onBuffersReleased() {
632    Mutex::Autolock lock(mMutex);
633
634    uint32_t slotMask;
635    if (mBufferQueue->getReleasedBuffers(&slotMask) != NO_ERROR) {
636        ALOGW("onBuffersReleased: unable to get released buffer set");
637        slotMask = 0xffffffff;
638    }
639
640    ALOGV("onBuffersReleased: 0x%08x", slotMask);
641
642    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
643        if ((slotMask & 0x01) != 0) {
644            mBufferSlot[i] = NULL;
645        }
646        slotMask >>= 1;
647    }
648}
649
650status_t GraphicBufferSource::setRepeatPreviousFrameDelayUs(
651        int64_t repeatAfterUs) {
652    Mutex::Autolock autoLock(mMutex);
653
654    if (mExecuting || repeatAfterUs <= 0ll) {
655        return INVALID_OPERATION;
656    }
657
658    mRepeatAfterUs = repeatAfterUs;
659
660    return OK;
661}
662
663void GraphicBufferSource::onMessageReceived(const sp<AMessage> &msg) {
664    switch (msg->what()) {
665        case kWhatRepeatLastFrame:
666        {
667            Mutex::Autolock autoLock(mMutex);
668
669            int32_t generation;
670            CHECK(msg->findInt32("generation", &generation));
671
672            if (generation != mRepeatLastFrameGeneration) {
673                // stale
674                break;
675            }
676
677            if (!mExecuting || mNumFramesAvailable > 0) {
678                break;
679            }
680
681            bool success = repeatLatestSubmittedBuffer_l();
682
683            if (success) {
684                ALOGV("repeatLatestSubmittedBuffer_l SUCCESS");
685            } else {
686                ALOGV("repeatLatestSubmittedBuffer_l FAILURE");
687                mRepeatBufferDeferred = true;
688            }
689            break;
690        }
691
692        default:
693            TRESPASS();
694    }
695}
696
697}  // namespace android
698