#ifndef CAMERA_TEST_BUFFER_QUEUE_H #define CAMERA_TEST_BUFFER_QUEUE_H #ifdef ANDROID_API_JB_OR_LATER #include <gui/Surface.h> #include <gui/GLConsumer.h> #include <gui/SurfaceComposerClient.h> #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> camera) : BufferSourceThread(camera) { mBufferQueue = new BufferQueue(true, 1); mFW = new FrameConsumer(); mBufferQueue->setSynchronousMode(true); mBufferQueue->consumerConnect(mFW); mCamera->setBufferSource(NULL, mBufferQueue); } virtual ~BQ_BufferSourceThread() { mCamera->releaseBufferSource(NULL, mBufferQueue); } virtual bool threadLoop() { sp<GraphicBuffer> graphic_buffer; BufferQueue::BufferItem item; mFW->waitForFrame(); if (!mDestroying) { status_t status; status = mBufferQueue->acquireBuffer(&item, 0); 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<GraphicBuffer> &gbuf, unsigned int slot) { mBufferQueue->releaseBuffer(slot, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); } private: sp<BufferQueue> mBufferQueue; sp<FrameConsumer> mFW; BufferQueue::BufferItem mBufferSlots[BufferQueue::NUM_BUFFER_SLOTS]; }; class BQ_BufferSourceInput : public BufferSourceInput { public: BQ_BufferSourceInput(int tex_id, sp<Camera> camera) : BufferSourceInput(camera), mTexId(tex_id) { mBufferQueue = new BufferQueue(true, 1); sp<IGraphicBufferProducer> bufferProducer = mBufferQueue; mWindowTapIn = new Surface(bufferProducer); 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); 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<BufferQueue> mBufferQueue; int mTexId; }; #endif // ANDROID_API_JB_OR_LATER #endif // CAMERA_TEST_BUFFER_QUEUE_H