From 9cf23c854edf66a64083618b0fdec42f766bc8cc Mon Sep 17 00:00:00 2001 From: Mattia Iavarone Date: Sat, 29 Sep 2018 02:27:43 -0300 Subject: [PATCH] Refined oval support --- MIGRATION.md | 5 ++++- .../cameraview/CameraPreviewTest.java | 4 ++-- .../com/otaliastudios/cameraview/EglViewport.java | 15 ++++----------- .../cameraview/TextureMediaEncoder.java | 13 ++++++++++--- .../com/otaliastudios/cameraview/Camera1.java | 4 ++-- .../cameraview/SnapshotPictureRecorder.java | 3 ++- .../cameraview/SnapshotVideoRecorder.java | 1 + .../otaliastudios/cameraview/CameraPreview.java | 4 +++- .../otaliastudios/cameraview/GlCameraPreview.java | 5 ++++- .../cameraview/TextureCameraPreview.java | 4 ++-- 10 files changed, 34 insertions(+), 24 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index 98f93694..852f39c4 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -59,4 +59,7 @@ - UI Changes in the demo app, changed controls appearance, added some missing controls. added all information from the VideoResult in the VideoPreviewActivity, same for pictures - BitmapCallback result is now @Nullable ! This will happen if we encounter an OutOfMemoryError during decoding. - You should consider passing a maxWidth and maxHeight instead of loading the full image. \ No newline at end of file + You should consider passing a maxWidth and maxHeight instead of loading the full image. +- TODO: add Shape control: RECT and OVAL. Pass this shape around, to the preview and whoever needs it +- TODO: add setPreviewSize API (think about it) +- TODO: fix video recording rotation: with front camera, it does not work. \ No newline at end of file diff --git a/cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraPreviewTest.java b/cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraPreviewTest.java index f9b483f9..3e765140 100644 --- a/cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraPreviewTest.java +++ b/cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraPreviewTest.java @@ -86,7 +86,7 @@ public abstract class CameraPreviewTest extends BaseTest { @Test public void testDesiredSize() { - preview.setInputStreamSize(160, 90); + preview.setInputStreamSize(160, 90, false); assertEquals(160, preview.getInputStreamSize().getWidth()); assertEquals(90, preview.getInputStreamSize().getHeight()); } @@ -136,7 +136,7 @@ public abstract class CameraPreviewTest extends BaseTest { private void setDesiredAspectRatio(float desiredAspectRatio) { preview.mCropTask.listen(); - preview.setInputStreamSize((int) (10f * desiredAspectRatio), 10); // Wait... + preview.setInputStreamSize((int) (10f * desiredAspectRatio), 10, false); // Wait... preview.mCropTask.await(); assertEquals(desiredAspectRatio, getViewAspectRatioWithScale(), 0.01f); diff --git a/cameraview/src/main/gles/com/otaliastudios/cameraview/EglViewport.java b/cameraview/src/main/gles/com/otaliastudios/cameraview/EglViewport.java index bda19470..7f437ed6 100644 --- a/cameraview/src/main/gles/com/otaliastudios/cameraview/EglViewport.java +++ b/cameraview/src/main/gles/com/otaliastudios/cameraview/EglViewport.java @@ -145,19 +145,12 @@ class EglViewport extends EglElement { return texId; } - void drawFrame(int textureId, float[] textureMatrix) { + void drawFrame(int textureId, float[] textureMatrix, float[] textureScale) { drawFrame(textureId, textureMatrix, mVertexCoordinatesArray, - mTextureCoordinatesArray, 1F, 1F); + mTextureCoordinatesArray, textureScale); } - void drawFrame(int textureId, float[] textureMatrix, float textureScaleX, float textureScaleY) { - drawFrame(textureId, textureMatrix, - mVertexCoordinatesArray, - mTextureCoordinatesArray, textureScaleX, textureScaleY); - } - - private static final FloatBuffer TEMP = floatBuffer(new float[] { 1.0F, 1.0F }); /** * The issue with the CIRCLE shader is that if the textureMatrix has a scale value, * it fails miserably, not taking the scale into account. @@ -174,7 +167,7 @@ class EglViewport extends EglElement { private void drawFrame(int textureId, float[] textureMatrix, FloatBuffer vertexBuffer, FloatBuffer texBuffer, - float textureScaleX, float textureScaleY) { + float[] textureScale) { check("draw start"); // Select the program. @@ -194,7 +187,7 @@ class EglViewport extends EglElement { check("glUniformMatrix4fv"); // Pass scale values. - GLES20.glUniform2f(muTextureScaleLocation, textureScaleX, textureScaleY); + GLES20.glUniform2fv(muTextureScaleLocation, 1, textureScale, 0); check("glUniform2f"); // Enable the "aPosition" vertex attribute. diff --git a/cameraview/src/main/gles/com/otaliastudios/cameraview/TextureMediaEncoder.java b/cameraview/src/main/gles/com/otaliastudios/cameraview/TextureMediaEncoder.java index 394ff7a8..f91107d3 100644 --- a/cameraview/src/main/gles/com/otaliastudios/cameraview/TextureMediaEncoder.java +++ b/cameraview/src/main/gles/com/otaliastudios/cameraview/TextureMediaEncoder.java @@ -28,14 +28,16 @@ class TextureMediaEncoder extends VideoMediaEncoder int textureId; float scaleX; float scaleY; + boolean scaleFlipped; EGLContext eglContext; Config(int width, int height, int bitRate, int frameRate, int rotation, String mimeType, - int textureId, float scaleX, float scaleY, EGLContext eglContext) { + int textureId, float scaleX, float scaleY, boolean scaleFlipped, EGLContext eglContext) { super(width, height, bitRate, frameRate, rotation, mimeType); this.textureId = textureId; this.scaleX = scaleX; this.scaleY = scaleY; + this.scaleFlipped = scaleFlipped; this.eglContext = eglContext; } } @@ -84,6 +86,8 @@ class TextureMediaEncoder extends VideoMediaEncoder // Nothing to do here. Waiting for the first frame. } + private float[] mScaleXY = new float[2]; + @EncoderThread @Override void notify(String event, Object data) { @@ -119,11 +123,14 @@ class TextureMediaEncoder extends VideoMediaEncoder // translate to origin, rotate, then back to where we were. Matrix.translateM(transform, 0, 0.5F, 0.5F, 0); - Matrix.rotateM(transform, 0, mConfig.rotation, 0, 0, 1); + Matrix.rotateM(transform, 0, mConfig.rotation /* VIEW-OUTPUT */, 0, 0, 1); Matrix.translateM(transform, 0, -0.5F, -0.5F, 0); drain(false); - mViewport.drawFrame(mConfig.textureId, transform, scaleX, scaleY); + boolean flip = mConfig.scaleFlipped;// mConfig.rotation % 180 != 0; + mScaleXY[0] = flip ? scaleY : scaleX; + mScaleXY[1] = flip ? scaleX : scaleY; + mViewport.drawFrame(mConfig.textureId, transform, mScaleXY); mWindow.setPresentationTime(timestamp); mWindow.swapBuffers(); } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java b/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java index e62178c4..9b9199b2 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java @@ -12,7 +12,6 @@ import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.WorkerThread; -import android.util.Log; import android.view.SurfaceHolder; import java.io.File; @@ -168,7 +167,8 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera mCameraCallbacks.onCameraPreviewSizeChanged(); Size previewSize = getPreviewSize(REF_VIEW); - mPreview.setInputStreamSize(previewSize.getWidth(), previewSize.getHeight()); + boolean wasFlipped = flip(REF_SENSOR, REF_VIEW); + mPreview.setInputStreamSize(previewSize.getWidth(), previewSize.getHeight(), wasFlipped); Camera.Parameters params = mCamera.getParameters(); mPreviewFormat = params.getPreviewFormat(); diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/SnapshotPictureRecorder.java b/cameraview/src/main/java/com/otaliastudios/cameraview/SnapshotPictureRecorder.java index dbaf4f93..2337b8b2 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/SnapshotPictureRecorder.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/SnapshotPictureRecorder.java @@ -119,7 +119,8 @@ class SnapshotPictureRecorder extends PictureRecorder { Matrix.rotateM(mTransform, 0, rotation, 0, 0, 1); Matrix.translateM(mTransform, 0, -0.5F, -0.5F, 0); - viewport.drawFrame(mTextureId, mTransform, realScaleX, realScaleY); + float[] scaleXY = new float[] { realScaleX, realScaleY }; + viewport.drawFrame(mTextureId, mTransform, scaleXY); // don't - surface.swapBuffers(); // TODO: need PNG when the preview is rounded, which is an experimental thing // In all the other cases this must be JPEG! diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/SnapshotVideoRecorder.java b/cameraview/src/main/java/com/otaliastudios/cameraview/SnapshotVideoRecorder.java index ea995fe6..4a3030d2 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/SnapshotVideoRecorder.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/SnapshotVideoRecorder.java @@ -78,6 +78,7 @@ class SnapshotVideoRecorder extends VideoRecorder implements GlCameraPreview.Ren mResult.rotation, type, mTextureId, scaleX, scaleY, + mPreview.mInputFlipped, EGL14.eglGetCurrentContext() ); TextureMediaEncoder videoEncoder = new TextureMediaEncoder(config); diff --git a/cameraview/src/main/views/com/otaliastudios/cameraview/CameraPreview.java b/cameraview/src/main/views/com/otaliastudios/cameraview/CameraPreview.java index 626e4e43..8babdaca 100644 --- a/cameraview/src/main/views/com/otaliastudios/cameraview/CameraPreview.java +++ b/cameraview/src/main/views/com/otaliastudios/cameraview/CameraPreview.java @@ -31,6 +31,7 @@ abstract class CameraPreview { // These are the preview stream dimensions, in REF_VIEW. protected int mInputStreamWidth; protected int mInputStreamHeight; + protected boolean mInputFlipped; CameraPreview(Context context, ViewGroup parent, SurfaceCallback callback) { mView = onCreateView(context, parent); @@ -52,10 +53,11 @@ abstract class CameraPreview { // As far as I can see, these are the actual preview dimensions, as set in CameraParameters. // This is called by the CameraImpl. // These must be alredy rotated, if needed, to be consistent with surface/view sizes. - void setInputStreamSize(int width, int height) { + void setInputStreamSize(int width, int height, boolean wasFlipped) { LOG.i("setInputStreamSize:", "desiredW=", width, "desiredH=", height); mInputStreamWidth = width; mInputStreamHeight = height; + mInputFlipped = wasFlipped; if (mInputStreamWidth > 0 && mInputStreamHeight > 0) { crop(); } diff --git a/cameraview/src/main/views/com/otaliastudios/cameraview/GlCameraPreview.java b/cameraview/src/main/views/com/otaliastudios/cameraview/GlCameraPreview.java index 6be84674..b1aaae72 100644 --- a/cameraview/src/main/views/com/otaliastudios/cameraview/GlCameraPreview.java +++ b/cameraview/src/main/views/com/otaliastudios/cameraview/GlCameraPreview.java @@ -69,6 +69,7 @@ class GlCameraPreview extends CameraPreview imple private Set mRendererFrameCallbacks = Collections.synchronizedSet(new HashSet()); /* for tests */ float mScaleX = 1F; /* for tests */ float mScaleY = 1F; + private float[] mScaleXY = new float[] { mScaleX, mScaleY }; GlCameraPreview(Context context, ViewGroup parent, SurfaceCallback callback) { super(context, parent, callback); @@ -227,7 +228,9 @@ class GlCameraPreview extends CameraPreview imple Matrix.translateM(mTransformMatrix, 0, translX, translY, 0); Matrix.scaleM(mTransformMatrix, 0, mScaleX, mScaleY, 1); } - mOutputViewport.drawFrame(mOutputTextureId, mTransformMatrix, mScaleX, mScaleY); + mScaleXY[0] = mInputFlipped ? mScaleY : mScaleX; + mScaleXY[1] = mInputFlipped ? mScaleX : mScaleY; + mOutputViewport.drawFrame(mOutputTextureId, mTransformMatrix, mScaleXY); for (RendererFrameCallback callback : mRendererFrameCallbacks) { callback.onRendererFrame(mInputSurfaceTexture, mScaleX, mScaleY); } diff --git a/cameraview/src/main/views/com/otaliastudios/cameraview/TextureCameraPreview.java b/cameraview/src/main/views/com/otaliastudios/cameraview/TextureCameraPreview.java index 422af7fa..af0571dd 100644 --- a/cameraview/src/main/views/com/otaliastudios/cameraview/TextureCameraPreview.java +++ b/cameraview/src/main/views/com/otaliastudios/cameraview/TextureCameraPreview.java @@ -58,8 +58,8 @@ class TextureCameraPreview extends CameraPreview { @TargetApi(15) @Override - void setInputStreamSize(int width, int height) { - super.setInputStreamSize(width, height); + void setInputStreamSize(int width, int height, boolean wasFlipped) { + super.setInputStreamSize(width, height, wasFlipped); if (getView().getSurfaceTexture() != null) { getView().getSurfaceTexture().setDefaultBufferSize(width, height); }