diff --git a/cameraview/src/androidTest/java/com/otaliastudios/cameraview/BaseEglTest.java b/cameraview/src/androidTest/java/com/otaliastudios/cameraview/BaseEglTest.java index 0bb74e0d..18865899 100644 --- a/cameraview/src/androidTest/java/com/otaliastudios/cameraview/BaseEglTest.java +++ b/cameraview/src/androidTest/java/com/otaliastudios/cameraview/BaseEglTest.java @@ -1,32 +1,13 @@ package com.otaliastudios.cameraview; +import android.opengl.EGL14; -import android.graphics.Canvas; +import com.otaliastudios.opengl.core.EglCore; +import com.otaliastudios.opengl.surface.EglOffscreenSurface; +import com.otaliastudios.opengl.surface.EglSurface; -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.SmallTest; - -import com.otaliastudios.cameraview.internal.egl.EglBaseSurface; -import com.otaliastudios.cameraview.internal.egl.EglCore; -import com.otaliastudios.cameraview.internal.egl.EglViewport; -import com.otaliastudios.cameraview.overlay.Overlay; -import com.otaliastudios.cameraview.overlay.OverlayDrawer; -import com.otaliastudios.cameraview.size.Size; - -import org.hamcrest.BaseMatcher; -import org.hamcrest.Description; import org.junit.After; import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.junit.Assert.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; @SuppressWarnings("WeakerAccess") @@ -36,19 +17,18 @@ public abstract class BaseEglTest extends BaseTest { protected final static int HEIGHT = 100; protected EglCore eglCore; - protected EglBaseSurface eglSurface; + protected EglSurface eglSurface; @Before public void setUp() { - eglCore = new EglCore(null, EglCore.FLAG_RECORDABLE); - eglSurface = new EglBaseSurface(eglCore); - eglSurface.createOffscreenSurface(WIDTH, HEIGHT); + eglCore = new EglCore(EGL14.EGL_NO_CONTEXT, EglCore.FLAG_RECORDABLE); + eglSurface = new EglOffscreenSurface(eglCore, WIDTH, HEIGHT); eglSurface.makeCurrent(); } @After public void tearDown() { - eglSurface.releaseEglSurface(); + eglSurface.release(); eglSurface = null; eglCore.release(); eglCore = null; diff --git a/cameraview/src/main/AndroidManifest.xml b/cameraview/src/main/AndroidManifest.xml index 5da7cf09..ce05aa56 100644 --- a/cameraview/src/main/AndroidManifest.xml +++ b/cameraview/src/main/AndroidManifest.xml @@ -1,4 +1,5 @@ @@ -20,6 +21,8 @@ android:name="android.hardware.microphone" android:required="false"/> + + \ No newline at end of file diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/internal/GlTextureDrawer.java b/cameraview/src/main/java/com/otaliastudios/cameraview/internal/GlTextureDrawer.java index 8a260b37..ff955e0b 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/internal/GlTextureDrawer.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/internal/GlTextureDrawer.java @@ -23,7 +23,7 @@ public class GlTextureDrawer { private final static int TEXTURE_UNIT = GLES20.GL_TEXTURE0; private final GlTexture mTexture; - private final float[] mTextureTransform = Egloo.IDENTITY_MATRIX.clone(); + private float[] mTextureTransform = Egloo.IDENTITY_MATRIX.clone(); @NonNull private Filter mFilter = new NoFilter(); @@ -59,6 +59,10 @@ public class GlTextureDrawer { return mTextureTransform; } + public void setTextureTransform(@NonNull float[] textureTransform) { + mTextureTransform = textureTransform; + } + public void draw(long timestampUs) { if (mPendingFilter != null) { release(); diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/picture/SnapshotGlPictureRecorder.java b/cameraview/src/main/java/com/otaliastudios/cameraview/picture/SnapshotGlPictureRecorder.java index 76d6c3f5..121a63bf 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/picture/SnapshotGlPictureRecorder.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/picture/SnapshotGlPictureRecorder.java @@ -10,15 +10,13 @@ import android.opengl.Matrix; import android.os.Build; import com.otaliastudios.cameraview.PictureResult; +import com.otaliastudios.cameraview.internal.GlTextureDrawer; import com.otaliastudios.cameraview.internal.egl.EglBaseSurface; import com.otaliastudios.cameraview.overlay.Overlay; import com.otaliastudios.cameraview.controls.Facing; import com.otaliastudios.cameraview.engine.CameraEngine; import com.otaliastudios.cameraview.engine.offset.Axis; import com.otaliastudios.cameraview.engine.offset.Reference; -import com.otaliastudios.cameraview.internal.egl.EglCore; -import com.otaliastudios.cameraview.internal.egl.EglViewport; -import com.otaliastudios.cameraview.internal.egl.EglWindowSurface; import com.otaliastudios.cameraview.internal.CropHelper; import com.otaliastudios.cameraview.internal.WorkerHandler; import com.otaliastudios.cameraview.overlay.OverlayDrawer; @@ -28,6 +26,9 @@ import com.otaliastudios.cameraview.preview.RendererThread; import com.otaliastudios.cameraview.filter.Filter; import com.otaliastudios.cameraview.size.AspectRatio; import com.otaliastudios.cameraview.size.Size; +import com.otaliastudios.opengl.core.EglCore; +import com.otaliastudios.opengl.surface.EglSurface; +import com.otaliastudios.opengl.surface.EglWindowSurface; import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; @@ -62,12 +63,7 @@ public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { private Overlay mOverlay; private boolean mHasOverlay; private OverlayDrawer mOverlayDrawer; - - private int mTextureId; - private float[] mTransform; - - - private EglViewport mViewport; + private GlTextureDrawer mTextureDrawer; public SnapshotGlPictureRecorder( @NonNull PictureResult.Stub stub, @@ -114,14 +110,10 @@ public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { @RendererThread @TargetApi(Build.VERSION_CODES.KITKAT) protected void onRendererTextureCreated(int textureId) { - mTextureId = textureId; - mViewport = new EglViewport(); + mTextureDrawer = new GlTextureDrawer(textureId); // Need to crop the size. Rect crop = CropHelper.computeCrop(mResult.size, mOutputRatio); mResult.size = new Size(crop.width(), crop.height()); - mTransform = new float[16]; - Matrix.setIdentityM(mTransform, 0); - if (mHasOverlay) { mOverlayDrawer = new OverlayDrawer(mOverlay, mResult.size); } @@ -131,7 +123,7 @@ public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { @RendererThread @TargetApi(Build.VERSION_CODES.KITKAT) protected void onRendererFilterChanged(@NonNull Filter filter) { - mViewport.setFilter(filter.copy()); + mTextureDrawer.setFilter(filter.copy()); } @SuppressWarnings("WeakerAccess") @@ -194,8 +186,9 @@ public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { // 1. Create an EGL surface final EglCore core = new EglCore(eglContext, EglCore.FLAG_RECORDABLE); - final EglBaseSurface eglSurface = new EglWindowSurface(core, fakeOutputSurface); + final EglSurface eglSurface = new EglWindowSurface(core, fakeOutputSurface); eglSurface.makeCurrent(); + final float[] transform = mTextureDrawer.getTextureTransform(); // 2. Apply scale and crop boolean flip = mEngine.getAngles().flip(Reference.VIEW, Reference.SENSOR); @@ -203,17 +196,17 @@ public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { float realScaleY = flip ? scaleX : scaleY; float scaleTranslX = (1F - realScaleX) / 2F; float scaleTranslY = (1F - realScaleY) / 2F; - Matrix.translateM(mTransform, 0, scaleTranslX, scaleTranslY, 0); - Matrix.scaleM(mTransform, 0, realScaleX, realScaleY, 1); + Matrix.translateM(transform, 0, scaleTranslX, scaleTranslY, 0); + Matrix.scaleM(transform, 0, realScaleX, realScaleY, 1); // 3. Apply rotation and flip - Matrix.translateM(mTransform, 0, 0.5F, 0.5F, 0); // Go back to 0,0 - Matrix.rotateM(mTransform, 0, -mResult.rotation, 0, 0, 1); // Rotate (not sure why we need the minus) + Matrix.translateM(transform, 0, 0.5F, 0.5F, 0); // Go back to 0,0 + Matrix.rotateM(transform, 0, -mResult.rotation, 0, 0, 1); // Rotate (not sure why we need the minus) mResult.rotation = 0; if (mResult.facing == Facing.FRONT) { // 5. Flip horizontally for front camera - Matrix.scaleM(mTransform, 0, -1, 1, 1); + Matrix.scaleM(transform, 0, -1, 1, 1); } - Matrix.translateM(mTransform, 0, -0.5F, -0.5F, 0); // Go back to old position + Matrix.translateM(transform, 0, -0.5F, -0.5F, 0); // Go back to old position // 4. Do pretty much the same for overlays if (mHasOverlay) { @@ -232,13 +225,13 @@ public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { // 5. Draw and save long timestampUs = surfaceTexture.getTimestamp() / 1000L; LOG.i("takeFrame:", "timestampUs:", timestampUs); - mViewport.draw(timestampUs, mTextureId, mTransform); + mTextureDrawer.draw(timestampUs); if (mHasOverlay) mOverlayDrawer.render(timestampUs); - mResult.data = eglSurface.saveFrameTo(Bitmap.CompressFormat.JPEG); + mResult.data = eglSurface.toByteArray(Bitmap.CompressFormat.JPEG); // 6. Cleanup - eglSurface.releaseEglSurface(); - mViewport.release(); + eglSurface.release(); + mTextureDrawer.release(); fakeOutputSurface.release(); if (mHasOverlay) mOverlayDrawer.release(); core.release(); diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/TextureMediaEncoder.java b/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/TextureMediaEncoder.java index 61d495cf..60fa10eb 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/TextureMediaEncoder.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/TextureMediaEncoder.java @@ -10,10 +10,10 @@ import androidx.annotation.RequiresApi; import com.otaliastudios.cameraview.CameraLogger; import com.otaliastudios.cameraview.filter.Filter; -import com.otaliastudios.cameraview.internal.egl.EglCore; -import com.otaliastudios.cameraview.internal.egl.EglViewport; -import com.otaliastudios.cameraview.internal.egl.EglWindowSurface; +import com.otaliastudios.cameraview.internal.GlTextureDrawer; import com.otaliastudios.cameraview.internal.Pool; +import com.otaliastudios.opengl.core.EglCore; +import com.otaliastudios.opengl.surface.EglWindowSurface; /** * Default implementation for video encoding. @@ -30,7 +30,7 @@ public class TextureMediaEncoder extends VideoMediaEncoder { private int mTransformRotation; private EglCore mEglCore; private EglWindowSurface mWindow; - private EglViewport mViewport; + private GlTextureDrawer mDrawer; private Pool mFramePool = new Pool<>(Integer.MAX_VALUE, new Pool.Factory() { @Override public Frame create() { @@ -99,7 +99,7 @@ public class TextureMediaEncoder extends VideoMediaEncoder { mEglCore = new EglCore(mConfig.eglContext, EglCore.FLAG_RECORDABLE); mWindow = new EglWindowSurface(mEglCore, mSurface, true); mWindow.makeCurrent(); - mViewport = new EglViewport(); + mDrawer = new GlTextureDrawer(mConfig.textureId); } /** @@ -149,7 +149,7 @@ public class TextureMediaEncoder extends VideoMediaEncoder { } private void onFilter(@NonNull Filter filter) { - mViewport.setFilter(filter); + mDrawer.setFilter(filter); } private void onFrame(@NonNull Frame frame) { @@ -229,7 +229,8 @@ public class TextureMediaEncoder extends VideoMediaEncoder { "hasReachedMaxLength:", hasReachedMaxLength(), "thread:", Thread.currentThread(), "- gl rendering."); - mViewport.draw(frame.timestampUs(), mConfig.textureId, transform); + mDrawer.setTextureTransform(transform); + mDrawer.draw(frame.timestampUs()); if (mConfig.hasOverlay()) { mConfig.overlayDrawer.render(frame.timestampUs()); } @@ -252,9 +253,9 @@ public class TextureMediaEncoder extends VideoMediaEncoder { mWindow.release(); mWindow = null; } - if (mViewport != null) { - mViewport.release(); - mViewport = null; + if (mDrawer != null) { + mDrawer.release(); + mDrawer = null; } if (mEglCore != null) { mEglCore.release();