VideoCapture: setTargetFrameRate

Relnote: Add setTargetFrameRate() API in the VideoCapture.Builder and getTargetFramerate() API in VideoCapture
Test: N/A
Bug: 266846318
Change-Id: I109d43a5c4ee38abb3c5fe03366166025aef9048
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java b/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java
index 3257ece..833c2e3 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java
@@ -22,6 +22,7 @@
 import static androidx.camera.core.impl.ImageOutputConfig.OPTION_RESOLUTION_SELECTOR;
 import static androidx.camera.core.impl.ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO;
 import static androidx.camera.core.impl.ImageOutputConfig.OPTION_TARGET_RESOLUTION;
+import static androidx.camera.core.impl.StreamSpec.FRAME_RATE_RANGE_UNSPECIFIED;
 import static androidx.camera.core.impl.utils.TransformUtils.within360;
 import static androidx.camera.core.processing.TargetUtils.isSuperset;
 import static androidx.core.util.Preconditions.checkArgument;
@@ -30,6 +31,7 @@
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.media.ImageReader;
+import android.util.Range;
 import android.util.Size;
 import android.view.Surface;
 
@@ -353,6 +355,17 @@
     }
 
     /**
+     * Returns the target frame rate range for the associated VideoCapture use case.
+     *
+     * @return The target frame rate.
+     */
+    @NonNull
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    protected Range<Integer> getTargetFramerateInternal() {
+        return mCurrentConfig.getTargetFramerate(FRAME_RATE_RANGE_UNSPECIFIED);
+    }
+
+    /**
      * Returns the mirror mode.
      *
      * <p>If mirror mode is not set, defaults to {@link MirrorMode#MIRROR_MODE_OFF}.
diff --git a/camera/camera-video/api/current.txt b/camera/camera-video/api/current.txt
index 208d9cd..423d499 100644
--- a/camera/camera-video/api/current.txt
+++ b/camera/camera-video/api/current.txt
@@ -133,6 +133,7 @@
 
   @RequiresApi(21) public final class VideoCapture<T extends androidx.camera.video.VideoOutput> extends androidx.camera.core.UseCase {
     method public T getOutput();
+    method public android.util.Range<java.lang.Integer!> getTargetFramerate();
     method public int getTargetRotation();
     method public void setTargetRotation(int);
     method public void setTargetRotationDegrees(int);
@@ -142,6 +143,7 @@
   @RequiresApi(21) public static final class VideoCapture.Builder<T extends androidx.camera.video.VideoOutput> implements androidx.camera.core.ExtendableBuilder<androidx.camera.video.VideoCapture> {
     ctor public VideoCapture.Builder(T);
     method public androidx.camera.video.VideoCapture<T!> build();
+    method public androidx.camera.video.VideoCapture.Builder<T!> setTargetFramerate(android.util.Range<java.lang.Integer!>);
     method public androidx.camera.video.VideoCapture.Builder<T!> setTargetRotation(int);
   }
 
diff --git a/camera/camera-video/api/public_plus_experimental_current.txt b/camera/camera-video/api/public_plus_experimental_current.txt
index 208d9cd..423d499 100644
--- a/camera/camera-video/api/public_plus_experimental_current.txt
+++ b/camera/camera-video/api/public_plus_experimental_current.txt
@@ -133,6 +133,7 @@
 
   @RequiresApi(21) public final class VideoCapture<T extends androidx.camera.video.VideoOutput> extends androidx.camera.core.UseCase {
     method public T getOutput();
+    method public android.util.Range<java.lang.Integer!> getTargetFramerate();
     method public int getTargetRotation();
     method public void setTargetRotation(int);
     method public void setTargetRotationDegrees(int);
@@ -142,6 +143,7 @@
   @RequiresApi(21) public static final class VideoCapture.Builder<T extends androidx.camera.video.VideoOutput> implements androidx.camera.core.ExtendableBuilder<androidx.camera.video.VideoCapture> {
     ctor public VideoCapture.Builder(T);
     method public androidx.camera.video.VideoCapture<T!> build();
+    method public androidx.camera.video.VideoCapture.Builder<T!> setTargetFramerate(android.util.Range<java.lang.Integer!>);
     method public androidx.camera.video.VideoCapture.Builder<T!> setTargetRotation(int);
   }
 
diff --git a/camera/camera-video/api/restricted_current.txt b/camera/camera-video/api/restricted_current.txt
index 208d9cd..423d499 100644
--- a/camera/camera-video/api/restricted_current.txt
+++ b/camera/camera-video/api/restricted_current.txt
@@ -133,6 +133,7 @@
 
   @RequiresApi(21) public final class VideoCapture<T extends androidx.camera.video.VideoOutput> extends androidx.camera.core.UseCase {
     method public T getOutput();
+    method public android.util.Range<java.lang.Integer!> getTargetFramerate();
     method public int getTargetRotation();
     method public void setTargetRotation(int);
     method public void setTargetRotationDegrees(int);
@@ -142,6 +143,7 @@
   @RequiresApi(21) public static final class VideoCapture.Builder<T extends androidx.camera.video.VideoOutput> implements androidx.camera.core.ExtendableBuilder<androidx.camera.video.VideoCapture> {
     ctor public VideoCapture.Builder(T);
     method public androidx.camera.video.VideoCapture<T!> build();
+    method public androidx.camera.video.VideoCapture.Builder<T!> setTargetFramerate(android.util.Range<java.lang.Integer!>);
     method public androidx.camera.video.VideoCapture.Builder<T!> setTargetRotation(int);
   }
 
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
index 3eb0bf2..5a9c691 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
@@ -32,6 +32,7 @@
 import static androidx.camera.core.impl.UseCaseConfig.OPTION_HIGH_RESOLUTION_DISABLED;
 import static androidx.camera.core.impl.UseCaseConfig.OPTION_SESSION_CONFIG_UNPACKER;
 import static androidx.camera.core.impl.UseCaseConfig.OPTION_SURFACE_OCCUPANCY_PRIORITY;
+import static androidx.camera.core.impl.UseCaseConfig.OPTION_TARGET_FRAME_RATE;
 import static androidx.camera.core.impl.UseCaseConfig.OPTION_ZSL_DISABLED;
 import static androidx.camera.core.impl.utils.Threads.isMainThread;
 import static androidx.camera.core.impl.utils.TransformUtils.rectToString;
@@ -253,6 +254,21 @@
     }
 
     /**
+     * Returns the target frame rate range for the associated VideoCapture use case.
+     *
+     * <p>The rotation can be set prior to constructing a VideoCapture using
+     * {@link VideoCapture.Builder#setTargetFramerate(Range)}
+     * If not set, the target frame rate defaults to the value of
+     * {@link StreamSpec#FRAME_RATE_RANGE_UNSPECIFIED}
+     *
+     * @return The rotation of the intended target.
+     */
+    @NonNull
+    public Range<Integer> getTargetFramerate() {
+        return getTargetFramerateInternal();
+    }
+
+    /**
      * Sets the desired rotation of the output video.
      *
      * <p>Valid values include: {@link Surface#ROTATION_0}, {@link Surface#ROTATION_90},
@@ -367,6 +383,7 @@
     }
 
     // TODO: to public API
+
     /**
      * Returns the mirror mode.
      *
@@ -384,6 +401,7 @@
 
     /**
      * {@inheritDoc}
+     *
      */
     @SuppressWarnings("unchecked")
     @RestrictTo(Scope.LIBRARY_GROUP)
@@ -409,6 +427,7 @@
 
     /**
      * {@inheritDoc}
+     *
      */
     @Override
     @RestrictTo(Scope.LIBRARY_GROUP)
@@ -419,6 +438,7 @@
 
     /**
      * {@inheritDoc}
+     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @Override
@@ -445,6 +465,7 @@
 
     /**
      * {@inheritDoc}
+     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @Override
@@ -465,6 +486,7 @@
 
     /**
      * {@inheritDoc}
+     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @NonNull
@@ -479,6 +501,7 @@
 
     /**
      * {@inheritDoc}
+     *
      */
     @NonNull
     @RestrictTo(Scope.LIBRARY_GROUP)
@@ -682,6 +705,7 @@
     }
 
     /**
+     *
      */
     @Nullable
     @RestrictTo(Scope.TESTS)
@@ -694,6 +718,7 @@
      *
      * <p>These values may be overridden by the implementation. They only provide a minimum set of
      * defaults that are implementation independent.
+     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     public static final class Defaults implements ConfigProvider<VideoCaptureConfig<?>> {
@@ -1309,6 +1334,7 @@
 
         /**
          * {@inheritDoc}
+         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @Override
@@ -1319,6 +1345,7 @@
 
         /**
          * {@inheritDoc}
+         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -1390,6 +1417,7 @@
          * setTargetAspectRatio is not supported on VideoCapture
          *
          * <p>To set aspect ratio, see {@link Recorder.Builder#setAspectRatio(int)}.
+         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -1433,6 +1461,7 @@
         }
 
         // TODO: to public API
+
         /**
          * Sets the mirror mode.
          *
@@ -1456,6 +1485,7 @@
          * setTargetResolution is not supported on VideoCapture
          *
          * <p>To set resolution, see {@link Recorder.Builder#setQualitySelector(QualitySelector)}.
+         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -1606,5 +1636,22 @@
             getMutableConfig().insertOption(OPTION_HIGH_RESOLUTION_DISABLED, disabled);
             return this;
         }
+
+        /**
+         * Sets the target frame rate range for the associated VideoCapture use case.
+         *
+         * <p>This target will be used as a part of the heuristics for the algorithm that determines
+         * the final frame rate range and resolution of all concurrently bound use cases.
+         * <p>It is not guaranteed that this target frame rate will be the final range,
+         * as other use cases as well as frame rate restrictions of the device may affect the
+         * outcome of the algorithm that chooses the actual frame rate.
+         *
+         * @param targetFrameRate the target frame rate range.
+         */
+        @NonNull
+        public Builder<T> setTargetFramerate(@NonNull Range<Integer> targetFrameRate) {
+            getMutableConfig().insertOption(OPTION_TARGET_FRAME_RATE, targetFrameRate);
+            return this;
+        }
     }
 }