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