|  |  |  | @ -12,14 +12,11 @@ import android.os.Build; | 
			
		
	
		
			
				
					|  |  |  |  | import com.otaliastudios.cameraview.PictureResult; | 
			
		
	
		
			
				
					|  |  |  |  | import com.otaliastudios.cameraview.internal.GlTextureDrawer; | 
			
		
	
		
			
				
					|  |  |  |  | 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.CropHelper; | 
			
		
	
		
			
				
					|  |  |  |  | import com.otaliastudios.cameraview.internal.WorkerHandler; | 
			
		
	
		
			
				
					|  |  |  |  | import com.otaliastudios.cameraview.overlay.OverlayDrawer; | 
			
		
	
		
			
				
					|  |  |  |  | import com.otaliastudios.cameraview.preview.GlCameraPreview; | 
			
		
	
		
			
				
					|  |  |  |  | import com.otaliastudios.cameraview.preview.RendererCameraPreview; | 
			
		
	
		
			
				
					|  |  |  |  | import com.otaliastudios.cameraview.preview.RendererFrameCallback; | 
			
		
	
		
			
				
					|  |  |  |  | import com.otaliastudios.cameraview.preview.RendererThread; | 
			
		
	
		
			
				
					|  |  |  |  | import com.otaliastudios.cameraview.filter.Filter; | 
			
		
	
	
		
			
				
					|  |  |  | @ -30,13 +27,14 @@ import com.otaliastudios.opengl.surface.EglSurface; | 
			
		
	
		
			
				
					|  |  |  |  | import com.otaliastudios.opengl.surface.EglWindowSurface; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | import androidx.annotation.NonNull; | 
			
		
	
		
			
				
					|  |  |  |  | import androidx.annotation.Nullable; | 
			
		
	
		
			
				
					|  |  |  |  | import androidx.annotation.WorkerThread; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | import android.view.Surface; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | /** | 
			
		
	
		
			
				
					|  |  |  |  |  * API 19. | 
			
		
	
		
			
				
					|  |  |  |  |  * Records a picture snapshots from the {@link GlCameraPreview}. It works as follows: | 
			
		
	
		
			
				
					|  |  |  |  |  * Records a picture snapshots from the {@link RendererCameraPreview}. It works as follows: | 
			
		
	
		
			
				
					|  |  |  |  |  * | 
			
		
	
		
			
				
					|  |  |  |  |  * - We register a one time {@link RendererFrameCallback} on the preview | 
			
		
	
		
			
				
					|  |  |  |  |  * - We get the textureId and the frame callback on the {@link RendererThread} | 
			
		
	
	
		
			
				
					|  |  |  | @ -55,8 +53,7 @@ import android.view.Surface; | 
			
		
	
		
			
				
					|  |  |  |  |  */ | 
			
		
	
		
			
				
					|  |  |  |  | public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     private CameraEngine mEngine; | 
			
		
	
		
			
				
					|  |  |  |  |     private GlCameraPreview mPreview; | 
			
		
	
		
			
				
					|  |  |  |  |     private RendererCameraPreview mPreview; | 
			
		
	
		
			
				
					|  |  |  |  |     private AspectRatio mOutputRatio; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     private Overlay mOverlay; | 
			
		
	
	
		
			
				
					|  |  |  | @ -66,14 +63,14 @@ public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     public SnapshotGlPictureRecorder( | 
			
		
	
		
			
				
					|  |  |  |  |             @NonNull PictureResult.Stub stub, | 
			
		
	
		
			
				
					|  |  |  |  |             @NonNull CameraEngine engine, | 
			
		
	
		
			
				
					|  |  |  |  |             @NonNull GlCameraPreview preview, | 
			
		
	
		
			
				
					|  |  |  |  |             @NonNull AspectRatio outputRatio) { | 
			
		
	
		
			
				
					|  |  |  |  |         super(stub, engine); | 
			
		
	
		
			
				
					|  |  |  |  |         mEngine = engine; | 
			
		
	
		
			
				
					|  |  |  |  |             @Nullable PictureResultListener listener, | 
			
		
	
		
			
				
					|  |  |  |  |             @NonNull RendererCameraPreview preview, | 
			
		
	
		
			
				
					|  |  |  |  |             @NonNull AspectRatio outputRatio, | 
			
		
	
		
			
				
					|  |  |  |  |             @Nullable Overlay overlay) { | 
			
		
	
		
			
				
					|  |  |  |  |         super(stub, listener); | 
			
		
	
		
			
				
					|  |  |  |  |         mPreview = preview; | 
			
		
	
		
			
				
					|  |  |  |  |         mOutputRatio = outputRatio; | 
			
		
	
		
			
				
					|  |  |  |  |         mOverlay = engine.getOverlay(); | 
			
		
	
		
			
				
					|  |  |  |  |         mOverlay = overlay; | 
			
		
	
		
			
				
					|  |  |  |  |         mHasOverlay = mOverlay != null && mOverlay.drawsOn(Overlay.Target.PICTURE_SNAPSHOT); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -96,10 +93,10 @@ public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { | 
			
		
	
		
			
				
					|  |  |  |  |             @RendererThread | 
			
		
	
		
			
				
					|  |  |  |  |             @Override | 
			
		
	
		
			
				
					|  |  |  |  |             public void onRendererFrame(@NonNull SurfaceTexture surfaceTexture, | 
			
		
	
		
			
				
					|  |  |  |  |                                         final float scaleX, | 
			
		
	
		
			
				
					|  |  |  |  |                                         final float scaleY) { | 
			
		
	
		
			
				
					|  |  |  |  |                                         int rotation, float scaleX, float scaleY) { | 
			
		
	
		
			
				
					|  |  |  |  |                 mPreview.removeRendererFrameCallback(this); | 
			
		
	
		
			
				
					|  |  |  |  |                 SnapshotGlPictureRecorder.this.onRendererFrame(surfaceTexture, scaleX, scaleY); | 
			
		
	
		
			
				
					|  |  |  |  |                 SnapshotGlPictureRecorder.this.onRendererFrame(surfaceTexture, | 
			
		
	
		
			
				
					|  |  |  |  |                         rotation, scaleX, scaleY); | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         }); | 
			
		
	
	
		
			
				
					|  |  |  | @ -129,18 +126,17 @@ public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { | 
			
		
	
		
			
				
					|  |  |  |  |     @RendererThread | 
			
		
	
		
			
				
					|  |  |  |  |     @TargetApi(Build.VERSION_CODES.KITKAT) | 
			
		
	
		
			
				
					|  |  |  |  |     protected void onRendererFrame(@SuppressWarnings("unused") @NonNull final SurfaceTexture surfaceTexture, | 
			
		
	
		
			
				
					|  |  |  |  |                                  final int rotation, | 
			
		
	
		
			
				
					|  |  |  |  |                                  final float scaleX, | 
			
		
	
		
			
				
					|  |  |  |  |                                  final float scaleY) { | 
			
		
	
		
			
				
					|  |  |  |  |         // Get egl context from the RendererThread, which is the one in which we have created
 | 
			
		
	
		
			
				
					|  |  |  |  |         // the textureId and the overlayTextureId, managed by the GlSurfaceView.
 | 
			
		
	
		
			
				
					|  |  |  |  |         // Next operations can then be performed on different threads using this handle.
 | 
			
		
	
		
			
				
					|  |  |  |  |         final EGLContext eglContext = EGL14.eglGetCurrentContext(); | 
			
		
	
		
			
				
					|  |  |  |  |         // Calling this invalidates the rotation/scale logic below:
 | 
			
		
	
		
			
				
					|  |  |  |  |         // surfaceTexture.getTransformMatrix(mTransform); // TODO activate and fix the logic.
 | 
			
		
	
		
			
				
					|  |  |  |  |         WorkerHandler.execute(new Runnable() { | 
			
		
	
		
			
				
					|  |  |  |  |             @Override | 
			
		
	
		
			
				
					|  |  |  |  |             public void run() { | 
			
		
	
		
			
				
					|  |  |  |  |                 takeFrame(surfaceTexture, scaleX, scaleY, eglContext); | 
			
		
	
		
			
				
					|  |  |  |  |                 takeFrame(surfaceTexture, rotation, scaleX, scaleY, eglContext); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         }); | 
			
		
	
	
		
			
				
					|  |  |  | @ -173,6 +169,7 @@ public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { | 
			
		
	
		
			
				
					|  |  |  |  |     @WorkerThread | 
			
		
	
		
			
				
					|  |  |  |  |     @TargetApi(Build.VERSION_CODES.KITKAT) | 
			
		
	
		
			
				
					|  |  |  |  |     protected void takeFrame(@NonNull SurfaceTexture surfaceTexture, | 
			
		
	
		
			
				
					|  |  |  |  |                              int rotation, | 
			
		
	
		
			
				
					|  |  |  |  |                              float scaleX, | 
			
		
	
		
			
				
					|  |  |  |  |                              float scaleY, | 
			
		
	
		
			
				
					|  |  |  |  |                              @NonNull EGLContext eglContext) { | 
			
		
	
	
		
			
				
					|  |  |  | @ -189,22 +186,18 @@ public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { | 
			
		
	
		
			
				
					|  |  |  |  |         eglSurface.makeCurrent(); | 
			
		
	
		
			
				
					|  |  |  |  |         final float[] transform = mTextureDrawer.getTextureTransform(); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         // 2. Apply scale and crop
 | 
			
		
	
		
			
				
					|  |  |  |  |         boolean flip = mEngine.getAngles().flip(Reference.VIEW, Reference.SENSOR); | 
			
		
	
		
			
				
					|  |  |  |  |         float realScaleX = flip ? scaleY : scaleX; | 
			
		
	
		
			
				
					|  |  |  |  |         float realScaleY = flip ? scaleX : scaleY; | 
			
		
	
		
			
				
					|  |  |  |  |         float scaleTranslX = (1F - realScaleX) / 2F; | 
			
		
	
		
			
				
					|  |  |  |  |         float scaleTranslY = (1F - realScaleY) / 2F; | 
			
		
	
		
			
				
					|  |  |  |  |         // 2. Apply preview transformations
 | 
			
		
	
		
			
				
					|  |  |  |  |         surfaceTexture.getTransformMatrix(transform); | 
			
		
	
		
			
				
					|  |  |  |  |         float scaleTranslX = (1F - scaleX) / 2F; | 
			
		
	
		
			
				
					|  |  |  |  |         float scaleTranslY = (1F - scaleY) / 2F; | 
			
		
	
		
			
				
					|  |  |  |  |         Matrix.translateM(transform, 0, scaleTranslX, scaleTranslY, 0); | 
			
		
	
		
			
				
					|  |  |  |  |         Matrix.scaleM(transform, 0, realScaleX, realScaleY, 1); | 
			
		
	
		
			
				
					|  |  |  |  |         Matrix.scaleM(transform, 0, scaleX, scaleY, 1); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         // 3. Apply rotation and flip
 | 
			
		
	
		
			
				
					|  |  |  |  |         // If this doesn't work, rotate "rotation" before scaling, like GlCameraPreview does.
 | 
			
		
	
		
			
				
					|  |  |  |  |         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(transform, 0, -1, 1, 1); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         Matrix.rotateM(transform, 0, rotation + mResult.rotation, 0, 0, 1); // Rotate to OUTPUT
 | 
			
		
	
		
			
				
					|  |  |  |  |         Matrix.scaleM(transform, 0, 1, -1, 1); // Vertical flip because we'll use glReadPixels
 | 
			
		
	
		
			
				
					|  |  |  |  |         Matrix.translateM(transform, 0, -0.5F, -0.5F, 0); // Go back to old position
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         // 4. Do pretty much the same for overlays
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -213,13 +206,12 @@ public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { | 
			
		
	
		
			
				
					|  |  |  |  |             mOverlayDrawer.draw(Overlay.Target.PICTURE_SNAPSHOT); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             // 2. Then we can apply the transformations
 | 
			
		
	
		
			
				
					|  |  |  |  |             int rotation = mEngine.getAngles().offset(Reference.VIEW, Reference.OUTPUT, Axis.ABSOLUTE); | 
			
		
	
		
			
				
					|  |  |  |  |             Matrix.translateM(mOverlayDrawer.getTransform(), 0, 0.5F, 0.5F, 0); | 
			
		
	
		
			
				
					|  |  |  |  |             Matrix.rotateM(mOverlayDrawer.getTransform(), 0, rotation, 0, 0, 1); | 
			
		
	
		
			
				
					|  |  |  |  |             // No need to flip the x axis for front camera, but need to flip the y axis always.
 | 
			
		
	
		
			
				
					|  |  |  |  |             Matrix.scaleM(mOverlayDrawer.getTransform(), 0, 1, -1, 1); | 
			
		
	
		
			
				
					|  |  |  |  |             Matrix.rotateM(mOverlayDrawer.getTransform(), 0, mResult.rotation, 0, 0, 1); | 
			
		
	
		
			
				
					|  |  |  |  |             Matrix.scaleM(mOverlayDrawer.getTransform(), 0, 1, -1, 1); // Vertical flip because we'll use glReadPixels
 | 
			
		
	
		
			
				
					|  |  |  |  |             Matrix.translateM(mOverlayDrawer.getTransform(), 0, -0.5F, -0.5F, 0); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         mResult.rotation = 0; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         // 5. Draw and save
 | 
			
		
	
		
			
				
					|  |  |  |  |         long timestampUs = surfaceTexture.getTimestamp() / 1000L; | 
			
		
	
	
		
			
				
					|  |  |  | @ -239,7 +231,6 @@ public class SnapshotGlPictureRecorder extends SnapshotPictureRecorder { | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     @Override | 
			
		
	
		
			
				
					|  |  |  |  |     protected void dispatchResult() { | 
			
		
	
		
			
				
					|  |  |  |  |         mEngine = null; | 
			
		
	
		
			
				
					|  |  |  |  |         mOutputRatio = null; | 
			
		
	
		
			
				
					|  |  |  |  |         super.dispatchResult(); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
	
		
			
				
					|  |  |  | 
 |