|
|
@ -57,7 +57,7 @@ import javax.microedition.khronos.opengles.GL10; |
|
|
|
* Callbacks are guaranteed to be called on the renderer thread, which means that we can fetch |
|
|
|
* Callbacks are guaranteed to be called on the renderer thread, which means that we can fetch |
|
|
|
* the GL context that was created and is managed by the {@link GLSurfaceView}. |
|
|
|
* the GL context that was created and is managed by the {@link GLSurfaceView}. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> implements GLSurfaceView.Renderer { |
|
|
|
public class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> { |
|
|
|
|
|
|
|
|
|
|
|
private boolean mDispatched; |
|
|
|
private boolean mDispatched; |
|
|
|
private final float[] mTransformMatrix = new float[16]; |
|
|
|
private final float[] mTransformMatrix = new float[16]; |
|
|
@ -68,33 +68,11 @@ public class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture |
|
|
|
@VisibleForTesting float mCropScaleX = 1F; |
|
|
|
@VisibleForTesting float mCropScaleX = 1F; |
|
|
|
@VisibleForTesting float mCropScaleY = 1F; |
|
|
|
@VisibleForTesting float mCropScaleY = 1F; |
|
|
|
private View mRootView; |
|
|
|
private View mRootView; |
|
|
|
|
|
|
|
private final GLSurfaceView.Renderer mRenderer; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
public GlCameraPreview(@NonNull Context context, @NonNull ViewGroup parent) { |
|
|
|
* Method specific to the GL preview. Adds a {@link RendererFrameCallback} |
|
|
|
super(context, parent); |
|
|
|
* to receive renderer frame events. |
|
|
|
mRenderer = new Renderer(); |
|
|
|
* @param callback a callback |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public void addRendererFrameCallback(@NonNull final RendererFrameCallback callback) { |
|
|
|
|
|
|
|
getView().queueEvent(new Runnable() { |
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public void run() { |
|
|
|
|
|
|
|
mRendererFrameCallbacks.add(callback); |
|
|
|
|
|
|
|
if (mOutputTextureId != 0) callback.onRendererTextureCreated(mOutputTextureId); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Method specific to the GL preview. Removes a {@link RendererFrameCallback} |
|
|
|
|
|
|
|
* that was previously added to receive renderer frame events. |
|
|
|
|
|
|
|
* @param callback a callback |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public void removeRendererFrameCallback(@NonNull final RendererFrameCallback callback) { |
|
|
|
|
|
|
|
mRendererFrameCallbacks.remove(callback); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public GlCameraPreview(@NonNull Context context, @NonNull ViewGroup parent, @Nullable SurfaceCallback callback) { |
|
|
|
|
|
|
|
super(context, parent, callback); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@NonNull |
|
|
|
@NonNull |
|
|
@ -103,11 +81,8 @@ public class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture |
|
|
|
ViewGroup root = (ViewGroup) LayoutInflater.from(context).inflate(R.layout.cameraview_gl_view, parent, false); |
|
|
|
ViewGroup root = (ViewGroup) LayoutInflater.from(context).inflate(R.layout.cameraview_gl_view, parent, false); |
|
|
|
GLSurfaceView glView = root.findViewById(R.id.gl_surface_view); |
|
|
|
GLSurfaceView glView = root.findViewById(R.id.gl_surface_view); |
|
|
|
glView.setEGLContextClientVersion(2); |
|
|
|
glView.setEGLContextClientVersion(2); |
|
|
|
glView.setRenderer(this); |
|
|
|
glView.setRenderer(mRenderer); |
|
|
|
glView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); |
|
|
|
glView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); |
|
|
|
// Tried these 2 to remove the black background, does not work.
|
|
|
|
|
|
|
|
// glView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
|
|
|
|
|
|
|
|
// glView.setZOrderMediaOverlay(true);
|
|
|
|
|
|
|
|
glView.getHolder().addCallback(new SurfaceHolder.Callback() { |
|
|
|
glView.getHolder().addCallback(new SurfaceHolder.Callback() { |
|
|
|
public void surfaceCreated(SurfaceHolder holder) {} |
|
|
|
public void surfaceCreated(SurfaceHolder holder) {} |
|
|
|
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } |
|
|
|
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } |
|
|
@ -158,6 +133,11 @@ public class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* The core renderer that performs the actual drawing operations. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public class Renderer implements GLSurfaceView.Renderer { |
|
|
|
|
|
|
|
|
|
|
|
@RendererThread |
|
|
|
@RendererThread |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void onSurfaceCreated(GL10 gl, EGLConfig config) { |
|
|
|
public void onSurfaceCreated(GL10 gl, EGLConfig config) { |
|
|
@ -184,7 +164,6 @@ public class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@RendererThread |
|
|
|
@RendererThread |
|
|
|
@SuppressWarnings("StatementWithEmptyBody") |
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void onSurfaceChanged(GL10 gl, final int width, final int height) { |
|
|
|
public void onSurfaceChanged(GL10 gl, final int width, final int height) { |
|
|
|
gl.glViewport(0, 0, width, height); |
|
|
|
gl.glViewport(0, 0, width, height); |
|
|
@ -218,10 +197,9 @@ public class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (isCropping()) { |
|
|
|
if (isCropping()) { |
|
|
|
// Scaling is easy. However:
|
|
|
|
// Scaling is easy, but we must also translate before:
|
|
|
|
// If the view is 10x1000 (very tall), it will show only the left strip of the preview (not the center one).
|
|
|
|
// If the view is 10x1000 (very tall), it will show only the left strip of the preview (not the center one).
|
|
|
|
// If the view is 1000x10 (very large), it will show only the bottom strip of the preview (not the center one).
|
|
|
|
// If the view is 1000x10 (very large), it will show only the bottom strip of the preview (not the center one).
|
|
|
|
// So we must use Matrix.translateM, and it must happen before the crop.
|
|
|
|
|
|
|
|
float translX = (1F - mCropScaleX) / 2F; |
|
|
|
float translX = (1F - mCropScaleX) / 2F; |
|
|
|
float translY = (1F - mCropScaleY) / 2F; |
|
|
|
float translY = (1F - mCropScaleY) / 2F; |
|
|
|
Matrix.translateM(mTransformMatrix, 0, translX, translY, 0); |
|
|
|
Matrix.translateM(mTransformMatrix, 0, translX, translY, 0); |
|
|
@ -234,6 +212,7 @@ public class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture |
|
|
|
callback.onRendererFrame(mInputSurfaceTexture, mCropScaleX, mCropScaleY); |
|
|
|
callback.onRendererFrame(mInputSurfaceTexture, mCropScaleX, mCropScaleY); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@NonNull |
|
|
|
@NonNull |
|
|
|
@Override |
|
|
|
@Override |
|
|
@ -262,7 +241,7 @@ public class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture |
|
|
|
* platform when its window is positioned asynchronously. |
|
|
|
* platform when its window is positioned asynchronously. |
|
|
|
* |
|
|
|
* |
|
|
|
* But to support older platforms, this seem to work - computing scale values and requesting a new frame, |
|
|
|
* But to support older platforms, this seem to work - computing scale values and requesting a new frame, |
|
|
|
* then drawing it with a scaled transformation matrix. See {@link #onDrawFrame(GL10)}. |
|
|
|
* then drawing it with a scaled transformation matrix. See {@link Renderer#onDrawFrame(GL10)}. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
protected void crop(@NonNull Op<Void> op) { |
|
|
|
protected void crop(@NonNull Op<Void> op) { |
|
|
@ -285,4 +264,47 @@ public class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture |
|
|
|
} |
|
|
|
} |
|
|
|
op.end(null); |
|
|
|
op.end(null); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Method specific to the GL preview. Adds a {@link RendererFrameCallback} |
|
|
|
|
|
|
|
* to receive renderer frame events. |
|
|
|
|
|
|
|
* @param callback a callback |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public void addRendererFrameCallback(@NonNull final RendererFrameCallback callback) { |
|
|
|
|
|
|
|
getView().queueEvent(new Runnable() { |
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public void run() { |
|
|
|
|
|
|
|
mRendererFrameCallbacks.add(callback); |
|
|
|
|
|
|
|
if (mOutputTextureId != 0) callback.onRendererTextureCreated(mOutputTextureId); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Method specific to the GL preview. Removes a {@link RendererFrameCallback} |
|
|
|
|
|
|
|
* that was previously added to receive renderer frame events. |
|
|
|
|
|
|
|
* @param callback a callback |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public void removeRendererFrameCallback(@NonNull final RendererFrameCallback callback) { |
|
|
|
|
|
|
|
mRendererFrameCallbacks.remove(callback); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Returns the output GL texture id. |
|
|
|
|
|
|
|
* @return the output GL texture id |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
@SuppressWarnings("unused") |
|
|
|
|
|
|
|
protected int getTextureId() { |
|
|
|
|
|
|
|
return mOutputTextureId; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Returns the GL renderer. |
|
|
|
|
|
|
|
* @return the GL renderer |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
@SuppressWarnings("unused") |
|
|
|
|
|
|
|
@NonNull |
|
|
|
|
|
|
|
protected GLSurfaceView.Renderer getRenderer() { |
|
|
|
|
|
|
|
return mRenderer; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|