#ifndef CAMERA_TEST_BUFFER_QUEUE_H #define CAMERA_TEST_BUFFER_QUEUE_H #ifdef ANDROID_API_JB_OR_LATER #include #include #include #include "camera_test.h" #define CAMHAL_LOGV ALOGV #define CAMHAL_LOGE ALOGE #define PRINTOVER(arg...) ALOGD(#arg) #define LOG_FUNCTION_NAME ALOGD("%d: %s() ENTER", __LINE__, __FUNCTION__); #define LOG_FUNCTION_NAME_EXIT ALOGD("%d: %s() EXIT", __LINE__, __FUNCTION__); using namespace android; class FrameConsumer : public BufferQueue::ProxyConsumerListener { public: FrameConsumer(): BufferQueue::ProxyConsumerListener(NULL), mPendingFrames(0) { } virtual ~FrameConsumer() { onFrameAvailable(); } void waitForFrame() { Mutex::Autolock lock(mMutex); while (mPendingFrames == 0) { mCondition.wait(mMutex); } mPendingFrames--; } virtual void onFrameAvailable() { Mutex::Autolock lock(mMutex); mPendingFrames++; mCondition.signal(); } virtual void onBuffersReleased() {} int mPendingFrames; Mutex mMutex; Condition mCondition; }; class BQ_BufferSourceThread : public BufferSourceThread { public: BQ_BufferSourceThread(int tex_id, sp camera) : BufferSourceThread(camera) { #ifdef ANDROID_API_JB_MR1_OR_LATER mBufferQueue = new BufferQueue(true); mBufferQueue->setMaxAcquiredBufferCount(1); #else mBufferQueue = new BufferQueue(true, 1); #endif mFW = new FrameConsumer(); mBufferQueue->setSynchronousMode(true); mBufferQueue->consumerConnect(mFW); mCamera->setBufferSource(NULL, mBufferQueue); } virtual ~BQ_BufferSourceThread() { mCamera->releaseBufferSource(NULL, mBufferQueue); } virtual bool threadLoop() { sp graphic_buffer; BufferQueue::BufferItem item; mFW->waitForFrame(); if (!mDestroying) { status_t status; status = mBufferQueue->acquireBuffer(&item); if (status == BufferQueue::NO_BUFFER_AVAILABLE) { // no buffer to handle, return and we'll try again return true; } printf("=== Metadata for buffer %d ===\n", mCounter); if (item.mGraphicBuffer != NULL) { unsigned int slot = item.mBuf; // For whatever reason, BufferQueue only gives us the graphic buffer // the first time we acquire it. We are expected to hold a reference to // it there after... mBufferSlots[slot].mGraphicBuffer = item.mGraphicBuffer; mBufferSlots[slot].mCrop = item.mCrop; } showMetadata(item.mMetadata); printf("\n"); graphic_buffer = mBufferSlots[item.mBuf].mGraphicBuffer; mDeferThread->add(graphic_buffer, item.mCrop, mCounter++, item.mBuf); restartCapture(); return true; } return false; } virtual void requestExit() { Thread::requestExit(); mDestroying = true; mFW->onFrameAvailable(); } virtual void setBuffer(android::ShotParameters ¶ms) { { String8 id = mBufferQueue->getId(); if (!id.isEmpty()) { params.set(KEY_TAP_OUT_SURFACES, id); } else { params.remove(KEY_TAP_OUT_SURFACES); } } } virtual void onHandled(sp &gbuf, unsigned int slot) { #ifdef ANDROID_API_JB_MR1_OR_LATER mBufferQueue->releaseBuffer(slot, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE); #else mBufferQueue->releaseBuffer(slot, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); #endif } private: sp mBufferQueue; sp mFW; BufferQueue::BufferItem mBufferSlots[BufferQueue::NUM_BUFFER_SLOTS]; }; class BQ_BufferSourceInput : public BufferSourceInput { public: BQ_BufferSourceInput(int tex_id, sp camera) : BufferSourceInput(camera), mTexId(tex_id) { #ifdef ANDROID_API_JB_MR1_OR_LATER mBufferQueue = new BufferQueue(true); mBufferQueue->setMaxAcquiredBufferCount(1); #else mBufferQueue = new BufferQueue(true, 1); #endif sp surfaceTexture = mBufferQueue; mWindowTapIn = new SurfaceTextureClient(surfaceTexture); mCamera->setBufferSource(mBufferQueue, NULL); } virtual ~BQ_BufferSourceInput() { mCamera->releaseBufferSource(mBufferQueue, NULL); } virtual void setInput(buffer_info_t bufinfo, const char *format, android::ShotParameters ¶ms) { mBufferQueue->setDefaultBufferSize(bufinfo.width, bufinfo.height); // Reset buffer slots, any remaining buffers slots that were // previously added should get flushed. mBufferQueue->setBufferCount(android::BufferQueue::NUM_BUFFER_SLOTS); BufferSourceInput::setInput(bufinfo, format, params); { String8 id = mBufferQueue->getId(); if (!id.isEmpty()) { params.set(KEY_TAP_IN_SURFACE, id); } else { params.remove(KEY_TAP_IN_SURFACE); } } } private: sp mBufferQueue; int mTexId; }; #endif // ANDROID_API_JB_OR_LATER #endif // CAMERA_TEST_BUFFER_QUEUE_H