summaryrefslogtreecommitdiff
path: root/test/CameraHal/camera_test_bufferqueue.h
blob: 0dcb886d018869b398019b5614f74ebd7589777b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#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);
            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 &params) {
        {
            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 &params) {
        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