diff --git a/cameraview/src/androidTest/java/com/otaliastudios/cameraview/engine/MockCameraEngine.java b/cameraview/src/androidTest/java/com/otaliastudios/cameraview/engine/MockCameraEngine.java index e3d17c62..b02dda08 100644 --- a/cameraview/src/androidTest/java/com/otaliastudios/cameraview/engine/MockCameraEngine.java +++ b/cameraview/src/androidTest/java/com/otaliastudios/cameraview/engine/MockCameraEngine.java @@ -212,4 +212,9 @@ public class MockCameraEngine extends CameraBaseEngine { @Override public void setPreviewFrameRate(float previewFrameRate) { mPreviewFrameRate = previewFrameRate; } + + @Override + public void setPreviewFrameRateExact(boolean previewFrameRateExact) { + mPreviewFrameRateExact = previewFrameRateExact; + } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java index f5066a42..3a81bf64 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java @@ -206,6 +206,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver { int videoBitRate = a.getInteger(R.styleable.CameraView_cameraVideoBitRate, 0); int audioBitRate = a.getInteger(R.styleable.CameraView_cameraAudioBitRate, 0); float videoFrameRate = a.getFloat(R.styleable.CameraView_cameraPreviewFrameRate, 0); + boolean videoFrameRateExact = a.getBoolean(R.styleable.CameraView_cameraPreviewFrameRateExact, false); long autoFocusResetDelay = (long) a.getInteger( R.styleable.CameraView_cameraAutoFocusResetDelay, (int) DEFAULT_AUTOFOCUS_RESET_DELAY_MILLIS); @@ -277,6 +278,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver { setVideoMaxDuration(videoMaxDuration); setVideoBitRate(videoBitRate); setAutoFocusResetDelay(autoFocusResetDelay); + setPreviewFrameRateExact(videoFrameRateExact); setPreviewFrameRate(videoFrameRate); setSnapshotMaxWidth(snapshotMaxWidth); setSnapshotMaxHeight(snapshotMaxHeight); @@ -1543,6 +1545,24 @@ public class CameraView extends FrameLayout implements LifecycleObserver { return mCameraEngine.getVideoBitRate(); } + /** + * A flag to control the behavior when calling {@link #setPreviewFrameRate(float)}. + * + * If the value is set to true, {@link #setPreviewFrameRate(float)} will choose the preview + * frame range as close to the desired new frame rate as possible. Which mean it may choose a + * narrow range around the desired frame rate. + * + * If the value is set to false, {@link #setPreviewFrameRate(float)} will choose as broad range + * as it can. + * + * @param videoFrameRateExact whether want a more exact preview frame range + * + * @see #setPreviewFrameRate(float) + */ + private void setPreviewFrameRateExact(boolean videoFrameRateExact) { + mCameraEngine.setPreviewFrameRateExact(videoFrameRateExact); + } + /** * Sets the preview frame rate in frames per second. * This rate will be used, for example, by the frame processor and in video diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java index 47f09bdb..1e401e72 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java @@ -52,6 +52,7 @@ import com.otaliastudios.cameraview.video.SnapshotVideoRecorder; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; @@ -696,6 +697,11 @@ public class Camera1Engine extends CameraBaseEngine implements return false; } + @Override + public void setPreviewFrameRateExact(boolean previewFrameRateExact) { + mPreviewFrameRateExact = previewFrameRateExact; + } + @Override public void setPreviewFrameRate(float previewFrameRate) { final float old = previewFrameRate; @@ -726,6 +732,7 @@ public class Camera1Engine extends CameraBaseEngine implements } } } else { + sortRanges(fpsRanges); // If out of boundaries, adjust it. mPreviewFrameRate = Math.min(mPreviewFrameRate, mCameraOptions.getPreviewFrameRateMaxValue()); @@ -745,6 +752,24 @@ public class Camera1Engine extends CameraBaseEngine implements return false; } + private void sortRanges(List fpsRanges) { + if (mPreviewFrameRateExact) { // sort by range width in ascending order + Collections.sort(fpsRanges, new Comparator() { + @Override + public int compare(int[] range1, int[] range2) { + return (range1[1] - range1[0]) - (range2[1] - range2[0]); + } + }); + } else { // sort by range width in descending order + Collections.sort(fpsRanges, new Comparator() { + @Override + public int compare(int[] range1, int[] range2) { + return (range2[1] - range2[0]) - (range1[1] - range1[0]); + } + }); + } + } + @Override public void setPictureFormat(@NonNull PictureFormat pictureFormat) { if (pictureFormat != PictureFormat.JPEG) { diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java index e0c2f1a2..f7e0a936 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java @@ -71,6 +71,8 @@ import com.otaliastudios.cameraview.video.Full2VideoRecorder; import com.otaliastudios.cameraview.video.SnapshotVideoRecorder; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.CopyOnWriteArrayList; @@ -1353,6 +1355,11 @@ public class Camera2Engine extends CameraBaseEngine implements mPlaySoundsTask = Tasks.forResult(null); } + @Override + public void setPreviewFrameRateExact(boolean previewFrameRateExact) { + mPreviewFrameRateExact = previewFrameRateExact; + } + @Override public void setPreviewFrameRate(float previewFrameRate) { final float oldPreviewFrameRate = mPreviewFrameRate; @@ -1387,6 +1394,7 @@ public class Camera2Engine extends CameraBaseEngine implements } } } else { + sortRanges(fpsRanges); // If out of boundaries, adjust it. mPreviewFrameRate = Math.min(mPreviewFrameRate, mCameraOptions.getPreviewFrameRateMaxValue()); @@ -1403,6 +1411,26 @@ public class Camera2Engine extends CameraBaseEngine implements return false; } + private void sortRanges(Range[] fpsRanges) { + if (mPreviewFrameRateExact) { + Arrays.sort(fpsRanges, new Comparator>() { + @Override + public int compare(Range range1, Range range2) { + return (range1.getUpper() - range1.getLower()) + - (range2.getUpper() - range2.getLower()); + } + }); + } else { + Arrays.sort(fpsRanges, new Comparator>() { + @Override + public int compare(Range range1, Range range2) { + return (range2.getUpper() - range2.getLower()) + - (range1.getUpper() - range1.getLower()); + } + }); + } + } + @Override public void setPictureFormat(final @NonNull PictureFormat pictureFormat) { if (pictureFormat != mPictureFormat) { diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraBaseEngine.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraBaseEngine.java index 0f21ac54..fd7c23e5 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraBaseEngine.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraBaseEngine.java @@ -70,6 +70,7 @@ public abstract class CameraBaseEngine extends CameraEngine { @SuppressWarnings("WeakerAccess") protected boolean mPictureMetering; @SuppressWarnings("WeakerAccess") protected boolean mPictureSnapshotMetering; @SuppressWarnings("WeakerAccess") protected float mPreviewFrameRate; + @SuppressWarnings("WeakerAccess") protected boolean mPreviewFrameRateExact; private FrameManager mFrameManager; private final Angles mAngles = new Angles(); diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java index 7b26330f..23a887fa 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java @@ -690,6 +690,7 @@ public abstract class CameraEngine implements public abstract void setPictureFormat(@NonNull PictureFormat pictureFormat); @NonNull public abstract PictureFormat getPictureFormat(); + public abstract void setPreviewFrameRateExact(boolean previewFrameRateExact); public abstract void setPreviewFrameRate(float previewFrameRate); public abstract float getPreviewFrameRate(); diff --git a/cameraview/src/main/res/values/attrs.xml b/cameraview/src/main/res/values/attrs.xml index 780566a0..609a69a3 100644 --- a/cameraview/src/main/res/values/attrs.xml +++ b/cameraview/src/main/res/values/attrs.xml @@ -34,6 +34,7 @@ +