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