content: /*
   * Copyright (C) 2010 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.media;
  
  import android.annotation.UnsupportedAppUsage;
  import android.hardware.Camera;
  import android.hardware.Camera.CameraInfo;
  import android.os.Build;
  
  /**
   * Retrieves the
   * predefined camcorder profile settings for camcorder applications.
   * These settings are read-only.
   *
   * <p>The compressed output from a recording session with a given
   * CamcorderProfile contains two tracks: one for audio and one for video.
   *
   * <p>Each profile specifies the following set of parameters:
   * <ul>
   * <li> The file output format
   * <li> Video codec format
   * <li> Video bit rate in bits per second
   * <li> Video frame rate in frames per second
   * <li> Video frame width and height,
   * <li> Audio codec format
   * <li> Audio bit rate in bits per second,
   * <li> Audio sample rate
   * <li> Number of audio channels for recording.
   * </ul>
   */
  public class CamcorderProfile
  {
      // Do not change these values/ordinals without updating their counterpart
      // in include/media/MediaProfiles.h!
  
      /**
       * Quality level corresponding to the lowest available resolution.
       */
      public static final int QUALITY_LOW  = 0;
  
      /**
       * Quality level corresponding to the highest available resolution.
       */
      public static final int QUALITY_HIGH = 1;
  
      /**
       * Quality level corresponding to the qcif (176 x 144) resolution.
       */
      public static final int QUALITY_QCIF = 2;
  
      /**
       * Quality level corresponding to the cif (352 x 288) resolution.
       */
      public static final int QUALITY_CIF = 3;
  
      /**
       * Quality level corresponding to the 480p (720 x 480) resolution.
       * Note that the horizontal resolution for 480p can also be other
       * values, such as 640 or 704, instead of 720.
       */
      public static final int QUALITY_480P = 4;
  
      /**
       * Quality level corresponding to the 720p (1280 x 720) resolution.
       */
      public static final int QUALITY_720P = 5;
  
      /**
       * Quality level corresponding to the 1080p (1920 x 1080) resolution.
       * Note that the vertical resolution for 1080p can also be 1088,
       * instead of 1080 (used by some vendors to avoid cropping during
       * video playback).
       */
      public static final int QUALITY_1080P = 6;
  
      /**
       * Quality level corresponding to the QVGA (320x240) resolution.
       */
      public static final int QUALITY_QVGA = 7;
  
      /**
       * Quality level corresponding to the 2160p (3840x2160) resolution.
       */
      public static final int QUALITY_2160P = 8;
  
      /**
       * Quality level corresponding to the VGA (640 x 480) resolution.
       * @hide
       */
      public static final int QUALITY_VGA = 9;
  
      /**
       * Quality level corresponding to 4k-DCI (4096 x 2160) resolution.
       * @hide
       */
      public static final int QUALITY_4KDCI = 10;
  
      /**
       * Quality level corresponding to QHD (2560 x 1440) resolution
       * @hide
       */
      public static final int QUALITY_QHD = 11;
  
      /**
       * Quality level corresponding to 2K (2048 x 1080) resolution
       * @hide
       */
      public static final int QUALITY_2K = 12;
  
      // Start and end of quality list
      private static final int QUALITY_LIST_START = QUALITY_LOW;
      private static final int QUALITY_LIST_END = QUALITY_2K;
  
      /**
       * Time lapse quality level corresponding to the lowest available resolution.
       */
      public static final int QUALITY_TIME_LAPSE_LOW  = 1000;
  
      /**
       * Time lapse quality level corresponding to the highest available resolution.
       */
      public static final int QUALITY_TIME_LAPSE_HIGH = 1001;
  
      /**
       * Time lapse quality level corresponding to the qcif (176 x 144) resolution.
       */
      public static final int QUALITY_TIME_LAPSE_QCIF = 1002;
  
      /**
       * Time lapse quality level corresponding to the cif (352 x 288) resolution.
       */
      public static final int QUALITY_TIME_LAPSE_CIF = 1003;
  
      /**
       * Time lapse quality level corresponding to the 480p (720 x 480) resolution.
       */
      public static final int QUALITY_TIME_LAPSE_480P = 1004;
  
      /**
       * Time lapse quality level corresponding to the 720p (1280 x 720) resolution.
       */
      public static final int QUALITY_TIME_LAPSE_720P = 1005;
  
      /**
       * Time lapse quality level corresponding to the 1080p (1920 x 1088) resolution.
       */
      public static final int QUALITY_TIME_LAPSE_1080P = 1006;
  
      /**
       * Time lapse quality level corresponding to the QVGA (320 x 240) resolution.
       */
      public static final int QUALITY_TIME_LAPSE_QVGA = 1007;
  
      /**
       * Time lapse quality level corresponding to the 2160p (3840 x 2160) resolution.
       */
      public static final int QUALITY_TIME_LAPSE_2160P = 1008;
  
      /**
       * Time lapse quality level corresponding to the VGA (640 x 480) resolution.
       * @hide
       */
      public static final int QUALITY_TIME_LAPSE_VGA = 1009;
  
      /**
       * Time lapse quality level corresponding to the 4k-DCI (4096 x 2160) resolution.
       * @hide
       */
      public static final int QUALITY_TIME_LAPSE_4KDCI = 1010;
  
      /**
       * Time lapse quality level corresponding to the QHD (2560 x 1440) resolution.
       * @hide
       */
      public static final int QUALITY_TIME_LAPSE_QHD = 1011;
  
      /**
       * Time lapse quality level corresponding to the 2K (2048 x 1080) resolution.
       * @hide
       */
      public static final int QUALITY_TIME_LAPSE_2K = 1012;
  
  
      // Start and end of timelapse quality list
      private static final int QUALITY_TIME_LAPSE_LIST_START = QUALITY_TIME_LAPSE_LOW;
      private static final int QUALITY_TIME_LAPSE_LIST_END = QUALITY_TIME_LAPSE_2K;
  
      /**
       * High speed ( >= 100fps) quality level corresponding to the lowest available resolution.
       * <p>
       * For all the high speed profiles defined below ((from {@link #QUALITY_HIGH_SPEED_LOW} to
       * {@link #QUALITY_HIGH_SPEED_2160P}), they are similar as normal recording profiles, with just
       * higher output frame rate and bit rate. Therefore, setting these profiles with
       * {@link MediaRecorder#setProfile} without specifying any other encoding parameters will
       * produce high speed videos rather than slow motion videos that have different capture and
       * output (playback) frame rates. To record slow motion videos, the application must set video
       * output (playback) frame rate and bit rate appropriately via
       * {@link MediaRecorder#setVideoFrameRate} and {@link MediaRecorder#setVideoEncodingBitRate}
       * based on the slow motion factor. If the application intends to do the video recording with
       * {@link MediaCodec} encoder, it must set each individual field of {@link MediaFormat}
       * similarly according to this CamcorderProfile.
       * </p>
       *
       * @see #videoBitRate
       * @see #videoFrameRate
       * @see MediaRecorder
       * @see MediaCodec
       * @see MediaFormat
       */
      public static final int QUALITY_HIGH_SPEED_LOW = 2000;
  
      /**
       * High speed ( >= 100fps) quality level corresponding to the highest available resolution.
       */
      public static final int QUALITY_HIGH_SPEED_HIGH = 2001;
  
      /**
       * High speed ( >= 100fps) quality level corresponding to the 480p (720 x 480) resolution.
       *
       * Note that the horizontal resolution for 480p can also be other
       * values, such as 640 or 704, instead of 720.
       */
      public static final int QUALITY_HIGH_SPEED_480P = 2002;
  
      /**
       * High speed ( >= 100fps) quality level corresponding to the 720p (1280 x 720) resolution.
       */
      public static final int QUALITY_HIGH_SPEED_720P = 2003;
  
      /**
       * High speed ( >= 100fps) quality level corresponding to the 1080p (1920 x 1080 or 1920x1088)
       * resolution.
       */
      public static final int QUALITY_HIGH_SPEED_1080P = 2004;
  
      /**
       * High speed ( >= 100fps) quality level corresponding to the 2160p (3840 x 2160)
       * resolution.
       */
      public static final int QUALITY_HIGH_SPEED_2160P = 2005;
  
      /**
       * High speed ( >= 100fps) quality level corresponding to the CIF (352 x 288)
       * @hide
       */
      public static final int QUALITY_HIGH_SPEED_CIF = 2006;
  
      /**
       * High speed ( >= 100fps) quality level corresponding to the VGA (640 x 480)
       * @hide
       */
      public static final int QUALITY_HIGH_SPEED_VGA = 2007;
  
      /**
       * High speed ( >= 100fps) quality level corresponding to the 4K-DCI (4096 x 2160)
       * @hide
       */
      public static final int QUALITY_HIGH_SPEED_4KDCI = 2008;
  
      // Start and end of high speed quality list
      private static final int QUALITY_HIGH_SPEED_LIST_START = QUALITY_HIGH_SPEED_LOW;
      private static final int QUALITY_HIGH_SPEED_LIST_END = QUALITY_HIGH_SPEED_4KDCI;
  
      /**
       * Default recording duration in seconds before the session is terminated.
       * This is useful for applications like MMS has limited file size requirement.
       */
      public int duration;
  
      /**
       * The quality level of the camcorder profile
       */
      public int quality;
  
      /**
       * The file output format of the camcorder profile
       * @see android.media.MediaRecorder.OutputFormat
       */
      public int fileFormat;
  
      /**
       * The video encoder being used for the video track
       * @see android.media.MediaRecorder.VideoEncoder
       */
      public int videoCodec;
  
      /**
       * The target video output bit rate in bits per second
       * <p>
       * This is the target recorded video output bit rate if the application configures the video
       * recording via {@link MediaRecorder#setProfile} without specifying any other
       * {@link MediaRecorder} encoding parameters. For example, for high speed quality profiles (from
       * {@link #QUALITY_HIGH_SPEED_LOW} to {@link #QUALITY_HIGH_SPEED_2160P}), this is the bit rate
       * where the video is recorded with. If the application intends to record slow motion videos
       * with the high speed quality profiles, it must set a different video bit rate that is
       * corresponding to the desired recording output bit rate (i.e., the encoded video bit rate
       * during normal playback) via {@link MediaRecorder#setVideoEncodingBitRate}. For example, if
       * {@link #QUALITY_HIGH_SPEED_720P} advertises 240fps {@link #videoFrameRate} and 64Mbps
       * {@link #videoBitRate} in the high speed CamcorderProfile, and the application intends to
       * record 1/8 factor slow motion recording videos, the application must set 30fps via
       * {@link MediaRecorder#setVideoFrameRate} and 8Mbps ( {@link #videoBitRate} * slow motion
       * factor) via {@link MediaRecorder#setVideoEncodingBitRate}. Failing to do so will result in
       * videos with unexpected frame rate and bit rate, or {@link MediaRecorder} error if the output
       * bit rate exceeds the encoder limit. If the application intends to do the video recording with
       * {@link MediaCodec} encoder, it must set each individual field of {@link MediaFormat}
       * similarly according to this CamcorderProfile.
       * </p>
       *
       * @see #videoFrameRate
       * @see MediaRecorder
       * @see MediaCodec
       * @see MediaFormat
       */
      public int videoBitRate;
  
      /**
       * The target video frame rate in frames per second.
       * <p>
       * This is the target recorded video output frame rate per second if the application configures
       * the video recording via {@link MediaRecorder#setProfile} without specifying any other
       * {@link MediaRecorder} encoding parameters. For example, for high speed quality profiles (from
       * {@link #QUALITY_HIGH_SPEED_LOW} to {@link #QUALITY_HIGH_SPEED_2160P}), this is the frame rate
       * where the video is recorded and played back with. If the application intends to create slow
       * motion use case with the high speed quality profiles, it must set a different video frame
       * rate that is corresponding to the desired output (playback) frame rate via
       * {@link MediaRecorder#setVideoFrameRate}. For example, if {@link #QUALITY_HIGH_SPEED_720P}
       * advertises 240fps {@link #videoFrameRate} in the CamcorderProfile, and the application
       * intends to create 1/8 factor slow motion recording videos, the application must set 30fps via
       * {@link MediaRecorder#setVideoFrameRate}. Failing to do so will result in high speed videos
       * with normal speed playback frame rate (240fps for above example). If the application intends
       * to do the video recording with {@link MediaCodec} encoder, it must set each individual field
       * of {@link MediaFormat} similarly according to this CamcorderProfile.
       * </p>
       *
       * @see #videoBitRate
       * @see MediaRecorder
       * @see MediaCodec
       * @see MediaFormat
       */
      public int videoFrameRate;
  
      /**
       * The target video frame width in pixels
       */
      public int videoFrameWidth;
  
      /**
       * The target video frame height in pixels
       */
      public int videoFrameHeight;
  
      /**
       * The audio encoder being used for the audio track.
       * @see android.media.MediaRecorder.AudioEncoder
       */
      public int audioCodec;
  
      /**
       * The target audio output bit rate in bits per second
       */
      public int audioBitRate;
  
      /**
       * The audio sampling rate used for the audio track
       */
      public int audioSampleRate;
  
      /**
       * The number of audio channels used for the audio track
       */
      public int audioChannels;
  
      /**
       * Returns the camcorder profile for the first back-facing camera on the
       * device at the given quality level. If the device has no back-facing
       * camera, this returns null.
       * @param quality the target quality level for the camcorder profile
       * @see #get(int, int)
       */
      public static CamcorderProfile get(int quality) {
          int numberOfCameras = Camera.getNumberOfCameras();
          CameraInfo cameraInfo = new CameraInfo();
          for (int i = 0; i < numberOfCameras; i++) {
              Camera.getCameraInfo(i, cameraInfo);
              if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
                  return get(i, quality);
              }
          }
          return null;
      }
  
      /**
       * Returns the camcorder profile for the given camera at the given
       * quality level.
       *
       * Quality levels QUALITY_LOW, QUALITY_HIGH are guaranteed to be supported, while
       * other levels may or may not be supported. The supported levels can be checked using
       * {@link #hasProfile(int, int)}.
       * QUALITY_LOW refers to the lowest quality available, while QUALITY_HIGH refers to
       * the highest quality available.
       * QUALITY_LOW/QUALITY_HIGH have to match one of qcif, cif, 480p, 720p, 1080p or 2160p.
       * E.g. if the device supports 480p, 720p, 1080p and 2160p, then low is 480p and high is
       * 2160p.
       *
       * The same is true for time lapse quality levels, i.e. QUALITY_TIME_LAPSE_LOW,
       * QUALITY_TIME_LAPSE_HIGH are guaranteed to be supported and have to match one of
       * qcif, cif, 480p, 720p, 1080p, or 2160p.
       *
       * For high speed quality levels, they may or may not be supported. If a subset of the levels
       * are supported, QUALITY_HIGH_SPEED_LOW and QUALITY_HIGH_SPEED_HIGH are guaranteed to be
       * supported and have to match one of 480p, 720p, or 1080p.
       *
       * A camcorder recording session with higher quality level usually has higher output
       * bit rate, better video and/or audio recording quality, larger video frame
       * resolution and higher audio sampling rate, etc, than those with lower quality
       * level.
       *
       * @param cameraId the id for the camera
       * @param quality the target quality level for the camcorder profile.
       * @see #QUALITY_LOW
       * @see #QUALITY_HIGH
       * @see #QUALITY_QCIF
       * @see #QUALITY_CIF
       * @see #QUALITY_480P
       * @see #QUALITY_720P
       * @see #QUALITY_1080P
       * @see #QUALITY_2160P
       * @see #QUALITY_TIME_LAPSE_LOW
       * @see #QUALITY_TIME_LAPSE_HIGH
       * @see #QUALITY_TIME_LAPSE_QCIF
       * @see #QUALITY_TIME_LAPSE_CIF
       * @see #QUALITY_TIME_LAPSE_480P
       * @see #QUALITY_TIME_LAPSE_720P
       * @see #QUALITY_TIME_LAPSE_1080P
       * @see #QUALITY_TIME_LAPSE_2160P
       * @see #QUALITY_HIGH_SPEED_LOW
       * @see #QUALITY_HIGH_SPEED_HIGH
       * @see #QUALITY_HIGH_SPEED_480P
       * @see #QUALITY_HIGH_SPEED_720P
       * @see #QUALITY_HIGH_SPEED_1080P
       * @see #QUALITY_HIGH_SPEED_2160P
      */
      public static CamcorderProfile get(int cameraId, int quality) {
          if (!((quality >= QUALITY_LIST_START &&
                 quality <= QUALITY_LIST_END) ||
                (quality >= QUALITY_TIME_LAPSE_LIST_START &&
                 quality <= QUALITY_TIME_LAPSE_LIST_END) ||
                 (quality >= QUALITY_HIGH_SPEED_LIST_START &&
                 quality <= QUALITY_HIGH_SPEED_LIST_END))) {
              String errMessage = "Unsupported quality level: " + quality;
              throw new IllegalArgumentException(errMessage);
          }
          return native_get_camcorder_profile(cameraId, quality);
      }
  
      /**
       * Returns true if camcorder profile exists for the first back-facing
       * camera at the given quality level.
       *
       * <p>
       * When using the Camera 2 API in {@code LEGACY} mode (i.e. when
       * {@link android.hardware.camera2.CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL} is set
       * to
       * {@link android.hardware.camera2.CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY}),
       * {@link #hasProfile} may return {@code true} for unsupported resolutions.  To ensure a
       * a given resolution is supported in LEGACY mode, the configuration given in
       * {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP}
       * must contain the the resolution in the supported output sizes.  The recommended way to check
       * this is with
       * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes(Class)} with the
       * class of the desired recording endpoint, and check that the desired resolution is contained
       * in the list returned.
       * </p>
       * @see android.hardware.camera2.CameraManager
       * @see android.hardware.camera2.CameraCharacteristics
       *
       * @param quality the target quality level for the camcorder profile
       */
      public static boolean hasProfile(int quality) {
          int numberOfCameras = Camera.getNumberOfCameras();
          CameraInfo cameraInfo = new CameraInfo();
          for (int i = 0; i < numberOfCameras; i++) {
              Camera.getCameraInfo(i, cameraInfo);
              if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
                  return hasProfile(i, quality);
              }
          }
          return false;
      }
  
      /**
       * Returns true if camcorder profile exists for the given camera at
       * the given quality level.
       *
       * <p>
       * When using the Camera 2 API in LEGACY mode (i.e. when
       * {@link android.hardware.camera2.CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL} is set
       * to
       * {@link android.hardware.camera2.CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY}),
       * {@link #hasProfile} may return {@code true} for unsupported resolutions.  To ensure a
       * a given resolution is supported in LEGACY mode, the configuration given in
       * {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP}
       * must contain the the resolution in the supported output sizes.  The recommended way to check
       * this is with
       * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes(Class)} with the
       * class of the desired recording endpoint, and check that the desired resolution is contained
       * in the list returned.
       * </p>
       * @see android.hardware.camera2.CameraManager
       * @see android.hardware.camera2.CameraCharacteristics
       *
       * @param cameraId the id for the camera
       * @param quality the target quality level for the camcorder profile
       */
      public static boolean hasProfile(int cameraId, int quality) {
          return native_has_camcorder_profile(cameraId, quality);
      }
  
      static {
          System.loadLibrary("media_jni");
          native_init();
      }
  
      // Private constructor called by JNI
      private CamcorderProfile(int duration,
                               int quality,
                               int fileFormat,
                               int videoCodec,
                               int videoBitRate,
                               int videoFrameRate,
                               int videoWidth,
                               int videoHeight,
                               int audioCodec,
                               int audioBitRate,
                               int audioSampleRate,
                               int audioChannels) {
  
          this.duration         = duration;
          this.quality          = quality;
          this.fileFormat       = fileFormat;
          this.videoCodec       = videoCodec;
          this.videoBitRate     = videoBitRate;
          this.videoFrameRate   = videoFrameRate;
          this.videoFrameWidth  = videoWidth;
          this.videoFrameHeight = videoHeight;
          this.audioCodec       = audioCodec;
          this.audioBitRate     = audioBitRate;
          this.audioSampleRate  = audioSampleRate;
          this.audioChannels    = audioChannels;
      }
  
      // Methods implemented by JNI
      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
      private static native final void native_init();
      @UnsupportedAppUsage
      private static native final CamcorderProfile native_get_camcorder_profile(
              int cameraId, int quality);
      private static native final boolean native_has_camcorder_profile(
              int cameraId, int quality);
  }
  