From 504ce8e74da699773809607df33b4832bf456402 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Thu, 31 Dec 2020 14:21:42 +0100 Subject: [PATCH 1/4] Refactured Camera and fix issue front facing camera --- .../io/flutter/plugins/camera/Camera.java | 445 ++++++++++-------- 1 file changed, 248 insertions(+), 197 deletions(-) diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index b7da94a613ba..a7aa83d0c9ce 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -39,6 +39,7 @@ import android.view.OrientationEventListener; import android.view.Surface; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugins.camera.PictureCaptureRequest.State; @@ -59,6 +60,11 @@ import java.util.Map; import java.util.concurrent.Executors; +@FunctionalInterface +interface ErrorCallback { + void onError(String errorCode, String errorMessage); +} + public class Camera { private final SurfaceTextureEntry flutterTexture; private final CameraManager cameraManager; @@ -73,6 +79,7 @@ public class Camera { private final CamcorderProfile recordingProfile; private final DartMessenger dartMessenger; private final CameraZoom cameraZoom; + private final CameraCharacteristics cameraCharacteristics; private CameraDevice cameraDevice; private CameraCaptureSession cameraCaptureSession; @@ -88,6 +95,7 @@ public class Camera { private PictureCaptureRequest pictureCaptureRequest; private CameraRegions cameraRegions; private int exposureOffset; + private boolean useAutoFocus; public Camera( final Activity activity, @@ -122,10 +130,10 @@ public void onOrientationChanged(int i) { }; orientationEventListener.enable(); - CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraName); - sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); + cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraName); + sensorOrientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); isFrontFacing = - characteristics.get(CameraCharacteristics.LENS_FACING) == CameraMetadata.LENS_FACING_FRONT; + cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) == CameraMetadata.LENS_FACING_FRONT; ResolutionPreset preset = ResolutionPreset.valueOf(resolutionPreset); recordingProfile = CameraUtils.getBestAvailableCamcorderProfileForResolutionPreset(cameraName, preset); @@ -133,8 +141,8 @@ public void onOrientationChanged(int i) { previewSize = computeBestPreviewSize(cameraName, preset); cameraZoom = new CameraZoom( - characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE), - characteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM)); + cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE), + cameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM)); } private void prepareMediaRecorder(String outputFilePath) throws IOException { @@ -221,6 +229,121 @@ public void onError(@NonNull CameraDevice cameraDevice, int errorCode) { null); } + private void createCaptureSession(int templateType, Surface... surfaces) + throws CameraAccessException { + createCaptureSession(templateType, null, surfaces); + } + + private void createCaptureSession( + int templateType, Runnable onSuccessCallback, Surface... surfaces) + throws CameraAccessException { + // Close any existing capture session. + closeCaptureSession(); + + // Create a new capture builder. + captureRequestBuilder = cameraDevice.createCaptureRequest(templateType); + + // Build Flutter surface to render to + SurfaceTexture surfaceTexture = flutterTexture.surfaceTexture(); + surfaceTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); + Surface flutterSurface = new Surface(surfaceTexture); + captureRequestBuilder.addTarget(flutterSurface); + + List remainingSurfaces = Arrays.asList(surfaces); + if (templateType != CameraDevice.TEMPLATE_PREVIEW) { + // If it is not preview mode, add all surfaces as targets. + for (Surface surface : remainingSurfaces) { + captureRequestBuilder.addTarget(surface); + } + } + + // Prepare the callback + CameraCaptureSession.StateCallback callback = + new CameraCaptureSession.StateCallback() { + @Override + public void onConfigured(@NonNull CameraCaptureSession session) { + if (cameraDevice == null) { + dartMessenger.sendCameraErrorEvent("The camera was closed during configuration."); + return; + } + cameraCaptureSession = session; + + updateAutoFocus(); + updateExposure(exposureMode); + updateFlash(flashMode); + + refreshPreviewCaptureSession( + onSuccessCallback, + (code, message) ->dartMessenger.sendCameraErrorEvent(message) + ); + } + + @Override + public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) { + dartMessenger.sendCameraErrorEvent("Failed to configure camera session."); + } + }; + + // Start the session + if (VERSION.SDK_INT >= VERSION_CODES.P) { + // Collect all surfaces we want to render to. + List configs = new ArrayList<>(); + configs.add(new OutputConfiguration(flutterSurface)); + for (Surface surface : remainingSurfaces) { + configs.add(new OutputConfiguration(surface)); + } + createCaptureSessionWithSessionConfig(configs, callback); + } else { + // Collect all surfaces we want to render to. + List surfaceList = new ArrayList<>(); + surfaceList.add(flutterSurface); + surfaceList.addAll(remainingSurfaces); + createCaptureSession(surfaceList, callback); + } + } + + @TargetApi(VERSION_CODES.P) + private void createCaptureSessionWithSessionConfig( + List outputConfigs, CameraCaptureSession.StateCallback callback) + throws CameraAccessException { + cameraDevice.createCaptureSession( + new SessionConfiguration( + SessionConfiguration.SESSION_REGULAR, + outputConfigs, + Executors.newSingleThreadExecutor(), + callback)); + } + + @TargetApi(VERSION_CODES.LOLLIPOP) + @SuppressWarnings("deprecation") + private void createCaptureSession( + List surfaces, CameraCaptureSession.StateCallback callback) + throws CameraAccessException { + cameraDevice.createCaptureSession(surfaces, callback, null); + } + + private void refreshPreviewCaptureSession( + @Nullable Runnable onSuccessCallback, + @NonNull ErrorCallback onErrorCallback + ) { + if (cameraCaptureSession == null) { + return; + } + + try { + cameraCaptureSession.setRepeatingRequest( + captureRequestBuilder.build(), + pictureCaptureCallback, + new Handler(Looper.getMainLooper())); + + if (onSuccessCallback != null) { + onSuccessCallback.run(); + } + } catch (CameraAccessException | IllegalStateException | IllegalArgumentException e) { + onErrorCallback.onError("cameraAccess", e.getMessage()); + } + } + private void writeToFile(ByteBuffer buffer, File file) throws IOException { try (FileOutputStream outputStream = new FileOutputStream(file)) { while (0 < buffer.remaining()) { @@ -261,7 +384,11 @@ public void takePicture(@NonNull final Result result) { }, null); - runPictureAutoFocus(); + if (useAutoFocus) { + runPictureAutoFocus(); + } else { + runPicturePreCapture(); + } } private final CameraCaptureSession.CaptureCallback pictureCaptureCallback = @@ -344,6 +471,7 @@ private void processCapture(CaptureResult result) { private void runPictureAutoFocus() { assert (pictureCaptureRequest != null); + pictureCaptureRequest.setState(PictureCaptureRequest.State.focusing); lockAutoFocus(); } @@ -355,14 +483,13 @@ private void runPicturePreCapture() { captureRequestBuilder.set( CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); - try { - cameraCaptureSession.capture(captureRequestBuilder.build(), pictureCaptureCallback, null); - captureRequestBuilder.set( - CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, - CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); - } catch (CameraAccessException e) { - pictureCaptureRequest.error("cameraAccess", e.getMessage(), null); - } + + refreshPreviewCaptureSession( + () -> captureRequestBuilder.set( + CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, + CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE), + (code, message) -> pictureCaptureRequest.error(code, message, null) + ); } private void runPictureCapture() { @@ -409,125 +536,27 @@ public void onCaptureCompleted( private void lockAutoFocus() { captureRequestBuilder.set( CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START); - try { - cameraCaptureSession.capture(captureRequestBuilder.build(), pictureCaptureCallback, null); - } catch (CameraAccessException e) { - pictureCaptureRequest.error("cameraAccess", e.getMessage(), null); - } + + refreshPreviewCaptureSession( + null, + (code, message) ->pictureCaptureRequest.error(code, message, null) + ); } private void unlockAutoFocus() { captureRequestBuilder.set( CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL); - initPreviewCaptureBuilder(); + updateAutoFocus(); try { cameraCaptureSession.capture(captureRequestBuilder.build(), null, null); } catch (CameraAccessException ignored) { } captureRequestBuilder.set( CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE); - try { - cameraCaptureSession.setRepeatingRequest( - captureRequestBuilder.build(), pictureCaptureCallback, null); - } catch (CameraAccessException e) { - pictureCaptureRequest.error("cameraAccess", e.getMessage(), null); - } - } - private void createCaptureSession(int templateType, Surface... surfaces) - throws CameraAccessException { - createCaptureSession(templateType, null, surfaces); - } - - private void createCaptureSession( - int templateType, Runnable onSuccessCallback, Surface... surfaces) - throws CameraAccessException { - // Close any existing capture session. - closeCaptureSession(); - - // Create a new capture builder. - captureRequestBuilder = cameraDevice.createCaptureRequest(templateType); - - // Build Flutter surface to render to - SurfaceTexture surfaceTexture = flutterTexture.surfaceTexture(); - surfaceTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); - Surface flutterSurface = new Surface(surfaceTexture); - captureRequestBuilder.addTarget(flutterSurface); - - List remainingSurfaces = Arrays.asList(surfaces); - if (templateType != CameraDevice.TEMPLATE_PREVIEW) { - // If it is not preview mode, add all surfaces as targets. - for (Surface surface : remainingSurfaces) { - captureRequestBuilder.addTarget(surface); - } - } - - // Prepare the callback - CameraCaptureSession.StateCallback callback = - new CameraCaptureSession.StateCallback() { - @Override - public void onConfigured(@NonNull CameraCaptureSession session) { - try { - if (cameraDevice == null) { - dartMessenger.sendCameraErrorEvent("The camera was closed during configuration."); - return; - } - cameraCaptureSession = session; - initPreviewCaptureBuilder(); - cameraCaptureSession.setRepeatingRequest( - captureRequestBuilder.build(), - pictureCaptureCallback, - new Handler(Looper.getMainLooper())); - if (onSuccessCallback != null) { - onSuccessCallback.run(); - } - } catch (CameraAccessException | IllegalStateException | IllegalArgumentException e) { - dartMessenger.sendCameraErrorEvent(e.getMessage()); - } - } - - @Override - public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) { - dartMessenger.sendCameraErrorEvent("Failed to configure camera session."); - } - }; - - // Start the session - if (VERSION.SDK_INT >= VERSION_CODES.P) { - // Collect all surfaces we want to render to. - List configs = new ArrayList<>(); - configs.add(new OutputConfiguration(flutterSurface)); - for (Surface surface : remainingSurfaces) { - configs.add(new OutputConfiguration(surface)); - } - createCaptureSessionWithSessionConfig(configs, callback); - } else { - // Collect all surfaces we want to render to. - List surfaceList = new ArrayList<>(); - surfaceList.add(flutterSurface); - surfaceList.addAll(remainingSurfaces); - createCaptureSession(surfaceList, callback); - } - } - - @TargetApi(VERSION_CODES.P) - private void createCaptureSessionWithSessionConfig( - List outputConfigs, CameraCaptureSession.StateCallback callback) - throws CameraAccessException { - cameraDevice.createCaptureSession( - new SessionConfiguration( - SessionConfiguration.SESSION_REGULAR, - outputConfigs, - Executors.newSingleThreadExecutor(), - callback)); - } - - @TargetApi(VERSION_CODES.LOLLIPOP) - @SuppressWarnings("deprecation") - private void createCaptureSession( - List surfaces, CameraCaptureSession.StateCallback callback) - throws CameraAccessException { - cameraDevice.createCaptureSession(surfaces, callback, null); + refreshPreviewCaptureSession( + null, + (errorCode, errorMessage) -> pictureCaptureRequest.error(errorCode, errorMessage, null)); } public void startVideoRecording(Result result) { @@ -630,8 +659,8 @@ public void setFlashMode(@NonNull final Result result, FlashMode mode) // If switching directly from torch to auto or on, make sure we turn off the torch. if (flashMode == FlashMode.torch && mode != FlashMode.torch && mode != FlashMode.off) { - this.flashMode = FlashMode.off; - initPreviewCaptureBuilder(); + updateFlash(FlashMode.off); + this.cameraCaptureSession.setRepeatingRequest( captureRequestBuilder.build(), new CaptureCallback() { @@ -647,8 +676,12 @@ public void onCaptureCompleted( } updateFlash(mode); - result.success(null); - isFinished = true; + refreshPreviewCaptureSession( + () -> { + result.success(null); + isFinished = true; }, + (code, message) -> result.error("setFlashModeFailed", "Could not set flash mode.", null) + ); } @Override @@ -667,26 +700,17 @@ public void onCaptureFailed( null); } else { updateFlash(mode); - result.success(null); - } - } - private void updateFlash(FlashMode mode) { - // Get flash - flashMode = mode; - initPreviewCaptureBuilder(); - try { - cameraCaptureSession.setRepeatingRequest( - captureRequestBuilder.build(), pictureCaptureCallback, null); - } catch (CameraAccessException e) { - pictureCaptureRequest.error("cameraAccess", e.getMessage(), null); + refreshPreviewCaptureSession( + () -> result.success(null) , + (code, message) -> result.error("setFlashModeFailed", "Could not set flash mode.", null) + ); } } public void setExposureMode(@NonNull final Result result, ExposureMode mode) throws CameraAccessException { - this.exposureMode = mode; - initPreviewCaptureBuilder(); + updateExposure(mode); cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null); result.success(null); } @@ -713,10 +737,11 @@ public void setExposurePoint(@NonNull final Result result, Double x, Double y) // Set the metering rectangle cameraRegions.setAutoExposureMeteringRectangleFromPoint(x, y); // Apply it - initPreviewCaptureBuilder(); - this.cameraCaptureSession.setRepeatingRequest( - captureRequestBuilder.build(), pictureCaptureCallback, null); - result.success(null); + updateExposure(exposureMode); + refreshPreviewCaptureSession( + () -> result.success(null), + (code, message) -> result.error("CameraAccess", message, null) + ); } @TargetApi(VERSION_CODES.P) @@ -802,13 +827,90 @@ public void setExposureOffset(@NonNull final Result result, double offset) double stepSize = getExposureOffsetStepSize(); exposureOffset = (int) (offset / stepSize); // Apply it - initPreviewCaptureBuilder(); + updateExposure(exposureMode); this.cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null); result.success(offset); } - private void initPreviewCaptureBuilder() { - captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO); + public float getMaxZoomLevel() { + return cameraZoom.maxZoom; + } + + public float getMinZoomLevel() { + return CameraZoom.DEFAULT_ZOOM_FACTOR; + } + + public void setZoomLevel(@NonNull final Result result, float zoom) throws CameraAccessException { + float maxZoom = cameraZoom.maxZoom; + float minZoom = CameraZoom.DEFAULT_ZOOM_FACTOR; + + if (zoom > maxZoom || zoom < minZoom) { + String errorMessage = + String.format( + Locale.ENGLISH, + "Zoom level out of bounds (zoom level should be between %f and %f).", + minZoom, + maxZoom); + result.error("ZOOM_ERROR", errorMessage, null); + return; + } + + //Zoom area is calculated relative to sensor area (activeRect) + if (captureRequestBuilder != null) { + final Rect computedZoom = cameraZoom.computeZoom(zoom); + captureRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, computedZoom); + cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null); + } + + result.success(null); + } + + private void updateAutoFocus() { + if (useAutoFocus) { + int[] modes = cameraCharacteristics.get( + CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES); + // Auto focus is not supported + if (modes == null || modes.length == 0 || + (modes.length == 1 && modes[0] == CameraCharacteristics.CONTROL_AF_MODE_OFF)) { + useAutoFocus = false; + captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, + CaptureRequest.CONTROL_AF_MODE_OFF); + } else { + captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, + CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); + } + } else { + captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, + CaptureRequest.CONTROL_AF_MODE_OFF); + } + } + + private void updateExposure(ExposureMode mode) { + exposureMode = mode; + + // Applying auto exposure + MeteringRectangle aeRect = cameraRegions.getAEMeteringRectangle(); + captureRequestBuilder.set( + CaptureRequest.CONTROL_AE_REGIONS, + aeRect == null ? null : new MeteringRectangle[] {cameraRegions.getAEMeteringRectangle()}); + + switch (mode) { + case locked: + captureRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true); + break; + case auto: + default: + captureRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false); + break; + } + + captureRequestBuilder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, exposureOffset); + } + + private void updateFlash(FlashMode mode) { + // Get flash + flashMode = mode; + // Applying flash modes switch (flashMode) { case off: @@ -833,24 +935,6 @@ private void initPreviewCaptureBuilder() { captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH); break; } - // Applying auto exposure - MeteringRectangle aeRect = cameraRegions.getAEMeteringRectangle(); - captureRequestBuilder.set( - CaptureRequest.CONTROL_AE_REGIONS, - aeRect == null ? null : new MeteringRectangle[] {cameraRegions.getAEMeteringRectangle()}); - switch (exposureMode) { - case locked: - captureRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true); - break; - case auto: - default: - captureRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false); - break; - } - captureRequestBuilder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, exposureOffset); - // Applying auto focus - captureRequestBuilder.set( - CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); } public void startPreview() throws CameraAccessException { @@ -910,39 +994,6 @@ private void setImageStreamImageAvailableListener(final EventChannel.EventSink i null); } - public float getMaxZoomLevel() { - return cameraZoom.maxZoom; - } - - public float getMinZoomLevel() { - return CameraZoom.DEFAULT_ZOOM_FACTOR; - } - - public void setZoomLevel(@NonNull final Result result, float zoom) throws CameraAccessException { - float maxZoom = cameraZoom.maxZoom; - float minZoom = CameraZoom.DEFAULT_ZOOM_FACTOR; - - if (zoom > maxZoom || zoom < minZoom) { - String errorMessage = - String.format( - Locale.ENGLISH, - "Zoom level out of bounds (zoom level should be between %f and %f).", - minZoom, - maxZoom); - result.error("ZOOM_ERROR", errorMessage, null); - return; - } - - //Zoom area is calculated relative to sensor area (activeRect) - if (captureRequestBuilder != null) { - final Rect computedZoom = cameraZoom.computeZoom(zoom); - captureRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, computedZoom); - cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null); - } - - result.success(null); - } - public void stopImageStream() throws CameraAccessException { if (imageStreamReader != null) { imageStreamReader.setOnImageAvailableListener(null, null); From 28866039393cef194328375cb50b17a1a9bf0aca Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Thu, 31 Dec 2020 16:40:01 +0100 Subject: [PATCH 2/4] Update FPS range on Android to have correct brightness --- packages/camera/camera/CHANGELOG.md | 4 ++ .../io/flutter/plugins/camera/Camera.java | 44 +++++++++++++++++-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index d38016a471e6..55c7eb1fcfd2 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.4+3 + +* Detect if selected camera supports auto focus and act accordingly on Android. This solves a problem where front facing cameras are not capturing the picture because auto focus is not supported. + ## 0.6.4+2 * Set ImageStreamReader listener to null to prevent stale images when streaming images. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index a7aa83d0c9ce..6098e6a8fc4a 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -33,6 +33,7 @@ import android.os.Build.VERSION_CODES; import android.os.Handler; import android.os.Looper; +import android.util.Log; import android.util.Range; import android.util.Rational; import android.util.Size; @@ -96,6 +97,7 @@ public class Camera { private CameraRegions cameraRegions; private int exposureOffset; private boolean useAutoFocus; + private Range fpsRange; public Camera( final Activity activity, @@ -131,6 +133,7 @@ public void onOrientationChanged(int i) { orientationEventListener.enable(); cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraName); + initFps(cameraCharacteristics); sensorOrientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); isFrontFacing = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) == CameraMetadata.LENS_FACING_FRONT; @@ -145,6 +148,26 @@ public void onOrientationChanged(int i) { cameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM)); } + private void initFps(CameraCharacteristics cameraCharacteristics){ + try { + Range[] ranges = cameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); + if(ranges != null) { + for (Range range : ranges) { + int upper = range.getUpper(); + Log.i("Camera", "[FPS Range Available] is:" + range); + if (upper >= 10) { + if (fpsRange == null || upper < fpsRange.getUpper()) { + fpsRange = range; + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + Log.i("Camera", "[FPS Range] is:" + fpsRange); + } + private void prepareMediaRecorder(String outputFilePath) throws IOException { if (mediaRecorder != null) { mediaRecorder.release(); @@ -268,9 +291,10 @@ public void onConfigured(@NonNull CameraCaptureSession session) { } cameraCaptureSession = session; + updateFpsRange(); updateAutoFocus(); - updateExposure(exposureMode); updateFlash(flashMode); + updateExposure(exposureMode); refreshPreviewCaptureSession( onSuccessCallback, @@ -589,8 +613,14 @@ public void stopVideoRecording(@NonNull final Result result) { try { recordingVideo = false; - closeCaptureSession(); - mediaRecorder.stop(); + + try { + cameraCaptureSession.abortCaptures(); + mediaRecorder.stop(); + } catch (CameraAccessException | IllegalStateException e) { + // Ignore exceptions and try to continue (changes are camera session already aborted capture) + } + mediaRecorder.reset(); startPreview(); result.success(videoRecordingFile.getAbsolutePath()); @@ -865,6 +895,14 @@ public void setZoomLevel(@NonNull final Result result, float zoom) throws Camera result.success(null); } + private void updateFpsRange() { + if (fpsRange == null) { + return; + } + + captureRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange); + } + private void updateAutoFocus() { if (useAutoFocus) { int[] modes = cameraCharacteristics.get( From 05e8304bd24972ac9560baccea19e81d99ea0159 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Thu, 31 Dec 2020 16:47:21 +0100 Subject: [PATCH 3/4] Formatted files --- .../io/flutter/plugins/camera/Camera.java | 87 +++++++++---------- 1 file changed, 40 insertions(+), 47 deletions(-) diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 6098e6a8fc4a..2db097ceadf7 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -136,7 +136,8 @@ public void onOrientationChanged(int i) { initFps(cameraCharacteristics); sensorOrientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); isFrontFacing = - cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) == CameraMetadata.LENS_FACING_FRONT; + cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) + == CameraMetadata.LENS_FACING_FRONT; ResolutionPreset preset = ResolutionPreset.valueOf(resolutionPreset); recordingProfile = CameraUtils.getBestAvailableCamcorderProfileForResolutionPreset(cameraName, preset); @@ -148,10 +149,11 @@ public void onOrientationChanged(int i) { cameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM)); } - private void initFps(CameraCharacteristics cameraCharacteristics){ + private void initFps(CameraCharacteristics cameraCharacteristics) { try { - Range[] ranges = cameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); - if(ranges != null) { + Range[] ranges = + cameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); + if (ranges != null) { for (Range range : ranges) { int upper = range.getUpper(); Log.i("Camera", "[FPS Range Available] is:" + range); @@ -285,21 +287,19 @@ private void createCaptureSession( new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { - if (cameraDevice == null) { - dartMessenger.sendCameraErrorEvent("The camera was closed during configuration."); - return; - } - cameraCaptureSession = session; + if (cameraDevice == null) { + dartMessenger.sendCameraErrorEvent("The camera was closed during configuration."); + return; + } + cameraCaptureSession = session; - updateFpsRange(); - updateAutoFocus(); - updateFlash(flashMode); - updateExposure(exposureMode); + updateFpsRange(); + updateAutoFocus(); + updateFlash(flashMode); + updateExposure(exposureMode); - refreshPreviewCaptureSession( - onSuccessCallback, - (code, message) ->dartMessenger.sendCameraErrorEvent(message) - ); + refreshPreviewCaptureSession( + onSuccessCallback, (code, message) -> dartMessenger.sendCameraErrorEvent(message)); } @Override @@ -347,9 +347,7 @@ private void createCaptureSession( } private void refreshPreviewCaptureSession( - @Nullable Runnable onSuccessCallback, - @NonNull ErrorCallback onErrorCallback - ) { + @Nullable Runnable onSuccessCallback, @NonNull ErrorCallback onErrorCallback) { if (cameraCaptureSession == null) { return; } @@ -509,11 +507,11 @@ private void runPicturePreCapture() { CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); refreshPreviewCaptureSession( - () -> captureRequestBuilder.set( - CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, - CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE), - (code, message) -> pictureCaptureRequest.error(code, message, null) - ); + () -> + captureRequestBuilder.set( + CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, + CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE), + (code, message) -> pictureCaptureRequest.error(code, message, null)); } private void runPictureCapture() { @@ -562,9 +560,7 @@ private void lockAutoFocus() { CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START); refreshPreviewCaptureSession( - null, - (code, message) ->pictureCaptureRequest.error(code, message, null) - ); + null, (code, message) -> pictureCaptureRequest.error(code, message, null)); } private void unlockAutoFocus() { @@ -709,9 +705,10 @@ public void onCaptureCompleted( refreshPreviewCaptureSession( () -> { result.success(null); - isFinished = true; }, - (code, message) -> result.error("setFlashModeFailed", "Could not set flash mode.", null) - ); + isFinished = true; + }, + (code, message) -> + result.error("setFlashModeFailed", "Could not set flash mode.", null)); } @Override @@ -732,9 +729,8 @@ public void onCaptureFailed( updateFlash(mode); refreshPreviewCaptureSession( - () -> result.success(null) , - (code, message) -> result.error("setFlashModeFailed", "Could not set flash mode.", null) - ); + () -> result.success(null), + (code, message) -> result.error("setFlashModeFailed", "Could not set flash mode.", null)); } } @@ -769,9 +765,7 @@ public void setExposurePoint(@NonNull final Result result, Double x, Double y) // Apply it updateExposure(exposureMode); refreshPreviewCaptureSession( - () -> result.success(null), - (code, message) -> result.error("CameraAccess", message, null) - ); + () -> result.success(null), (code, message) -> result.error("CameraAccess", message, null)); } @TargetApi(VERSION_CODES.P) @@ -905,21 +899,20 @@ private void updateFpsRange() { private void updateAutoFocus() { if (useAutoFocus) { - int[] modes = cameraCharacteristics.get( - CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES); + int[] modes = cameraCharacteristics.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES); // Auto focus is not supported - if (modes == null || modes.length == 0 || - (modes.length == 1 && modes[0] == CameraCharacteristics.CONTROL_AF_MODE_OFF)) { + if (modes == null + || modes.length == 0 + || (modes.length == 1 && modes[0] == CameraCharacteristics.CONTROL_AF_MODE_OFF)) { useAutoFocus = false; - captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, - CaptureRequest.CONTROL_AF_MODE_OFF); + captureRequestBuilder.set( + CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF); } else { - captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, - CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); + captureRequestBuilder.set( + CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); } } else { - captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, - CaptureRequest.CONTROL_AF_MODE_OFF); + captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF); } } From 60ff949adb3742aeea32c36256dec2a8d0a378fc Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Tue, 5 Jan 2021 11:58:39 +0100 Subject: [PATCH 4/4] Fix version conflict --- packages/camera/camera/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 02f874bf9ea3..99f41fb165a5 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.4+2 +version: 0.6.4+3 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: