Refactor CameraPreviews

pull/494/head
Mattia Iavarone 6 years ago
parent 62cfb5d7f0
commit 98741c2bfa
  1. 5
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/preview/CameraPreviewTest.java
  2. 4
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/preview/GlCameraPreviewTest.java
  3. 4
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/preview/SurfaceCameraPreviewTest.java
  4. 4
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/preview/TextureCameraPreviewTest.java
  5. 6
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java
  6. 12
      cameraview/src/main/java/com/otaliastudios/cameraview/preview/CameraPreview.java
  7. 92
      cameraview/src/main/java/com/otaliastudios/cameraview/preview/GlCameraPreview.java
  8. 5
      cameraview/src/main/java/com/otaliastudios/cameraview/preview/SurfaceCameraPreview.java
  9. 4
      cameraview/src/main/java/com/otaliastudios/cameraview/preview/TextureCameraPreview.java

@ -27,7 +27,7 @@ public abstract class CameraPreviewTest extends BaseTest {
private final static long DELAY = 4000;
protected abstract CameraPreview createPreview(Context context, ViewGroup parent, CameraPreview.SurfaceCallback callback);
protected abstract CameraPreview createPreview(Context context, ViewGroup parent);
@Rule
public ActivityTestRule<TestActivity> rule = new ActivityTestRule<>(TestActivity.class);
@ -69,7 +69,8 @@ public abstract class CameraPreviewTest extends BaseTest {
}
}).when(callback).onSurfaceDestroyed();
preview = createPreview(a, a.getContentView(), callback);
preview = createPreview(a, a.getContentView());
preview.setSurfaceCallback(callback);
}
});
}

@ -14,8 +14,8 @@ import org.junit.runner.RunWith;
public class GlCameraPreviewTest extends CameraPreviewTest {
@Override
protected CameraPreview createPreview(Context context, ViewGroup parent, CameraPreview.SurfaceCallback callback) {
return new GlCameraPreview(context, parent, callback);
protected CameraPreview createPreview(Context context, ViewGroup parent) {
return new GlCameraPreview(context, parent);
}
@Override

@ -18,8 +18,8 @@ import org.junit.runner.RunWith;
public class SurfaceCameraPreviewTest extends CameraPreviewTest {
@Override
protected CameraPreview createPreview(Context context, ViewGroup parent, CameraPreview.SurfaceCallback callback) {
return new SurfaceCameraPreview(context, parent, callback);
protected CameraPreview createPreview(Context context, ViewGroup parent) {
return new SurfaceCameraPreview(context, parent);
}
@Override

@ -18,8 +18,8 @@ import org.junit.runner.RunWith;
public class TextureCameraPreviewTest extends CameraPreviewTest {
@Override
protected CameraPreview createPreview(Context context, ViewGroup parent, CameraPreview.SurfaceCallback callback) {
return new TextureCameraPreview(context, parent, callback);
protected CameraPreview createPreview(Context context, ViewGroup parent) {
return new TextureCameraPreview(context, parent);
}
@Override

@ -276,16 +276,16 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
LOG.w("preview:", "isHardwareAccelerated:", isHardwareAccelerated());
switch (preview) {
case SURFACE:
return new SurfaceCameraPreview(context, container, null);
return new SurfaceCameraPreview(context, container);
case TEXTURE: {
if (isHardwareAccelerated()) {
// TextureView is not supported without hardware acceleration.
return new TextureCameraPreview(context, container, null);
return new TextureCameraPreview(context, container);
}
}
case GL_SURFACE: default: {
mPreview = Preview.GL_SURFACE;
return new GlCameraPreview(context, container, null);
return new GlCameraPreview(context, container);
}
}
}

@ -67,11 +67,9 @@ public abstract class CameraPreview<T extends View, Output> {
* Creates a new preview.
* @param context a context
* @param parent where to inflate our view
* @param callback the callback
*/
public CameraPreview(@NonNull Context context, @NonNull ViewGroup parent, @Nullable SurfaceCallback callback) {
public CameraPreview(@NonNull Context context, @NonNull ViewGroup parent) {
mView = onCreateView(context, parent);
mSurfaceCallback = callback;
}
/**
@ -79,10 +77,12 @@ public abstract class CameraPreview<T extends View, Output> {
* @param callback a callback
*/
public final void setSurfaceCallback(@Nullable SurfaceCallback callback) {
if (hasSurface() && mSurfaceCallback != null) {
mSurfaceCallback.onSurfaceDestroyed();
}
mSurfaceCallback = callback;
// If surface already available, dispatch.
if (mOutputSurfaceWidth != 0 || mOutputSurfaceHeight != 0) {
if (callback != null) callback.onSurfaceAvailable();
if (hasSurface() && mSurfaceCallback != null) {
mSurfaceCallback.onSurfaceAvailable();
}
}

@ -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
* 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 final float[] mTransformMatrix = new float[16];
@ -68,33 +68,11 @@ public class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture
@VisibleForTesting float mCropScaleX = 1F;
@VisibleForTesting float mCropScaleY = 1F;
private View mRootView;
private final GLSurfaceView.Renderer mRenderer;
/**
* 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);
}
public GlCameraPreview(@NonNull Context context, @NonNull ViewGroup parent, @Nullable SurfaceCallback callback) {
super(context, parent, callback);
public GlCameraPreview(@NonNull Context context, @NonNull ViewGroup parent) {
super(context, parent);
mRenderer = new Renderer();
}
@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);
GLSurfaceView glView = root.findViewById(R.id.gl_surface_view);
glView.setEGLContextClientVersion(2);
glView.setRenderer(this);
glView.setRenderer(mRenderer);
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() {
public void surfaceCreated(SurfaceHolder holder) {}
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
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
@ -184,7 +164,6 @@ public class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture
}
@RendererThread
@SuppressWarnings("StatementWithEmptyBody")
@Override
public void onSurfaceChanged(GL10 gl, final int width, final int height) {
gl.glViewport(0, 0, width, height);
@ -218,10 +197,9 @@ public class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture
}
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 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 translY = (1F - mCropScaleY) / 2F;
Matrix.translateM(mTransformMatrix, 0, translX, translY, 0);
@ -234,6 +212,7 @@ public class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture
callback.onRendererFrame(mInputSurfaceTexture, mCropScaleX, mCropScaleY);
}
}
}
@NonNull
@Override
@ -262,7 +241,7 @@ public class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture
* platform when its window is positioned asynchronously.
*
* 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
protected void crop(@NonNull Op<Void> op) {
@ -285,4 +264,47 @@ public class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture
}
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;
}
}

@ -26,8 +26,8 @@ public class SurfaceCameraPreview extends CameraPreview<SurfaceView, SurfaceHold
private boolean mDispatched;
private View mRootView;
public SurfaceCameraPreview(@NonNull Context context, @NonNull ViewGroup parent, @Nullable SurfaceCallback callback) {
super(context, parent, callback);
public SurfaceCameraPreview(@NonNull Context context, @NonNull ViewGroup parent) {
super(context, parent);
}
@NonNull
@ -37,7 +37,6 @@ public class SurfaceCameraPreview extends CameraPreview<SurfaceView, SurfaceHold
parent.addView(root, 0);
SurfaceView surfaceView = root.findViewById(R.id.surface_view);
final SurfaceHolder holder = surfaceView.getHolder();
//noinspection deprecation
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
holder.addCallback(new SurfaceHolder.Callback() {

@ -30,8 +30,8 @@ public class TextureCameraPreview extends CameraPreview<TextureView, SurfaceText
private View mRootView;
public TextureCameraPreview(@NonNull Context context, @NonNull ViewGroup parent, @Nullable SurfaceCallback callback) {
super(context, parent, callback);
public TextureCameraPreview(@NonNull Context context, @NonNull ViewGroup parent) {
super(context, parent);
}
@NonNull

Loading…
Cancel
Save