|
|
@ -10,15 +10,13 @@ import android.opengl.Matrix; |
|
|
|
import android.os.Build; |
|
|
|
import android.os.Build; |
|
|
|
|
|
|
|
|
|
|
|
import com.otaliastudios.cameraview.PictureResult; |
|
|
|
import com.otaliastudios.cameraview.PictureResult; |
|
|
|
|
|
|
|
import com.otaliastudios.cameraview.internal.GlTextureDrawer; |
|
|
|
import com.otaliastudios.cameraview.internal.egl.EglBaseSurface; |
|
|
|
import com.otaliastudios.cameraview.internal.egl.EglBaseSurface; |
|
|
|
import com.otaliastudios.cameraview.overlay.Overlay; |
|
|
|
import com.otaliastudios.cameraview.overlay.Overlay; |
|
|
|
import com.otaliastudios.cameraview.controls.Facing; |
|
|
|
import com.otaliastudios.cameraview.controls.Facing; |
|
|
|
import com.otaliastudios.cameraview.engine.CameraEngine; |
|
|
|
import com.otaliastudios.cameraview.engine.CameraEngine; |
|
|
|
import com.otaliastudios.cameraview.engine.offset.Axis; |
|
|
|
import com.otaliastudios.cameraview.engine.offset.Axis; |
|
|
|
import com.otaliastudios.cameraview.engine.offset.Reference; |
|
|
|
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.CropHelper; |
|
|
|
import com.otaliastudios.cameraview.internal.WorkerHandler; |
|
|
|
import com.otaliastudios.cameraview.internal.WorkerHandler; |
|
|
|
import com.otaliastudios.cameraview.overlay.OverlayDrawer; |
|
|
|
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.filter.Filter; |
|
|
|
import com.otaliastudios.cameraview.size.AspectRatio; |
|
|
|
import com.otaliastudios.cameraview.size.AspectRatio; |
|
|
|
import com.otaliastudios.cameraview.size.Size; |
|
|
|
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.NonNull; |
|
|
|
import androidx.annotation.WorkerThread; |
|
|
|
import androidx.annotation.WorkerThread; |
|
|
@ -62,12 +63,7 @@ public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { |
|
|
|
private Overlay mOverlay; |
|
|
|
private Overlay mOverlay; |
|
|
|
private boolean mHasOverlay; |
|
|
|
private boolean mHasOverlay; |
|
|
|
private OverlayDrawer mOverlayDrawer; |
|
|
|
private OverlayDrawer mOverlayDrawer; |
|
|
|
|
|
|
|
private GlTextureDrawer mTextureDrawer; |
|
|
|
private int mTextureId; |
|
|
|
|
|
|
|
private float[] mTransform; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private EglViewport mViewport; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public SnapshotGlPictureRecorder( |
|
|
|
public SnapshotGlPictureRecorder( |
|
|
|
@NonNull PictureResult.Stub stub, |
|
|
|
@NonNull PictureResult.Stub stub, |
|
|
@ -114,14 +110,10 @@ public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { |
|
|
|
@RendererThread |
|
|
|
@RendererThread |
|
|
|
@TargetApi(Build.VERSION_CODES.KITKAT) |
|
|
|
@TargetApi(Build.VERSION_CODES.KITKAT) |
|
|
|
protected void onRendererTextureCreated(int textureId) { |
|
|
|
protected void onRendererTextureCreated(int textureId) { |
|
|
|
mTextureId = textureId; |
|
|
|
mTextureDrawer = new GlTextureDrawer(textureId); |
|
|
|
mViewport = new EglViewport(); |
|
|
|
|
|
|
|
// Need to crop the size.
|
|
|
|
// Need to crop the size.
|
|
|
|
Rect crop = CropHelper.computeCrop(mResult.size, mOutputRatio); |
|
|
|
Rect crop = CropHelper.computeCrop(mResult.size, mOutputRatio); |
|
|
|
mResult.size = new Size(crop.width(), crop.height()); |
|
|
|
mResult.size = new Size(crop.width(), crop.height()); |
|
|
|
mTransform = new float[16]; |
|
|
|
|
|
|
|
Matrix.setIdentityM(mTransform, 0); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (mHasOverlay) { |
|
|
|
if (mHasOverlay) { |
|
|
|
mOverlayDrawer = new OverlayDrawer(mOverlay, mResult.size); |
|
|
|
mOverlayDrawer = new OverlayDrawer(mOverlay, mResult.size); |
|
|
|
} |
|
|
|
} |
|
|
@ -131,7 +123,7 @@ public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { |
|
|
|
@RendererThread |
|
|
|
@RendererThread |
|
|
|
@TargetApi(Build.VERSION_CODES.KITKAT) |
|
|
|
@TargetApi(Build.VERSION_CODES.KITKAT) |
|
|
|
protected void onRendererFilterChanged(@NonNull Filter filter) { |
|
|
|
protected void onRendererFilterChanged(@NonNull Filter filter) { |
|
|
|
mViewport.setFilter(filter.copy()); |
|
|
|
mTextureDrawer.setFilter(filter.copy()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("WeakerAccess") |
|
|
|
@SuppressWarnings("WeakerAccess") |
|
|
@ -194,8 +186,9 @@ public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { |
|
|
|
|
|
|
|
|
|
|
|
// 1. Create an EGL surface
|
|
|
|
// 1. Create an EGL surface
|
|
|
|
final EglCore core = new EglCore(eglContext, EglCore.FLAG_RECORDABLE); |
|
|
|
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(); |
|
|
|
eglSurface.makeCurrent(); |
|
|
|
|
|
|
|
final float[] transform = mTextureDrawer.getTextureTransform(); |
|
|
|
|
|
|
|
|
|
|
|
// 2. Apply scale and crop
|
|
|
|
// 2. Apply scale and crop
|
|
|
|
boolean flip = mEngine.getAngles().flip(Reference.VIEW, Reference.SENSOR); |
|
|
|
boolean flip = mEngine.getAngles().flip(Reference.VIEW, Reference.SENSOR); |
|
|
@ -203,17 +196,17 @@ public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { |
|
|
|
float realScaleY = flip ? scaleX : scaleY; |
|
|
|
float realScaleY = flip ? scaleX : scaleY; |
|
|
|
float scaleTranslX = (1F - realScaleX) / 2F; |
|
|
|
float scaleTranslX = (1F - realScaleX) / 2F; |
|
|
|
float scaleTranslY = (1F - realScaleY) / 2F; |
|
|
|
float scaleTranslY = (1F - realScaleY) / 2F; |
|
|
|
Matrix.translateM(mTransform, 0, scaleTranslX, scaleTranslY, 0); |
|
|
|
Matrix.translateM(transform, 0, scaleTranslX, scaleTranslY, 0); |
|
|
|
Matrix.scaleM(mTransform, 0, realScaleX, realScaleY, 1); |
|
|
|
Matrix.scaleM(transform, 0, realScaleX, realScaleY, 1); |
|
|
|
|
|
|
|
|
|
|
|
// 3. Apply rotation and flip
|
|
|
|
// 3. Apply rotation and flip
|
|
|
|
Matrix.translateM(mTransform, 0, 0.5F, 0.5F, 0); // Go back to 0,0
|
|
|
|
Matrix.translateM(transform, 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.rotateM(transform, 0, -mResult.rotation, 0, 0, 1); // Rotate (not sure why we need the minus)
|
|
|
|
mResult.rotation = 0; |
|
|
|
mResult.rotation = 0; |
|
|
|
if (mResult.facing == Facing.FRONT) { // 5. Flip horizontally for front camera
|
|
|
|
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
|
|
|
|
// 4. Do pretty much the same for overlays
|
|
|
|
if (mHasOverlay) { |
|
|
|
if (mHasOverlay) { |
|
|
@ -232,13 +225,13 @@ public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { |
|
|
|
// 5. Draw and save
|
|
|
|
// 5. Draw and save
|
|
|
|
long timestampUs = surfaceTexture.getTimestamp() / 1000L; |
|
|
|
long timestampUs = surfaceTexture.getTimestamp() / 1000L; |
|
|
|
LOG.i("takeFrame:", "timestampUs:", timestampUs); |
|
|
|
LOG.i("takeFrame:", "timestampUs:", timestampUs); |
|
|
|
mViewport.draw(timestampUs, mTextureId, mTransform); |
|
|
|
mTextureDrawer.draw(timestampUs); |
|
|
|
if (mHasOverlay) mOverlayDrawer.render(timestampUs); |
|
|
|
if (mHasOverlay) mOverlayDrawer.render(timestampUs); |
|
|
|
mResult.data = eglSurface.saveFrameTo(Bitmap.CompressFormat.JPEG); |
|
|
|
mResult.data = eglSurface.toByteArray(Bitmap.CompressFormat.JPEG); |
|
|
|
|
|
|
|
|
|
|
|
// 6. Cleanup
|
|
|
|
// 6. Cleanup
|
|
|
|
eglSurface.releaseEglSurface(); |
|
|
|
eglSurface.release(); |
|
|
|
mViewport.release(); |
|
|
|
mTextureDrawer.release(); |
|
|
|
fakeOutputSurface.release(); |
|
|
|
fakeOutputSurface.release(); |
|
|
|
if (mHasOverlay) mOverlayDrawer.release(); |
|
|
|
if (mHasOverlay) mOverlayDrawer.release(); |
|
|
|
core.release(); |
|
|
|
core.release(); |
|
|
|