status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { ATRACE_CALL(); ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage); if ((w && !h) || (!w && h)) { ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h); return BAD_VALUE; } status_t returnFlags(OK); EGLDisplay dpy = EGL_NO_DISPLAY; EGLSyncKHR fence = EGL_NO_SYNC_KHR; { // Scope for the lock Mutex::Autolock lock(mMutex); if (format == 0) { format = mDefaultBufferFormat; } // turn on usage bits the consumer requested usage |= mConsumerUsageBits; int found = -1; int foundSync = -1; int dequeuedCount = 0; bool tryAgain = true; while (tryAgain) { if (mAbandoned) { ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!"); return NO_INIT; } // We need to wait for the FIFO to drain if the number of buffer // needs to change. // // The condition "number of buffers needs to change" is true if // - the client doesn't care about how many buffers there are // - AND the actual number of buffer is different from what was // set in the last setBufferCountServer() // - OR - // setBufferCountServer() was set to a value incompatible with // the synchronization mode (for instance because the sync mode // changed since) // // As long as this condition is true AND the FIFO is not empty, we // wait on mDequeueCondition. const int minBufferCountNeeded = mSynchronousMode ? mMinSyncBufferSlots : mMinAsyncBufferSlots; const bool numberOfBuffersNeedsToChange = !mClientBufferCount && ((mServerBufferCount != mBufferCount) || (mServerBufferCount < minBufferCountNeeded)); if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) { // wait for the FIFO to drain mDequeueCondition.wait(mMutex); // NOTE: we continue here because we need to reevaluate our // whole state (eg: we could be abandoned or disconnected) continue; } if (numberOfBuffersNeedsToChange) { // here we're guaranteed that mQueue is empty freeAllBuffersLocked(); mBufferCount = mServerBufferCount; if (mBufferCount < minBufferCountNeeded) mBufferCount = minBufferCountNeeded; mBufferHasBeenQueued = false; returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS; } // look for a free buffer to give to the client found = INVALID_BUFFER_SLOT; foundSync = INVALID_BUFFER_SLOT; dequeuedCount = 0; for (int i = 0; i < mBufferCount; i++) { const int state = mSlots[i].mBufferState; if (state == BufferSlot::DEQUEUED) { dequeuedCount++; } // this logic used to be if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) // but dequeuing the current buffer is disabled. if (false) { // This functionality has been temporarily removed so // BufferQueue and SurfaceTexture can be refactored into // separate objects } else { if (state == BufferSlot::FREE) { /* We return the oldest of the free buffers to avoid * stalling the producer if possible. This is because * the consumer may still have pending reads of the * buffers in flight. */ bool isOlder = mSlots[i].mFrameNumber < mSlots[found].mFrameNumber; if (found < 0 || isOlder) { foundSync = i; found = i; } } } } // clients are not allowed to dequeue more than one buffer // if they didn't set a buffer count. if (!mClientBufferCount && dequeuedCount) { ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without " "setting the buffer count"); return -EINVAL; } // See whether a buffer has been queued since the last // setBufferCount so we know whether to perform the // mMinUndequeuedBuffers check below. if (mBufferHasBeenQueued) { // make sure the client is not trying to dequeue more buffers // than allowed. const int avail = mBufferCount - (dequeuedCount+1); if (avail < (mMinUndequeuedBuffers-int(mSynchronousMode))) { ST_LOGE("dequeueBuffer: mMinUndequeuedBuffers=%d exceeded " "(dequeued=%d)", mMinUndequeuedBuffers-int(mSynchronousMode), dequeuedCount); return -EBUSY; } } // if no buffer is found, wait for a buffer to be released tryAgain = found == INVALID_BUFFER_SLOT; if (tryAgain) { mDequeueCondition.wait(mMutex); } } if (found == INVALID_BUFFER_SLOT) { // This should not happen. ST_LOGE("dequeueBuffer: no available buffer slots"); return -EBUSY; } const int buf = found; *outBuf = found; ATRACE_BUFFER_INDEX(buf); const bool useDefaultSize = !w && !h; if (useDefaultSize) { // use the default size w = mDefaultWidth; h = mDefaultHeight; } const bool updateFormat = (format != 0); if (!updateFormat) { // keep the current (or default) format format = mPixelFormat; } // buffer is now in DEQUEUED (but can also be current at the same time, // if we're in synchronous mode) mSlots[buf].mBufferState = BufferSlot::DEQUEUED; const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer); if ((buffer == NULL) || (uint32_t(buffer->width) != w) || (uint32_t(buffer->height) != h) || (uint32_t(buffer->format) != format) || ((uint32_t(buffer->usage) & usage) != usage)) { status_t error; sp<GraphicBuffer> graphicBuffer( mGraphicBufferAlloc->createGraphicBuffer( w, h, format, usage, &error)); if (graphicBuffer == 0) { ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer " "failed"); return error; } if (updateFormat) { mPixelFormat = format; } mSlots[buf].mAcquireCalled = false; mSlots[buf].mGraphicBuffer = graphicBuffer; mSlots[buf].mRequestBufferCalled = false; mSlots[buf].mFence = EGL_NO_SYNC_KHR; mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; } dpy = mSlots[buf].mEglDisplay; fence = mSlots[buf].mFence; mSlots[buf].mFence = EGL_NO_SYNC_KHR; } // end lock scope if (fence != EGL_NO_SYNC_KHR) { EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000); // If something goes wrong, log the error, but return the buffer without // synchronizing access to it. It's too late at this point to abort the // dequeue operation. if (result == EGL_FALSE) { ST_LOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError()); } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { ST_LOGE("dequeueBuffer: timeout waiting for fence"); } eglDestroySyncKHR(dpy, fence); } ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf, mSlots[*outBuf].mGraphicBuffer->handle, returnFlags); return returnFlags; }
status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { ATRACE_CALL(); ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage); if ((w && !h) || (!w && h)) { ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h); return BAD_VALUE; } status_t returnFlags(OK); EGLDisplay dpy = EGL_NO_DISPLAY; EGLSyncKHR eglFence = EGL_NO_SYNC_KHR; { // Scope for the lock Mutex::Autolock lock(mMutex); if (format == 0) { format = mDefaultBufferFormat; } // turn on usage bits the consumer requested usage |= mConsumerUsageBits; int found = -1; int dequeuedCount = 0; bool tryAgain = true; while (tryAgain) { if (mAbandoned) { ST_LOGE("dequeueBuffer: BufferQueue has been abandoned!"); return NO_INIT; } const int maxBufferCount = getMaxBufferCountLocked(); // Free up any buffers that are in slots beyond the max buffer // count. for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) { assert(mSlots[i].mBufferState == BufferSlot::FREE); if (mSlots[i].mGraphicBuffer != NULL) { freeBufferLocked(i); returnFlags |= IGraphicBufferProducer::RELEASE_ALL_BUFFERS; } } // look for a free buffer to give to the client found = INVALID_BUFFER_SLOT; dequeuedCount = 0; for (int i = 0; i < maxBufferCount; i++) { const int state = mSlots[i].mBufferState; if (state == BufferSlot::DEQUEUED) { dequeuedCount++; } if (state == BufferSlot::FREE) { /* We return the oldest of the free buffers to avoid * stalling the producer if possible. This is because * the consumer may still have pending reads of the * buffers in flight. */ if ((found < 0) || mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) { found = i; } } } // clients are not allowed to dequeue more than one buffer // if they didn't set a buffer count. if (!mOverrideMaxBufferCount && dequeuedCount) { ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without " "setting the buffer count"); return -EINVAL; } // See whether a buffer has been queued since the last // setBufferCount so we know whether to perform the min undequeued // buffers check below. if (mBufferHasBeenQueued) { // make sure the client is not trying to dequeue more buffers // than allowed. const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1); const int minUndequeuedCount = getMinUndequeuedBufferCountLocked(); if (newUndequeuedCount < minUndequeuedCount) { ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) " "exceeded (dequeued=%d undequeudCount=%d)", minUndequeuedCount, dequeuedCount, newUndequeuedCount); return -EBUSY; } } // If no buffer is found, wait for a buffer to be released or for // the max buffer count to change. tryAgain = found == INVALID_BUFFER_SLOT; if (tryAgain) { mDequeueCondition.wait(mMutex); } } if (found == INVALID_BUFFER_SLOT) { // This should not happen. ST_LOGE("dequeueBuffer: no available buffer slots"); return -EBUSY; } const int buf = found; *outBuf = found; ATRACE_BUFFER_INDEX(buf); const bool useDefaultSize = !w && !h; if (useDefaultSize) { // use the default size w = mDefaultWidth; h = mDefaultHeight; } mSlots[buf].mBufferState = BufferSlot::DEQUEUED; const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer); if ((buffer == NULL) || (uint32_t(buffer->width) != w) || (uint32_t(buffer->height) != h) || (uint32_t(buffer->format) != format) || ((uint32_t(buffer->usage) & usage) != usage)) { mSlots[buf].mAcquireCalled = false; mSlots[buf].mGraphicBuffer = NULL; mSlots[buf].mRequestBufferCalled = false; mSlots[buf].mEglFence = EGL_NO_SYNC_KHR; mSlots[buf].mFence = Fence::NO_FENCE; mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; returnFlags |= IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION; } dpy = mSlots[buf].mEglDisplay; eglFence = mSlots[buf].mEglFence; *outFence = mSlots[buf].mFence; mSlots[buf].mEglFence = EGL_NO_SYNC_KHR; mSlots[buf].mFence = Fence::NO_FENCE; } // end lock scope if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) { status_t error; sp<GraphicBuffer> graphicBuffer( mGraphicBufferAlloc->createGraphicBuffer( w, h, format, usage, &error)); if (graphicBuffer == 0) { ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer " "failed"); return error; } { // Scope for the lock Mutex::Autolock lock(mMutex); if (mAbandoned) { ST_LOGE("dequeueBuffer: BufferQueue has been abandoned!"); return NO_INIT; } mSlots[*outBuf].mGraphicBuffer = graphicBuffer; } } if (eglFence != EGL_NO_SYNC_KHR) { EGLint result = eglClientWaitSyncKHR(dpy, eglFence, 0, 1000000000); // If something goes wrong, log the error, but return the buffer without // synchronizing access to it. It's too late at this point to abort the // dequeue operation. if (result == EGL_FALSE) { ST_LOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError()); } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { ST_LOGE("dequeueBuffer: timeout waiting for fence"); } eglDestroySyncKHR(dpy, eglFence); } ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf, mSlots[*outBuf].mGraphicBuffer->handle, returnFlags); return returnFlags; }
status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage); if ((w && !h) || (!w && h)) { ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h); return BAD_VALUE; } status_t returnFlags(OK); EGLDisplay dpy = EGL_NO_DISPLAY; EGLSyncKHR fence = EGL_NO_SYNC_KHR; { // Scope for the lock Mutex::Autolock lock(mMutex); int found = -1; int foundSync = -1; int dequeuedCount = 0; bool tryAgain = true; #ifdef MISSING_GRALLOC_BUFFERS int dequeueRetries = 5; #endif while (tryAgain) { if (mAbandoned) { ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!"); return NO_INIT; } // We need to wait for the FIFO to drain if the number of buffer // needs to change. // // The condition "number of buffers needs to change" is true if // - the client doesn't care about how many buffers there are // - AND the actual number of buffer is different from what was // set in the last setBufferCountServer() // - OR - // setBufferCountServer() was set to a value incompatible with // the synchronization mode (for instance because the sync mode // changed since) // // As long as this condition is true AND the FIFO is not empty, we // wait on mDequeueCondition. const int minBufferCountNeeded = mSynchronousMode ? MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS; const bool numberOfBuffersNeedsToChange = !mClientBufferCount && ((mServerBufferCount != mBufferCount) || (mServerBufferCount < minBufferCountNeeded)); if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) { // wait for the FIFO to drain mDequeueCondition.wait(mMutex); // NOTE: we continue here because we need to reevaluate our // whole state (eg: we could be abandoned or disconnected) continue; } if (numberOfBuffersNeedsToChange) { // here we're guaranteed that mQueue is empty freeAllBuffersLocked(); mBufferCount = mServerBufferCount; if (mBufferCount < minBufferCountNeeded) mBufferCount = minBufferCountNeeded; mCurrentTexture = INVALID_BUFFER_SLOT; returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS; } // look for a free buffer to give to the client found = INVALID_BUFFER_SLOT; foundSync = INVALID_BUFFER_SLOT; dequeuedCount = 0; for (int i = 0; i < mBufferCount; i++) { const int state = mSlots[i].mBufferState; if (state == BufferSlot::DEQUEUED) { dequeuedCount++; } // if buffer is FREE it CANNOT be current LOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i), "dequeueBuffer: buffer %d is both FREE and current!", i); if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) { if (state == BufferSlot::FREE || i == mCurrentTexture) { foundSync = i; if (i != mCurrentTexture) { found = i; break; } } } else { if (state == BufferSlot::FREE) { /* We return the oldest of the free buffers to avoid * stalling the producer if possible. This is because * the consumer may still have pending reads of the * buffers in flight. */ bool isOlder = mSlots[i].mFrameNumber < mSlots[found].mFrameNumber; if (found < 0 || isOlder) { foundSync = i; found = i; } } } } // clients are not allowed to dequeue more than one buffer // if they didn't set a buffer count. if (!mClientBufferCount && dequeuedCount) { #ifdef MISSING_GRALLOC_BUFFERS if (--dequeueRetries) { LOGD("SurfaceTexture::dequeue: Not allowed to dequeue more " "than a buffer SLEEPING\n"); usleep(10000); } else { mClientBufferCount = mServerBufferCount; LOGD("SurfaceTexture::dequeue: Not allowed to dequeue more " "than a buffer RETRY mBufferCount:%d mServerBufferCount:%d\n", mBufferCount, mServerBufferCount); } continue; #else ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without " "setting the buffer count"); #endif return -EINVAL; } // See whether a buffer has been queued since the last // setBufferCount so we know whether to perform the // MIN_UNDEQUEUED_BUFFERS check below. bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT; if (bufferHasBeenQueued) { // make sure the client is not trying to dequeue more buffers // than allowed. const int avail = mBufferCount - (dequeuedCount+1); if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) { #ifdef MISSING_GRALLOC_BUFFERS if (mClientBufferCount != 0) { mBufferCount++; mClientBufferCount = mServerBufferCount = mBufferCount; LOGD("SurfaceTexture::dequeuebuffer: MIN EXCEEDED " "mBuffer:%d bumped\n", mBufferCount); continue; } #endif ST_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded " "(dequeued=%d)", MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode), dequeuedCount); return -EBUSY; } } // we're in synchronous mode and didn't find a buffer, we need to // wait for some buffers to be consumed tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT); if (tryAgain) { mDequeueCondition.wait(mMutex); } } if (mSynchronousMode && found == INVALID_BUFFER_SLOT) { // foundSync guaranteed to be != INVALID_BUFFER_SLOT found = foundSync; } if (found == INVALID_BUFFER_SLOT) { // This should not happen. ST_LOGE("dequeueBuffer: no available buffer slots"); return -EBUSY; } const int buf = found; *outBuf = found; const bool useDefaultSize = !w && !h; if (useDefaultSize) { // use the default size w = mDefaultWidth; h = mDefaultHeight; } const bool updateFormat = (format != 0); if (!updateFormat) { // keep the current (or default) format format = mPixelFormat; } // buffer is now in DEQUEUED (but can also be current at the same time, // if we're in synchronous mode) mSlots[buf].mBufferState = BufferSlot::DEQUEUED; const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer); #ifdef QCOM_HARDWARE qBufGeometry currentGeometry; if (buffer != NULL) currentGeometry.set(buffer->width, buffer->height, buffer->format); else currentGeometry.set(0, 0, 0); qBufGeometry requiredGeometry; requiredGeometry.set(w, h, format); qBufGeometry updatedGeometry; updatedGeometry.set(mNextBufferInfo.width, mNextBufferInfo.height, mNextBufferInfo.format); #endif if ((buffer == NULL) || #ifdef QCOM_HARDWARE needNewBuffer(currentGeometry, requiredGeometry, updatedGeometry) || #else (uint32_t(buffer->width) != w) || (uint32_t(buffer->height) != h) || (uint32_t(buffer->format) != format) || #endif ((uint32_t(buffer->usage) & usage) != usage)) { #ifdef QCOM_HARDWARE if (buffer != NULL) { mGraphicBufferAlloc->freeGraphicBufferAtIndex(buf); } #endif usage |= GraphicBuffer::USAGE_HW_TEXTURE; status_t error; sp<GraphicBuffer> graphicBuffer( mGraphicBufferAlloc->createGraphicBuffer( w, h, format, usage, &error)); if (graphicBuffer == 0) { ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer " "failed"); return error; } if (updateFormat) { mPixelFormat = format; } #ifdef QCOM_HARDWARE checkBuffer((native_handle_t *)graphicBuffer->handle, mReqSize, usage); #endif mSlots[buf].mGraphicBuffer = graphicBuffer; mSlots[buf].mRequestBufferCalled = false; mSlots[buf].mFence = EGL_NO_SYNC_KHR; if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) { eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage); mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR; mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; } if (mCurrentTexture == buf) { // The current texture no longer references the buffer in this slot // since we just allocated a new buffer. mCurrentTexture = INVALID_BUFFER_SLOT; } returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; } dpy = mSlots[buf].mEglDisplay; fence = mSlots[buf].mFence; mSlots[buf].mFence = EGL_NO_SYNC_KHR; } if (fence != EGL_NO_SYNC_KHR) { EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000); // If something goes wrong, log the error, but return the buffer without // synchronizing access to it. It's too late at this point to abort the // dequeue operation. if (result == EGL_FALSE) { LOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError()); } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { LOGE("dequeueBuffer: timeout waiting for fence"); } eglDestroySyncKHR(dpy, fence); } ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf, mSlots[*outBuf].mGraphicBuffer->handle, returnFlags); return returnFlags; }
status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { LOGV("dequeueBuffer"); Mutex::Autolock lock(mMutex); // Check for the buffer size- the client should just use the // default width and height, and not try to set those. // This is needed since // the getFormat() returns mDefaultWidth/ Height for the OMX. It is // queried by OMX in the beginning and not every time a frame comes. // Not sure if there is a way to update the // frame size while recording. So as of now, the client side // sets the default values via the constructor, and the encoder is // setup to encode frames of that size // The design might need to change in the future. // TODO: Currently just uses mDefaultWidth/Height. In the future // we might declare mHeight and mWidth and check against those here. if ((w != 0) || (h != 0)) { if ((w != mDefaultWidth) || (h != mDefaultHeight)) { LOGE("dequeuebuffer: invalid buffer size! Req: %dx%d, Found: %dx%d", mDefaultWidth, mDefaultHeight, w, h); return BAD_VALUE; } } status_t returnFlags(OK); int found, foundSync; int dequeuedCount = 0; bool tryAgain = true; while (tryAgain) { // We need to wait for the FIFO to drain if the number of buffer // needs to change. // // The condition "number of buffer needs to change" is true if // - the client doesn't care about how many buffers there are // - AND the actual number of buffer is different from what was // set in the last setBufferCountServer() // - OR - // setBufferCountServer() was set to a value incompatible with // the synchronization mode (for instance because the sync mode // changed since) // // As long as this condition is true AND the FIFO is not empty, we // wait on mDequeueCondition. int minBufferCountNeeded = mSynchronousMode ? MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS; if (!mClientBufferCount && ((mServerBufferCount != mBufferCount) || (mServerBufferCount < minBufferCountNeeded))) { // wait for the FIFO to drain while (!mQueue.isEmpty()) { LOGV("Waiting for the FIFO to drain"); mDequeueCondition.wait(mMutex); } if (mStopped) { return NO_INIT; } // need to check again since the mode could have changed // while we were waiting minBufferCountNeeded = mSynchronousMode ? MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS; } if (!mClientBufferCount && ((mServerBufferCount != mBufferCount) || (mServerBufferCount < minBufferCountNeeded))) { // here we're guaranteed that mQueue is empty freeAllBuffersLocked(); mBufferCount = mServerBufferCount; if (mBufferCount < minBufferCountNeeded) mBufferCount = minBufferCountNeeded; mCurrentSlot = INVALID_BUFFER_SLOT; returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS; } // look for a free buffer to give to the client found = INVALID_BUFFER_SLOT; foundSync = INVALID_BUFFER_SLOT; dequeuedCount = 0; for (int i = 0; i < mBufferCount; i++) { const int state = mSlots[i].mBufferState; if (state == BufferSlot::DEQUEUED) { dequeuedCount++; continue; // won't be continuing if could // dequeue a non 'FREE' current slot like // that in SurfaceTexture } // In case of Encoding, we do not deque the mCurrentSlot buffer // since we follow synchronous mode (unlike possibly in // SurfaceTexture that could be using the asynch mode // or has some mechanism in GL to be able to wait till the // currentslot is done using the data) // Here, we have to wait for the MPEG4Writer(or equiv) // to tell us when it's done using the current buffer if (state == BufferSlot::FREE) { foundSync = i; // Unlike that in SurfaceTexture, // We don't need to worry if it is the // currentslot or not as it is in state FREE found = i; break; } } // clients are not allowed to dequeue more than one buffer // if they didn't set a buffer count. if (!mClientBufferCount && dequeuedCount) { return -EINVAL; } // See whether a buffer has been queued since the last setBufferCount so // we know whether to perform the MIN_UNDEQUEUED_BUFFERS check below. bool bufferHasBeenQueued = mCurrentSlot != INVALID_BUFFER_SLOT; if (bufferHasBeenQueued) { // make sure the client is not trying to dequeue more buffers // than allowed. const int avail = mBufferCount - (dequeuedCount+1); if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) { LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded (dequeued=%d)", MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode), dequeuedCount); return -EBUSY; } } // we're in synchronous mode and didn't find a buffer, we need to wait // for for some buffers to be consumed tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT); if (tryAgain) { LOGV("Waiting..In synchronous mode and no buffer to dequeue"); mDequeueCondition.wait(mMutex); } if (mStopped) { return NO_INIT; } } if (mSynchronousMode && found == INVALID_BUFFER_SLOT) { // foundSync guaranteed to be != INVALID_BUFFER_SLOT found = foundSync; } if (found == INVALID_BUFFER_SLOT) { return -EBUSY; } const int bufIndex = found; *outBuf = found; const bool useDefaultSize = !w && !h; if (useDefaultSize) { // use the default size w = mDefaultWidth; h = mDefaultHeight; } const bool updateFormat = (format != 0); if (!updateFormat) { // keep the current (or default) format format = mPixelFormat; } // buffer is now in DEQUEUED (but can also be current at the same time, // if we're in synchronous mode) mSlots[bufIndex].mBufferState = BufferSlot::DEQUEUED; const sp<GraphicBuffer>& buffer(mSlots[bufIndex].mGraphicBuffer); if ((buffer == NULL) || (uint32_t(buffer->width) != w) || (uint32_t(buffer->height) != h) || (uint32_t(buffer->format) != format) || ((uint32_t(buffer->usage) & usage) != usage)) { // XXX: This will be changed to USAGE_HW_VIDEO_ENCODER once driver // issues with that flag get fixed. usage |= GraphicBuffer::USAGE_HW_TEXTURE; status_t error; sp<GraphicBuffer> graphicBuffer( mGraphicBufferAlloc->createGraphicBuffer( w, h, format, usage, &error)); if (graphicBuffer == 0) { LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer failed"); return error; } if (updateFormat) { mPixelFormat = format; } mSlots[bufIndex].mGraphicBuffer = graphicBuffer; mSlots[bufIndex].mRequestBufferCalled = false; returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; } return returnFlags; }