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