GraphicBufferSource.cpp revision cf49a51ff59c3cd228d178d23252ac0d39d5a893
1f2038fb01417bcf7698b87a5dfaa4a861539618aerik.corry@gmail.com/* 23484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org * Copyright (C) 2013 The Android Open Source Project 33484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org * 4a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org * Licensed under the Apache License, Version 2.0 (the "License"); 5196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org * you may not use this file except in compliance with the License. 6a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org * You may obtain a copy of the License at 7e2a8937454723a720c81acc3f9e4162b18999b43machenbach@chromium.org * 8196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org * http://www.apache.org/licenses/LICENSE-2.0 9196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org * 10196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org * Unless required by applicable law or agreed to in writing, software 11196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org * distributed under the License is distributed on an "AS IS" BASIS, 12a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org * See the License for the specific language governing permissions and 144b0feeef5d01dbc2948080b4f69daa37e1083461machenbach@chromium.org * limitations under the License. 15a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org */ 164b0feeef5d01dbc2948080b4f69daa37e1083461machenbach@chromium.org 17fa0c3c69b9d632e5730bdd9c745c375beef5e54dmachenbach@chromium.org#define LOG_TAG "GraphicBufferSource" 184b0feeef5d01dbc2948080b4f69daa37e1083461machenbach@chromium.org//#define LOG_NDEBUG 0 19a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org#include <utils/Log.h> 204b0feeef5d01dbc2948080b4f69daa37e1083461machenbach@chromium.org 217516f05132429850aa326421ed3e25f23b4c071blrn@chromium.org#include "GraphicBufferSource.h" 224b0feeef5d01dbc2948080b4f69daa37e1083461machenbach@chromium.org 2312e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org#include <OMX_Core.h> 2412e05e8fde625d746b998a15049e8487c43a3b17machenbach@chromium.org#include <media/stagefright/foundation/ADebug.h> 25864abd7677f434b5aef191e3388e71cd4dd1e6c8machenbach@chromium.org#include <media/stagefright/foundation/AMessage.h> 264b0feeef5d01dbc2948080b4f69daa37e1083461machenbach@chromium.org 27a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org#include <media/hardware/MetadataBufferType.h> 28a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org#include <ui/GraphicBuffer.h> 29a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 30a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgnamespace android { 31975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.org 32975b940441085887fc02bebf8877d5ec97e1e06cmachenbach@chromium.orgstatic const bool EXTRA_CHECK = true; 33a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 34a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 35a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgGraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, 36a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bufferCount) : 37a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mInitCheck(UNKNOWN_ERROR), 38a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mNodeInstance(nodeInstance), 39a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mExecuting(false), 40a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mSuspended(false), 41a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mNumFramesAvailable(0), 42a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mEndOfStream(false), 43a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mEndOfStreamSent(false), 4409d7ab5aba54ebac170eac755664c45eefb0be7dulan@chromium.org mRepeatAfterUs(-1ll), 45e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org mMaxTimestampGapUs(-1ll), 46750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org mPrevOriginalTimeUs(-1ll), 4709d7ab5aba54ebac170eac755664c45eefb0be7dulan@chromium.org mPrevModifiedTimeUs(-1ll), 4809d7ab5aba54ebac170eac755664c45eefb0be7dulan@chromium.org mRepeatLastFrameGeneration(0), 4909d7ab5aba54ebac170eac755664c45eefb0be7dulan@chromium.org mRepeatLastFrameTimestamp(-1ll), 507304bcac06a6a63b9f3dcebac2eeceada87ca146vegorov@chromium.org mLatestSubmittedBufferId(-1), 517304bcac06a6a63b9f3dcebac2eeceada87ca146vegorov@chromium.org mLatestSubmittedBufferFrameNum(0), 527304bcac06a6a63b9f3dcebac2eeceada87ca146vegorov@chromium.org mLatestSubmittedBufferUseCount(0), 537304bcac06a6a63b9f3dcebac2eeceada87ca146vegorov@chromium.org mRepeatBufferDeferred(false) { 547304bcac06a6a63b9f3dcebac2eeceada87ca146vegorov@chromium.org 557304bcac06a6a63b9f3dcebac2eeceada87ca146vegorov@chromium.org ALOGV("GraphicBufferSource w=%u h=%u c=%u", 567304bcac06a6a63b9f3dcebac2eeceada87ca146vegorov@chromium.org bufferWidth, bufferHeight, bufferCount); 577304bcac06a6a63b9f3dcebac2eeceada87ca146vegorov@chromium.org 587304bcac06a6a63b9f3dcebac2eeceada87ca146vegorov@chromium.org if (bufferWidth == 0 || bufferHeight == 0) { 597304bcac06a6a63b9f3dcebac2eeceada87ca146vegorov@chromium.org ALOGE("Invalid dimensions %ux%u", bufferWidth, bufferHeight); 601510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org mInitCheck = BAD_VALUE; 61e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org return; 62fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org } 63fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org 64fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org String8 name("GraphicBufferSource"); 65fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org 66fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org mBufferQueue = new BufferQueue(); 67fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org mBufferQueue->setConsumerName(name); 68fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org mBufferQueue->setDefaultBufferSize(bufferWidth, bufferHeight); 69b752d4061aaeb7d6a6ec368607871789d54b0207dslomov@chromium.org mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER | 70fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org GRALLOC_USAGE_HW_TEXTURE); 71fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org 72fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org mInitCheck = mBufferQueue->setMaxAcquiredBufferCount(bufferCount); 73fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org if (mInitCheck != NO_ERROR) { 74fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org ALOGE("Unable to set BQ max acquired buffer count to %u: %d", 75fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org bufferCount, mInitCheck); 76fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org return; 77fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org } 78fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org 79fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org // Note that we can't create an sp<...>(this) in a ctor that will not keep a 80fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org // reference once the ctor ends, as that would cause the refcount of 'this' 81fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org // dropping to 0 at the end of the ctor. Since all we need is a wp<...> 82fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org // that's what we create. 83fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org wp<BufferQueue::ConsumerListener> listener = static_cast<BufferQueue::ConsumerListener*>(this); 84fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org sp<BufferQueue::ProxyConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener); 85fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org 86fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org mInitCheck = mBufferQueue->consumerConnect(proxy, false); 87fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org if (mInitCheck != NO_ERROR) { 88e31286d471eb2e656a1809383fa16b76053dd673machenbach@chromium.org ALOGE("Error connecting to BufferQueue: %s (%d)", 89fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org strerror(-mInitCheck), mInitCheck); 90fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org return; 91fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org } 92fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org 93fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org CHECK(mInitCheck == NO_ERROR); 94a53e8e03bcb23716d1025de362626f90f00da892svenpanne@chromium.org} 95fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org 96fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.orgGraphicBufferSource::~GraphicBufferSource() { 97fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org ALOGV("~GraphicBufferSource"); 98fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org if (mBufferQueue != NULL) { 99a53e8e03bcb23716d1025de362626f90f00da892svenpanne@chromium.org status_t err = mBufferQueue->consumerDisconnect(); 100fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org if (err != NO_ERROR) { 101fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org ALOGW("consumerDisconnect failed: %d", err); 102fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org } 103fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org } 104fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org} 105fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org 1061510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgvoid GraphicBufferSource::omxExecuting() { 107fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org Mutex::Autolock autoLock(mMutex); 108fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org ALOGV("--> executing; avail=%d, codec vec size=%zd", 109fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org mNumFramesAvailable, mCodecBuffers.size()); 1101510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org CHECK(!mExecuting); 111d4be0f0c0edfc0a0b46e745055c3dc497c0ffcb5verwaest@chromium.org mExecuting = true; 112d4be0f0c0edfc0a0b46e745055c3dc497c0ffcb5verwaest@chromium.org 113d4be0f0c0edfc0a0b46e745055c3dc497c0ffcb5verwaest@chromium.org // Start by loading up as many buffers as possible. We want to do this, 114fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org // rather than just submit the first buffer, to avoid a degenerate case: 115fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org // if all BQ buffers arrive before we start executing, and we only submit 116fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org // one here, the other BQ buffers will just sit until we get notified 117fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org // that the codec buffer has been released. We'd then acquire and 118fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org // submit a single additional buffer, repeatedly, never using more than 119fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org // one codec buffer simultaneously. (We could instead try to submit 120fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org // all BQ buffers whenever any codec buffer is freed, but if we get the 1211510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org // initial conditions right that will never be useful.) 122fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org while (mNumFramesAvailable) { 123fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org if (!fillCodecBuffer_l()) { 124fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org ALOGV("stop load with frames available (codecAvail=%d)", 125fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org isCodecBufferAvailable_l()); 126fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org break; 127fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org } 128fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org } 129fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org 130fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.org ALOGV("done loading initial frames, avail=%d", mNumFramesAvailable); 131fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org 132fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org // If EOS has already been signaled, and there are no more frames to 133fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org // submit, try to send EOS now as well. 134fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org if (mEndOfStream && mNumFramesAvailable == 0) { 135fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org submitEndOfInputStream_l(); 136fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org } 137fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org 138fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org if (mRepeatAfterUs > 0ll && mLooper == NULL) { 139fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org mReflector = new AHandlerReflector<GraphicBufferSource>(this); 140fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org 141fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org mLooper = new ALooper; 142fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org mLooper->registerHandler(mReflector); 143fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org mLooper->start(); 144fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org 145fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org if (mLatestSubmittedBufferId >= 0) { 146fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org sp<AMessage> msg = 147fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org new AMessage(kWhatRepeatLastFrame, mReflector->id()); 148fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org 149fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org msg->setInt32("generation", ++mRepeatLastFrameGeneration); 150fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org msg->post(mRepeatAfterUs); 151fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org } 152a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 1535f0c45f2cacb31d36a8f80c31f17bda7751a3644ager@chromium.org} 154a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 155a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgvoid GraphicBufferSource::omxIdle() { 156a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org ALOGV("omxIdle"); 157fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org 158fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org Mutex::Autolock autoLock(mMutex); 159fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org 160fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org if (mExecuting) { 1615f0c45f2cacb31d36a8f80c31f17bda7751a3644ager@chromium.org // We are only interested in the transition from executing->idle, 162fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org // not loaded->idle. 163a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mExecuting = false; 164a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 165a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org} 166fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org 167fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.orgvoid GraphicBufferSource::omxLoaded(){ 168fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org Mutex::Autolock autoLock(mMutex); 169fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org if (!mExecuting) { 1705f0c45f2cacb31d36a8f80c31f17bda7751a3644ager@chromium.org // This can happen if something failed very early. 171fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org ALOGW("Dropped back down to Loaded without Executing"); 1725f0c45f2cacb31d36a8f80c31f17bda7751a3644ager@chromium.org } 173a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 174a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (mLooper != NULL) { 175fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org mLooper->unregisterHandler(mReflector->id()); 176fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org mReflector.clear(); 177fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org 178fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org mLooper->stop(); 1795f0c45f2cacb31d36a8f80c31f17bda7751a3644ager@chromium.org mLooper.clear(); 180fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org } 181a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 182a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org ALOGV("--> loaded; avail=%d eos=%d eosSent=%d", 183a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mNumFramesAvailable, mEndOfStream, mEndOfStreamSent); 184a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 185a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org // Codec is no longer executing. Discard all codec-related state. 186a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mCodecBuffers.clear(); 187a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org // TODO: scan mCodecBuffers to verify that all mGraphicBuffer entries 188a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org // are null; complain if not 189a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 190a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mExecuting = false; 191a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org} 192a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 193a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgvoid GraphicBufferSource::addCodecBuffer(OMX_BUFFERHEADERTYPE* header) { 194a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org Mutex::Autolock autoLock(mMutex); 195a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 196a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (mExecuting) { 1975f0c45f2cacb31d36a8f80c31f17bda7751a3644ager@chromium.org // This should never happen -- buffers can only be allocated when 198a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org // transitioning from "loaded" to "idle". 1995f0c45f2cacb31d36a8f80c31f17bda7751a3644ager@chromium.org ALOGE("addCodecBuffer: buffer added while executing"); 200fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org return; 201fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org } 202fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org 203c3b37129d6387b2db313f9100256d2d5f60dd9a8jkummerow@chromium.org ALOGV("addCodecBuffer h=%p size=%lu p=%p", 204a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org header, header->nAllocLen, header->pBuffer); 205c3b37129d6387b2db313f9100256d2d5f60dd9a8jkummerow@chromium.org CodecBuffer codecBuffer; 206a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org codecBuffer.mHeader = header; 207a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mCodecBuffers.add(codecBuffer); 208a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org} 2098f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org 2108f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.orgvoid GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) { 2118f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org Mutex::Autolock autoLock(mMutex); 2128f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org 2138f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org if (!mExecuting) { 2148f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org return; 2158f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org } 2168f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org 2178f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org int cbi = findMatchingCodecBuffer_l(header); 2188f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org if (cbi < 0) { 2198f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org // This should never happen. 2208f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org ALOGE("codecBufferEmptied: buffer not recognized (h=%p)", header); 2218f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org return; 2228f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org } 2238f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org 2248f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org ALOGV("codecBufferEmptied h=%p size=%lu filled=%lu p=%p", 225471f2f1d24adb4bad1edc3bf0ee35092486de187mstarzinger@chromium.org header, header->nAllocLen, header->nFilledLen, 226471f2f1d24adb4bad1edc3bf0ee35092486de187mstarzinger@chromium.org header->pBuffer); 227471f2f1d24adb4bad1edc3bf0ee35092486de187mstarzinger@chromium.org CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi)); 228471f2f1d24adb4bad1edc3bf0ee35092486de187mstarzinger@chromium.org 229471f2f1d24adb4bad1edc3bf0ee35092486de187mstarzinger@chromium.org // header->nFilledLen may not be the original value, so we can't compare 230471f2f1d24adb4bad1edc3bf0ee35092486de187mstarzinger@chromium.org // that to zero to see of this was the EOS buffer. Instead we just 231471f2f1d24adb4bad1edc3bf0ee35092486de187mstarzinger@chromium.org // see if the GraphicBuffer reference was null, which should only ever 232471f2f1d24adb4bad1edc3bf0ee35092486de187mstarzinger@chromium.org // happen for EOS. 233471f2f1d24adb4bad1edc3bf0ee35092486de187mstarzinger@chromium.org if (codecBuffer.mGraphicBuffer == NULL) { 234471f2f1d24adb4bad1edc3bf0ee35092486de187mstarzinger@chromium.org if (!(mEndOfStream && mEndOfStreamSent)) { 235471f2f1d24adb4bad1edc3bf0ee35092486de187mstarzinger@chromium.org // This can happen when broken code sends us the same buffer 236471f2f1d24adb4bad1edc3bf0ee35092486de187mstarzinger@chromium.org // twice in a row. 237471f2f1d24adb4bad1edc3bf0ee35092486de187mstarzinger@chromium.org ALOGE("ERROR: codecBufferEmptied on non-EOS null buffer " 238471f2f1d24adb4bad1edc3bf0ee35092486de187mstarzinger@chromium.org "(buffer emptied twice?)"); 2398f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org } 2408f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org // No GraphicBuffer to deal with, no additional input or output is 2418f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org // expected, so just return. 2428f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org return; 2438f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org } 2448f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org 2458f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org if (EXTRA_CHECK) { 2468f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org // Pull the graphic buffer handle back out of the buffer, and confirm 2478f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org // that it matches expectations. 2488f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org OMX_U8* data = header->pBuffer; 2498f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org buffer_handle_t bufferHandle; 2508f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org memcpy(&bufferHandle, data + 4, sizeof(buffer_handle_t)); 2518f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org if (bufferHandle != codecBuffer.mGraphicBuffer->handle) { 2528f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org // should never happen 2538f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org ALOGE("codecBufferEmptied: buffer's handle is %p, expected %p", 2548f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org bufferHandle, codecBuffer.mGraphicBuffer->handle); 2558f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org CHECK(!"codecBufferEmptied: mismatched buffer"); 2568f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org } 2578f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org } 2588f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org 2598f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org // Find matching entry in our cached copy of the BufferQueue slots. 2608f806e8b8f108ca2c8899c5d31861ef1273dcd4akarlklose@chromium.org // If we find a match, release that slot. If we don't, the BufferQueue 261fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org // has dropped that GraphicBuffer, and there's nothing for us to release. 2625f0c45f2cacb31d36a8f80c31f17bda7751a3644ager@chromium.org int id = codecBuffer.mBuf; 263fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org if (mBufferSlot[id] != NULL && 264fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) { 265a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org ALOGV("cbi %d matches bq slot %d, handle=%p", 266c3b37129d6387b2db313f9100256d2d5f60dd9a8jkummerow@chromium.org cbi, id, mBufferSlot[id]->handle); 267a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 268c3b37129d6387b2db313f9100256d2d5f60dd9a8jkummerow@chromium.org if (id == mLatestSubmittedBufferId) { 2695f0c45f2cacb31d36a8f80c31f17bda7751a3644ager@chromium.org CHECK_GT(mLatestSubmittedBufferUseCount--, 0); 270a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } else { 271a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mBufferQueue->releaseBuffer(id, codecBuffer.mFrameNumber, 272a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); 273fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org } 2745f0c45f2cacb31d36a8f80c31f17bda7751a3644ager@chromium.org } else { 275fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org ALOGV("codecBufferEmptied: no match for emptied buffer in cbi %d", 276fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org cbi); 277a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 278c3b37129d6387b2db313f9100256d2d5f60dd9a8jkummerow@chromium.org 279a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org // Mark the codec buffer as available by clearing the GraphicBuffer ref. 280c3b37129d6387b2db313f9100256d2d5f60dd9a8jkummerow@chromium.org codecBuffer.mGraphicBuffer = NULL; 2815f0c45f2cacb31d36a8f80c31f17bda7751a3644ager@chromium.org 282a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (mNumFramesAvailable) { 283a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org // Fill this codec buffer. 284a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org CHECK(!mEndOfStreamSent); 285a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org ALOGV("buffer freed, %d frames avail (eos=%d)", 286a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mNumFramesAvailable, mEndOfStream); 287a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org fillCodecBuffer_l(); 288a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } else if (mEndOfStream) { 289a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org // No frames available, but EOS is pending, so use this buffer to 290a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org // send that. 291a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org ALOGV("buffer freed, EOS pending"); 292a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org submitEndOfInputStream_l(); 293a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } else if (mRepeatBufferDeferred) { 294c3b37129d6387b2db313f9100256d2d5f60dd9a8jkummerow@chromium.org bool success = repeatLatestSubmittedBuffer_l(); 295a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (success) { 296e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org ALOGV("deferred repeatLatestSubmittedBuffer_l SUCCESS"); 297a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } else { 298c3b37129d6387b2db313f9100256d2d5f60dd9a8jkummerow@chromium.org ALOGV("deferred repeatLatestSubmittedBuffer_l FAILURE"); 299a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 300a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mRepeatBufferDeferred = false; 301fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org } 302a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 303fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org return; 304fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org} 305fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.org 306fb732b17922ea75830be4db6b80534c4827d8a55jkummerow@chromium.orgvoid GraphicBufferSource::codecBufferFilled(OMX_BUFFERHEADERTYPE* header) { 307a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org Mutex::Autolock autoLock(mMutex); 308a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 309c3b37129d6387b2db313f9100256d2d5f60dd9a8jkummerow@chromium.org if (mMaxTimestampGapUs > 0ll 310a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org && !(header->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) { 311c3b37129d6387b2db313f9100256d2d5f60dd9a8jkummerow@chromium.org ssize_t index = mOriginalTimeUs.indexOfKey(header->nTimeStamp); 312a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (index >= 0) { 313a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org ALOGV("OUT timestamp: %lld -> %lld", 314a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org header->nTimeStamp, mOriginalTimeUs[index]); 315a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org header->nTimeStamp = mOriginalTimeUs[index]; 3163847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com mOriginalTimeUs.removeItemsAt(index); 3173847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com } else { 3183847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com // giving up the effort as encoder doesn't appear to preserve pts 3193847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com ALOGW("giving up limiting timestamp gap (pts = %lld)", 3203847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com header->nTimeStamp); 321ab30bb83bf3dae0053739c57b1db9ad13c1f9e3ayangguo@chromium.org mMaxTimestampGapUs = -1ll; 322ab30bb83bf3dae0053739c57b1db9ad13c1f9e3ayangguo@chromium.org } 323ab30bb83bf3dae0053739c57b1db9ad13c1f9e3ayangguo@chromium.org if (mOriginalTimeUs.size() > BufferQueue::NUM_BUFFER_SLOTS) { 324ab30bb83bf3dae0053739c57b1db9ad13c1f9e3ayangguo@chromium.org // something terribly wrong must have happened, giving up... 325ab30bb83bf3dae0053739c57b1db9ad13c1f9e3ayangguo@chromium.org ALOGE("mOriginalTimeUs has too many entries (%d)", 326ab30bb83bf3dae0053739c57b1db9ad13c1f9e3ayangguo@chromium.org mOriginalTimeUs.size()); 327ab30bb83bf3dae0053739c57b1db9ad13c1f9e3ayangguo@chromium.org mMaxTimestampGapUs = -1ll; 328ab30bb83bf3dae0053739c57b1db9ad13c1f9e3ayangguo@chromium.org } 329ab30bb83bf3dae0053739c57b1db9ad13c1f9e3ayangguo@chromium.org } 330c00ec2b94bc5505fa81f81daefd956f5a8776a09danno@chromium.org} 331812308e1488cd8261e4dbbda1d8022642d522b9bulan@chromium.org 332fb37721ea34922d8758d5cb26ae465aaf241e6b6yangguo@chromium.orgvoid GraphicBufferSource::suspend(bool suspend) { 333812308e1488cd8261e4dbbda1d8022642d522b9bulan@chromium.org Mutex::Autolock autoLock(mMutex); 334812308e1488cd8261e4dbbda1d8022642d522b9bulan@chromium.org 335812308e1488cd8261e4dbbda1d8022642d522b9bulan@chromium.org if (suspend) { 336812308e1488cd8261e4dbbda1d8022642d522b9bulan@chromium.org mSuspended = true; 337812308e1488cd8261e4dbbda1d8022642d522b9bulan@chromium.org 338812308e1488cd8261e4dbbda1d8022642d522b9bulan@chromium.org while (mNumFramesAvailable > 0) { 339662436e7b124b3535773535c671c53db322070b5verwaest@chromium.org BufferQueue::BufferItem item; 340662436e7b124b3535773535c671c53db322070b5verwaest@chromium.org status_t err = mBufferQueue->acquireBuffer(&item, 0); 341662436e7b124b3535773535c671c53db322070b5verwaest@chromium.org 342662436e7b124b3535773535c671c53db322070b5verwaest@chromium.org if (err == BufferQueue::NO_BUFFER_AVAILABLE) { 343662436e7b124b3535773535c671c53db322070b5verwaest@chromium.org // shouldn't happen. 344662436e7b124b3535773535c671c53db322070b5verwaest@chromium.org ALOGW("suspend: frame was not available"); 345662436e7b124b3535773535c671c53db322070b5verwaest@chromium.org break; 346662436e7b124b3535773535c671c53db322070b5verwaest@chromium.org } else if (err != OK) { 347662436e7b124b3535773535c671c53db322070b5verwaest@chromium.org ALOGW("suspend: acquireBuffer returned err=%d", err); 348662436e7b124b3535773535c671c53db322070b5verwaest@chromium.org break; 349662436e7b124b3535773535c671c53db322070b5verwaest@chromium.org } 350662436e7b124b3535773535c671c53db322070b5verwaest@chromium.org 351c00ec2b94bc5505fa81f81daefd956f5a8776a09danno@chromium.org --mNumFramesAvailable; 352837a67edd9afdbfe1b59482b41693f59c48846ffulan@chromium.org 353837a67edd9afdbfe1b59482b41693f59c48846ffulan@chromium.org mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, 354837a67edd9afdbfe1b59482b41693f59c48846ffulan@chromium.org EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence); 355837a67edd9afdbfe1b59482b41693f59c48846ffulan@chromium.org } 356837a67edd9afdbfe1b59482b41693f59c48846ffulan@chromium.org return; 357837a67edd9afdbfe1b59482b41693f59c48846ffulan@chromium.org } 358837a67edd9afdbfe1b59482b41693f59c48846ffulan@chromium.org 359837a67edd9afdbfe1b59482b41693f59c48846ffulan@chromium.org mSuspended = false; 360837a67edd9afdbfe1b59482b41693f59c48846ffulan@chromium.org 361837a67edd9afdbfe1b59482b41693f59c48846ffulan@chromium.org if (mExecuting && mNumFramesAvailable == 0 && mRepeatBufferDeferred) { 3623847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com if (repeatLatestSubmittedBuffer_l()) { 3633847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com ALOGV("suspend/deferred repeatLatestSubmittedBuffer_l SUCCESS"); 3643847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com 3653847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com mRepeatBufferDeferred = false; 3663847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com } else { 3673847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com ALOGV("suspend/deferred repeatLatestSubmittedBuffer_l FAILURE"); 3683847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com } 3693847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com } 3703847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com} 3713847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com 3723847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.combool GraphicBufferSource::fillCodecBuffer_l() { 373a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org CHECK(mExecuting && mNumFramesAvailable > 0); 374a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 375a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (mSuspended) { 376a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org return false; 3773847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com } 3783847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com 3793847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com int cbi = findAvailableCodecBuffer_l(); 3803847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com if (cbi < 0) { 381a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org // No buffers available, bail. 382a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org ALOGV("fillCodecBuffer_l: no codec buffers, avail now %d", 383a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mNumFramesAvailable); 3843847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com return false; 3853847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com } 3863847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com 3873847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com ALOGV("fillCodecBuffer_l: acquiring buffer, avail=%d", 3883847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com mNumFramesAvailable); 3893847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com BufferQueue::BufferItem item; 3903847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com status_t err = mBufferQueue->acquireBuffer(&item, 0); 3913847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com if (err == BufferQueue::NO_BUFFER_AVAILABLE) { 3923847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com // shouldn't happen 3933847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com ALOGW("fillCodecBuffer_l: frame was not available"); 3943847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com return false; 395a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } else if (err != OK) { 3963847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com // now what? fake end-of-stream? 3973847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com ALOGW("fillCodecBuffer_l: acquireBuffer returned err=%d", err); 3983847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com return false; 399a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 4003847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com 4013847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com mNumFramesAvailable--; 4023847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com 4033847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com // Wait for it to become available. 4043847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com err = item.mFence->waitForever("GraphicBufferSource::fillCodecBuffer_l"); 4057028c05c1c71b9d5c5fe1bca01f2461d17a2dda7mmassi@chromium.org if (err != OK) { 4067028c05c1c71b9d5c5fe1bca01f2461d17a2dda7mmassi@chromium.org ALOGW("failed to wait for buffer fence: %d", err); 4073847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com // keep going 4083847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com } 4093847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com 4103847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com // If this is the first time we're seeing this buffer, add it to our 4113847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com // slot table. 412a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (item.mGraphicBuffer != NULL) { 413a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mBuf); 414a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mBufferSlot[item.mBuf] = item.mGraphicBuffer; 4153a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org } 416a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 417a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org err = submitBuffer_l(item, cbi); 418a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (err != OK) { 41931b1277ec3b8cd17acb01c66d85a456159072157kmillikin@chromium.org ALOGV("submitBuffer_l failed, releasing bq buf %d", item.mBuf); 420a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, 421a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); 422a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } else { 423a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org ALOGV("buffer submitted (bq %d, cbi %d)", item.mBuf, cbi); 424a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org setLatestSubmittedBuffer_l(item); 425e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org } 426a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 427a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org return true; 428a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org} 429a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 4303a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.orgbool GraphicBufferSource::repeatLatestSubmittedBuffer_l() { 431a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org CHECK(mExecuting && mNumFramesAvailable == 0); 432a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 433a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (mLatestSubmittedBufferId < 0 || mSuspended) { 434a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org return false; 435a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 436a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (mBufferSlot[mLatestSubmittedBufferId] == NULL) { 437a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org // This can happen if the remote side disconnects, causing 438a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org // onBuffersReleased() to NULL out our copy of the slots. The 439a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org // buffer is gone, so we have nothing to show. 440dcebac0f4c6c0da579b7cc91a0cbba8f3c820c8dricow@chromium.org // 441dcebac0f4c6c0da579b7cc91a0cbba8f3c820c8dricow@chromium.org // To be on the safe side we try to release the buffer. 442dcebac0f4c6c0da579b7cc91a0cbba8f3c820c8dricow@chromium.org ALOGD("repeatLatestSubmittedBuffer_l: slot was NULL"); 443dcebac0f4c6c0da579b7cc91a0cbba8f3c820c8dricow@chromium.org mBufferQueue->releaseBuffer( 444dcebac0f4c6c0da579b7cc91a0cbba8f3c820c8dricow@chromium.org mLatestSubmittedBufferId, 445dcebac0f4c6c0da579b7cc91a0cbba8f3c820c8dricow@chromium.org mLatestSubmittedBufferFrameNum, 446dcebac0f4c6c0da579b7cc91a0cbba8f3c820c8dricow@chromium.org EGL_NO_DISPLAY, 447dcebac0f4c6c0da579b7cc91a0cbba8f3c820c8dricow@chromium.org EGL_NO_SYNC_KHR, 448dcebac0f4c6c0da579b7cc91a0cbba8f3c820c8dricow@chromium.org Fence::NO_FENCE); 449dcebac0f4c6c0da579b7cc91a0cbba8f3c820c8dricow@chromium.org mLatestSubmittedBufferId = -1; 450dcebac0f4c6c0da579b7cc91a0cbba8f3c820c8dricow@chromium.org mLatestSubmittedBufferFrameNum = 0; 451d8a3a149cb9dac7437e264a2fe50f680418c3a45jkummerow@chromium.org return false; 452d8a3a149cb9dac7437e264a2fe50f680418c3a45jkummerow@chromium.org } 453d8a3a149cb9dac7437e264a2fe50f680418c3a45jkummerow@chromium.org 454d8a3a149cb9dac7437e264a2fe50f680418c3a45jkummerow@chromium.org int cbi = findAvailableCodecBuffer_l(); 455d8a3a149cb9dac7437e264a2fe50f680418c3a45jkummerow@chromium.org if (cbi < 0) { 4562ebef182c49d59eba907b120c3c2a50808bd1f12machenbach@chromium.org // No buffers available, bail. 457255043f8054e713a64509c707cfabadd42344683machenbach@chromium.org ALOGV("repeatLatestSubmittedBuffer_l: no codec buffers."); 458d8a3a149cb9dac7437e264a2fe50f680418c3a45jkummerow@chromium.org return false; 459d8a3a149cb9dac7437e264a2fe50f680418c3a45jkummerow@chromium.org } 460d8a3a149cb9dac7437e264a2fe50f680418c3a45jkummerow@chromium.org 461d8a3a149cb9dac7437e264a2fe50f680418c3a45jkummerow@chromium.org BufferQueue::BufferItem item; 462d8a3a149cb9dac7437e264a2fe50f680418c3a45jkummerow@chromium.org item.mBuf = mLatestSubmittedBufferId; 463d8a3a149cb9dac7437e264a2fe50f680418c3a45jkummerow@chromium.org item.mFrameNumber = mLatestSubmittedBufferFrameNum; 4647c3372bc426136cb79479c1b59d1770f5528882ahpayer@chromium.org item.mTimestamp = mRepeatLastFrameTimestamp; 4659af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org 4667c3372bc426136cb79479c1b59d1770f5528882ahpayer@chromium.org status_t err = submitBuffer_l(item, cbi); 4677c3372bc426136cb79479c1b59d1770f5528882ahpayer@chromium.org 4687c3372bc426136cb79479c1b59d1770f5528882ahpayer@chromium.org if (err != OK) { 4697c3372bc426136cb79479c1b59d1770f5528882ahpayer@chromium.org return false; 4709af454f6b1c6a921ac79ba0b9a979c73adb2ca1emachenbach@chromium.org } 4717c3372bc426136cb79479c1b59d1770f5528882ahpayer@chromium.org 4727c3372bc426136cb79479c1b59d1770f5528882ahpayer@chromium.org ++mLatestSubmittedBufferUseCount; 4737c3372bc426136cb79479c1b59d1770f5528882ahpayer@chromium.org 474b228be01a466e0ba4d8389148671d196b2081f76mstarzinger@chromium.org /* repeat last frame up to kRepeatLastFrameCount times. 475b228be01a466e0ba4d8389148671d196b2081f76mstarzinger@chromium.org * in case of static scene, a single repeat might not get rid of encoder 476b228be01a466e0ba4d8389148671d196b2081f76mstarzinger@chromium.org * ghosting completely, refresh a couple more times to get better quality 477b228be01a466e0ba4d8389148671d196b2081f76mstarzinger@chromium.org */ 478b228be01a466e0ba4d8389148671d196b2081f76mstarzinger@chromium.org if (--mRepeatLastFrameCount > 0) { 479a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000; 480a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 481a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (mReflector != NULL) { 482a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector->id()); 483a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org msg->setInt32("generation", ++mRepeatLastFrameGeneration); 484a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org msg->post(mRepeatAfterUs); 4853847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com } 4863847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com } 4873847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com 488ab30bb83bf3dae0053739c57b1db9ad13c1f9e3ayangguo@chromium.org return true; 489a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org} 490a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 491a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgvoid GraphicBufferSource::setLatestSubmittedBuffer_l( 492a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org const BufferQueue::BufferItem &item) { 4933847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com ALOGV("setLatestSubmittedBuffer_l"); 4943847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com 4953847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com if (mLatestSubmittedBufferId >= 0) { 4963847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com if (mLatestSubmittedBufferUseCount == 0) { 497e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org mBufferQueue->releaseBuffer( 4983847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com mLatestSubmittedBufferId, 4993847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com mLatestSubmittedBufferFrameNum, 5003847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com EGL_NO_DISPLAY, 5013847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com EGL_NO_SYNC_KHR, 502a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org Fence::NO_FENCE); 503a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 504a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 505a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 506ab30bb83bf3dae0053739c57b1db9ad13c1f9e3ayangguo@chromium.org mLatestSubmittedBufferId = item.mBuf; 507ab30bb83bf3dae0053739c57b1db9ad13c1f9e3ayangguo@chromium.org mLatestSubmittedBufferFrameNum = item.mFrameNumber; 508ab30bb83bf3dae0053739c57b1db9ad13c1f9e3ayangguo@chromium.org mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000; 509ab30bb83bf3dae0053739c57b1db9ad13c1f9e3ayangguo@chromium.org 510ab30bb83bf3dae0053739c57b1db9ad13c1f9e3ayangguo@chromium.org mLatestSubmittedBufferUseCount = 1; 5113847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com mRepeatBufferDeferred = false; 512ab30bb83bf3dae0053739c57b1db9ad13c1f9e3ayangguo@chromium.org mRepeatLastFrameCount = kRepeatLastFrameCount; 513efdb9d70bddd496ceb6a281dadcc065efbce37a1yangguo@chromium.org 514ab30bb83bf3dae0053739c57b1db9ad13c1f9e3ayangguo@chromium.org if (mReflector != NULL) { 515e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector->id()); 516ab30bb83bf3dae0053739c57b1db9ad13c1f9e3ayangguo@chromium.org msg->setInt32("generation", ++mRepeatLastFrameGeneration); 517ab30bb83bf3dae0053739c57b1db9ad13c1f9e3ayangguo@chromium.org msg->post(mRepeatAfterUs); 518a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 519a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org} 520a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 521a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgstatus_t GraphicBufferSource::signalEndOfInputStream() { 522a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org Mutex::Autolock autoLock(mMutex); 523e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org ALOGV("signalEndOfInputStream: exec=%d avail=%d eos=%d", 524a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mExecuting, mNumFramesAvailable, mEndOfStream); 525a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 526a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (mEndOfStream) { 527a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org ALOGE("EOS was already signaled"); 528a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org return INVALID_OPERATION; 529a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 530a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 531f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org // Set the end-of-stream flag. If no frames are pending from the 532d0bddc653152f270a27fe32d5d7b0f5c0fa3b00cmachenbach@chromium.org // BufferQueue, and a codec buffer is available, and we're executing, 533d0bddc653152f270a27fe32d5d7b0f5c0fa3b00cmachenbach@chromium.org // we initiate the EOS from here. Otherwise, we'll let 534f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org // codecBufferEmptied() (or omxExecuting) do it. 535f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org // 536f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org // Note: if there are no pending frames and all codec buffers are 537f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org // available, we *must* submit the EOS from here or we'll just 538f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org // stall since no future events are expected. 53983a4728861129dc263ded92157f3e6389f851f19karlklose@chromium.org mEndOfStream = true; 54083a4728861129dc263ded92157f3e6389f851f19karlklose@chromium.org 54183a4728861129dc263ded92157f3e6389f851f19karlklose@chromium.org if (mExecuting && mNumFramesAvailable == 0) { 542f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org submitEndOfInputStream_l(); 543f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org } 544f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org 545f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org return OK; 546f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org} 547f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org 54883a4728861129dc263ded92157f3e6389f851f19karlklose@chromium.orgint64_t GraphicBufferSource::getTimestamp(const BufferQueue::BufferItem &item) { 54983a4728861129dc263ded92157f3e6389f851f19karlklose@chromium.org int64_t timeUs = item.mTimestamp / 1000; 550f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org 551f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org if (mMaxTimestampGapUs > 0ll) { 552f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org /* Cap timestamp gap between adjacent frames to specified max 553f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org * 554f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org * In the scenario of cast mirroring, encoding could be suspended for 555f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org * prolonged periods. Limiting the pts gap to workaround the problem 55628faa982749c4aa9c090939453dea14bb118f613jkummerow@chromium.org * where encoder's rate control logic produces huge frames after a 55728faa982749c4aa9c090939453dea14bb118f613jkummerow@chromium.org * long period of suspension. 55883a4728861129dc263ded92157f3e6389f851f19karlklose@chromium.org */ 55983a4728861129dc263ded92157f3e6389f851f19karlklose@chromium.org 560f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org int64_t originalTimeUs = timeUs; 561a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (mPrevOriginalTimeUs >= 0ll) { 562a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (originalTimeUs < mPrevOriginalTimeUs) { 563a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org // Drop the frame if it's going backward in time. Bad timestamp 564d16d8531698e91e9c60a7db9e0ba3c3bb15aff20mvstanton@chromium.org // could disrupt encoder's rate control completely. 565d16d8531698e91e9c60a7db9e0ba3c3bb15aff20mvstanton@chromium.org ALOGW("Dropping frame that's going backward in time"); 566d16d8531698e91e9c60a7db9e0ba3c3bb15aff20mvstanton@chromium.org return -1; 567d16d8531698e91e9c60a7db9e0ba3c3bb15aff20mvstanton@chromium.org } 568d16d8531698e91e9c60a7db9e0ba3c3bb15aff20mvstanton@chromium.org int64_t timestampGapUs = originalTimeUs - mPrevOriginalTimeUs; 569a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org timeUs = (timestampGapUs < mMaxTimestampGapUs ? 570a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org timestampGapUs : mMaxTimestampGapUs) + mPrevModifiedTimeUs; 571a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 572a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mPrevOriginalTimeUs = originalTimeUs; 573a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mPrevModifiedTimeUs = timeUs; 574a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mOriginalTimeUs.add(timeUs, originalTimeUs); 575a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org ALOGV("IN timestamp: %lld -> %lld", originalTimeUs, timeUs); 576a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 577a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 578a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org return timeUs; 579a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org} 5803847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com 5813847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.comstatus_t GraphicBufferSource::submitBuffer_l( 5823847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com const BufferQueue::BufferItem &item, int cbi) { 5833847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com ALOGV("submitBuffer_l cbi=%d", cbi); 5843847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com 5853847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com int64_t timeUs = getTimestamp(item); 586a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (timeUs < 0ll) { 5873847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com return UNKNOWN_ERROR; 5887028c05c1c71b9d5c5fe1bca01f2461d17a2dda7mmassi@chromium.org } 5897028c05c1c71b9d5c5fe1bca01f2461d17a2dda7mmassi@chromium.org 5903847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi)); 5913847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com codecBuffer.mGraphicBuffer = mBufferSlot[item.mBuf]; 5923847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com codecBuffer.mBuf = item.mBuf; 5933847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com codecBuffer.mFrameNumber = item.mFrameNumber; 594a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 595a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org OMX_BUFFERHEADERTYPE* header = codecBuffer.mHeader; 596a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org CHECK(header->nAllocLen >= 4 + sizeof(buffer_handle_t)); 597a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org OMX_U8* data = header->pBuffer; 598812308e1488cd8261e4dbbda1d8022642d522b9bulan@chromium.org const OMX_U32 type = kMetadataBufferTypeGrallocSource; 599812308e1488cd8261e4dbbda1d8022642d522b9bulan@chromium.org buffer_handle_t handle = codecBuffer.mGraphicBuffer->handle; 600812308e1488cd8261e4dbbda1d8022642d522b9bulan@chromium.org memcpy(data, &type, 4); 601e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org memcpy(data + 4, &handle, sizeof(buffer_handle_t)); 602a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 603a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org status_t err = mNodeInstance->emptyDirectBuffer(header, 0, 604a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 4 + sizeof(buffer_handle_t), OMX_BUFFERFLAG_ENDOFFRAME, 605a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org timeUs); 606a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (err != OK) { 607a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org ALOGW("WARNING: emptyDirectBuffer failed: 0x%x", err); 608e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org codecBuffer.mGraphicBuffer = NULL; 609e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org return err; 610a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 611a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 612a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org ALOGV("emptyDirectBuffer succeeded, h=%p p=%p bufhandle=%p", 613a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org header, header->pBuffer, handle); 614812308e1488cd8261e4dbbda1d8022642d522b9bulan@chromium.org return OK; 615e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org} 616812308e1488cd8261e4dbbda1d8022642d522b9bulan@chromium.org 617e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.orgvoid GraphicBufferSource::submitEndOfInputStream_l() { 618a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org CHECK(mEndOfStream); 619a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (mEndOfStreamSent) { 620a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org ALOGV("EOS already sent"); 621f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org return; 622f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org } 623f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org 624f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org int cbi = findAvailableCodecBuffer_l(); 625f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org if (cbi < 0) { 626f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org ALOGV("submitEndOfInputStream_l: no codec buffers available"); 627f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org return; 628f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org } 629f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org 630f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org // We reject any additional incoming graphic buffers, so there's no need 631f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org // to stick a placeholder into codecBuffer.mGraphicBuffer to mark it as 632f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org // in-use. 633f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi)); 634f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org 635f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org OMX_BUFFERHEADERTYPE* header = codecBuffer.mHeader; 636f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org if (EXTRA_CHECK) { 637f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org // Guard against implementations that don't check nFilledLen. 63883a4728861129dc263ded92157f3e6389f851f19karlklose@chromium.org size_t fillLen = 4 + sizeof(buffer_handle_t); 639a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org CHECK(header->nAllocLen >= fillLen); 640a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org OMX_U8* data = header->pBuffer; 641f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org memset(data, 0xcd, fillLen); 6424e308cf00936c6e7bead43e5141a04e37b49b9b5jkummerow@chromium.org } 643f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org 644f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org uint64_t timestamp = 0; // does this matter? 6454e308cf00936c6e7bead43e5141a04e37b49b9b5jkummerow@chromium.org 646f15d0cdbef11a212e108432465f014a7d3c3aa12machenbach@chromium.org status_t err = mNodeInstance->emptyDirectBuffer(header, /*offset*/ 0, 647a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org /*length*/ 0, OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS, 648a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org timestamp); 649a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (err != OK) { 650a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org ALOGW("emptyDirectBuffer EOS failed: 0x%x", err); 651e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org } else { 652e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org ALOGV("submitEndOfInputStream_l: buffer submitted, header=%p cbi=%d", 653e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org header, cbi); 654e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org mEndOfStreamSent = true; 65549edbdf52640c88918f8e6638ab4965819eb1dfekmillikin@chromium.org } 65649edbdf52640c88918f8e6638ab4965819eb1dfekmillikin@chromium.org} 657e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org 65849edbdf52640c88918f8e6638ab4965819eb1dfekmillikin@chromium.orgint GraphicBufferSource::findAvailableCodecBuffer_l() { 65949edbdf52640c88918f8e6638ab4965819eb1dfekmillikin@chromium.org CHECK(mCodecBuffers.size() > 0); 66049edbdf52640c88918f8e6638ab4965819eb1dfekmillikin@chromium.org 66149edbdf52640c88918f8e6638ab4965819eb1dfekmillikin@chromium.org for (int i = (int)mCodecBuffers.size() - 1; i>= 0; --i) { 662a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (mCodecBuffers[i].mGraphicBuffer == NULL) { 663a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org return i; 664a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 665a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 666a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org return -1; 667e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org} 668e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org 669e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.orgint GraphicBufferSource::findMatchingCodecBuffer_l( 670e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org const OMX_BUFFERHEADERTYPE* header) { 671e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org for (int i = (int)mCodecBuffers.size() - 1; i>= 0; --i) { 672a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (mCodecBuffers[i].mHeader == header) { 673a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org return i; 674a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 675a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 676a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org return -1; 677a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org} 678f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org 67971f9fca5cfb606009211e0631f33b76cc2ddce3cbmeurer@chromium.org// BufferQueue::ConsumerListener callback 68071f9fca5cfb606009211e0631f33b76cc2ddce3cbmeurer@chromium.orgvoid GraphicBufferSource::onFrameAvailable() { 681a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org Mutex::Autolock autoLock(mMutex); 682a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 683a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org ALOGV("onFrameAvailable exec=%d avail=%d", 684a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mExecuting, mNumFramesAvailable); 685e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org 686e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org if (mEndOfStream || mSuspended) { 687e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org if (mEndOfStream) { 688a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org // This should only be possible if a new buffer was queued after 689a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org // EOS was signaled, i.e. the app is misbehaving. 690a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 691a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org ALOGW("onFrameAvailable: EOS is set, ignoring frame"); 692e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org } else { 693a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org ALOGV("onFrameAvailable: suspended, ignoring frame"); 694a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 695a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 696a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org BufferQueue::BufferItem item; 697a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org status_t err = mBufferQueue->acquireBuffer(&item, 0); 698a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (err == OK) { 699a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org // If this is the first time we're seeing this buffer, add it to our 700a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org // slot table. 701c3b37129d6387b2db313f9100256d2d5f60dd9a8jkummerow@chromium.org if (item.mGraphicBuffer != NULL) { 702e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mBuf); 703a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mBufferSlot[item.mBuf] = item.mGraphicBuffer; 704a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 705a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, 706a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence); 707a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 708a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org return; 709a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 710a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 711a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mNumFramesAvailable++; 71228faa982749c4aa9c090939453dea14bb118f613jkummerow@chromium.org 71328faa982749c4aa9c090939453dea14bb118f613jkummerow@chromium.org mRepeatBufferDeferred = false; 71428faa982749c4aa9c090939453dea14bb118f613jkummerow@chromium.org ++mRepeatLastFrameGeneration; 715f5a24546072ecdbbd6372c85c42157e01e913561titzer@chromium.org 71671f9fca5cfb606009211e0631f33b76cc2ddce3cbmeurer@chromium.org if (mExecuting) { 71771f9fca5cfb606009211e0631f33b76cc2ddce3cbmeurer@chromium.org fillCodecBuffer_l(); 718a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 719a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org} 720a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 72138de99aae2d4efc5796aa6935c1648447ec32fc8machenbach@chromium.org// BufferQueue::ConsumerListener callback 72238de99aae2d4efc5796aa6935c1648447ec32fc8machenbach@chromium.orgvoid GraphicBufferSource::onBuffersReleased() { 72338de99aae2d4efc5796aa6935c1648447ec32fc8machenbach@chromium.org Mutex::Autolock lock(mMutex); 72438de99aae2d4efc5796aa6935c1648447ec32fc8machenbach@chromium.org 72538de99aae2d4efc5796aa6935c1648447ec32fc8machenbach@chromium.org uint32_t slotMask; 72638de99aae2d4efc5796aa6935c1648447ec32fc8machenbach@chromium.org if (mBufferQueue->getReleasedBuffers(&slotMask) != NO_ERROR) { 72738de99aae2d4efc5796aa6935c1648447ec32fc8machenbach@chromium.org ALOGW("onBuffersReleased: unable to get released buffer set"); 72838de99aae2d4efc5796aa6935c1648447ec32fc8machenbach@chromium.org slotMask = 0xffffffff; 72938de99aae2d4efc5796aa6935c1648447ec32fc8machenbach@chromium.org } 73038de99aae2d4efc5796aa6935c1648447ec32fc8machenbach@chromium.org 73138de99aae2d4efc5796aa6935c1648447ec32fc8machenbach@chromium.org ALOGV("onBuffersReleased: 0x%08x", slotMask); 73238de99aae2d4efc5796aa6935c1648447ec32fc8machenbach@chromium.org 73338de99aae2d4efc5796aa6935c1648447ec32fc8machenbach@chromium.org for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { 73438de99aae2d4efc5796aa6935c1648447ec32fc8machenbach@chromium.org if ((slotMask & 0x01) != 0) { 73538de99aae2d4efc5796aa6935c1648447ec32fc8machenbach@chromium.org mBufferSlot[i] = NULL; 736a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 737378b34e3f8852e94739bb77a528278fe0e2bb532ager@chromium.org slotMask >>= 1; 738a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 739a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org} 740a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 741a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgstatus_t GraphicBufferSource::setRepeatPreviousFrameDelayUs( 742efdb9d70bddd496ceb6a281dadcc065efbce37a1yangguo@chromium.org int64_t repeatAfterUs) { 743a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org Mutex::Autolock autoLock(mMutex); 744a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 745a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (mExecuting || repeatAfterUs <= 0ll) { 746394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com return INVALID_OPERATION; 747a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 748a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 749394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com mRepeatAfterUs = repeatAfterUs; 750a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 751a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org return OK; 752e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org} 753a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 754a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgstatus_t GraphicBufferSource::setMaxTimestampGapUs(int64_t maxGapUs) { 755c53e10d01c5495df3896b9d318910b58688c6929kmillikin@chromium.org Mutex::Autolock autoLock(mMutex); 756c53e10d01c5495df3896b9d318910b58688c6929kmillikin@chromium.org 757e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org if (mExecuting || maxGapUs <= 0ll) { 758a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org return INVALID_OPERATION; 759a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 760a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 761a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org mMaxTimestampGapUs = maxGapUs; 762a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 763c3b37129d6387b2db313f9100256d2d5f60dd9a8jkummerow@chromium.org return OK; 764e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org} 765a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.orgvoid GraphicBufferSource::onMessageReceived(const sp<AMessage> &msg) { 766378b34e3f8852e94739bb77a528278fe0e2bb532ager@chromium.org switch (msg->what()) { 767378b34e3f8852e94739bb77a528278fe0e2bb532ager@chromium.org case kWhatRepeatLastFrame: 768378b34e3f8852e94739bb77a528278fe0e2bb532ager@chromium.org { 769378b34e3f8852e94739bb77a528278fe0e2bb532ager@chromium.org Mutex::Autolock autoLock(mMutex); 770378b34e3f8852e94739bb77a528278fe0e2bb532ager@chromium.org 7717c3372bc426136cb79479c1b59d1770f5528882ahpayer@chromium.org int32_t generation; 7727c3372bc426136cb79479c1b59d1770f5528882ahpayer@chromium.org CHECK(msg->findInt32("generation", &generation)); 7737c3372bc426136cb79479c1b59d1770f5528882ahpayer@chromium.org 7747c3372bc426136cb79479c1b59d1770f5528882ahpayer@chromium.org if (generation != mRepeatLastFrameGeneration) { 775e3c177a423baa3c30225c4e422b6f6c76d38b951machenbach@chromium.org // stale 7767c3372bc426136cb79479c1b59d1770f5528882ahpayer@chromium.org break; 7777c3372bc426136cb79479c1b59d1770f5528882ahpayer@chromium.org } 778a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org 779a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org if (!mExecuting || mNumFramesAvailable > 0) { 780a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org break; 781a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org } 782b5ed9300c59e8590c9dc588727b6564c244b0f5cmachenbach@chromium.org 783b5ed9300c59e8590c9dc588727b6564c244b0f5cmachenbach@chromium.org bool success = repeatLatestSubmittedBuffer_l(); 784b5ed9300c59e8590c9dc588727b6564c244b0f5cmachenbach@chromium.org 785255043f8054e713a64509c707cfabadd42344683machenbach@chromium.org if (success) { 786b5ed9300c59e8590c9dc588727b6564c244b0f5cmachenbach@chromium.org ALOGV("repeatLatestSubmittedBuffer_l SUCCESS"); 787255043f8054e713a64509c707cfabadd42344683machenbach@chromium.org } else { 788b5ed9300c59e8590c9dc588727b6564c244b0f5cmachenbach@chromium.org ALOGV("repeatLatestSubmittedBuffer_l FAILURE"); 789b5ed9300c59e8590c9dc588727b6564c244b0f5cmachenbach@chromium.org mRepeatBufferDeferred = true; 790b5ed9300c59e8590c9dc588727b6564c244b0f5cmachenbach@chromium.org } 791255043f8054e713a64509c707cfabadd42344683machenbach@chromium.org break; 792b5ed9300c59e8590c9dc588727b6564c244b0f5cmachenbach@chromium.org } 793255043f8054e713a64509c707cfabadd42344683machenbach@chromium.org 794255043f8054e713a64509c707cfabadd42344683machenbach@chromium.org default: 795255043f8054e713a64509c707cfabadd42344683machenbach@chromium.org TRESPASS(); 796255043f8054e713a64509c707cfabadd42344683machenbach@chromium.org } 797255043f8054e713a64509c707cfabadd42344683machenbach@chromium.org} 798b5ed9300c59e8590c9dc588727b6564c244b0f5cmachenbach@chromium.org 799255043f8054e713a64509c707cfabadd42344683machenbach@chromium.org} // namespace android 800255043f8054e713a64509c707cfabadd42344683machenbach@chromium.org