mirror of https://github.com/opencv/opencv.git
Merge pull request #5470 from apavlenko:android_camera_gl_view
commit
441eeef319
17 changed files with 974 additions and 688 deletions
@ -0,0 +1,440 @@ |
|||||||
|
package org.opencv.android; |
||||||
|
|
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import java.nio.ByteOrder; |
||||||
|
import java.nio.FloatBuffer; |
||||||
|
|
||||||
|
import javax.microedition.khronos.egl.EGLConfig; |
||||||
|
import javax.microedition.khronos.opengles.GL10; |
||||||
|
|
||||||
|
import org.opencv.android.CameraGLSurfaceView.CameraTextureListener; |
||||||
|
|
||||||
|
import android.annotation.TargetApi; |
||||||
|
import android.graphics.SurfaceTexture; |
||||||
|
import android.opengl.GLES11Ext; |
||||||
|
import android.opengl.GLES20; |
||||||
|
import android.opengl.GLSurfaceView; |
||||||
|
import android.util.Log; |
||||||
|
import android.view.View; |
||||||
|
|
||||||
|
@TargetApi(15) |
||||||
|
public abstract class CameraGLRendererBase implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener { |
||||||
|
|
||||||
|
protected final String LOGTAG = "CameraGLRendererBase"; |
||||||
|
|
||||||
|
// shaders
|
||||||
|
private final String vss = "" |
||||||
|
+ "attribute vec2 vPosition;\n" |
||||||
|
+ "attribute vec2 vTexCoord;\n" + "varying vec2 texCoord;\n" |
||||||
|
+ "void main() {\n" + " texCoord = vTexCoord;\n" |
||||||
|
+ " gl_Position = vec4 ( vPosition.x, vPosition.y, 0.0, 1.0 );\n" |
||||||
|
+ "}"; |
||||||
|
|
||||||
|
private final String fssOES = "" |
||||||
|
+ "#extension GL_OES_EGL_image_external : require\n" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "uniform samplerExternalOES sTexture;\n" |
||||||
|
+ "varying vec2 texCoord;\n" |
||||||
|
+ "void main() {\n" |
||||||
|
+ " gl_FragColor = texture2D(sTexture,texCoord);\n" + "}"; |
||||||
|
|
||||||
|
private final String fss2D = "" |
||||||
|
+ "precision mediump float;\n" |
||||||
|
+ "uniform sampler2D sTexture;\n" |
||||||
|
+ "varying vec2 texCoord;\n" |
||||||
|
+ "void main() {\n" |
||||||
|
+ " gl_FragColor = texture2D(sTexture,texCoord);\n" + "}"; |
||||||
|
|
||||||
|
// coord-s
|
||||||
|
private final float vertices[] = { |
||||||
|
-1, -1, |
||||||
|
-1, 1, |
||||||
|
1, -1, |
||||||
|
1, 1 }; |
||||||
|
private final float texCoordOES[] = { |
||||||
|
0, 1, |
||||||
|
0, 0, |
||||||
|
1, 1, |
||||||
|
1, 0 }; |
||||||
|
private final float texCoord2D[] = { |
||||||
|
0, 0, |
||||||
|
0, 1, |
||||||
|
1, 0, |
||||||
|
1, 1 }; |
||||||
|
|
||||||
|
private int[] texCamera = {0}, texFBO = {0}, texDraw = {0}; |
||||||
|
private int[] FBO = {0}; |
||||||
|
private int progOES = -1, prog2D = -1; |
||||||
|
private int vPosOES, vTCOES, vPos2D, vTC2D; |
||||||
|
|
||||||
|
private FloatBuffer vert, texOES, tex2D; |
||||||
|
|
||||||
|
protected int mCameraWidth = -1, mCameraHeight = -1; |
||||||
|
protected int mFBOWidth = -1, mFBOHeight = -1; |
||||||
|
protected int mMaxCameraWidth = -1, mMaxCameraHeight = -1; |
||||||
|
protected int mCameraIndex = CameraBridgeViewBase.CAMERA_ID_ANY; |
||||||
|
|
||||||
|
protected SurfaceTexture mSTexture; |
||||||
|
|
||||||
|
protected boolean mHaveSurface = false; |
||||||
|
protected boolean mHaveFBO = false; |
||||||
|
protected boolean mUpdateST = false; |
||||||
|
protected boolean mEnabled = true; |
||||||
|
protected boolean mIsStarted = false; |
||||||
|
|
||||||
|
protected CameraGLSurfaceView mView; |
||||||
|
|
||||||
|
protected abstract void openCamera(int id); |
||||||
|
protected abstract void closeCamera(); |
||||||
|
protected abstract void setCameraPreviewSize(int width, int height); // updates mCameraWidth & mCameraHeight
|
||||||
|
|
||||||
|
public CameraGLRendererBase(CameraGLSurfaceView view) { |
||||||
|
mView = view; |
||||||
|
int bytes = vertices.length * Float.SIZE / Byte.SIZE; |
||||||
|
vert = ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder()).asFloatBuffer(); |
||||||
|
texOES = ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder()).asFloatBuffer(); |
||||||
|
tex2D = ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder()).asFloatBuffer(); |
||||||
|
vert.put(vertices).position(0); |
||||||
|
texOES.put(texCoordOES).position(0); |
||||||
|
tex2D.put(texCoord2D).position(0); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public synchronized void onFrameAvailable(SurfaceTexture surfaceTexture) { |
||||||
|
//Log.i(LOGTAG, "onFrameAvailable");
|
||||||
|
mUpdateST = true; |
||||||
|
mView.requestRender(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onDrawFrame(GL10 gl) { |
||||||
|
//Log.i(LOGTAG, "onDrawFrame start");
|
||||||
|
|
||||||
|
if (!mHaveFBO) |
||||||
|
return; |
||||||
|
|
||||||
|
synchronized(this) { |
||||||
|
if (mUpdateST) { |
||||||
|
mSTexture.updateTexImage(); |
||||||
|
mUpdateST = false; |
||||||
|
} |
||||||
|
|
||||||
|
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); |
||||||
|
|
||||||
|
CameraTextureListener texListener = mView.getCameraTextureListener(); |
||||||
|
if(texListener != null) { |
||||||
|
//Log.d(LOGTAG, "haveUserCallback");
|
||||||
|
// texCamera(OES) -> texFBO
|
||||||
|
drawTex(texCamera[0], true, FBO[0]); |
||||||
|
|
||||||
|
// call user code (texFBO -> texDraw)
|
||||||
|
boolean modified = texListener.onCameraTexture(texFBO[0], texDraw[0], mCameraWidth, mCameraHeight); |
||||||
|
|
||||||
|
if(modified) { |
||||||
|
// texDraw -> screen
|
||||||
|
drawTex(texDraw[0], false, 0); |
||||||
|
} else { |
||||||
|
// texFBO -> screen
|
||||||
|
drawTex(texFBO[0], false, 0); |
||||||
|
} |
||||||
|
} else { |
||||||
|
Log.d(LOGTAG, "texCamera(OES) -> screen"); |
||||||
|
// texCamera(OES) -> screen
|
||||||
|
drawTex(texCamera[0], true, 0); |
||||||
|
} |
||||||
|
//Log.i(LOGTAG, "onDrawFrame end");
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onSurfaceChanged(GL10 gl, int surfaceWidth, int surfaceHeight) { |
||||||
|
Log.i(LOGTAG, "onSurfaceChanged("+surfaceWidth+"x"+surfaceHeight+")"); |
||||||
|
mHaveSurface = true; |
||||||
|
updateState(); |
||||||
|
setPreviewSize(surfaceWidth, surfaceHeight); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onSurfaceCreated(GL10 gl, EGLConfig config) { |
||||||
|
Log.i(LOGTAG, "onSurfaceCreated"); |
||||||
|
initShaders(); |
||||||
|
} |
||||||
|
|
||||||
|
private void initShaders() { |
||||||
|
String strGLVersion = GLES20.glGetString(GLES20.GL_VERSION); |
||||||
|
if (strGLVersion != null) |
||||||
|
Log.i(LOGTAG, "OpenGL ES version: " + strGLVersion); |
||||||
|
|
||||||
|
GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); |
||||||
|
|
||||||
|
progOES = loadShader(vss, fssOES); |
||||||
|
vPosOES = GLES20.glGetAttribLocation(progOES, "vPosition"); |
||||||
|
vTCOES = GLES20.glGetAttribLocation(progOES, "vTexCoord"); |
||||||
|
GLES20.glEnableVertexAttribArray(vPosOES); |
||||||
|
GLES20.glEnableVertexAttribArray(vTCOES); |
||||||
|
|
||||||
|
prog2D = loadShader(vss, fss2D); |
||||||
|
vPos2D = GLES20.glGetAttribLocation(prog2D, "vPosition"); |
||||||
|
vTC2D = GLES20.glGetAttribLocation(prog2D, "vTexCoord"); |
||||||
|
GLES20.glEnableVertexAttribArray(vPos2D); |
||||||
|
GLES20.glEnableVertexAttribArray(vTC2D); |
||||||
|
} |
||||||
|
|
||||||
|
private void initSurfaceTexture() { |
||||||
|
Log.d(LOGTAG, "initSurfaceTexture"); |
||||||
|
deleteSurfaceTexture(); |
||||||
|
initTexOES(texCamera); |
||||||
|
mSTexture = new SurfaceTexture(texCamera[0]); |
||||||
|
mSTexture.setOnFrameAvailableListener(this); |
||||||
|
} |
||||||
|
|
||||||
|
private void deleteSurfaceTexture() { |
||||||
|
Log.d(LOGTAG, "deleteSurfaceTexture"); |
||||||
|
if(mSTexture != null) { |
||||||
|
mSTexture.release(); |
||||||
|
mSTexture = null; |
||||||
|
deleteTex(texCamera); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void initTexOES(int[] tex) { |
||||||
|
if(tex.length == 1) { |
||||||
|
GLES20.glGenTextures(1, tex, 0); |
||||||
|
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, tex[0]); |
||||||
|
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); |
||||||
|
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); |
||||||
|
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); |
||||||
|
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static void deleteTex(int[] tex) { |
||||||
|
if(tex.length == 1) { |
||||||
|
GLES20.glDeleteTextures(1, tex, 0); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static int loadShader(String vss, String fss) { |
||||||
|
Log.d("CameraGLRendererBase", "loadShader"); |
||||||
|
int vshader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER); |
||||||
|
GLES20.glShaderSource(vshader, vss); |
||||||
|
GLES20.glCompileShader(vshader); |
||||||
|
int[] status = new int[1]; |
||||||
|
GLES20.glGetShaderiv(vshader, GLES20.GL_COMPILE_STATUS, status, 0); |
||||||
|
if (status[0] == 0) { |
||||||
|
Log.e("CameraGLRendererBase", "Could not compile vertex shader: "+GLES20.glGetShaderInfoLog(vshader)); |
||||||
|
GLES20.glDeleteShader(vshader); |
||||||
|
vshader = 0; |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int fshader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER); |
||||||
|
GLES20.glShaderSource(fshader, fss); |
||||||
|
GLES20.glCompileShader(fshader); |
||||||
|
GLES20.glGetShaderiv(fshader, GLES20.GL_COMPILE_STATUS, status, 0); |
||||||
|
if (status[0] == 0) { |
||||||
|
Log.e("CameraGLRendererBase", "Could not compile fragment shader:"+GLES20.glGetShaderInfoLog(fshader)); |
||||||
|
GLES20.glDeleteShader(vshader); |
||||||
|
GLES20.glDeleteShader(fshader); |
||||||
|
fshader = 0; |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int program = GLES20.glCreateProgram(); |
||||||
|
GLES20.glAttachShader(program, vshader); |
||||||
|
GLES20.glAttachShader(program, fshader); |
||||||
|
GLES20.glLinkProgram(program); |
||||||
|
GLES20.glDeleteShader(vshader); |
||||||
|
GLES20.glDeleteShader(fshader); |
||||||
|
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, status, 0); |
||||||
|
if (status[0] == 0) { |
||||||
|
Log.e("CameraGLRendererBase", "Could not link shader program: "+GLES20.glGetProgramInfoLog(program)); |
||||||
|
program = 0; |
||||||
|
return 0; |
||||||
|
} |
||||||
|
GLES20.glValidateProgram(program); |
||||||
|
GLES20.glGetProgramiv(program, GLES20.GL_VALIDATE_STATUS, status, 0); |
||||||
|
if (status[0] == 0) |
||||||
|
{ |
||||||
|
Log.e("CameraGLRendererBase", "Shader program validation error: "+GLES20.glGetProgramInfoLog(program)); |
||||||
|
GLES20.glDeleteProgram(program); |
||||||
|
program = 0; |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
Log.d("CameraGLRendererBase", "Shader program is built OK"); |
||||||
|
|
||||||
|
return program; |
||||||
|
} |
||||||
|
|
||||||
|
private void deleteFBO() |
||||||
|
{ |
||||||
|
Log.d(LOGTAG, "deleteFBO("+mFBOWidth+"x"+mFBOHeight+")"); |
||||||
|
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); |
||||||
|
GLES20.glDeleteFramebuffers(1, FBO, 0); |
||||||
|
|
||||||
|
deleteTex(texFBO); |
||||||
|
deleteTex(texDraw); |
||||||
|
mFBOWidth = mFBOHeight = 0; |
||||||
|
} |
||||||
|
|
||||||
|
private void initFBO(int width, int height) |
||||||
|
{ |
||||||
|
Log.d(LOGTAG, "initFBO("+width+"x"+height+")"); |
||||||
|
|
||||||
|
deleteFBO(); |
||||||
|
|
||||||
|
GLES20.glGenTextures(1, texDraw, 0); |
||||||
|
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texDraw[0]); |
||||||
|
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null); |
||||||
|
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); |
||||||
|
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); |
||||||
|
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); |
||||||
|
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); |
||||||
|
|
||||||
|
GLES20.glGenTextures(1, texFBO, 0); |
||||||
|
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texFBO[0]); |
||||||
|
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null); |
||||||
|
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); |
||||||
|
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); |
||||||
|
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); |
||||||
|
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); |
||||||
|
|
||||||
|
//int hFBO;
|
||||||
|
GLES20.glGenFramebuffers(1, FBO, 0); |
||||||
|
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, FBO[0]); |
||||||
|
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, texFBO[0], 0); |
||||||
|
Log.d(LOGTAG, "initFBO error status: " + GLES20.glGetError()); |
||||||
|
|
||||||
|
int FBOstatus = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER); |
||||||
|
if (FBOstatus != GLES20.GL_FRAMEBUFFER_COMPLETE) |
||||||
|
Log.e(LOGTAG, "initFBO failed, status: " + FBOstatus); |
||||||
|
|
||||||
|
mFBOWidth = width; |
||||||
|
mFBOHeight = height; |
||||||
|
} |
||||||
|
|
||||||
|
// draw texture to FBO or to screen if fbo == 0
|
||||||
|
private void drawTex(int tex, boolean isOES, int fbo) |
||||||
|
{ |
||||||
|
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo); |
||||||
|
|
||||||
|
if(fbo == 0) |
||||||
|
GLES20.glViewport(0, 0, mView.getWidth(), mView.getHeight()); |
||||||
|
else |
||||||
|
GLES20.glViewport(0, 0, mFBOWidth, mFBOHeight); |
||||||
|
|
||||||
|
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); |
||||||
|
|
||||||
|
if(isOES) { |
||||||
|
GLES20.glUseProgram(progOES); |
||||||
|
GLES20.glVertexAttribPointer(vPosOES, 2, GLES20.GL_FLOAT, false, 4*2, vert); |
||||||
|
GLES20.glVertexAttribPointer(vTCOES, 2, GLES20.GL_FLOAT, false, 4*2, texOES); |
||||||
|
} else { |
||||||
|
GLES20.glUseProgram(prog2D); |
||||||
|
GLES20.glVertexAttribPointer(vPos2D, 2, GLES20.GL_FLOAT, false, 4*2, vert); |
||||||
|
GLES20.glVertexAttribPointer(vTC2D, 2, GLES20.GL_FLOAT, false, 4*2, tex2D); |
||||||
|
} |
||||||
|
|
||||||
|
GLES20.glActiveTexture(GLES20.GL_TEXTURE0); |
||||||
|
|
||||||
|
if(isOES) { |
||||||
|
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, tex); |
||||||
|
GLES20.glUniform1i(GLES20.glGetUniformLocation(progOES, "sTexture"), 0); |
||||||
|
} else { |
||||||
|
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tex); |
||||||
|
GLES20.glUniform1i(GLES20.glGetUniformLocation(prog2D, "sTexture"), 0); |
||||||
|
} |
||||||
|
|
||||||
|
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); |
||||||
|
GLES20.glFlush(); |
||||||
|
} |
||||||
|
|
||||||
|
public synchronized void enableView() { |
||||||
|
Log.d(LOGTAG, "enableView"); |
||||||
|
mEnabled = true; |
||||||
|
updateState(); |
||||||
|
} |
||||||
|
|
||||||
|
public synchronized void disableView() { |
||||||
|
Log.d(LOGTAG, "disableView"); |
||||||
|
mEnabled = false; |
||||||
|
updateState(); |
||||||
|
} |
||||||
|
|
||||||
|
protected void updateState() { |
||||||
|
Log.d(LOGTAG, "updateState"); |
||||||
|
Log.d(LOGTAG, "mEnabled="+mEnabled+", mHaveSurface="+mHaveSurface); |
||||||
|
boolean willStart = mEnabled && mHaveSurface && mView.getVisibility() == View.VISIBLE; |
||||||
|
if (willStart != mIsStarted) { |
||||||
|
if(willStart) doStart(); |
||||||
|
else doStop(); |
||||||
|
} else { |
||||||
|
Log.d(LOGTAG, "keeping State unchanged"); |
||||||
|
} |
||||||
|
Log.d(LOGTAG, "updateState end"); |
||||||
|
} |
||||||
|
|
||||||
|
protected synchronized void doStart() { |
||||||
|
Log.d(LOGTAG, "doStart"); |
||||||
|
initSurfaceTexture(); |
||||||
|
openCamera(mCameraIndex); |
||||||
|
mIsStarted = true; |
||||||
|
if(mCameraWidth>0 && mCameraHeight>0) |
||||||
|
setPreviewSize(mCameraWidth, mCameraHeight); // start preview and call listener.onCameraViewStarted()
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
protected void doStop() { |
||||||
|
Log.d(LOGTAG, "doStop"); |
||||||
|
synchronized(this) { |
||||||
|
mUpdateST = false; |
||||||
|
mIsStarted = false; |
||||||
|
mHaveFBO = false; |
||||||
|
closeCamera(); |
||||||
|
deleteSurfaceTexture(); |
||||||
|
} |
||||||
|
CameraTextureListener listener = mView.getCameraTextureListener(); |
||||||
|
if(listener != null) listener.onCameraViewStopped(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
protected void setPreviewSize(int width, int height) { |
||||||
|
synchronized(this) { |
||||||
|
mHaveFBO = false; |
||||||
|
mCameraWidth = width; |
||||||
|
mCameraHeight = height; |
||||||
|
setCameraPreviewSize(width, height); // can change mCameraWidth & mCameraHeight
|
||||||
|
initFBO(mCameraWidth, mCameraHeight); |
||||||
|
mHaveFBO = true; |
||||||
|
} |
||||||
|
|
||||||
|
CameraTextureListener listener = mView.getCameraTextureListener(); |
||||||
|
if(listener != null) listener.onCameraViewStarted(mCameraWidth, mCameraHeight); |
||||||
|
} |
||||||
|
|
||||||
|
public void setCameraIndex(int cameraIndex) { |
||||||
|
disableView(); |
||||||
|
mCameraIndex = cameraIndex; |
||||||
|
enableView(); |
||||||
|
} |
||||||
|
|
||||||
|
public void setMaxCameraPreviewSize(int maxWidth, int maxHeight) { |
||||||
|
disableView(); |
||||||
|
mMaxCameraWidth = maxWidth; |
||||||
|
mMaxCameraHeight = maxHeight; |
||||||
|
enableView(); |
||||||
|
} |
||||||
|
|
||||||
|
public void onResume() { |
||||||
|
Log.i(LOGTAG, "onResume"); |
||||||
|
} |
||||||
|
|
||||||
|
public void onPause() { |
||||||
|
Log.i(LOGTAG, "onPause"); |
||||||
|
mHaveSurface = false; |
||||||
|
updateState(); |
||||||
|
mCameraWidth = mCameraHeight = -1; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,119 @@ |
|||||||
|
package org.opencv.android; |
||||||
|
|
||||||
|
import org.opencv.R; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.content.res.TypedArray; |
||||||
|
import android.opengl.GLSurfaceView; |
||||||
|
import android.util.AttributeSet; |
||||||
|
import android.util.Log; |
||||||
|
import android.view.SurfaceHolder; |
||||||
|
|
||||||
|
public class CameraGLSurfaceView extends GLSurfaceView { |
||||||
|
|
||||||
|
private static final String LOGTAG = "CameraGLSurfaceView"; |
||||||
|
|
||||||
|
public interface CameraTextureListener { |
||||||
|
/** |
||||||
|
* This method is invoked when camera preview has started. After this method is invoked |
||||||
|
* the frames will start to be delivered to client via the onCameraFrame() callback. |
||||||
|
* @param width - the width of the frames that will be delivered |
||||||
|
* @param height - the height of the frames that will be delivered |
||||||
|
*/ |
||||||
|
public void onCameraViewStarted(int width, int height); |
||||||
|
|
||||||
|
/** |
||||||
|
* This method is invoked when camera preview has been stopped for some reason. |
||||||
|
* No frames will be delivered via onCameraFrame() callback after this method is called. |
||||||
|
*/ |
||||||
|
public void onCameraViewStopped(); |
||||||
|
|
||||||
|
/** |
||||||
|
* This method is invoked when a new preview frame from Camera is ready. |
||||||
|
* @param texIn - the OpenGL texture ID that contains frame in RGBA format |
||||||
|
* @param texOut - the OpenGL texture ID that can be used to store modified frame image t display |
||||||
|
* @param width - the width of the frame |
||||||
|
* @param height - the height of the frame |
||||||
|
* @return `true` if `texOut` should be displayed, `false` - to show `texIn` |
||||||
|
*/ |
||||||
|
public boolean onCameraTexture(int texIn, int texOut, int width, int height); |
||||||
|
}; |
||||||
|
|
||||||
|
private CameraTextureListener mTexListener; |
||||||
|
private CameraGLRendererBase mRenderer; |
||||||
|
|
||||||
|
public CameraGLSurfaceView(Context context, AttributeSet attrs) { |
||||||
|
super(context, attrs); |
||||||
|
|
||||||
|
TypedArray styledAttrs = getContext().obtainStyledAttributes(attrs, R.styleable.CameraBridgeViewBase); |
||||||
|
int cameraIndex = styledAttrs.getInt(R.styleable.CameraBridgeViewBase_camera_id, -1); |
||||||
|
styledAttrs.recycle(); |
||||||
|
|
||||||
|
if(android.os.Build.VERSION.SDK_INT >= 21) |
||||||
|
mRenderer = new Camera2Renderer(this); |
||||||
|
else |
||||||
|
mRenderer = new CameraRenderer(this); |
||||||
|
|
||||||
|
setCameraIndex(cameraIndex); |
||||||
|
|
||||||
|
setEGLContextClientVersion(2); |
||||||
|
setRenderer(mRenderer); |
||||||
|
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); |
||||||
|
} |
||||||
|
|
||||||
|
public void setCameraTextureListener(CameraTextureListener texListener) |
||||||
|
{ |
||||||
|
mTexListener = texListener; |
||||||
|
} |
||||||
|
|
||||||
|
public CameraTextureListener getCameraTextureListener() |
||||||
|
{ |
||||||
|
return mTexListener; |
||||||
|
} |
||||||
|
|
||||||
|
public void setCameraIndex(int cameraIndex) { |
||||||
|
mRenderer.setCameraIndex(cameraIndex); |
||||||
|
} |
||||||
|
|
||||||
|
public void setMaxCameraPreviewSize(int maxWidth, int maxHeight) { |
||||||
|
mRenderer.setMaxCameraPreviewSize(maxWidth, maxHeight); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void surfaceCreated(SurfaceHolder holder) { |
||||||
|
super.surfaceCreated(holder); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void surfaceDestroyed(SurfaceHolder holder) { |
||||||
|
mRenderer.mHaveSurface = false; |
||||||
|
super.surfaceDestroyed(holder); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { |
||||||
|
super.surfaceChanged(holder, format, w, h); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onResume() { |
||||||
|
Log.i(LOGTAG, "onResume"); |
||||||
|
super.onResume(); |
||||||
|
mRenderer.onResume(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onPause() { |
||||||
|
Log.i(LOGTAG, "onPause"); |
||||||
|
mRenderer.onPause(); |
||||||
|
super.onPause(); |
||||||
|
} |
||||||
|
|
||||||
|
public void enableView() { |
||||||
|
mRenderer.enableView(); |
||||||
|
} |
||||||
|
|
||||||
|
public void disableView() { |
||||||
|
mRenderer.disableView(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,166 @@ |
|||||||
|
package org.opencv.android; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import android.annotation.TargetApi; |
||||||
|
import android.hardware.Camera; |
||||||
|
import android.hardware.Camera.Size; |
||||||
|
import android.os.Build; |
||||||
|
import android.util.Log; |
||||||
|
|
||||||
|
@TargetApi(15) |
||||||
|
@SuppressWarnings("deprecation") |
||||||
|
public class CameraRenderer extends CameraGLRendererBase { |
||||||
|
|
||||||
|
public static final String LOGTAG = "CameraRenderer"; |
||||||
|
|
||||||
|
private Camera mCamera; |
||||||
|
private boolean mPreviewStarted = false; |
||||||
|
|
||||||
|
CameraRenderer(CameraGLSurfaceView view) { |
||||||
|
super(view); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected synchronized void closeCamera() { |
||||||
|
Log.i(LOGTAG, "closeCamera"); |
||||||
|
if(mCamera != null) { |
||||||
|
mCamera.stopPreview(); |
||||||
|
mPreviewStarted = false; |
||||||
|
mCamera.release(); |
||||||
|
mCamera = null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected synchronized void openCamera(int id) { |
||||||
|
Log.i(LOGTAG, "openCamera"); |
||||||
|
closeCamera(); |
||||||
|
if (id == CameraBridgeViewBase.CAMERA_ID_ANY) { |
||||||
|
Log.d(LOGTAG, "Trying to open camera with old open()"); |
||||||
|
try { |
||||||
|
mCamera = Camera.open(); |
||||||
|
} |
||||||
|
catch (Exception e){ |
||||||
|
Log.e(LOGTAG, "Camera is not available (in use or does not exist): " + e.getLocalizedMessage()); |
||||||
|
} |
||||||
|
|
||||||
|
if(mCamera == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { |
||||||
|
boolean connected = false; |
||||||
|
for (int camIdx = 0; camIdx < Camera.getNumberOfCameras(); ++camIdx) { |
||||||
|
Log.d(LOGTAG, "Trying to open camera with new open(" + camIdx + ")"); |
||||||
|
try { |
||||||
|
mCamera = Camera.open(camIdx); |
||||||
|
connected = true; |
||||||
|
} catch (RuntimeException e) { |
||||||
|
Log.e(LOGTAG, "Camera #" + camIdx + "failed to open: " + e.getLocalizedMessage()); |
||||||
|
} |
||||||
|
if (connected) break; |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { |
||||||
|
int localCameraIndex = mCameraIndex; |
||||||
|
if (mCameraIndex == CameraBridgeViewBase.CAMERA_ID_BACK) { |
||||||
|
Log.i(LOGTAG, "Trying to open BACK camera"); |
||||||
|
Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); |
||||||
|
for (int camIdx = 0; camIdx < Camera.getNumberOfCameras(); ++camIdx) { |
||||||
|
Camera.getCameraInfo( camIdx, cameraInfo ); |
||||||
|
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { |
||||||
|
localCameraIndex = camIdx; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (mCameraIndex == CameraBridgeViewBase.CAMERA_ID_FRONT) { |
||||||
|
Log.i(LOGTAG, "Trying to open FRONT camera"); |
||||||
|
Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); |
||||||
|
for (int camIdx = 0; camIdx < Camera.getNumberOfCameras(); ++camIdx) { |
||||||
|
Camera.getCameraInfo( camIdx, cameraInfo ); |
||||||
|
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { |
||||||
|
localCameraIndex = camIdx; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (localCameraIndex == CameraBridgeViewBase.CAMERA_ID_BACK) { |
||||||
|
Log.e(LOGTAG, "Back camera not found!"); |
||||||
|
} else if (localCameraIndex == CameraBridgeViewBase.CAMERA_ID_FRONT) { |
||||||
|
Log.e(LOGTAG, "Front camera not found!"); |
||||||
|
} else { |
||||||
|
Log.d(LOGTAG, "Trying to open camera with new open(" + localCameraIndex + ")"); |
||||||
|
try { |
||||||
|
mCamera = Camera.open(localCameraIndex); |
||||||
|
} catch (RuntimeException e) { |
||||||
|
Log.e(LOGTAG, "Camera #" + localCameraIndex + "failed to open: " + e.getLocalizedMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if(mCamera == null) { |
||||||
|
Log.e(LOGTAG, "Error: can't open camera"); |
||||||
|
return; |
||||||
|
} |
||||||
|
Camera.Parameters params = mCamera.getParameters(); |
||||||
|
List<String> FocusModes = params.getSupportedFocusModes(); |
||||||
|
if (FocusModes != null && FocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) |
||||||
|
{ |
||||||
|
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); |
||||||
|
} |
||||||
|
mCamera.setParameters(params); |
||||||
|
|
||||||
|
try { |
||||||
|
mCamera.setPreviewTexture(mSTexture); |
||||||
|
} catch (IOException ioe) { |
||||||
|
Log.e(LOGTAG, "setPreviewTexture() failed: " + ioe.getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public synchronized void setCameraPreviewSize(int width, int height) { |
||||||
|
Log.i(LOGTAG, "setCameraPreviewSize: "+width+"x"+height); |
||||||
|
if(mCamera == null) { |
||||||
|
Log.e(LOGTAG, "Camera isn't initialized!"); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if(mMaxCameraWidth > 0 && mMaxCameraWidth < width) width = mMaxCameraWidth; |
||||||
|
if(mMaxCameraHeight > 0 && mMaxCameraHeight < height) height = mMaxCameraHeight; |
||||||
|
|
||||||
|
Camera.Parameters param = mCamera.getParameters(); |
||||||
|
List<Size> psize = param.getSupportedPreviewSizes(); |
||||||
|
int bestWidth = 0, bestHeight = 0; |
||||||
|
if (psize.size() > 0) { |
||||||
|
float aspect = (float)width / height; |
||||||
|
for (Size size : psize) { |
||||||
|
int w = size.width, h = size.height; |
||||||
|
Log.d(LOGTAG, "checking camera preview size: "+w+"x"+h); |
||||||
|
if ( w <= width && h <= height && |
||||||
|
w >= bestWidth && h >= bestHeight && |
||||||
|
Math.abs(aspect - (float)w/h) < 0.2 ) { |
||||||
|
bestWidth = w; |
||||||
|
bestHeight = h; |
||||||
|
} |
||||||
|
} |
||||||
|
if(bestWidth <= 0 || bestHeight <= 0) { |
||||||
|
bestWidth = psize.get(0).width; |
||||||
|
bestHeight = psize.get(0).height; |
||||||
|
Log.e(LOGTAG, "Error: best size was not selected, using "+bestWidth+" x "+bestHeight); |
||||||
|
} else { |
||||||
|
Log.i(LOGTAG, "Selected best size: "+bestWidth+" x "+bestHeight); |
||||||
|
} |
||||||
|
|
||||||
|
if(mPreviewStarted) { |
||||||
|
mCamera.stopPreview(); |
||||||
|
mPreviewStarted = false; |
||||||
|
} |
||||||
|
mCameraWidth = bestWidth; |
||||||
|
mCameraHeight = bestHeight; |
||||||
|
param.setPreviewSize(bestWidth, bestHeight); |
||||||
|
} |
||||||
|
param.set("orientation", "landscape"); |
||||||
|
mCamera.setParameters(param); |
||||||
|
mCamera.startPreview(); |
||||||
|
mPreviewStarted = true; |
||||||
|
} |
||||||
|
} |
@ -1,375 +0,0 @@ |
|||||||
#include <GLES2/gl2.h> |
|
||||||
#include <GLES2/gl2ext.h> |
|
||||||
|
|
||||||
#include <opencv2/core.hpp> |
|
||||||
#include <opencv2/imgproc.hpp> |
|
||||||
|
|
||||||
#include "common.hpp" |
|
||||||
|
|
||||||
float vertices[] = { |
|
||||||
-1.0f, -1.0f, |
|
||||||
-1.0f, 1.0f, |
|
||||||
1.0f, -1.0f, |
|
||||||
1.0f, 1.0f |
|
||||||
}; |
|
||||||
float texCoordOES[] = { |
|
||||||
0.0f, 1.0f, |
|
||||||
0.0f, 0.0f, |
|
||||||
1.0f, 1.0f, |
|
||||||
1.0f, 0.0f |
|
||||||
}; |
|
||||||
float texCoord2D[] = { |
|
||||||
0.0f, 0.0f, |
|
||||||
0.0f, 1.0f, |
|
||||||
1.0f, 0.0f, |
|
||||||
1.0f, 1.0f |
|
||||||
}; |
|
||||||
|
|
||||||
const char vss[] = \
|
|
||||||
"attribute vec2 vPosition;\n" \
|
|
||||||
"attribute vec2 vTexCoord;\n" \
|
|
||||||
"varying vec2 texCoord;\n" \
|
|
||||||
"void main() {\n" \
|
|
||||||
" texCoord = vTexCoord;\n" \
|
|
||||||
" gl_Position = vec4 ( vPosition, 0.0, 1.0 );\n" \
|
|
||||||
"}"; |
|
||||||
|
|
||||||
const char fssOES[] = \
|
|
||||||
"#extension GL_OES_EGL_image_external : require\n" \
|
|
||||||
"precision mediump float;\n" \
|
|
||||||
"uniform samplerExternalOES sTexture;\n" \
|
|
||||||
"varying vec2 texCoord;\n" \
|
|
||||||
"void main() {\n" \
|
|
||||||
" gl_FragColor = texture2D(sTexture,texCoord);\n" \
|
|
||||||
"}"; |
|
||||||
|
|
||||||
const char fss2D[] = \
|
|
||||||
"precision mediump float;\n" \
|
|
||||||
"uniform sampler2D sTexture;\n" \
|
|
||||||
"varying vec2 texCoord;\n" \
|
|
||||||
"void main() {\n" \
|
|
||||||
" gl_FragColor = texture2D(sTexture,texCoord);\n" \
|
|
||||||
"}"; |
|
||||||
|
|
||||||
GLuint progOES = 0; |
|
||||||
GLuint prog2D = 0; |
|
||||||
|
|
||||||
GLint vPosOES, vTCOES; |
|
||||||
GLint vPos2D, vTC2D; |
|
||||||
|
|
||||||
GLuint FBOtex = 0, FBOtex2 = 0; |
|
||||||
GLuint FBO = 0; |
|
||||||
|
|
||||||
GLuint texOES = 0; |
|
||||||
int texWidth = 0, texHeight = 0; |
|
||||||
|
|
||||||
enum ProcMode {PROC_MODE_NO_PROC=0, PROC_MODE_CPU=1, PROC_MODE_OCL_DIRECT=2, PROC_MODE_OCL_OCV=3}; |
|
||||||
|
|
||||||
ProcMode procMode = PROC_MODE_NO_PROC; |
|
||||||
|
|
||||||
static inline void deleteTex(GLuint* tex) |
|
||||||
{ |
|
||||||
if(tex && *tex) |
|
||||||
{ |
|
||||||
glDeleteTextures(1, tex); |
|
||||||
*tex = 0; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static void releaseFBO() |
|
||||||
{ |
|
||||||
if (FBO != 0) |
|
||||||
{ |
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0); |
|
||||||
glDeleteFramebuffers(1, &FBO); |
|
||||||
FBO = 0; |
|
||||||
} |
|
||||||
deleteTex(&FBOtex); |
|
||||||
deleteTex(&FBOtex2); |
|
||||||
glDeleteProgram(prog2D); |
|
||||||
prog2D = 0; |
|
||||||
} |
|
||||||
|
|
||||||
static inline void logShaderCompileError(GLuint shader, bool isProgram = false) |
|
||||||
{ |
|
||||||
GLchar msg[512]; |
|
||||||
msg[0] = 0; |
|
||||||
GLsizei len; |
|
||||||
if(isProgram) |
|
||||||
glGetProgramInfoLog(shader, sizeof(msg)-1, &len, msg); |
|
||||||
else |
|
||||||
glGetShaderInfoLog(shader, sizeof(msg)-1, &len, msg); |
|
||||||
LOGE("Could not compile shader/program: %s", msg); |
|
||||||
} |
|
||||||
|
|
||||||
static int makeShaderProg(const char* vss, const char* fss) |
|
||||||
{ |
|
||||||
LOGD("makeShaderProg: setup GL_VERTEX_SHADER"); |
|
||||||
GLuint vshader = glCreateShader(GL_VERTEX_SHADER); |
|
||||||
const GLchar* text = vss; |
|
||||||
glShaderSource(vshader, 1, &text, 0); |
|
||||||
glCompileShader(vshader); |
|
||||||
GLint compiled; |
|
||||||
glGetShaderiv(vshader, GL_COMPILE_STATUS, &compiled); |
|
||||||
if (!compiled) { |
|
||||||
logShaderCompileError(vshader); |
|
||||||
glDeleteShader(vshader); |
|
||||||
vshader = 0; |
|
||||||
} |
|
||||||
|
|
||||||
LOGD("makeShaderProg: setup GL_FRAGMENT_SHADER"); |
|
||||||
GLuint fshader = glCreateShader(GL_FRAGMENT_SHADER); |
|
||||||
text = fss; |
|
||||||
glShaderSource(fshader, 1, &text, 0); |
|
||||||
glCompileShader(fshader); |
|
||||||
glGetShaderiv(fshader, GL_COMPILE_STATUS, &compiled); |
|
||||||
if (!compiled) { |
|
||||||
logShaderCompileError(fshader); |
|
||||||
glDeleteShader(fshader); |
|
||||||
fshader = 0; |
|
||||||
} |
|
||||||
|
|
||||||
LOGD("makeShaderProg: glCreateProgram"); |
|
||||||
GLuint program = glCreateProgram(); |
|
||||||
glAttachShader(program, vshader); |
|
||||||
glAttachShader(program, fshader); |
|
||||||
glLinkProgram(program); |
|
||||||
GLint linked; |
|
||||||
glGetProgramiv(program, GL_LINK_STATUS, &linked); |
|
||||||
if (!linked) |
|
||||||
{ |
|
||||||
logShaderCompileError(program, true); |
|
||||||
glDeleteProgram(program); |
|
||||||
program = 0; |
|
||||||
} |
|
||||||
glValidateProgram(program); |
|
||||||
GLint validated; |
|
||||||
glGetProgramiv(program, GL_VALIDATE_STATUS, &validated); |
|
||||||
if (!validated) |
|
||||||
{ |
|
||||||
logShaderCompileError(program, true); |
|
||||||
glDeleteProgram(program); |
|
||||||
program = 0; |
|
||||||
} |
|
||||||
|
|
||||||
if(vshader) glDeleteShader(vshader); |
|
||||||
if(fshader) glDeleteShader(fshader); |
|
||||||
|
|
||||||
return program; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
static void initFBO(int width, int height) |
|
||||||
{ |
|
||||||
LOGD("initFBO(%d, %d)", width, height); |
|
||||||
releaseFBO(); |
|
||||||
|
|
||||||
glGenTextures(1, &FBOtex2); |
|
||||||
glBindTexture(GL_TEXTURE_2D, FBOtex2); |
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); |
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
|
||||||
|
|
||||||
glGenTextures(1, &FBOtex); |
|
||||||
glBindTexture(GL_TEXTURE_2D, FBOtex); |
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); |
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
|
||||||
|
|
||||||
//int hFBO;
|
|
||||||
glGenFramebuffers(1, &FBO); |
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, FBO); |
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, FBOtex, 0); |
|
||||||
LOGD("initFBO status: %d", glGetError()); |
|
||||||
|
|
||||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) |
|
||||||
LOGE("initFBO failed: %d", glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
|
||||||
|
|
||||||
prog2D = makeShaderProg(vss, fss2D); |
|
||||||
vPos2D = glGetAttribLocation(prog2D, "vPosition"); |
|
||||||
vTC2D = glGetAttribLocation(prog2D, "vTexCoord"); |
|
||||||
glEnableVertexAttribArray(vPos2D); |
|
||||||
glEnableVertexAttribArray(vTC2D); |
|
||||||
} |
|
||||||
|
|
||||||
void drawTex(int tex, GLenum texType, GLuint fbo) |
|
||||||
{ |
|
||||||
int64_t t = getTimeMs(); |
|
||||||
//draw texture to FBO or to screen
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
|
||||||
glViewport(0, 0, texWidth, texHeight); |
|
||||||
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT); |
|
||||||
|
|
||||||
GLuint prog = texType == GL_TEXTURE_EXTERNAL_OES ? progOES : prog2D; |
|
||||||
GLint vPos = texType == GL_TEXTURE_EXTERNAL_OES ? vPosOES : vPos2D; |
|
||||||
GLint vTC = texType == GL_TEXTURE_EXTERNAL_OES ? vTCOES : vTC2D; |
|
||||||
float* texCoord = texType == GL_TEXTURE_EXTERNAL_OES ? texCoordOES : texCoord2D; |
|
||||||
glUseProgram(prog); |
|
||||||
glVertexAttribPointer(vPos, 2, GL_FLOAT, false, 4*2, vertices); |
|
||||||
glVertexAttribPointer(vTC, 2, GL_FLOAT, false, 4*2, texCoord); |
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0); |
|
||||||
glBindTexture(texType, tex); |
|
||||||
glUniform1i(glGetUniformLocation(prog, "sTexture"), 0); |
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
|
||||||
glFlush(); |
|
||||||
LOGD("drawTex(%u) costs %d ms", tex, getTimeInterval(t)); |
|
||||||
} |
|
||||||
|
|
||||||
void drawFrameOrig() |
|
||||||
{ |
|
||||||
drawTex(texOES, GL_TEXTURE_EXTERNAL_OES, 0); |
|
||||||
} |
|
||||||
|
|
||||||
void procCPU(char* buff, int w, int h) |
|
||||||
{ |
|
||||||
int64_t t = getTimeMs(); |
|
||||||
cv::Mat m(h, w, CV_8UC4, buff); |
|
||||||
cv::Laplacian(m, m, CV_8U); |
|
||||||
m *= 10; |
|
||||||
LOGD("procCPU() costs %d ms", getTimeInterval(t)); |
|
||||||
} |
|
||||||
|
|
||||||
void drawFrameProcCPU() |
|
||||||
{ |
|
||||||
int64_t t; |
|
||||||
drawTex(texOES, GL_TEXTURE_EXTERNAL_OES, FBO); |
|
||||||
|
|
||||||
// let's modify pixels in FBO texture in C++ code (on CPU)
|
|
||||||
const int BUFF_SIZE = 1<<24;//2k*2k*4;
|
|
||||||
static char tmpBuff[BUFF_SIZE]; |
|
||||||
if(texWidth*texHeight > BUFF_SIZE) |
|
||||||
{ |
|
||||||
LOGE("Internal temp buffer is too small, can't make CPU frame processing"); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
// read
|
|
||||||
t = getTimeMs(); |
|
||||||
glReadPixels(0, 0, texWidth, texHeight, GL_RGBA, GL_UNSIGNED_BYTE, tmpBuff); |
|
||||||
LOGD("glReadPixels() costs %d ms", getTimeInterval(t)); |
|
||||||
|
|
||||||
// modify
|
|
||||||
procCPU(tmpBuff, texWidth, texHeight); |
|
||||||
|
|
||||||
// write back
|
|
||||||
t = getTimeMs(); |
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texWidth, texHeight, GL_RGBA, GL_UNSIGNED_BYTE, tmpBuff); |
|
||||||
LOGD("glTexSubImage2D() costs %d ms", getTimeInterval(t)); |
|
||||||
|
|
||||||
// render to screen
|
|
||||||
drawTex(FBOtex, GL_TEXTURE_2D, 0); |
|
||||||
} |
|
||||||
|
|
||||||
void procOCL_I2I(int texIn, int texOut, int w, int h); |
|
||||||
void procOCL_OCV(int texIn, int texOut, int w, int h); |
|
||||||
void drawFrameProcOCL() |
|
||||||
{ |
|
||||||
drawTex(texOES, GL_TEXTURE_EXTERNAL_OES, FBO); |
|
||||||
|
|
||||||
// modify pixels in FBO texture using OpenCL and CL-GL interop
|
|
||||||
procOCL_I2I(FBOtex, FBOtex2, texWidth, texHeight); |
|
||||||
|
|
||||||
// render to screen
|
|
||||||
drawTex(FBOtex2, GL_TEXTURE_2D, 0); |
|
||||||
} |
|
||||||
|
|
||||||
void drawFrameProcOCLOCV() |
|
||||||
{ |
|
||||||
drawTex(texOES, GL_TEXTURE_EXTERNAL_OES, FBO); |
|
||||||
|
|
||||||
// modify pixels in FBO texture using OpenCL and CL-GL interop
|
|
||||||
procOCL_OCV(FBOtex, FBOtex2, texWidth, texHeight); |
|
||||||
|
|
||||||
// render to screen
|
|
||||||
drawTex(FBOtex2, GL_TEXTURE_2D, 0); |
|
||||||
} |
|
||||||
|
|
||||||
extern "C" void drawFrame() |
|
||||||
{ |
|
||||||
LOGD("*** drawFrame() ***"); |
|
||||||
int64_t t = getTimeMs(); |
|
||||||
|
|
||||||
switch(procMode) |
|
||||||
{ |
|
||||||
case PROC_MODE_NO_PROC: drawFrameOrig(); break; |
|
||||||
case PROC_MODE_CPU: drawFrameProcCPU(); break; |
|
||||||
case PROC_MODE_OCL_DIRECT: drawFrameProcOCL(); break; |
|
||||||
case PROC_MODE_OCL_OCV: drawFrameProcOCLOCV(); break; |
|
||||||
default: drawFrameOrig(); |
|
||||||
} |
|
||||||
|
|
||||||
glFinish(); |
|
||||||
LOGD("*** drawFrame() costs %d ms ***", getTimeInterval(t)); |
|
||||||
} |
|
||||||
|
|
||||||
void closeCL(); |
|
||||||
extern "C" void closeGL() |
|
||||||
{ |
|
||||||
closeCL(); |
|
||||||
LOGD("closeGL"); |
|
||||||
deleteTex(&texOES); |
|
||||||
|
|
||||||
glUseProgram(0); |
|
||||||
glDeleteProgram(progOES); |
|
||||||
progOES = 0; |
|
||||||
|
|
||||||
releaseFBO(); |
|
||||||
} |
|
||||||
|
|
||||||
void initCL(); |
|
||||||
extern "C" int initGL() |
|
||||||
{ |
|
||||||
LOGD("initGL"); |
|
||||||
|
|
||||||
closeGL(); |
|
||||||
|
|
||||||
const char* vs = (const char*)glGetString(GL_VERSION); |
|
||||||
LOGD("GL_VERSION = %s", vs); |
|
||||||
|
|
||||||
progOES = makeShaderProg(vss, fssOES); |
|
||||||
vPosOES = glGetAttribLocation(progOES, "vPosition"); |
|
||||||
vTCOES = glGetAttribLocation(progOES, "vTexCoord"); |
|
||||||
glEnableVertexAttribArray(vPosOES); |
|
||||||
glEnableVertexAttribArray(vTCOES); |
|
||||||
|
|
||||||
glClearColor(1.0f, 1.0f, 1.0f, 1.0f); |
|
||||||
|
|
||||||
texOES = 0; |
|
||||||
glGenTextures(1, &texOES); |
|
||||||
glBindTexture(GL_TEXTURE_EXTERNAL_OES, texOES); |
|
||||||
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
|
||||||
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
|
||||||
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
|
||||||
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
|
||||||
|
|
||||||
initCL(); |
|
||||||
|
|
||||||
return texOES; |
|
||||||
} |
|
||||||
|
|
||||||
extern "C" void changeSize(int width, int height) |
|
||||||
{ |
|
||||||
const int MAX_W=1<<11, MAX_H=1<<11; |
|
||||||
LOGD("changeSize: %dx%d", width, height); |
|
||||||
texWidth = width <= MAX_W ? width : MAX_W; |
|
||||||
texHeight = height <= MAX_H ? height : MAX_H; |
|
||||||
initFBO(texWidth, texHeight); |
|
||||||
} |
|
||||||
|
|
||||||
extern "C" void setProcessingMode(int mode) |
|
||||||
{ |
|
||||||
switch(mode) |
|
||||||
{ |
|
||||||
case PROC_MODE_NO_PROC: procMode = PROC_MODE_NO_PROC; break; |
|
||||||
case PROC_MODE_CPU: procMode = PROC_MODE_CPU; break; |
|
||||||
case PROC_MODE_OCL_DIRECT: procMode = PROC_MODE_OCL_DIRECT; break; |
|
||||||
case PROC_MODE_OCL_OCV: procMode = PROC_MODE_OCL_OCV; break; |
|
||||||
} |
|
||||||
} |
|
@ -1,32 +1,20 @@ |
|||||||
#include <jni.h> |
#include <jni.h> |
||||||
|
|
||||||
int initGL(); |
int initCL(); |
||||||
void closeGL(); |
void closeCL(); |
||||||
void changeSize(int width, int height); |
void processFrame(int tex1, int tex2, int w, int h, int mode); |
||||||
void drawFrame(); |
|
||||||
void setProcessingMode(int mode); |
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_org_opencv_samples_tutorial4_NativeGLRenderer_initGL(JNIEnv * env, jclass cls) |
JNIEXPORT jint JNICALL Java_org_opencv_samples_tutorial4_NativePart_initCL(JNIEnv * env, jclass cls) |
||||||
{ |
{ |
||||||
return initGL(); |
return initCL(); |
||||||
} |
} |
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial4_NativeGLRenderer_closeGL(JNIEnv * env, jclass cls) |
JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial4_NativePart_closeCL(JNIEnv * env, jclass cls) |
||||||
{ |
{ |
||||||
closeGL(); |
closeCL(); |
||||||
} |
} |
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial4_NativeGLRenderer_changeSize(JNIEnv * env, jclass cls, jint width, jint height) |
JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial4_NativePart_processFrame(JNIEnv * env, jclass cls, jint tex1, jint tex2, jint w, jint h, jint mode) |
||||||
{ |
{ |
||||||
changeSize(width, height); |
processFrame(tex1, tex2, w, h, mode); |
||||||
} |
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial4_NativeGLRenderer_drawFrame(JNIEnv * env, jclass cls) |
|
||||||
{ |
|
||||||
drawFrame(); |
|
||||||
} |
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial4_NativeGLRenderer_setProcessingMode(JNIEnv * env, jclass cls, jint mode) |
|
||||||
{ |
|
||||||
setProcessingMode(mode); |
|
||||||
} |
} |
||||||
|
@ -1,75 +0,0 @@ |
|||||||
package org.opencv.samples.tutorial4; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import android.hardware.Camera; |
|
||||||
import android.hardware.Camera.Size; |
|
||||||
import android.util.Log; |
|
||||||
|
|
||||||
@SuppressWarnings("deprecation") |
|
||||||
public class CameraRenderer extends MyGLRendererBase { |
|
||||||
|
|
||||||
protected final String LOGTAG = "CameraRenderer"; |
|
||||||
private Camera mCamera; |
|
||||||
boolean mPreviewStarted = false; |
|
||||||
|
|
||||||
CameraRenderer(MyGLSurfaceView view) { |
|
||||||
super(view); |
|
||||||
} |
|
||||||
|
|
||||||
protected void closeCamera() { |
|
||||||
Log.i(LOGTAG, "closeCamera"); |
|
||||||
if(mCamera != null) { |
|
||||||
mCamera.stopPreview(); |
|
||||||
mPreviewStarted = false; |
|
||||||
mCamera.release(); |
|
||||||
mCamera = null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected void openCamera() { |
|
||||||
Log.i(LOGTAG, "openCamera"); |
|
||||||
closeCamera(); |
|
||||||
mCamera = Camera.open(); |
|
||||||
try { |
|
||||||
mCamera.setPreviewTexture(mSTex); |
|
||||||
} catch (IOException ioe) { |
|
||||||
Log.e(LOGTAG, "setPreviewTexture() failed: " + ioe.getMessage()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void setCameraPreviewSize(int width, int height) { |
|
||||||
Log.i(LOGTAG, "setCameraPreviewSize: "+width+"x"+height); |
|
||||||
if(mCamera == null) |
|
||||||
return; |
|
||||||
if(mPreviewStarted) { |
|
||||||
mCamera.stopPreview(); |
|
||||||
mPreviewStarted = false; |
|
||||||
} |
|
||||||
Camera.Parameters param = mCamera.getParameters(); |
|
||||||
List<Size> psize = param.getSupportedPreviewSizes(); |
|
||||||
int bestWidth = 0, bestHeight = 0; |
|
||||||
if (psize.size() > 0) { |
|
||||||
float aspect = (float)width / height; |
|
||||||
for (Size size : psize) { |
|
||||||
int w = size.width, h = size.height; |
|
||||||
Log.d("Renderer", "checking camera preview size: "+w+"x"+h); |
|
||||||
if ( w <= width && h <= height && |
|
||||||
w >= bestWidth && h >= bestHeight && |
|
||||||
Math.abs(aspect - (float)w/h) < 0.2 ) { |
|
||||||
bestWidth = w; |
|
||||||
bestHeight = h; |
|
||||||
} |
|
||||||
} |
|
||||||
if(bestWidth > 0 && bestHeight > 0) { |
|
||||||
param.setPreviewSize(bestWidth, bestHeight); |
|
||||||
Log.i(LOGTAG, "size: "+bestWidth+" x "+bestHeight); |
|
||||||
} |
|
||||||
} |
|
||||||
param.set("orientation", "landscape"); |
|
||||||
mCamera.setParameters(param); |
|
||||||
mCamera.startPreview(); |
|
||||||
mPreviewStarted = true; |
|
||||||
} |
|
||||||
} |
|
@ -1,117 +0,0 @@ |
|||||||
package org.opencv.samples.tutorial4; |
|
||||||
|
|
||||||
import javax.microedition.khronos.egl.EGLConfig; |
|
||||||
import javax.microedition.khronos.opengles.GL10; |
|
||||||
|
|
||||||
import android.graphics.SurfaceTexture; |
|
||||||
import android.opengl.GLES20; |
|
||||||
import android.opengl.GLSurfaceView; |
|
||||||
import android.os.Handler; |
|
||||||
import android.os.Looper; |
|
||||||
import android.util.Log; |
|
||||||
import android.widget.TextView; |
|
||||||
|
|
||||||
public abstract class MyGLRendererBase implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener { |
|
||||||
protected final String LOGTAG = "MyGLRendererBase"; |
|
||||||
protected int frameCounter; |
|
||||||
protected long lastNanoTime; |
|
||||||
|
|
||||||
protected SurfaceTexture mSTex; |
|
||||||
protected MyGLSurfaceView mView; |
|
||||||
protected TextView mFpsText; |
|
||||||
|
|
||||||
protected boolean mGLInit = false; |
|
||||||
protected boolean mTexUpdate = false; |
|
||||||
|
|
||||||
MyGLRendererBase(MyGLSurfaceView view) { |
|
||||||
mView = view; |
|
||||||
} |
|
||||||
|
|
||||||
protected abstract void openCamera(); |
|
||||||
protected abstract void closeCamera(); |
|
||||||
protected abstract void setCameraPreviewSize(int width, int height); |
|
||||||
|
|
||||||
public void setFpsTextView(TextView fpsTV) |
|
||||||
{ |
|
||||||
mFpsText = fpsTV; |
|
||||||
} |
|
||||||
|
|
||||||
public void onResume() { |
|
||||||
Log.i(LOGTAG, "onResume"); |
|
||||||
frameCounter = 0; |
|
||||||
lastNanoTime = System.nanoTime(); |
|
||||||
} |
|
||||||
|
|
||||||
public void onPause() { |
|
||||||
Log.i(LOGTAG, "onPause"); |
|
||||||
mGLInit = false; |
|
||||||
mTexUpdate = false; |
|
||||||
closeCamera(); |
|
||||||
if(mSTex != null) { |
|
||||||
mSTex.release(); |
|
||||||
mSTex = null; |
|
||||||
NativeGLRenderer.closeGL(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public synchronized void onFrameAvailable(SurfaceTexture surfaceTexture) { |
|
||||||
//Log.i(LOGTAG, "onFrameAvailable");
|
|
||||||
mTexUpdate = true; |
|
||||||
mView.requestRender(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onDrawFrame(GL10 gl) { |
|
||||||
//Log.i(LOGTAG, "onDrawFrame");
|
|
||||||
if (!mGLInit) |
|
||||||
return; |
|
||||||
|
|
||||||
synchronized (this) { |
|
||||||
if (mTexUpdate) { |
|
||||||
mSTex.updateTexImage(); |
|
||||||
mTexUpdate = false; |
|
||||||
} |
|
||||||
} |
|
||||||
NativeGLRenderer.drawFrame(); |
|
||||||
|
|
||||||
// log FPS
|
|
||||||
frameCounter++; |
|
||||||
if(frameCounter >= 10) |
|
||||||
{ |
|
||||||
final int fps = (int) (frameCounter * 1e9 / (System.nanoTime() - lastNanoTime)); |
|
||||||
Log.i(LOGTAG, "drawFrame() FPS: "+fps); |
|
||||||
if(mFpsText != null) { |
|
||||||
Runnable fpsUpdater = new Runnable() { |
|
||||||
public void run() { |
|
||||||
mFpsText.setText("FPS: " + fps); |
|
||||||
} |
|
||||||
}; |
|
||||||
new Handler(Looper.getMainLooper()).post(fpsUpdater); |
|
||||||
} |
|
||||||
frameCounter = 0; |
|
||||||
lastNanoTime = System.nanoTime(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onSurfaceChanged(GL10 gl, int surfaceWidth, int surfaceHeight) { |
|
||||||
Log.i(LOGTAG, "onSurfaceChanged("+surfaceWidth+"x"+surfaceHeight+")"); |
|
||||||
NativeGLRenderer.changeSize(surfaceWidth, surfaceHeight); |
|
||||||
setCameraPreviewSize(surfaceWidth, surfaceHeight); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onSurfaceCreated(GL10 gl, EGLConfig config) { |
|
||||||
Log.i(LOGTAG, "onSurfaceCreated"); |
|
||||||
String strGLVersion = GLES20.glGetString(GLES20.GL_VERSION); |
|
||||||
if (strGLVersion != null) |
|
||||||
Log.i(LOGTAG, "OpenGL ES version: " + strGLVersion); |
|
||||||
|
|
||||||
int hTex = NativeGLRenderer.initGL(); |
|
||||||
mSTex = new SurfaceTexture(hTex); |
|
||||||
mSTex.setOnFrameAvailableListener(this); |
|
||||||
openCamera(); |
|
||||||
mGLInit = true; |
|
||||||
} |
|
||||||
} |
|
@ -1,65 +1,112 @@ |
|||||||
package org.opencv.samples.tutorial4; |
package org.opencv.samples.tutorial4; |
||||||
|
|
||||||
|
import org.opencv.android.CameraGLSurfaceView; |
||||||
|
|
||||||
import android.app.Activity; |
import android.app.Activity; |
||||||
import android.content.Context; |
import android.content.Context; |
||||||
import android.opengl.GLSurfaceView; |
import android.os.Handler; |
||||||
|
import android.os.Looper; |
||||||
import android.util.AttributeSet; |
import android.util.AttributeSet; |
||||||
|
import android.util.Log; |
||||||
import android.view.MotionEvent; |
import android.view.MotionEvent; |
||||||
import android.view.SurfaceHolder; |
import android.view.SurfaceHolder; |
||||||
import android.widget.TextView; |
import android.widget.TextView; |
||||||
|
import android.widget.Toast; |
||||||
|
|
||||||
public class MyGLSurfaceView extends GLSurfaceView { |
public class MyGLSurfaceView extends CameraGLSurfaceView implements CameraGLSurfaceView.CameraTextureListener { |
||||||
|
|
||||||
MyGLRendererBase mRenderer; |
static final String LOGTAG = "MyGLSurfaceView"; |
||||||
|
protected int procMode = NativePart.PROCESSING_MODE_NO_PROCESSING; |
||||||
|
static final String[] procModeName = new String[] {"No Processing", "CPU", "OpenCL Direct", "OpenCL via OpenCV"}; |
||||||
|
protected int frameCounter; |
||||||
|
protected long lastNanoTime; |
||||||
|
TextView mFpsText = null; |
||||||
|
|
||||||
public MyGLSurfaceView(Context context, AttributeSet attrs) { |
public MyGLSurfaceView(Context context, AttributeSet attrs) { |
||||||
super(context, attrs); |
super(context, attrs); |
||||||
|
|
||||||
if(android.os.Build.VERSION.SDK_INT >= 21) |
|
||||||
mRenderer = new Camera2Renderer(this); |
|
||||||
else |
|
||||||
mRenderer = new CameraRenderer(this); |
|
||||||
|
|
||||||
setEGLContextClientVersion(2); |
|
||||||
setRenderer(mRenderer); |
|
||||||
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); |
|
||||||
} |
} |
||||||
|
|
||||||
public void setFpsTextView(TextView tv) { |
@Override |
||||||
mRenderer.setFpsTextView(tv); |
public boolean onTouchEvent(MotionEvent e) { |
||||||
|
if(e.getAction() == MotionEvent.ACTION_DOWN) |
||||||
|
((Activity)getContext()).openOptionsMenu(); |
||||||
|
return true; |
||||||
} |
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
public void surfaceCreated(SurfaceHolder holder) { |
public void surfaceCreated(SurfaceHolder holder) { |
||||||
super.surfaceCreated(holder); |
super.surfaceCreated(holder); |
||||||
|
//NativePart.initCL();
|
||||||
} |
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
public void surfaceDestroyed(SurfaceHolder holder) { |
public void surfaceDestroyed(SurfaceHolder holder) { |
||||||
|
//NativePart.closeCL();
|
||||||
super.surfaceDestroyed(holder); |
super.surfaceDestroyed(holder); |
||||||
} |
} |
||||||
|
|
||||||
@Override |
public void setProcessingMode(int newMode) { |
||||||
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { |
if(newMode>=0 && newMode<procModeName.length) |
||||||
super.surfaceChanged(holder, format, w, h); |
procMode = newMode; |
||||||
|
else |
||||||
|
Log.e(LOGTAG, "Ignoring invalid processing mode: " + newMode); |
||||||
|
|
||||||
|
((Activity) getContext()).runOnUiThread(new Runnable() { |
||||||
|
public void run() { |
||||||
|
Toast.makeText(getContext(), "Selected mode: " + procModeName[procMode], Toast.LENGTH_LONG).show(); |
||||||
|
} |
||||||
|
}); |
||||||
} |
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
public void onResume() { |
public void onCameraViewStarted(int width, int height) { |
||||||
super.onResume(); |
((Activity) getContext()).runOnUiThread(new Runnable() { |
||||||
mRenderer.onResume(); |
public void run() { |
||||||
|
Toast.makeText(getContext(), "onCameraViewStarted", Toast.LENGTH_SHORT).show(); |
||||||
|
} |
||||||
|
}); |
||||||
|
NativePart.initCL(); |
||||||
|
frameCounter = 0; |
||||||
|
lastNanoTime = System.nanoTime(); |
||||||
} |
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
public void onPause() { |
public void onCameraViewStopped() { |
||||||
mRenderer.onPause(); |
((Activity) getContext()).runOnUiThread(new Runnable() { |
||||||
super.onPause(); |
public void run() { |
||||||
|
Toast.makeText(getContext(), "onCameraViewStopped", Toast.LENGTH_SHORT).show(); |
||||||
|
} |
||||||
|
}); |
||||||
} |
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
public boolean onTouchEvent(MotionEvent e) { |
public boolean onCameraTexture(int texIn, int texOut, int width, int height) { |
||||||
if(e.getAction() == MotionEvent.ACTION_DOWN) |
// FPS
|
||||||
((Activity)getContext()).openOptionsMenu(); |
frameCounter++; |
||||||
|
if(frameCounter >= 30) |
||||||
|
{ |
||||||
|
final int fps = (int) (frameCounter * 1e9 / (System.nanoTime() - lastNanoTime)); |
||||||
|
Log.i(LOGTAG, "drawFrame() FPS: "+fps); |
||||||
|
if(mFpsText != null) { |
||||||
|
Runnable fpsUpdater = new Runnable() { |
||||||
|
public void run() { |
||||||
|
mFpsText.setText("FPS: " + fps); |
||||||
|
} |
||||||
|
}; |
||||||
|
new Handler(Looper.getMainLooper()).post(fpsUpdater); |
||||||
|
} else { |
||||||
|
Log.d(LOGTAG, "mFpsText == null"); |
||||||
|
mFpsText = (TextView)((Activity) getContext()).findViewById(R.id.fps_text_view); |
||||||
|
} |
||||||
|
frameCounter = 0; |
||||||
|
lastNanoTime = System.nanoTime(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
if(procMode == NativePart.PROCESSING_MODE_NO_PROCESSING) |
||||||
|
return false; |
||||||
|
|
||||||
|
NativePart.processFrame(texIn, texOut, width, height, procMode); |
||||||
return true; |
return true; |
||||||
} |
} |
||||||
} |
} |
||||||
|
Loading…
Reference in new issue