diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraOptions.java b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraOptions.java index 7568c66c..7087373a 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraOptions.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraOptions.java @@ -54,6 +54,7 @@ public class CameraOptions { private Set supportedVideoSizes = new HashSet<>(5); private Set supportedPictureAspectRatio = new HashSet<>(4); private Set supportedVideoAspectRatio = new HashSet<>(3); + private Set> supportedFpsRange = new HashSet<>(4); private boolean zoomSupported; private boolean exposureCorrectionSupported; @@ -272,6 +273,10 @@ public class CameraOptions { supportedVideoAspectRatio.add(AspectRatio.of(width, height)); } } + + //fps Range + Range[] range = cameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); + supportedFpsRange.addAll(Arrays.asList(range)); } /** @@ -498,4 +503,13 @@ public class CameraOptions { public float getExposureCorrectionMaxValue() { return exposureCorrectionMaxValue; } + + /** + * Set of supported FPS Range + * @return a collection of fps range + */ + @NonNull + public Collection> getSupportedFpsRange() { + return Collections.unmodifiableSet(supportedFpsRange); + } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java index f55e9289..271650f8 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java @@ -189,6 +189,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver { 0); 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_cameraVideoFrameRate, 30); long autoFocusResetDelay = (long) a.getInteger( R.styleable.CameraView_cameraAutoFocusResetDelay, (int) DEFAULT_AUTOFOCUS_RESET_DELAY_MILLIS); @@ -251,6 +252,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver { setVideoMaxDuration(videoMaxDuration); setVideoBitRate(videoBitRate); setAutoFocusResetDelay(autoFocusResetDelay); + setPreviewFrameRate(videoFrameRate); // Apply gestures mapGesture(Gesture.TAP, gestures.getTapAction()); @@ -952,6 +954,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver { setVideoMaxDuration(oldEngine.getVideoMaxDuration()); setVideoBitRate(oldEngine.getVideoBitRate()); setAutoFocusResetDelay(oldEngine.getAutoFocusResetDelay()); + setPreviewFrameRate(oldEngine.getPreviewFrameRate()); } /** @@ -1446,6 +1449,23 @@ public class CameraView extends FrameLayout implements LifecycleObserver { return mCameraEngine.getVideoBitRate(); } + /** + * Sets the frame rate for the video + * Will be used by {@link #takeVideoSnapshot(File)}. + * @param frameRate desired frame rate + */ + public void setPreviewFrameRate(float frameRate) { + mCameraEngine.setPreviewFrameRate(frameRate); + } + + /** + * Returns the current frame rate. + * @return current frame rate + */ + public float getPreviewFrameRate() { + return mCameraEngine.getPreviewFrameRate(); + } + /** * Sets the bit rate in bits per second for audio capturing. * Will be used by both {@link #takeVideo(File)} and {@link #takeVideoSnapshot(File)}. 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 60d63cb7..f32232e2 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java @@ -666,6 +666,10 @@ public class Camera1Engine extends CameraEngine implements return false; } + @Override public void setPreviewFrameRate(float previewFrameRate) { + // This method does nothing + } + //endregion //region Frame Processing 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 7387259c..02a3bfaf 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java @@ -69,6 +69,7 @@ import com.otaliastudios.cameraview.video.Full2VideoRecorder; import com.otaliastudios.cameraview.video.SnapshotVideoRecorder; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.CopyOnWriteArrayList; @@ -83,7 +84,6 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv private static final int FRAME_PROCESSING_FORMAT = ImageFormat.NV21; private static final int FRAME_PROCESSING_INPUT_FORMAT = ImageFormat.YUV_420_888; - private static final int HIGHER_FRAME_RATE = 60; @VisibleForTesting static final long METER_TIMEOUT = 2500; private final CameraManager mManager; @@ -358,15 +358,6 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv int sensorOffset = readCharacteristic(characteristics, CameraCharacteristics.SENSOR_ORIENTATION, 0); getAngles().setSensorOffset(facing, sensorOffset); - Range[] range = characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); - if (range != null) { - for (Range fpsRange : range) { - if (fpsRange.getUpper() >= HIGHER_FRAME_RATE) { - mIsHigherFrameRateSupported = true; - break; - } - } - } return true; } } catch (CameraAccessException ignore) { @@ -789,9 +780,6 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv @Override protected void onTakeVideo(@NonNull VideoResult.Stub stub) { LOG.i("onTakeVideo", "called."); - if (mIsHigherFrameRateSupported) { - stub.videoFrameRate = HIGHER_FRAME_RATE; - } stub.rotation = getAngles().offset(Reference.SENSOR, Reference.OUTPUT, Axis.RELATIVE_TO_SENSOR); stub.size = getAngles().flip(Reference.SENSOR, Reference.OUTPUT) ? @@ -831,7 +819,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv throw new IllegalStateException("Video snapshots are only supported with GL_SURFACE."); } if (mIsHigherFrameRateSupported) { - stub.videoFrameRate = HIGHER_FRAME_RATE; + stub.videoFrameRate = (int) mPreviewFrameRate; } GlCameraPreview glPreview = (GlCameraPreview) mPreview; Size outputSize = getUncroppedSnapshotSize(Reference.OUTPUT); @@ -933,6 +921,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv applyHdr(builder, Hdr.OFF); applyZoom(builder, 0F); applyExposureCorrection(builder, 0F); + applyPreviewFrameRate(builder); if (oldBuilder != null) { // We might be in a metering operation, or the old builder might have some special @@ -1272,6 +1261,33 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv mPlaySoundsOp.end(null); } + @Override public void setPreviewFrameRate(float previewFrameRate) { + mPreviewFrameRate = previewFrameRate; + mHandler.run(new Runnable() { + @Override + public void run() { + if (getEngineState() == STATE_STARTED) { + if (applyPreviewFrameRate(mRepeatingRequestBuilder)) { + applyRepeatingRequestBuilder(); + } + } + } + }); + } + + @SuppressWarnings("WeakerAccess") + protected boolean applyPreviewFrameRate(@NonNull CaptureRequest.Builder builder) { + Collection> fpsRange = mCameraOptions.getSupportedFpsRange(); + for (Range range : fpsRange) { + if (range.getUpper() >= mPreviewFrameRate) { + mIsHigherFrameRateSupported = true; + builder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, range); + return true; + } + } + return false; + } + //endregion //region Frame Processing 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 2631b2b9..226718fa 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java @@ -174,6 +174,7 @@ public abstract class CameraEngine implements @SuppressWarnings("WeakerAccess") protected boolean mPlaySounds; @SuppressWarnings("WeakerAccess") protected boolean mPictureMetering; @SuppressWarnings("WeakerAccess") protected boolean mPictureSnapshotMetering; + @SuppressWarnings("WeakerAccess") protected float mPreviewFrameRate; // Can be private @VisibleForTesting Handler mCrashHandler; @@ -1026,6 +1027,10 @@ public abstract class CameraEngine implements return mExposureCorrectionValue; } + public final float getPreviewFrameRate() { + return mPreviewFrameRate; + } + @CallSuper public void setHasFrameProcessors(boolean hasFrameProcessors) { mHasFrameProcessors = hasFrameProcessors; @@ -1107,6 +1112,8 @@ public abstract class CameraEngine implements public abstract void setPlaySounds(boolean playSounds); + public abstract void setPreviewFrameRate(float previewFrameRate); + //endregion //region picture and video control diff --git a/cameraview/src/main/res/values/attrs.xml b/cameraview/src/main/res/values/attrs.xml index f11dde3b..17a34f1c 100644 --- a/cameraview/src/main/res/values/attrs.xml +++ b/cameraview/src/main/res/values/attrs.xml @@ -27,6 +27,7 @@ +