#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