#ifndef CAMERA_TEST_SURFACE_TEXTURE_H
#define CAMERA_TEST_SURFACE_TEXTURE_H
#include "camera_test.h"
#ifdef ANDROID_API_JB_OR_LATER
#include <gui/Surface.h>
#include <gui/GLConsumer.h>
#include <gui/SurfaceComposerClient.h>
#else
#include <surfaceflinger/Surface.h>
#include <surfaceflinger/ISurface.h>
#include <surfaceflinger/ISurfaceComposer.h>
#include <surfaceflinger/ISurfaceComposerClient.h>
#include <surfaceflinger/SurfaceComposerClient.h>
#endif
#ifdef ANDROID_API_JB_OR_LATER
# 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__);
#else
# define CAMHAL_LOGV LOGV
# define CAMHAL_LOGE LOGE
# define PRINTOVER(arg...) LOGD(#arg)
# define LOG_FUNCTION_NAME LOGD("%d: %s() ENTER", __LINE__, __FUNCTION__);
# define LOG_FUNCTION_NAME_EXIT LOGD("%d: %s() EXIT", __LINE__, __FUNCTION__);
#endif
using namespace android;
class FrameWaiter : public android::GLConsumer::FrameAvailableListener {
public:
FrameWaiter():
mPendingFrames(0) {
}
virtual ~FrameWaiter() {
onFrameAvailable();
}
void waitForFrame() {
Mutex::Autolock lock(mMutex);
while (mPendingFrames == 0) {
mCondition.wait(mMutex);
}
mPendingFrames--;
}
virtual void onFrameAvailable() {
Mutex::Autolock lock(mMutex);
mPendingFrames++;
mCondition.signal();
}
int mPendingFrames;
Mutex mMutex;
Condition mCondition;
};
class GLSurface {
public:
GLSurface():
mEglDisplay(EGL_NO_DISPLAY),
mEglSurface(EGL_NO_SURFACE),
mEglContext(EGL_NO_CONTEXT) {
}
virtual ~GLSurface() {}
void initialize(int display);
void deinit();
void loadShader(GLenum shaderType, const char* pSource, GLuint* outShader);
void createProgram(const char* pVertexSource, const char* pFragmentSource,
GLuint* outPgm);
private:
EGLint const* getConfigAttribs();
EGLint const* getContextAttribs();
protected:
sp<SurfaceComposerClient> mComposerClient;
sp<SurfaceControl> mSurfaceControl;
EGLDisplay mEglDisplay;
EGLSurface mEglSurface;
EGLContext mEglContext;
EGLConfig mGlConfig;
};
class SurfaceTextureBase {
public:
virtual ~SurfaceTextureBase() {}
void initialize(int tex_id, EGLenum tex_target = EGL_NONE);
void deinit();
void getId(const char **name);
virtual sp<GLConsumer> getST();
protected:
sp<GLConsumer> mST;
sp<Surface> mSTC;
sp<ANativeWindow> mANW;
int mTexId;
};
class SurfaceTextureGL : public GLSurface, public SurfaceTextureBase {
public:
virtual ~SurfaceTextureGL() {}
void initialize(int display, int tex_id);
void deinit();
// drawTexture draws the GLConsumer over the entire GL viewport.
void drawTexture();
private:
GLuint mPgm;
GLint mPositionHandle;
GLint mTexSamplerHandle;
GLint mTexMatrixHandle;
};
class ST_BufferSourceThread : public BufferSourceThread {
public:
ST_BufferSourceThread(int tex_id, sp<Camera> camera) : BufferSourceThread(camera) {
mSurfaceTextureBase = new SurfaceTextureBase();
mSurfaceTextureBase->initialize(tex_id);
mSurfaceTexture = mSurfaceTextureBase->getST();
mSurfaceTexture->setSynchronousMode(true);
mFW = new FrameWaiter();
mSurfaceTexture->setFrameAvailableListener(mFW);
#ifndef ANDROID_API_JB_OR_LATER
mCamera->setBufferSource(NULL, mSurfaceTexture);
#endif
}
virtual ~ST_BufferSourceThread() {
#ifndef ANDROID_API_JB_OR_LATER
mCamera->releaseBufferSource(NULL, mSurfaceTexture);
#endif
mSurfaceTextureBase->deinit();
delete mSurfaceTextureBase;
}
virtual bool threadLoop() {
sp<GraphicBuffer> graphic_buffer;
mFW->waitForFrame();
if (!mDestroying) {
float mtx[16] = {0.0};
mSurfaceTexture->updateTexImage();
printf("=== Metadata for buffer %d ===\n", mCounter);
#ifndef ANDROID_API_JB_OR_LATER
showMetadata(mSurfaceTexture->getMetadata());
#endif
printf("\n");
graphic_buffer = mSurfaceTexture->getCurrentBuffer();
mSurfaceTexture->getTransformMatrix(mtx);
Rect crop = getCrop(graphic_buffer, mtx);
mDeferThread->add(graphic_buffer, crop, mCounter++);
restartCapture();
return true;
}
return false;
}
virtual void requestExit() {
Thread::requestExit();
mDestroying = true;
mFW->onFrameAvailable();
}
virtual void setBuffer(android::ShotParameters ¶ms) {
{
const char* id = NULL;
mSurfaceTextureBase->getId(&id);
if (id) {
params.set(KEY_TAP_OUT_SURFACES, id);
} else {
params.remove(KEY_TAP_OUT_SURFACES);
}
}
}
private:
SurfaceTextureBase *mSurfaceTextureBase;
sp<GLConsumer> mSurfaceTexture;
sp<FrameWaiter> mFW;
};
class ST_BufferSourceInput : public BufferSourceInput {
public:
ST_BufferSourceInput(int tex_id, sp<Camera> camera) :
BufferSourceInput(camera), mTexId(tex_id) {
mSurfaceTexture = new SurfaceTextureBase();
sp<GLConsumer> surface_texture;
mSurfaceTexture->initialize(mTexId);
surface_texture = mSurfaceTexture->getST();
surface_texture->setSynchronousMode(true);
mWindowTapIn = new Surface(surface_texture);
#ifndef ANDROID_API_JB_OR_LATER
mCamera->setBufferSource(mSurfaceTexture->getST(), NULL);
#else
mCamera->setBufferSource(mSurfaceTexture->getST()->getBufferQueue(), NULL);
#endif
}
virtual ~ST_BufferSourceInput() {
#ifndef ANDROID_API_JB_OR_LATER
mCamera->releaseBufferSource(mSurfaceTexture->getST(), NULL);
#else
mCamera->releaseBufferSource(mSurfaceTexture->getST()->getBufferQueue(), NULL);
#endif
delete mSurfaceTexture;
}
virtual void setInput(buffer_info_t bufinfo, const char *format) {
android::ShotParameters params;
mSurfaceTexture->getST()->setDefaultBufferSize(bufinfo.width, bufinfo.height);
BufferSourceInput::setInput(bufinfo, format, params);
}
private:
int mTexId;
SurfaceTextureBase *mSurfaceTexture;
};
#endif