From 1412e803663ed4a687df5818f076393e57b73e8c Mon Sep 17 00:00:00 2001 From: Mattia Iavarone Date: Sun, 24 Feb 2019 17:22:37 +0100 Subject: [PATCH] New snapshotMaxWidth and snapshotMaxHeight APIs --- .../com/otaliastudios/cameraview/Camera1.java | 21 +-------- .../cameraview/CameraController.java | 44 +++++++++++++++++++ .../otaliastudios/cameraview/CameraView.java | 23 +++++++++- cameraview/src/main/res/values/attrs.xml | 3 ++ 4 files changed, 71 insertions(+), 20 deletions(-) diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java b/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java index 76c09970..758bb895 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java @@ -580,18 +580,6 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera /** * Just a note about the snapshot size - it is the PreviewStreamSize, cropped with the view ratio. - * One might be tempted to say that it is the SurfaceSize (which already matches the view ratio), - * but it's not. - * - * The camera sensor will capture preview frames with PreviewStreamSize and that's it. Then they - * are hardware-scaled by the preview surface, but this does not affect the snapshot, as the - * snapshot recorder simply creates another surface. - * - * Done tests to ensure that this is true, by using - * 1. small SurfaceSize and biggest() PreviewStreamSize: output is not low quality - * 2. big SurfaceSize and smallest() PreviewStreamSize: output is low quality - * In both cases the result.size here was set to the biggest of the two. - * * @param viewAspectRatio the view aspect ratio */ @Override @@ -607,7 +595,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera result.location = mLocation; result.isSnapshot = true; result.facing = mFacing; - result.size = getPreviewStreamSize(REF_OUTPUT); // Not the real size: it will be cropped to match the view ratio + result.size = getUncroppedSnapshotSize(REF_OUTPUT); // Not the real size: it will be cropped to match the view ratio result.rotation = offset(REF_SENSOR, REF_OUTPUT); // Actually it will be rotated and set to 0. AspectRatio outputRatio = flip(REF_OUTPUT, REF_VIEW) ? viewAspectRatio.inverse() : viewAspectRatio; // LOG.e("ROTBUG_pic", "aspectRatio (REF_VIEW):", viewAspectRatio); @@ -713,11 +701,6 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera } /** - * Is output size the SurfaceSize or the PreviewStreamSize ? - * I could not find evidence by testing, but I think that comments in {@link #takePictureSnapshot(AspectRatio)} - * would still apply here, despite the capturing mechanism being different. - * So we should use PreviewStreamSize as output size, cropped by the view aspect ratio. - * * @param file the output file * @param viewAspectRatio the view aspect ratio */ @@ -783,7 +766,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera // Based on this we will use VO for everything. See if we get issues about distortion // and maybe we can improve. The reason why this happen is beyond my understanding. - Size outputSize = getPreviewStreamSize(REF_OUTPUT); + Size outputSize = getUncroppedSnapshotSize(REF_OUTPUT); AspectRatio outputRatio = flip(REF_OUTPUT, REF_VIEW) ? viewAspectRatio.inverse() : viewAspectRatio; Rect outputCrop = CropHelper.computeCrop(outputSize, outputRatio); outputSize = new Size(outputCrop.width(), outputCrop.height()); diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java index bf48253c..9699ea9e 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java @@ -53,6 +53,9 @@ abstract class CameraController implements private SizeSelector mPictureSizeSelector; private SizeSelector mVideoSizeSelector; + private int mSnapshotMaxWidth = Integer.MAX_VALUE; // in REF_VIEW for consistency with SizeSelectors + private int mSnapshotMaxHeight = Integer.MAX_VALUE; // in REF_VIEW for consistency with SizeSelectors + protected int mCameraId; protected CameraOptions mCameraOptions; protected Mapper mMapper; @@ -311,6 +314,14 @@ abstract class CameraController implements mAudioBitRate = audioBitRate; } + final void setSnapshotMaxWidth(int maxWidth) { + mSnapshotMaxWidth = maxWidth; + } + + final void setSnapshotMaxHeight(int maxHeight) { + mSnapshotMaxHeight = maxHeight; + } + //endregion //region Abstract setters and APIs @@ -518,6 +529,39 @@ abstract class CameraController implements return flip(REF_VIEW, reference) ? mPreview.getSurfaceSize().flip() : mPreview.getSurfaceSize(); } + /** + * Returns the snapshot size, but not cropped with the view dimensions, which + * is what we will do before creating the snapshot. However, cropping is done at various + * levels so we don't want to perform the op here. + * + * The base snapshot size is based on PreviewStreamSize (later cropped with view ratio). Why? + * One might be tempted to say that it is the SurfaceSize (which already matches the view ratio). + * + * The camera sensor will capture preview frames with PreviewStreamSize and that's it. Then they + * are hardware-scaled by the preview surface, but this does not affect the snapshot, as the + * snapshot recorder simply creates another surface. + * + * Done tests to ensure that this is true, by using + * 1. small SurfaceSize and biggest() PreviewStreamSize: output is not low quality + * 2. big SurfaceSize and smallest() PreviewStreamSize: output is low quality + * In both cases the result.size here was set to the biggest of the two. + * + * I could not find the same evidence for videos, but I would say that the same things should + * apply, despite the capturing mechanism being different. + */ + @Nullable + final Size getUncroppedSnapshotSize(int reference) { + Size baseSize = getPreviewStreamSize(reference); + if (baseSize == null) return null; + boolean flip = flip(reference, REF_VIEW); + int maxWidth = flip ? mSnapshotMaxHeight : mSnapshotMaxWidth; + int maxHeight = flip ? mSnapshotMaxWidth : mSnapshotMaxHeight; + return new Size( + Math.min(baseSize.getWidth(), maxWidth), + Math.max(baseSize.getHeight(), maxHeight) + ); + } + //endregion diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java index 489a5cfe..deafbe50 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java @@ -1388,6 +1388,27 @@ public class CameraView extends FrameLayout implements LifecycleObserver { }); } + /** + * Sets the max width for snapshots taken with {@link #takePictureSnapshot()} or + * {@link #takeVideoSnapshot(File)}. If the snapshot width exceeds this value, the snapshot + * will be scaled down to match this constraint. + * + * @param maxWidth max width for snapshots + */ + public void setSnapshotMaxWidth(int maxWidth) { + mCameraController.setSnapshotMaxWidth(maxWidth); + } + + /** + * Sets the max height for snapshots taken with {@link #takePictureSnapshot()} or + * {@link #takeVideoSnapshot(File)}. If the snapshot height exceeds this value, the snapshot + * will be scaled down to match this constraint. + * + * @param maxHeight max height for snapshots + */ + public void setSnapshotMaxHeight(int maxHeight) { + mCameraController.setSnapshotMaxHeight(maxHeight); + } /** * Returns the size used for snapshots, or null if it hasn't been computed @@ -1402,7 +1423,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver { // Get the preview size and crop according to the current view size. // It's better to do calculations in the REF_VIEW reference, and then flip if needed. - Size preview = mCameraController.getPreviewStreamSize(CameraController.REF_VIEW); + Size preview = mCameraController.getUncroppedSnapshotSize(CameraController.REF_VIEW); AspectRatio viewRatio = AspectRatio.of(getWidth(), getHeight()); Rect crop = CropHelper.computeCrop(preview, viewRatio); Size cropSize = new Size(crop.width(), crop.height()); diff --git a/cameraview/src/main/res/values/attrs.xml b/cameraview/src/main/res/values/attrs.xml index f25628fe..5ea86273 100644 --- a/cameraview/src/main/res/values/attrs.xml +++ b/cameraview/src/main/res/values/attrs.xml @@ -25,6 +25,9 @@ + + +