Refactor SnapshotPictureRecorder

pull/421/head
Giacomo Randazzo 7 years ago
parent 076c53aab1
commit 3939f84d8f
  1. 2
      cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java
  2. 12
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java
  3. 16
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java
  4. 58
      cameraview/src/main/java/com/otaliastudios/cameraview/OverlayLayout.java
  5. 39
      cameraview/src/main/java/com/otaliastudios/cameraview/SnapshotPictureRecorder.java
  6. 18
      cameraview/src/main/java/com/otaliastudios/cameraview/SnapshotVideoRecorder.java
  7. 7
      cameraview/src/main/java/com/otaliastudios/cameraview/SurfaceDrawer.java
  8. 107
      cameraview/src/main/views/com/otaliastudios/cameraview/GlCameraPreview.java

@ -616,7 +616,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
LOG.v("Rotations", "SO", offset(REF_SENSOR, REF_OUTPUT), "OS", offset(REF_OUTPUT, REF_SENSOR)); LOG.v("Rotations", "SO", offset(REF_SENSOR, REF_OUTPUT), "OS", offset(REF_OUTPUT, REF_SENSOR));
LOG.v("Rotations", "VO", offset(REF_VIEW, REF_OUTPUT), "OV", offset(REF_OUTPUT, REF_VIEW)); LOG.v("Rotations", "VO", offset(REF_VIEW, REF_OUTPUT), "OV", offset(REF_OUTPUT, REF_VIEW));
mPictureRecorder = new SnapshotPictureRecorder(result, Camera1.this, mCamera, outputRatio); mPictureRecorder = new SnapshotPictureRecorder(result, Camera1.this, mCamera, outputRatio, pictureSurfaceDrawerList);
mPictureRecorder.take(); mPictureRecorder.take();
} }
}); });

@ -38,6 +38,8 @@ abstract class CameraController implements
protected WorkerHandler mHandler; protected WorkerHandler mHandler;
/* for tests */ Handler mCrashHandler; /* for tests */ Handler mCrashHandler;
protected final ArrayList<SurfaceDrawer> pictureSurfaceDrawerList = new ArrayList<>();
protected Facing mFacing; protected Facing mFacing;
protected Flash mFlash; protected Flash mFlash;
protected WhiteBalance mWhiteBalance; protected WhiteBalance mWhiteBalance;
@ -668,4 +670,14 @@ abstract class CameraController implements
} }
//endregion //endregion
public void addPictureSurfaceDrawer(@NonNull SurfaceDrawer surfaceDrawer) {
if (!pictureSurfaceDrawerList.contains(surfaceDrawer)) {
pictureSurfaceDrawerList.add(surfaceDrawer);
}
}
public void removePictureSurfaceDrawer(@NonNull SurfaceDrawer surfaceDrawer) {
pictureSurfaceDrawerList.remove(surfaceDrawer);
}
} }

@ -259,7 +259,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
} }
case GL_SURFACE: default: { case GL_SURFACE: default: {
mPreview = Preview.GL_SURFACE; mPreview = Preview.GL_SURFACE;
return new GlCameraPreview(context, container, null, mHasOverlay); return new GlCameraPreview(context, container, null);
} }
} }
} }
@ -291,18 +291,6 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
mPreviewOverlayLayout = findViewById(R.id.preview_overlay_layout); mPreviewOverlayLayout = findViewById(R.id.preview_overlay_layout);
((GlCameraPreview) mCameraPreview).addOverlayInputSurfaceListener(new GlCameraPreview.OverlayInputSurfaceListener() {
@Override
public void onSurface(@NonNull final Surface surface) {
mUiHandler.post(new Runnable() {
@Override
public void run() {
mPreviewOverlayLayout.setOutputSurface(surface);
}
});
}
});
LinkedList<View> overlayViews = new LinkedList<>(); LinkedList<View> overlayViews = new LinkedList<>();
for (int i = 0; i < getChildCount(); i++) { for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i); View view = getChildAt(i);
@ -318,6 +306,8 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
mPreviewOverlayLayout.addView(view); mPreviewOverlayLayout.addView(view);
} }
} }
mCameraController.addPictureSurfaceDrawer(mPreviewOverlayLayout);
} }
if (!isInEditMode()) { if (!isInEditMode()) {
mOrientationHelper.enable(getContext()); mOrientationHelper.enable(getContext());

@ -13,9 +13,7 @@ import android.widget.FrameLayout;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
public class OverlayLayout extends FrameLayout { public class OverlayLayout extends FrameLayout implements SurfaceDrawer {
private Surface outputSurface = null;
public OverlayLayout(@NonNull Context context) { public OverlayLayout(@NonNull Context context) {
super(context); super(context);
@ -29,36 +27,46 @@ public class OverlayLayout extends FrameLayout {
@Override @Override
public void draw(Canvas canvas) { public void draw(Canvas canvas) {
if (outputSurface != null ) { // if (outputSurface != null ) {
// Requires a try/catch for .lockCanvas( null ) // // Requires a try/catch for .lockCanvas( null )
try { // try {
final Canvas surfaceCanvas = outputSurface.lockCanvas(null); // final Canvas surfaceCanvas = outputSurface.lockCanvas(null);
//
float xScale = surfaceCanvas.getWidth() / (float) canvas.getWidth(); // float xScale = surfaceCanvas.getWidth() / (float) canvas.getWidth();
float yScale = surfaceCanvas.getHeight() / (float) canvas.getHeight(); // float yScale = surfaceCanvas.getHeight() / (float) canvas.getHeight();
surfaceCanvas.scale(xScale, yScale); // surfaceCanvas.scale(xScale, yScale);
surfaceCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); // surfaceCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
super.draw(surfaceCanvas); // super.draw(surfaceCanvas);
//
outputSurface.unlockCanvasAndPost(surfaceCanvas); // outputSurface.unlockCanvasAndPost(surfaceCanvas);
} catch (Surface.OutOfResourcesException e) { // } catch (Surface.OutOfResourcesException e) {
e.printStackTrace(); // e.printStackTrace();
} // }
} // }
// draw the view as always, since we are already drawing on the preview this step can be // draw the view as always, since we are already drawing on the preview this step can be
// skipped // skipped
//super.draw(canvas); super.draw(canvas);
} }
@Override
public void drawOnSurface(Surface outputSurface) {
// postInvalidate();
// postInvalidateRecursive(this);
try {
final Canvas surfaceCanvas = outputSurface.lockCanvas(null);
public void setOutputSurface(Surface outputSurface) { float xScale = surfaceCanvas.getWidth() / (float) getWidth();
this.outputSurface = outputSurface; float yScale = surfaceCanvas.getHeight() / (float) getHeight();
surfaceCanvas.scale(xScale, yScale);
surfaceCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
super.draw(surfaceCanvas);
// force redrawing outputSurface.unlockCanvasAndPost(surfaceCanvas);
postInvalidate(); } catch (Surface.OutOfResourcesException e) {
postInvalidateRecursive(this); e.printStackTrace();
}
} }
// invalidates children (and nested children) recursively // invalidates children (and nested children) recursively

@ -11,10 +11,13 @@ import android.opengl.EGL14;
import android.opengl.EGLContext; import android.opengl.EGLContext;
import android.opengl.Matrix; import android.opengl.Matrix;
import android.util.Log; import android.util.Log;
import android.view.Surface;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
/** /**
* A {@link PictureResult} that uses standard APIs. * A {@link PictureResult} that uses standard APIs.
@ -30,11 +33,13 @@ class SnapshotPictureRecorder extends PictureRecorder {
private AspectRatio mOutputRatio; private AspectRatio mOutputRatio;
private Size mSensorPreviewSize; private Size mSensorPreviewSize;
private int mFormat; private int mFormat;
private List<SurfaceDrawer> mSurfaceDrawerList;
private boolean mWithOverlay; private boolean mWithOverlay;
SnapshotPictureRecorder(@NonNull PictureResult stub, @NonNull Camera1 controller, SnapshotPictureRecorder(@NonNull PictureResult stub, @NonNull Camera1 controller,
@NonNull Camera camera, @NonNull AspectRatio outputRatio) { @NonNull Camera camera, @NonNull AspectRatio outputRatio,
@NonNull List<SurfaceDrawer> surfaceDrawerList) {
super(stub, controller); super(stub, controller);
mController = controller; mController = controller;
mPreview = controller.mPreview; mPreview = controller.mPreview;
@ -43,7 +48,7 @@ class SnapshotPictureRecorder extends PictureRecorder {
mFormat = mController.mPreviewFormat; mFormat = mController.mPreviewFormat;
mSensorPreviewSize = mController.mPreviewStreamSize; mSensorPreviewSize = mController.mPreviewStreamSize;
mWithOverlay = mController.mDisableOverlayFor != DisableOverlayFor.PICTURE; mWithOverlay = mController.mDisableOverlayFor != DisableOverlayFor.PICTURE;
mSurfaceDrawerList = surfaceDrawerList;
} }
@Override @Override
@ -65,17 +70,18 @@ class SnapshotPictureRecorder extends PictureRecorder {
SurfaceTexture mOverlaySurfaceTexture; SurfaceTexture mOverlaySurfaceTexture;
float[] mTransform; float[] mTransform;
float[] mOverlayTransform; float[] mOverlayTransform;
EglViewport overlayViewport;
@RendererThread @RendererThread
public void onRendererTextureCreated(int... textureIds) { public void onRendererTextureCreated(int textureId) {
mTextureId = textureIds[0]; mTextureId = textureId;
if (textureIds.length > 1 && mWithOverlay) { overlayViewport = new EglViewport();
mOverlayTextureId = textureIds[1]; if (mWithOverlay) {
mOverlayTextureId = overlayViewport.createTexture();
} }
mSurfaceTexture = new SurfaceTexture(mTextureId, true); mSurfaceTexture = new SurfaceTexture(mTextureId, true);
if (mOverlayTextureId != 0) { if (mOverlayTextureId != 0) {
mOverlaySurfaceTexture = null; mOverlaySurfaceTexture = new SurfaceTexture(mOverlayTextureId, true);
// mOverlaySurfaceTexture = new SurfaceTexture(mOverlayTextureId, true);
} }
// Need to crop the size. // Need to crop the size.
Rect crop = CropHelper.computeCrop(mResult.size, mOutputRatio); Rect crop = CropHelper.computeCrop(mResult.size, mOutputRatio);
@ -92,7 +98,7 @@ class SnapshotPictureRecorder extends PictureRecorder {
@RendererThread @RendererThread
@Override @Override
public void onRendererFrame(SurfaceTexture surfaceTexture, final SurfaceTexture overlaySurfaceTexture, final float scaleX, final float scaleY) { public void onRendererFrame(SurfaceTexture surfaceTexture, final float scaleX, final float scaleY) {
preview.removeRendererFrameCallback(this); preview.removeRendererFrameCallback(this);
// This kinda work but has drawbacks: // This kinda work but has drawbacks:
@ -124,7 +130,12 @@ class SnapshotPictureRecorder extends PictureRecorder {
EglViewport viewport = new EglViewport(); EglViewport viewport = new EglViewport();
mSurfaceTexture.updateTexImage(); mSurfaceTexture.updateTexImage();
mSurfaceTexture.getTransformMatrix(mTransform); mSurfaceTexture.getTransformMatrix(mTransform);
Surface drawOnto = new Surface(mOverlaySurfaceTexture);
if (mOverlaySurfaceTexture != null) { if (mOverlaySurfaceTexture != null) {
for (SurfaceDrawer surfaceDrawer : mSurfaceDrawerList) {
surfaceDrawer.drawOnSurface(drawOnto);
}
mOverlaySurfaceTexture.updateTexImage();
mOverlaySurfaceTexture.getTransformMatrix(mOverlayTransform); mOverlaySurfaceTexture.getTransformMatrix(mOverlayTransform);
} }
@ -142,7 +153,7 @@ class SnapshotPictureRecorder extends PictureRecorder {
// TODO Not sure why we need the minus here... It makes no sense to me. // TODO Not sure why we need the minus here... It makes no sense to me.
LOG.w("Recording frame. Rotation:", mResult.rotation, "Actual:", -mResult.rotation); LOG.w("Recording frame. Rotation:", mResult.rotation, "Actual:", -mResult.rotation);
int rotation = -mResult.rotation; int rotation = -mResult.rotation;
int overlayRotation = -mController.offset(CameraController.REF_VIEW, CameraController.REF_OUTPUT); int overlayRotation = mController.offset(CameraController.REF_VIEW, CameraController.REF_OUTPUT);
// apparently with front facing camera with don't need the minus sign // apparently with front facing camera with don't need the minus sign
if (mResult.facing == Facing.FRONT) { if (mResult.facing == Facing.FRONT) {
overlayRotation = -overlayRotation; overlayRotation = -overlayRotation;
@ -169,6 +180,10 @@ class SnapshotPictureRecorder extends PictureRecorder {
Matrix.scaleM(mOverlayTransform, 0, -1, -1, 1); Matrix.scaleM(mOverlayTransform, 0, -1, -1, 1);
} }
} }
if (mOverlayTransform != null) {
// not sure why we have to flip the mirror the y axis
Matrix.scaleM(mOverlayTransform, 0, 1, -1, 1);
}
// Go back to old position. // Go back to old position.
Matrix.translateM(mTransform, 0, -0.5F, -0.5F, 0); Matrix.translateM(mTransform, 0, -0.5F, -0.5F, 0);
@ -180,7 +195,7 @@ class SnapshotPictureRecorder extends PictureRecorder {
// They are simply realScaleX and realScaleY. // They are simply realScaleX and realScaleY.
viewport.drawFrame(mTextureId, mTransform); viewport.drawFrame(mTextureId, mTransform);
if (mOverlayTransform != null) { if (mOverlayTransform != null) {
// viewport.drawFrameOverlay(mOverlayTextureId, mOverlayTransform); overlayViewport.drawFrame(mOverlayTextureId, mOverlayTransform);
} }
// don't - surface.swapBuffers(); // don't - surface.swapBuffers();
mResult.data = surface.saveFrameTo(Bitmap.CompressFormat.JPEG); mResult.data = surface.saveFrameTo(Bitmap.CompressFormat.JPEG);
@ -190,6 +205,8 @@ class SnapshotPictureRecorder extends PictureRecorder {
// EGL14.eglMakeCurrent(oldDisplay, oldSurface, oldSurface, eglContext); // EGL14.eglMakeCurrent(oldDisplay, oldSurface, oldSurface, eglContext);
surface.release(); surface.release();
viewport.release(); viewport.release();
overlayViewport.release();
drawOnto.release();
mSurfaceTexture.release(); mSurfaceTexture.release();
if (mOverlaySurfaceTexture != null) { if (mOverlaySurfaceTexture != null) {
mOverlaySurfaceTexture.release(); mOverlaySurfaceTexture.release();

@ -54,16 +54,16 @@ class SnapshotVideoRecorder extends VideoRecorder implements GlCameraPreview.Ren
@RendererThread @RendererThread
@Override @Override
public void onRendererTextureCreated(int... textureId) { public void onRendererTextureCreated(int textureId) {
mTextureId = textureId[0]; mTextureId = textureId;
if (textureId.length > 1) { // if (textureId.length > 1) {
mOverlayTextureId = textureId[1]; // mOverlayTextureId = textureId[1];
} // }
} }
@RendererThread @RendererThread
@Override @Override
public void onRendererFrame(@NonNull SurfaceTexture surfaceTexture, SurfaceTexture overlaySurfaceTexture, float scaleX, float scaleY) { public void onRendererFrame(@NonNull SurfaceTexture surfaceTexture, float scaleX, float scaleY) {
if (mCurrentState == STATE_NOT_RECORDING && mDesiredState == STATE_RECORDING) { if (mCurrentState == STATE_NOT_RECORDING && mDesiredState == STATE_RECORDING) {
// Set default options // Set default options
if (mResult.videoBitRate <= 0) mResult.videoBitRate = DEFAULT_VIDEO_BITRATE; if (mResult.videoBitRate <= 0) mResult.videoBitRate = DEFAULT_VIDEO_BITRATE;
@ -114,9 +114,9 @@ class SnapshotVideoRecorder extends VideoRecorder implements GlCameraPreview.Ren
TextureMediaEncoder.TextureFrame textureFrame = textureEncoder.acquireFrame(); TextureMediaEncoder.TextureFrame textureFrame = textureEncoder.acquireFrame();
textureFrame.timestamp = surfaceTexture.getTimestamp(); textureFrame.timestamp = surfaceTexture.getTimestamp();
surfaceTexture.getTransformMatrix(textureFrame.transform); surfaceTexture.getTransformMatrix(textureFrame.transform);
if (mWithOverlay && overlaySurfaceTexture != null) { // if (mWithOverlay && overlaySurfaceTexture != null) {
overlaySurfaceTexture.getTransformMatrix(textureFrame.overlayTransform); // overlaySurfaceTexture.getTransformMatrix(textureFrame.overlayTransform);
} // }
mEncoderEngine.notify(TextureMediaEncoder.FRAME_EVENT, textureFrame); mEncoderEngine.notify(TextureMediaEncoder.FRAME_EVENT, textureFrame);
} }

@ -0,0 +1,7 @@
package com.otaliastudios.cameraview;
import android.view.Surface;
public interface SurfaceDrawer {
void drawOnSurface(Surface surface);
}

@ -7,14 +7,11 @@ import android.opengl.Matrix;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Surface;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@ -58,23 +55,17 @@ class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple
private boolean mDispatched; private boolean mDispatched;
private final float[] mTransformMatrix = new float[16]; private final float[] mTransformMatrix = new float[16];
private final float[] mOverlayTransformMatrix = new float[16]; private int mOutputTextureId = 0;
private int[] mOutputTextureIds = new int[]{0, 0};
private SurfaceTexture mInputSurfaceTexture; private SurfaceTexture mInputSurfaceTexture;
private SurfaceTexture mOverlaySurfaceTexture;
private Surface mOverlaySurface;
private EglViewport mOutputViewport; private EglViewport mOutputViewport;
private EglViewport mOutputOverlayViewport;
private Set<RendererFrameCallback> mRendererFrameCallbacks = Collections.synchronizedSet(new HashSet<RendererFrameCallback>()); private Set<RendererFrameCallback> mRendererFrameCallbacks = Collections.synchronizedSet(new HashSet<RendererFrameCallback>());
/* for tests */ float mScaleX = 1F; /* for tests */ float mScaleX = 1F;
/* for tests */ float mScaleY = 1F; /* for tests */ float mScaleY = 1F;
private View mRootView; private View mRootView;
private ArrayList<OverlayInputSurfaceListener> overlayListeners = new ArrayList<>(); GlCameraPreview(@NonNull Context context, @NonNull ViewGroup parent, @Nullable SurfaceCallback callback) {
super(context, parent, callback);
GlCameraPreview(@NonNull Context context, @NonNull ViewGroup parent, @Nullable SurfaceCallback callback, boolean hasOverlay) {
super(context, parent, callback, hasOverlay);
} }
@NonNull @NonNull
@ -131,54 +122,24 @@ class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple
mInputSurfaceTexture.release(); mInputSurfaceTexture.release();
mInputSurfaceTexture = null; mInputSurfaceTexture = null;
} }
if (mOverlaySurface != null) { mOutputTextureId = 0;
mOverlaySurface.release();
mOverlaySurface = null;
}
if (mOverlaySurfaceTexture != null) {
mOverlaySurfaceTexture.release();
mOverlaySurfaceTexture = null;
}
mOutputTextureIds[0] = 0;
mOutputTextureIds[1] = 0;
if (mOutputViewport != null) { if (mOutputViewport != null) {
mOutputViewport.release(); mOutputViewport.release();
mOutputViewport = null; mOutputViewport = null;
} }
if (mOutputOverlayViewport != null) {
mOutputOverlayViewport.release();
mOutputOverlayViewport = null;
}
} }
@RendererThread @RendererThread
@Override @Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) { public void onSurfaceCreated(GL10 gl, EGLConfig config) {
mOutputViewport = new EglViewport(); mOutputViewport = new EglViewport();
mOutputOverlayViewport = new EglViewport(); mOutputTextureId = mOutputViewport.createTexture();
mOutputTextureIds[0] = mOutputViewport.createTexture(); mInputSurfaceTexture = new SurfaceTexture(mOutputTextureId);
if (hasOverlay()) {
mOutputTextureIds[1] = mOutputOverlayViewport.createTexture();
mOverlaySurfaceTexture = new SurfaceTexture(mOutputTextureIds[1]);
mOverlaySurface = new Surface(mOverlaySurfaceTexture);
for (OverlayInputSurfaceListener listener : overlayListeners) {
if (listener != null) {
listener.onSurface(mOverlaySurface);
}
}
mOverlaySurfaceTexture.setDefaultBufferSize(mInputStreamWidth, mInputStreamHeight);
}
mInputSurfaceTexture = new SurfaceTexture(mOutputTextureIds[0]);
getView().queueEvent(new Runnable() { getView().queueEvent(new Runnable() {
@Override @Override
public void run() { public void run() {
for (RendererFrameCallback callback : mRendererFrameCallbacks) { for (RendererFrameCallback callback : mRendererFrameCallbacks) {
if (mOutputTextureIds[1] != 0) { callback.onRendererTextureCreated(mOutputTextureId);
callback.onRendererTextureCreated(mOutputTextureIds[0], mOutputTextureIds[1]);
} else {
callback.onRendererTextureCreated(mOutputTextureIds[0]);
}
} }
} }
}); });
@ -197,25 +158,12 @@ class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple
@SuppressWarnings("StatementWithEmptyBody") @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);
if (!mDispatched) { if (!mDispatched) {
dispatchOnSurfaceAvailable(width, height); dispatchOnSurfaceAvailable(width, height);
mDispatched = true; mDispatched = true;
} else if (mOutputSurfaceWidth == width && mOutputSurfaceHeight == height) { } else if (width != mOutputSurfaceWidth || height != mOutputSurfaceHeight){
// I was experimenting and this was happening. dispatchOnSurfaceSizeChanged(width, height);
// Not sure if it is stil needed now.
} else {
// With other CameraPreview implementation we could just dispatch the 'size changed' event
// to the controller and everything would go straight. In case of GL, apparently we have to
// force recreate the EGLContext by calling onPause and onResume in the UI thread.
dispatchOnSurfaceDestroyed();
getView().post(new Runnable() {
@Override
public void run() {
getView().onPause();
getView().onResume();
dispatchOnSurfaceAvailable(width, height);
}
});
} }
} }
@ -225,18 +173,12 @@ class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple
// Latch the latest frame. If there isn't anything new, // Latch the latest frame. If there isn't anything new,
// we'll just re-use whatever was there before. // we'll just re-use whatever was there before.
mInputSurfaceTexture.updateTexImage(); mInputSurfaceTexture.updateTexImage();
if (hasOverlay()) {
mOverlaySurfaceTexture.updateTexImage();
}
if (mInputStreamWidth <= 0 || mInputStreamHeight <= 0) { if (mInputStreamWidth <= 0 || mInputStreamHeight <= 0) {
// Skip drawing. Camera was not opened. // Skip drawing. Camera was not opened.
return; return;
} }
mInputSurfaceTexture.getTransformMatrix(mTransformMatrix); mInputSurfaceTexture.getTransformMatrix(mTransformMatrix);
if (hasOverlay()) {
mOverlaySurfaceTexture.getTransformMatrix(mOverlayTransformMatrix);
}
if (isCropping()) { if (isCropping()) {
// Scaling is easy. However: // Scaling is easy. However:
// 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).
@ -249,12 +191,9 @@ class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple
} }
// Future note: passing scale to the viewport? // Future note: passing scale to the viewport?
// They are scaleX an scaleY, but flipped based on mInputFlipped. // They are scaleX an scaleY, but flipped based on mInputFlipped.
mOutputViewport.drawFrame(mOutputTextureIds[0], mTransformMatrix); mOutputViewport.drawFrame(mOutputTextureId, mTransformMatrix);
if (hasOverlay() && mOutputTextureIds[1] != 0) {
mOutputOverlayViewport.drawFrame(mOutputTextureIds[1], mOverlayTransformMatrix);
}
for (RendererFrameCallback callback : mRendererFrameCallbacks) { for (RendererFrameCallback callback : mRendererFrameCallbacks) {
callback.onRendererFrame(mInputSurfaceTexture, mOverlaySurfaceTexture, mScaleX, mScaleY); callback.onRendererFrame(mInputSurfaceTexture, mScaleX, mScaleY);
} }
} }
@ -315,10 +254,10 @@ class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple
* Called on the renderer thread, hopefully only once, to notify that * Called on the renderer thread, hopefully only once, to notify that
* the texture was created (or to inform a new callback of the old texture). * the texture was created (or to inform a new callback of the old texture).
* *
* @param textureId the GL textures linked to the image stream * @param textureId the GL texture linked to the image stream
*/ */
@RendererThread @RendererThread
void onRendererTextureCreated(int... textureId); void onRendererTextureCreated(int textureId);
/** /**
* Called on the renderer thread after each frame was drawn. * Called on the renderer thread after each frame was drawn.
@ -330,7 +269,7 @@ class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple
* @param scaleY the scaleY (in REF_VIEW) value * @param scaleY the scaleY (in REF_VIEW) value
*/ */
@RendererThread @RendererThread
void onRendererFrame(SurfaceTexture surfaceTexture, SurfaceTexture overlaySurfaceTexture, float scaleX, float scaleY); void onRendererFrame(SurfaceTexture surfaceTexture, float scaleX, float scaleY);
} }
void addRendererFrameCallback(@NonNull final RendererFrameCallback callback) { void addRendererFrameCallback(@NonNull final RendererFrameCallback callback) {
@ -338,10 +277,7 @@ class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple
@Override @Override
public void run() { public void run() {
mRendererFrameCallbacks.add(callback); mRendererFrameCallbacks.add(callback);
if (mOutputTextureIds[0] != 0 && mOutputTextureIds[1] != 0) { if (mOutputTextureId != 0) callback.onRendererTextureCreated(mOutputTextureId);
callback.onRendererTextureCreated(mOutputTextureIds);
}
else if (mOutputTextureIds[0] != 0) callback.onRendererTextureCreated(mOutputTextureIds[0]);
} }
}); });
} }
@ -349,15 +285,4 @@ class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple
void removeRendererFrameCallback(@NonNull final RendererFrameCallback callback) { void removeRendererFrameCallback(@NonNull final RendererFrameCallback callback) {
mRendererFrameCallbacks.remove(callback); mRendererFrameCallbacks.remove(callback);
} }
public void addOverlayInputSurfaceListener(@NonNull OverlayInputSurfaceListener listener) {
overlayListeners.add(listener);
if (mOverlaySurface != null) {
listener.onSurface(mOverlaySurface);
}
}
interface OverlayInputSurfaceListener {
void onSurface(@NonNull Surface surface);
}
} }

Loading…
Cancel
Save