|  |  |  | @ -2,7 +2,7 @@ package com.otaliastudios.cameraview.engine; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | import android.annotation.SuppressLint; | 
			
		
	
		
			
				
					|  |  |  |  | import android.content.Context; | 
			
		
	
		
			
				
					|  |  |  |  | import android.graphics.ImageFormat; | 
			
		
	
		
			
				
					|  |  |  |  | import android.graphics.Camera; | 
			
		
	
		
			
				
					|  |  |  |  | import android.graphics.PointF; | 
			
		
	
		
			
				
					|  |  |  |  | import android.graphics.Rect; | 
			
		
	
		
			
				
					|  |  |  |  | import android.graphics.SurfaceTexture; | 
			
		
	
	
		
			
				
					|  |  |  | @ -69,9 +69,11 @@ public class Camera2Engine extends CameraEngine { | 
			
		
	
		
			
				
					|  |  |  |  |     private CameraDevice mCamera; | 
			
		
	
		
			
				
					|  |  |  |  |     private CameraCharacteristics mCameraCharacteristics; | 
			
		
	
		
			
				
					|  |  |  |  |     private CameraCaptureSession mSession; | 
			
		
	
		
			
				
					|  |  |  |  |     private CaptureRequest.Builder mPreviewStreamRequestBuilder; | 
			
		
	
		
			
				
					|  |  |  |  |     private CaptureRequest mPreviewStreamRequest; | 
			
		
	
		
			
				
					|  |  |  |  |     private CaptureRequest.Builder mRepeatingRequestBuilder; | 
			
		
	
		
			
				
					|  |  |  |  |     private CaptureRequest mRepeatingRequest; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     private Surface mPreviewStreamSurface; | 
			
		
	
		
			
				
					|  |  |  |  |     private Surface mFrameProcessingSurface; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     // API 23+ for full video recording. The surface is created before.
 | 
			
		
	
		
			
				
					|  |  |  |  |     private Surface mFullVideoPersistentSurface; | 
			
		
	
	
		
			
				
					|  |  |  | @ -123,6 +125,77 @@ public class Camera2Engine extends CameraEngine { | 
			
		
	
		
			
				
					|  |  |  |  |         return new CameraException(reason); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     /** | 
			
		
	
		
			
				
					|  |  |  |  |      * When creating a new builder, we want to | 
			
		
	
		
			
				
					|  |  |  |  |      * - set it to {@link #mRepeatingRequestBuilder}, the current one | 
			
		
	
		
			
				
					|  |  |  |  |      * - add a tag for the template just in case | 
			
		
	
		
			
				
					|  |  |  |  |      * - apply all the current parameters | 
			
		
	
		
			
				
					|  |  |  |  |      */ | 
			
		
	
		
			
				
					|  |  |  |  |     @SuppressWarnings("UnusedReturnValue") | 
			
		
	
		
			
				
					|  |  |  |  |     @NonNull | 
			
		
	
		
			
				
					|  |  |  |  |     private CaptureRequest.Builder createRepeatingRequestBuilder(int template) throws CameraAccessException { | 
			
		
	
		
			
				
					|  |  |  |  |         mRepeatingRequestBuilder = mCamera.createCaptureRequest(template); | 
			
		
	
		
			
				
					|  |  |  |  |         mRepeatingRequestBuilder.setTag(template); | 
			
		
	
		
			
				
					|  |  |  |  |         applyAll(mRepeatingRequestBuilder); | 
			
		
	
		
			
				
					|  |  |  |  |         return mRepeatingRequestBuilder; | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     /** | 
			
		
	
		
			
				
					|  |  |  |  |      * Sets up the repeating request builder with default surfaces and extra ones | 
			
		
	
		
			
				
					|  |  |  |  |      * if needed (like a video recording surface). | 
			
		
	
		
			
				
					|  |  |  |  |      */ | 
			
		
	
		
			
				
					|  |  |  |  |     private void addRepeatingRequestBuilderSurfaces(@NonNull Surface... extraSurfaces) { | 
			
		
	
		
			
				
					|  |  |  |  |         mRepeatingRequestBuilder.addTarget(mPreviewStreamSurface); | 
			
		
	
		
			
				
					|  |  |  |  |         if (mFrameProcessingSurface != null) { | 
			
		
	
		
			
				
					|  |  |  |  |             mRepeatingRequestBuilder.addTarget(mFrameProcessingSurface); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         for (Surface extraSurface : extraSurfaces) { | 
			
		
	
		
			
				
					|  |  |  |  |             mRepeatingRequestBuilder.addTarget(extraSurface); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     /** | 
			
		
	
		
			
				
					|  |  |  |  |      * Sets up the repeating request builder with default surfaces and extra ones | 
			
		
	
		
			
				
					|  |  |  |  |      * if needed (like a video recording surface). | 
			
		
	
		
			
				
					|  |  |  |  |      */ | 
			
		
	
		
			
				
					|  |  |  |  |     private void removeRepeatingRequestBuilderSurfaces() { | 
			
		
	
		
			
				
					|  |  |  |  |         mRepeatingRequestBuilder.removeTarget(mPreviewStreamSurface); | 
			
		
	
		
			
				
					|  |  |  |  |         if (mFrameProcessingSurface != null) { | 
			
		
	
		
			
				
					|  |  |  |  |             mRepeatingRequestBuilder.removeTarget(mFrameProcessingSurface); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     /** | 
			
		
	
		
			
				
					|  |  |  |  |      * Applies the repeating request builder to the preview, assuming we actually have a preview | 
			
		
	
		
			
				
					|  |  |  |  |      * running. Can be called after changing parameters to the builder. | 
			
		
	
		
			
				
					|  |  |  |  |      * | 
			
		
	
		
			
				
					|  |  |  |  |      * To apply a new builder (for example switch between TEMPLATE_PREVIEW and TEMPLATE_RECORD) | 
			
		
	
		
			
				
					|  |  |  |  |      * it should be set before calling this method, for example by calling | 
			
		
	
		
			
				
					|  |  |  |  |      * {@link #createRepeatingRequestBuilder(int)}. | 
			
		
	
		
			
				
					|  |  |  |  |      */ | 
			
		
	
		
			
				
					|  |  |  |  |     private void applyRepeatingRequestBuilder() { | 
			
		
	
		
			
				
					|  |  |  |  |         applyRepeatingRequestBuilder(true, CameraException.REASON_DISCONNECTED, null); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     private void applyRepeatingRequestBuilder(boolean checkStarted, int errorReason, @Nullable final Runnable onFirstFrame) { | 
			
		
	
		
			
				
					|  |  |  |  |         if (!checkStarted || getPreviewState() == STATE_STARTED) { | 
			
		
	
		
			
				
					|  |  |  |  |             try { | 
			
		
	
		
			
				
					|  |  |  |  |                 mRepeatingRequest = mRepeatingRequestBuilder.build(); | 
			
		
	
		
			
				
					|  |  |  |  |                 final AtomicBoolean firstFrame = new AtomicBoolean(false); | 
			
		
	
		
			
				
					|  |  |  |  |                 mSession.setRepeatingRequest(mRepeatingRequest, new CameraCaptureSession.CaptureCallback() { | 
			
		
	
		
			
				
					|  |  |  |  |                     @Override | 
			
		
	
		
			
				
					|  |  |  |  |                     public void onCaptureStarted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, long timestamp, long frameNumber) { | 
			
		
	
		
			
				
					|  |  |  |  |                         super.onCaptureStarted(session, request, timestamp, frameNumber); | 
			
		
	
		
			
				
					|  |  |  |  |                         if (firstFrame.compareAndSet(false, true) && onFirstFrame != null) { | 
			
		
	
		
			
				
					|  |  |  |  |                             onFirstFrame.run(); | 
			
		
	
		
			
				
					|  |  |  |  |                         } | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                 }, null); | 
			
		
	
		
			
				
					|  |  |  |  |             } catch (CameraAccessException e) { | 
			
		
	
		
			
				
					|  |  |  |  |                 throw new CameraException(e, errorReason); | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  |     //endregion
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     //region Protected APIs
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -204,8 +277,7 @@ public class Camera2Engine extends CameraEngine { | 
			
		
	
		
			
				
					|  |  |  |  |                         LOG.i("createCamera:", "Applying default parameters."); | 
			
		
	
		
			
				
					|  |  |  |  |                         mCameraCharacteristics = mManager.getCameraCharacteristics(mCameraId); | 
			
		
	
		
			
				
					|  |  |  |  |                         mCameraOptions = new CameraOptions(mManager, mCameraId, flip(REF_SENSOR, REF_VIEW)); | 
			
		
	
		
			
				
					|  |  |  |  |                         mPreviewStreamRequestBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); | 
			
		
	
		
			
				
					|  |  |  |  |                         applyAll(mPreviewStreamRequestBuilder); | 
			
		
	
		
			
				
					|  |  |  |  |                         createRepeatingRequestBuilder(CameraDevice.TEMPLATE_PREVIEW); | 
			
		
	
		
			
				
					|  |  |  |  |                     } catch (CameraAccessException e) { | 
			
		
	
		
			
				
					|  |  |  |  |                         task.trySetException(createCameraException(e)); | 
			
		
	
		
			
				
					|  |  |  |  |                         return; | 
			
		
	
	
		
			
				
					|  |  |  | @ -245,8 +317,13 @@ public class Camera2Engine extends CameraEngine { | 
			
		
	
		
			
				
					|  |  |  |  |         mCaptureSize = computeCaptureSize(); | 
			
		
	
		
			
				
					|  |  |  |  |         mPreviewStreamSize = computePreviewStreamSize(); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         // Create a preview surface with the correct size.In Camera2, instead of applying it to
 | 
			
		
	
		
			
				
					|  |  |  |  |         // the camera params object, we must resize our own surfaces.
 | 
			
		
	
		
			
				
					|  |  |  |  |         // Deal with surfaces.
 | 
			
		
	
		
			
				
					|  |  |  |  |         // In Camera2, instead of applying the size to the camera params object,
 | 
			
		
	
		
			
				
					|  |  |  |  |         // we must resize our own surfaces and configure them before opening the session.
 | 
			
		
	
		
			
				
					|  |  |  |  |         List<Surface> outputSurfaces = new ArrayList<>(); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         // 1. PREVIEW
 | 
			
		
	
		
			
				
					|  |  |  |  |         // Create a preview surface with the correct size.
 | 
			
		
	
		
			
				
					|  |  |  |  |         final Object output = mPreview.getOutput(); | 
			
		
	
		
			
				
					|  |  |  |  |         if (output instanceof SurfaceHolder) { | 
			
		
	
		
			
				
					|  |  |  |  |             try { | 
			
		
	
	
		
			
				
					|  |  |  | @ -254,7 +331,9 @@ public class Camera2Engine extends CameraEngine { | 
			
		
	
		
			
				
					|  |  |  |  |                 Tasks.await(Tasks.call(new Callable<Void>() { | 
			
		
	
		
			
				
					|  |  |  |  |                     @Override | 
			
		
	
		
			
				
					|  |  |  |  |                     public Void call() { | 
			
		
	
		
			
				
					|  |  |  |  |                         ((SurfaceHolder) output).setFixedSize(mPreviewStreamSize.getWidth(), mPreviewStreamSize.getHeight()); | 
			
		
	
		
			
				
					|  |  |  |  |                         ((SurfaceHolder) output).setFixedSize( | 
			
		
	
		
			
				
					|  |  |  |  |                                 mPreviewStreamSize.getWidth(), | 
			
		
	
		
			
				
					|  |  |  |  |                                 mPreviewStreamSize.getHeight()); | 
			
		
	
		
			
				
					|  |  |  |  |                         return null; | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                 })); | 
			
		
	
	
		
			
				
					|  |  |  | @ -263,23 +342,24 @@ public class Camera2Engine extends CameraEngine { | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |             mPreviewStreamSurface = ((SurfaceHolder) output).getSurface(); | 
			
		
	
		
			
				
					|  |  |  |  |         } else if (output instanceof SurfaceTexture) { | 
			
		
	
		
			
				
					|  |  |  |  |             ((SurfaceTexture) output).setDefaultBufferSize(mPreviewStreamSize.getWidth(), mPreviewStreamSize.getHeight()); | 
			
		
	
		
			
				
					|  |  |  |  |             ((SurfaceTexture) output).setDefaultBufferSize( | 
			
		
	
		
			
				
					|  |  |  |  |                     mPreviewStreamSize.getWidth(), | 
			
		
	
		
			
				
					|  |  |  |  |                     mPreviewStreamSize.getHeight()); | 
			
		
	
		
			
				
					|  |  |  |  |             mPreviewStreamSurface = new Surface((SurfaceTexture) output); | 
			
		
	
		
			
				
					|  |  |  |  |         } else { | 
			
		
	
		
			
				
					|  |  |  |  |             throw new RuntimeException("Unknown CameraPreview output class."); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         outputSurfaces.add(mPreviewStreamSurface); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         Surface captureSurface = null; | 
			
		
	
		
			
				
					|  |  |  |  |         if (mMode == Mode.PICTURE) { | 
			
		
	
		
			
				
					|  |  |  |  |             // TODO picture recorder
 | 
			
		
	
		
			
				
					|  |  |  |  |         } else { | 
			
		
	
		
			
				
					|  |  |  |  |         // 2. VIDEO RECORDING
 | 
			
		
	
		
			
				
					|  |  |  |  |         if (mMode == Mode.VIDEO) { | 
			
		
	
		
			
				
					|  |  |  |  |             if (Full2VideoRecorder.SUPPORTS_PERSISTENT_SURFACE) { | 
			
		
	
		
			
				
					|  |  |  |  |                 mFullVideoPersistentSurface = MediaCodec.createPersistentInputSurface(); | 
			
		
	
		
			
				
					|  |  |  |  |                 captureSurface = mFullVideoPersistentSurface; | 
			
		
	
		
			
				
					|  |  |  |  |                 outputSurfaces.add(mFullVideoPersistentSurface); | 
			
		
	
		
			
				
					|  |  |  |  |             } else if (mFullVideoPendingStub != null) { | 
			
		
	
		
			
				
					|  |  |  |  |                 Full2VideoRecorder recorder = new Full2VideoRecorder(this, mCameraId, null); | 
			
		
	
		
			
				
					|  |  |  |  |                 try { | 
			
		
	
		
			
				
					|  |  |  |  |                     captureSurface = recorder.createInputSurface(mFullVideoPendingStub); | 
			
		
	
		
			
				
					|  |  |  |  |                     outputSurfaces.add(recorder.createInputSurface(mFullVideoPendingStub)); | 
			
		
	
		
			
				
					|  |  |  |  |                 } catch (Full2VideoRecorder.PrepareException e) { | 
			
		
	
		
			
				
					|  |  |  |  |                     throw new CameraException(e, CameraException.REASON_FAILED_TO_CONNECT); | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
	
		
			
				
					|  |  |  | @ -287,13 +367,20 @@ public class Camera2Engine extends CameraEngine { | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         List<Surface> outputSurfaces = new ArrayList<>(); | 
			
		
	
		
			
				
					|  |  |  |  |         outputSurfaces.add(mPreviewStreamSurface); | 
			
		
	
		
			
				
					|  |  |  |  |         if (captureSurface != null) outputSurfaces.add(captureSurface); | 
			
		
	
		
			
				
					|  |  |  |  |         // 3. PICTURE RECORDING
 | 
			
		
	
		
			
				
					|  |  |  |  |         if (mMode == Mode.PICTURE) { | 
			
		
	
		
			
				
					|  |  |  |  |             // TODO picture recorder
 | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         try { | 
			
		
	
		
			
				
					|  |  |  |  |             mPreviewStreamRequestBuilder.addTarget(mPreviewStreamSurface); | 
			
		
	
		
			
				
					|  |  |  |  |         // 4. FRAME PROCESSING
 | 
			
		
	
		
			
				
					|  |  |  |  |         if (mHasFrameProcessors) { | 
			
		
	
		
			
				
					|  |  |  |  |             // TODO
 | 
			
		
	
		
			
				
					|  |  |  |  |             outputSurfaces.add(mFrameProcessingSurface); | 
			
		
	
		
			
				
					|  |  |  |  |         } else { | 
			
		
	
		
			
				
					|  |  |  |  |             mFrameProcessingSurface = null; | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         try { | 
			
		
	
		
			
				
					|  |  |  |  |             // null handler means using the current looper which is totally ok.
 | 
			
		
	
		
			
				
					|  |  |  |  |             mCamera.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() { | 
			
		
	
		
			
				
					|  |  |  |  |                 @Override | 
			
		
	
	
		
			
				
					|  |  |  | @ -336,14 +423,8 @@ public class Camera2Engine extends CameraEngine { | 
			
		
	
		
			
				
					|  |  |  |  |         // TODO mFrameManager.setUp(ImageFormat.getBitsPerPixel(mPreviewStreamFormat), mPreviewStreamSize);
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         LOG.i("onStartPreview", "Starting preview with startPreview()."); | 
			
		
	
		
			
				
					|  |  |  |  |         try { | 
			
		
	
		
			
				
					|  |  |  |  |             mPreviewStreamRequest = mPreviewStreamRequestBuilder.build(); | 
			
		
	
		
			
				
					|  |  |  |  |             mSession.setRepeatingRequest(mPreviewStreamRequest, null, null); | 
			
		
	
		
			
				
					|  |  |  |  |         } catch (Exception e) { | 
			
		
	
		
			
				
					|  |  |  |  |             // This is an unrecoverable exception that will stop everything.
 | 
			
		
	
		
			
				
					|  |  |  |  |             LOG.e("onStartPreview", "Failed to start preview.", e); | 
			
		
	
		
			
				
					|  |  |  |  |             throw new CameraException(e, CameraException.REASON_FAILED_TO_START_PREVIEW); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         addRepeatingRequestBuilderSurfaces(); | 
			
		
	
		
			
				
					|  |  |  |  |         applyRepeatingRequestBuilder(false, CameraException.REASON_FAILED_TO_START_PREVIEW, null); | 
			
		
	
		
			
				
					|  |  |  |  |         LOG.i("onStartPreview", "Started preview."); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         // Start delayed video if needed.
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -362,6 +443,8 @@ public class Camera2Engine extends CameraEngine { | 
			
		
	
		
			
				
					|  |  |  |  |     @Override | 
			
		
	
		
			
				
					|  |  |  |  |     protected Task<Void> onStopPreview() { | 
			
		
	
		
			
				
					|  |  |  |  |         if (mVideoRecorder != null) { | 
			
		
	
		
			
				
					|  |  |  |  |             // This should synchronously call onVideoResult that will reset the repeating builder
 | 
			
		
	
		
			
				
					|  |  |  |  |             // to the PREVIEW template. This is very important.
 | 
			
		
	
		
			
				
					|  |  |  |  |             mVideoRecorder.stop(); | 
			
		
	
		
			
				
					|  |  |  |  |             mVideoRecorder = null; | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
	
		
			
				
					|  |  |  | @ -378,7 +461,8 @@ public class Camera2Engine extends CameraEngine { | 
			
		
	
		
			
				
					|  |  |  |  |             LOG.w("stopRepeating failed!", e); | 
			
		
	
		
			
				
					|  |  |  |  |             throw createCameraException(e); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         mPreviewStreamRequest = null; | 
			
		
	
		
			
				
					|  |  |  |  |         removeRepeatingRequestBuilderSurfaces(); | 
			
		
	
		
			
				
					|  |  |  |  |         mRepeatingRequest = null; | 
			
		
	
		
			
				
					|  |  |  |  |         return Tasks.forResult(null); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -390,7 +474,7 @@ public class Camera2Engine extends CameraEngine { | 
			
		
	
		
			
				
					|  |  |  |  |             mFullVideoPersistentSurface.release(); | 
			
		
	
		
			
				
					|  |  |  |  |             mFullVideoPersistentSurface = null; | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         mPreviewStreamRequestBuilder.removeTarget(mPreviewStreamSurface); | 
			
		
	
		
			
				
					|  |  |  |  |         mFrameProcessingSurface = null; | 
			
		
	
		
			
				
					|  |  |  |  |         mPreviewStreamSurface = null; | 
			
		
	
		
			
				
					|  |  |  |  |         mPreviewStreamSize = null; | 
			
		
	
		
			
				
					|  |  |  |  |         mCaptureSize = null; | 
			
		
	
	
		
			
				
					|  |  |  | @ -414,7 +498,7 @@ public class Camera2Engine extends CameraEngine { | 
			
		
	
		
			
				
					|  |  |  |  |         mCamera = null; | 
			
		
	
		
			
				
					|  |  |  |  |         mCameraOptions = null; | 
			
		
	
		
			
				
					|  |  |  |  |         mVideoRecorder = null; | 
			
		
	
		
			
				
					|  |  |  |  |         mPreviewStreamRequestBuilder = null; | 
			
		
	
		
			
				
					|  |  |  |  |         mRepeatingRequestBuilder = null; | 
			
		
	
		
			
				
					|  |  |  |  |         LOG.w("onStopEngine:", "Returning."); | 
			
		
	
		
			
				
					|  |  |  |  |         return Tasks.forResult(null); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
	
		
			
				
					|  |  |  | @ -473,22 +557,20 @@ public class Camera2Engine extends CameraEngine { | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         Full2VideoRecorder recorder = (Full2VideoRecorder) mVideoRecorder; | 
			
		
	
		
			
				
					|  |  |  |  |         try { | 
			
		
	
		
			
				
					|  |  |  |  |             CaptureRequest.Builder builder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_RECORD); | 
			
		
	
		
			
				
					|  |  |  |  |             applyAll(builder); | 
			
		
	
		
			
				
					|  |  |  |  |             //noinspection ConstantConditions
 | 
			
		
	
		
			
				
					|  |  |  |  |             builder.addTarget(recorder.getInputSurface()); | 
			
		
	
		
			
				
					|  |  |  |  |             builder.addTarget(mPreviewStreamSurface); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             final AtomicBoolean started = new AtomicBoolean(false); | 
			
		
	
		
			
				
					|  |  |  |  |             mSession.setRepeatingRequest(builder.build(), new CameraCaptureSession.CaptureCallback() { | 
			
		
	
		
			
				
					|  |  |  |  |             createRepeatingRequestBuilder(CameraDevice.TEMPLATE_RECORD); | 
			
		
	
		
			
				
					|  |  |  |  |             addRepeatingRequestBuilderSurfaces(recorder.getInputSurface()); | 
			
		
	
		
			
				
					|  |  |  |  |             applyRepeatingRequestBuilder(true, CameraException.REASON_DISCONNECTED, new Runnable() { | 
			
		
	
		
			
				
					|  |  |  |  |                 @Override | 
			
		
	
		
			
				
					|  |  |  |  |                 public void onCaptureStarted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, long timestamp, long frameNumber) { | 
			
		
	
		
			
				
					|  |  |  |  |                     if (started.compareAndSet(false, true)) mVideoRecorder.start(stub); | 
			
		
	
		
			
				
					|  |  |  |  |                 public void run() { | 
			
		
	
		
			
				
					|  |  |  |  |                     mVideoRecorder.start(stub); | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |             }, null); | 
			
		
	
		
			
				
					|  |  |  |  |             }); | 
			
		
	
		
			
				
					|  |  |  |  |         } catch (CameraAccessException e) { | 
			
		
	
		
			
				
					|  |  |  |  |             onVideoResult(null, e); | 
			
		
	
		
			
				
					|  |  |  |  |             throw createCameraException(e); | 
			
		
	
		
			
				
					|  |  |  |  |         } catch (CameraException e) { | 
			
		
	
		
			
				
					|  |  |  |  |             onVideoResult(null, e); | 
			
		
	
		
			
				
					|  |  |  |  |             throw e; | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -525,39 +607,24 @@ public class Camera2Engine extends CameraEngine { | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     @Override | 
			
		
	
		
			
				
					|  |  |  |  |     public void onVideoResult(@Nullable VideoResult.Stub result, @Nullable Exception exception) { | 
			
		
	
		
			
				
					|  |  |  |  |         if (mVideoRecorder instanceof Full2VideoRecorder) { | 
			
		
	
		
			
				
					|  |  |  |  |         boolean wasRecordingFullVideo = mVideoRecorder instanceof Full2VideoRecorder; | 
			
		
	
		
			
				
					|  |  |  |  |         super.onVideoResult(result, exception); | 
			
		
	
		
			
				
					|  |  |  |  |         if (wasRecordingFullVideo) { | 
			
		
	
		
			
				
					|  |  |  |  |             // We have to stop all repeating requests and restart them.
 | 
			
		
	
		
			
				
					|  |  |  |  |             try { | 
			
		
	
		
			
				
					|  |  |  |  |                 if (getBindState() == STATE_STARTED) { | 
			
		
	
		
			
				
					|  |  |  |  |                     mSession.stopRepeating(); | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 if (getPreviewState() == STATE_STARTED) { | 
			
		
	
		
			
				
					|  |  |  |  |                     mPreviewStreamRequest = mPreviewStreamRequestBuilder.build(); | 
			
		
	
		
			
				
					|  |  |  |  |                     mSession.setRepeatingRequest(mPreviewStreamRequest, null, null); | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 createRepeatingRequestBuilder(CameraDevice.TEMPLATE_PREVIEW); | 
			
		
	
		
			
				
					|  |  |  |  |                 addRepeatingRequestBuilderSurfaces(); | 
			
		
	
		
			
				
					|  |  |  |  |                 applyRepeatingRequestBuilder(); | 
			
		
	
		
			
				
					|  |  |  |  |             } catch (CameraAccessException e) { | 
			
		
	
		
			
				
					|  |  |  |  |                 throw createCameraException(e); | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         super.onVideoResult(result, exception); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     //endregion
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     //region Parameters
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     private void syncStream() { | 
			
		
	
		
			
				
					|  |  |  |  |         if (getPreviewState() == STATE_STARTED) { | 
			
		
	
		
			
				
					|  |  |  |  |             try { | 
			
		
	
		
			
				
					|  |  |  |  |                 // TODO if we are capturing a video or a picture, this is not what we should do!
 | 
			
		
	
		
			
				
					|  |  |  |  |                 mPreviewStreamRequest = mPreviewStreamRequestBuilder.build(); | 
			
		
	
		
			
				
					|  |  |  |  |                 mSession.setRepeatingRequest(mPreviewStreamRequest, null, null); | 
			
		
	
		
			
				
					|  |  |  |  |             } catch (Exception e) { | 
			
		
	
		
			
				
					|  |  |  |  |                 throw new CameraException(e, CameraException.REASON_DISCONNECTED); | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     private void applyAll(@NonNull CaptureRequest.Builder builder) { | 
			
		
	
		
			
				
					|  |  |  |  |         builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO); | 
			
		
	
		
			
				
					|  |  |  |  |         applyDefaultFocus(builder); | 
			
		
	
	
		
			
				
					|  |  |  | @ -603,7 +670,9 @@ public class Camera2Engine extends CameraEngine { | 
			
		
	
		
			
				
					|  |  |  |  |             @Override | 
			
		
	
		
			
				
					|  |  |  |  |             public void run() { | 
			
		
	
		
			
				
					|  |  |  |  |                 if (getEngineState() == STATE_STARTED) { | 
			
		
	
		
			
				
					|  |  |  |  |                     if (applyFlash(mPreviewStreamRequestBuilder, old)) syncStream(); | 
			
		
	
		
			
				
					|  |  |  |  |                     if (applyFlash(mRepeatingRequestBuilder, old)) { | 
			
		
	
		
			
				
					|  |  |  |  |                         applyRepeatingRequestBuilder(); | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 mFlashOp.end(null); | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
	
		
			
				
					|  |  |  | @ -658,7 +727,9 @@ public class Camera2Engine extends CameraEngine { | 
			
		
	
		
			
				
					|  |  |  |  |             @Override | 
			
		
	
		
			
				
					|  |  |  |  |             public void run() { | 
			
		
	
		
			
				
					|  |  |  |  |                 if (getEngineState() == STATE_STARTED) { | 
			
		
	
		
			
				
					|  |  |  |  |                     if (applyLocation(mPreviewStreamRequestBuilder, old)) syncStream(); | 
			
		
	
		
			
				
					|  |  |  |  |                     if (applyLocation(mRepeatingRequestBuilder, old)) { | 
			
		
	
		
			
				
					|  |  |  |  |                         applyRepeatingRequestBuilder(); | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 mLocationOp.end(null); | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
	
		
			
				
					|  |  |  | @ -681,7 +752,9 @@ public class Camera2Engine extends CameraEngine { | 
			
		
	
		
			
				
					|  |  |  |  |             @Override | 
			
		
	
		
			
				
					|  |  |  |  |             public void run() { | 
			
		
	
		
			
				
					|  |  |  |  |                 if (getEngineState() == STATE_STARTED) { | 
			
		
	
		
			
				
					|  |  |  |  |                     if (applyWhiteBalance(mPreviewStreamRequestBuilder, old)) syncStream(); | 
			
		
	
		
			
				
					|  |  |  |  |                     if (applyWhiteBalance(mRepeatingRequestBuilder, old)) { | 
			
		
	
		
			
				
					|  |  |  |  |                         applyRepeatingRequestBuilder(); | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 mWhiteBalanceOp.end(null); | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
	
		
			
				
					|  |  |  | @ -707,7 +780,9 @@ public class Camera2Engine extends CameraEngine { | 
			
		
	
		
			
				
					|  |  |  |  |             @Override | 
			
		
	
		
			
				
					|  |  |  |  |             public void run() { | 
			
		
	
		
			
				
					|  |  |  |  |                 if (getEngineState() == STATE_STARTED) { | 
			
		
	
		
			
				
					|  |  |  |  |                     if (applyHdr(mPreviewStreamRequestBuilder, old)) syncStream(); | 
			
		
	
		
			
				
					|  |  |  |  |                     if (applyHdr(mRepeatingRequestBuilder, old)) { | 
			
		
	
		
			
				
					|  |  |  |  |                         applyRepeatingRequestBuilder(); | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 mHdrOp.end(null); | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
	
		
			
				
					|  |  |  | @ -751,8 +826,22 @@ public class Camera2Engine extends CameraEngine { | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     @Override | 
			
		
	
		
			
				
					|  |  |  |  |     public void setHasFrameProcessors(boolean hasFrameProcessors) { | 
			
		
	
		
			
				
					|  |  |  |  |     public void setHasFrameProcessors(final boolean hasFrameProcessors) { | 
			
		
	
		
			
				
					|  |  |  |  |         LOG.i("setHasFrameProcessors", "changed to", hasFrameProcessors, "posting."); | 
			
		
	
		
			
				
					|  |  |  |  |         mHasFrameProcessors = hasFrameProcessors; | 
			
		
	
		
			
				
					|  |  |  |  |         mHandler.run(new Runnable() { | 
			
		
	
		
			
				
					|  |  |  |  |             @Override | 
			
		
	
		
			
				
					|  |  |  |  |             public void run() { | 
			
		
	
		
			
				
					|  |  |  |  |                 LOG.i("setHasFrameProcessors", "changed to", hasFrameProcessors, "executing. BindState:", getBindState()); | 
			
		
	
		
			
				
					|  |  |  |  |                 if (getBindState() == STATE_STARTED) { | 
			
		
	
		
			
				
					|  |  |  |  |                     LOG.i("setHasFrameProcessors", "triggering a restart."); | 
			
		
	
		
			
				
					|  |  |  |  |                     // TODO if taking video, this stops it.
 | 
			
		
	
		
			
				
					|  |  |  |  |                     restartBind(); | 
			
		
	
		
			
				
					|  |  |  |  |                 } else { | 
			
		
	
		
			
				
					|  |  |  |  |                     LOG.i("setHasFrameProcessors", "not bound so won't restart."); | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         }); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     //endregion
 | 
			
		
	
	
		
			
				
					|  |  |  | 
 |