1#ifndef CAMERA_TEST_BUFFER_QUEUE_H
2#define CAMERA_TEST_BUFFER_QUEUE_H
3
4#ifdef ANDROID_API_JB_OR_LATER
5
6#include <gui/Surface.h>
7#include <gui/GLConsumer.h>
8#include <gui/SurfaceComposerClient.h>
9
10#include "camera_test.h"
11
12#define CAMHAL_LOGV            ALOGV
13#define CAMHAL_LOGE            ALOGE
14#define PRINTOVER(arg...)      ALOGD(#arg)
15#define LOG_FUNCTION_NAME      ALOGD("%d: %s() ENTER", __LINE__, __FUNCTION__);
16#define LOG_FUNCTION_NAME_EXIT ALOGD("%d: %s() EXIT", __LINE__, __FUNCTION__);
17
18using namespace android;
19
20class FrameConsumer : public BufferQueue::ProxyConsumerListener {
21public:
22    FrameConsumer():
23            BufferQueue::ProxyConsumerListener(NULL), mPendingFrames(0) {
24    }
25
26    virtual ~FrameConsumer() {
27        onFrameAvailable();
28    }
29
30    void waitForFrame() {
31        Mutex::Autolock lock(mMutex);
32        while (mPendingFrames == 0) {
33            mCondition.wait(mMutex);
34        }
35        mPendingFrames--;
36    }
37
38    virtual void onFrameAvailable() {
39        Mutex::Autolock lock(mMutex);
40        mPendingFrames++;
41        mCondition.signal();
42    }
43
44    virtual void onBuffersReleased() {}
45
46    int mPendingFrames;
47    Mutex mMutex;
48    Condition mCondition;
49};
50
51class BQ_BufferSourceThread : public BufferSourceThread {
52public:
53    BQ_BufferSourceThread(int tex_id, sp<Camera> camera) : BufferSourceThread(camera) {
54        mBufferQueue = new BufferQueue(true, 1);
55        mFW = new FrameConsumer();
56        mBufferQueue->setSynchronousMode(true);
57        mBufferQueue->consumerConnect(mFW);
58        mCamera->setBufferSource(NULL, mBufferQueue);
59    }
60    virtual ~BQ_BufferSourceThread() {
61        mCamera->releaseBufferSource(NULL, mBufferQueue);
62    }
63
64    virtual bool threadLoop() {
65        sp<GraphicBuffer> graphic_buffer;
66        BufferQueue::BufferItem item;
67
68        mFW->waitForFrame();
69        if (!mDestroying) {
70            status_t status;
71            status = mBufferQueue->acquireBuffer(&item, 0);
72            if (status == BufferQueue::NO_BUFFER_AVAILABLE) {
73                // no buffer to handle, return and we'll try again
74                return true;
75            }
76            printf("=== Metadata for buffer %d ===\n", mCounter);
77            if (item.mGraphicBuffer != NULL) {
78                unsigned int slot = item.mBuf;
79                // For whatever reason, BufferQueue only gives us the graphic buffer
80                // the first time we acquire it. We are expected to hold a reference to
81                // it there after...
82                mBufferSlots[slot].mGraphicBuffer = item.mGraphicBuffer;
83                mBufferSlots[slot].mCrop = item.mCrop;
84            }
85            showMetadata(item.mMetadata);
86            printf("\n");
87            graphic_buffer = mBufferSlots[item.mBuf].mGraphicBuffer;
88            mDeferThread->add(graphic_buffer, item.mCrop, mCounter++, item.mBuf);
89            restartCapture();
90            return true;
91        }
92        return false;
93    }
94
95    virtual void requestExit() {
96        Thread::requestExit();
97
98        mDestroying = true;
99        mFW->onFrameAvailable();
100    }
101
102    virtual void setBuffer(android::ShotParameters &params) {
103        {
104            String8 id = mBufferQueue->getId();
105
106            if (!id.isEmpty()) {
107                params.set(KEY_TAP_OUT_SURFACES, id);
108            } else {
109                params.remove(KEY_TAP_OUT_SURFACES);
110            }
111        }
112    }
113
114    virtual void onHandled(sp<GraphicBuffer> &gbuf, unsigned int slot) {
115        mBufferQueue->releaseBuffer(slot, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
116    }
117
118private:
119    sp<BufferQueue> mBufferQueue;
120    sp<FrameConsumer> mFW;
121    BufferQueue::BufferItem mBufferSlots[BufferQueue::NUM_BUFFER_SLOTS];
122};
123
124class BQ_BufferSourceInput : public BufferSourceInput {
125public:
126    BQ_BufferSourceInput(int tex_id, sp<Camera> camera) :
127                  BufferSourceInput(camera), mTexId(tex_id) {
128        mBufferQueue = new BufferQueue(true, 1);
129        sp<IGraphicBufferProducer> bufferProducer = mBufferQueue;
130        mWindowTapIn = new Surface(bufferProducer);
131        mCamera->setBufferSource(mBufferQueue, NULL);
132    }
133    virtual ~BQ_BufferSourceInput() {
134        mCamera->releaseBufferSource(mBufferQueue, NULL);
135    }
136
137    virtual void setInput(buffer_info_t bufinfo, const char *format, android::ShotParameters &params) {
138        mBufferQueue->setDefaultBufferSize(bufinfo.width, bufinfo.height);
139        BufferSourceInput::setInput(bufinfo, format, params);
140        {
141            String8 id = mBufferQueue->getId();
142
143            if (!id.isEmpty()) {
144                params.set(KEY_TAP_IN_SURFACE, id);
145            } else {
146                params.remove(KEY_TAP_IN_SURFACE);
147            }
148        }
149    }
150
151private:
152    sp<BufferQueue> mBufferQueue;
153    int mTexId;
154};
155#endif // ANDROID_API_JB_OR_LATER
156#endif // CAMERA_TEST_BUFFER_QUEUE_H
157