Loading core/api/current.txt +29 −0 Original line number Diff line number Diff line Loading @@ -20898,6 +20898,7 @@ package android.media { public class CamcorderProfile { method public static android.media.CamcorderProfile get(int); method public static android.media.CamcorderProfile get(int, int); method @Nullable public static android.media.EncoderProfiles getAll(@NonNull String, int); method public static boolean hasProfile(int); method public static boolean hasProfile(int, int); field public static final int QUALITY_1080P = 6; // 0x6 Loading Loading @@ -20978,6 +20979,32 @@ package android.media { field @NonNull public final java.util.UUID uuid; } public class EncoderProfiles { method @NonNull public java.util.List<android.media.EncoderProfiles.AudioProfile> getAudioProfiles(); method public int getDurationSeconds(); method public int getFileFormat(); method @NonNull public java.util.List<android.media.EncoderProfiles.VideoProfile> getVideoProfiles(); } public static class EncoderProfiles.AudioProfile { method public int getBitrate(); method public int getChannels(); method public int getCodec(); method @NonNull public String getMediaType(); method public int getProfile(); method public int getSampleRate(); } public static class EncoderProfiles.VideoProfile { method public int getBitrate(); method public int getCodec(); method public int getFrameRate(); method public int getHeight(); method @NonNull public String getMediaType(); method public int getProfile(); method public int getWidth(); } public class ExifInterface { ctor public ExifInterface(@NonNull java.io.File) throws java.io.IOException; ctor public ExifInterface(@NonNull String) throws java.io.IOException; Loading Loading @@ -22904,6 +22931,7 @@ package android.media { method public void setAudioChannels(int); method public void setAudioEncoder(int) throws java.lang.IllegalStateException; method public void setAudioEncodingBitRate(int); method public void setAudioProfile(@NonNull android.media.EncoderProfiles.AudioProfile); method public void setAudioSamplingRate(int); method public void setAudioSource(int) throws java.lang.IllegalStateException; method @Deprecated public void setCamera(android.hardware.Camera); Loading Loading @@ -22932,6 +22960,7 @@ package android.media { method public void setVideoEncodingBitRate(int); method public void setVideoEncodingProfileLevel(int, int); method public void setVideoFrameRate(int) throws java.lang.IllegalStateException; method public void setVideoProfile(@NonNull android.media.EncoderProfiles.VideoProfile); method public void setVideoSize(int, int) throws java.lang.IllegalStateException; method public void setVideoSource(int) throws java.lang.IllegalStateException; method public void start() throws java.lang.IllegalStateException; media/java/android/media/CamcorderProfile.java +171 −7 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.hardware.Camera; import android.hardware.Camera.CameraInfo; Loading @@ -23,6 +26,9 @@ import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraMetadata; import android.os.Build; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Retrieves the * predefined camcorder profile settings for camcorder applications. Loading Loading @@ -275,6 +281,53 @@ public class CamcorderProfile 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; /** * @hide */ @IntDef({ QUALITY_LOW, QUALITY_HIGH, QUALITY_QCIF, QUALITY_CIF, QUALITY_480P, QUALITY_720P, QUALITY_1080P, QUALITY_QVGA, QUALITY_2160P, QUALITY_VGA, QUALITY_4KDCI, QUALITY_QHD, QUALITY_2K, QUALITY_8KUHD, QUALITY_TIME_LAPSE_LOW , QUALITY_TIME_LAPSE_HIGH, QUALITY_TIME_LAPSE_QCIF, QUALITY_TIME_LAPSE_CIF, QUALITY_TIME_LAPSE_480P, QUALITY_TIME_LAPSE_720P, QUALITY_TIME_LAPSE_1080P, QUALITY_TIME_LAPSE_QVGA, QUALITY_TIME_LAPSE_2160P, QUALITY_TIME_LAPSE_VGA, QUALITY_TIME_LAPSE_4KDCI, QUALITY_TIME_LAPSE_QHD, QUALITY_TIME_LAPSE_2K, QUALITY_TIME_LAPSE_8KUHD, QUALITY_HIGH_SPEED_LOW, QUALITY_HIGH_SPEED_HIGH, QUALITY_HIGH_SPEED_480P, QUALITY_HIGH_SPEED_720P, QUALITY_HIGH_SPEED_1080P, QUALITY_HIGH_SPEED_2160P, QUALITY_HIGH_SPEED_CIF, QUALITY_HIGH_SPEED_VGA, QUALITY_HIGH_SPEED_4KDCI, }) @Retention(RetentionPolicy.SOURCE) public @interface Quality {} /** * Default recording duration in seconds before the session is terminated. * This is useful for applications like MMS has limited file size requirement. Loading Loading @@ -385,9 +438,8 @@ public class CamcorderProfile 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. * Returns the default camcorder profile at the given quality level for the first back-facing * camera on the device. 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) */ Loading @@ -404,8 +456,7 @@ public class CamcorderProfile } /** * Returns the camcorder profile for the given camera at the given * quality level. * Returns the default 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 Loading Loading @@ -457,6 +508,7 @@ public class CamcorderProfile * @see #QUALITY_HIGH_SPEED_720P * @see #QUALITY_HIGH_SPEED_1080P * @see #QUALITY_HIGH_SPEED_2160P * @throws IllegalArgumentException if quality is not one of the defined QUALITY_ values. */ public static CamcorderProfile get(int cameraId, int quality) { if (!((quality >= QUALITY_LIST_START && Loading @@ -472,7 +524,119 @@ public class CamcorderProfile } /** * Returns true if camcorder profile exists for the first back-facing * Returns all encoder profiles of a 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. Numeric camera ids parsed from the list received by * invoking {@link CameraManager#getCameraIdList} can be used as long as they * are {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE} * and not * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL EXTERNAL}. * @param quality the target quality level for the camcorder profile. * @return null if there are no encoder profiles defined for the quality level for the * given camera. * @throws IllegalArgumentException if quality is not one of the defined QUALITY_ values. * @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 */ @Nullable public static EncoderProfiles getAll( @NonNull String cameraId, @Quality 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); } // TODO: get all profiles int id; try { id = Integer.valueOf(cameraId); } catch (NumberFormatException e) { return null; } CamcorderProfile cp = native_get_camcorder_profile(id, quality); if (cp == null) { return null; }; EncoderProfiles.AudioProfile[] audioProfiles; // timelapse profiles do not list audio profiles if (cp.quality >= QUALITY_TIME_LAPSE_LIST_START && cp.quality <= QUALITY_TIME_LAPSE_LIST_END) { audioProfiles = new EncoderProfiles.AudioProfile[] { }; } else { audioProfiles = new EncoderProfiles.AudioProfile[] { new EncoderProfiles.AudioProfile( cp.audioCodec, cp.audioChannels, cp.audioSampleRate, cp.audioBitRate) }; } return new EncoderProfiles( cp.duration, cp.fileFormat, new EncoderProfiles.VideoProfile[] { new EncoderProfiles.VideoProfile( cp.videoCodec, cp.videoFrameWidth, cp.videoFrameHeight, cp.videoFrameRate, cp.videoBitRate, 0 /* TODO: get profile */) }, audioProfiles); } /** * Returns true if a camcorder profile exists for the first back-facing * camera at the given quality level. * * <p> Loading Loading @@ -507,7 +671,7 @@ public class CamcorderProfile } /** * Returns true if camcorder profile exists for the given camera at * Returns true if a camcorder profile exists for the given camera at * the given quality level. * * <p> Loading media/java/android/media/EncoderProfiles.java 0 → 100644 +351 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.NonNull; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * Describes a set of encoding profiles for a given media (audio and/or video) profile. * These settings are read-only. * * <p>Currently, this is used to describe camera recording profile with more detail than {@link * CamcorderProfile}, by providing encoding parameters for more than just the default audio * and/or video codec. * * <p>The compressed output from a camera recording session contains two tracks: * one for audio and one for video. * <p>In the future audio-only recording profiles may be defined. * * <p>Each media profile specifies a set of audio and a set of video specific settings. * <ul> * <li> The file output format * <li> Default file duration * <p>Video-specific settings are: * <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> Video encoder profile. * <p>Audio-specific settings are: * <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 EncoderProfiles { /** * Default recording duration in seconds before the session is terminated. * This is useful for applications like MMS has limited file size requirement. * This could be 0 if there is no default recording duration. */ public int getDurationSeconds() { return durationSecs; } /** * Recommended output file format * @see android.media.MediaRecorder.OutputFormat */ public int getFileFormat() { return fileFormat; } /** * Configuration for a video encoder. */ public static class VideoProfile { /** * The video encoder being used for the video track * @see android.media.MediaRecorder.VideoEncoder */ public int getCodec() { return codec; } /** * The media type of the video encoder being used for the video track * @see android.media.MediaFormat#KEY_MIME */ public @NonNull String getMediaType() { if (codec == MediaRecorder.VideoEncoder.H263) { return MediaFormat.MIMETYPE_VIDEO_H263; } else if (codec == MediaRecorder.VideoEncoder.H264) { return MediaFormat.MIMETYPE_VIDEO_AVC; } else if (codec == MediaRecorder.VideoEncoder.MPEG_4_SP) { return MediaFormat.MIMETYPE_VIDEO_MPEG4; } else if (codec == MediaRecorder.VideoEncoder.VP8) { return MediaFormat.MIMETYPE_VIDEO_VP8; } else if (codec == MediaRecorder.VideoEncoder.HEVC) { return MediaFormat.MIMETYPE_VIDEO_HEVC; } // we should never be here throw new RuntimeException("Unknown codec"); } /** * The target video output bitrate in bits per second * <p> * This is the target recorded video output bitrate 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 CamcorderProfile#QUALITY_HIGH_SPEED_LOW} to {@link * CamcorderProfile#QUALITY_HIGH_SPEED_2160P}), this is the bitrate 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 bitrate that is corresponding to * the desired recording output bit rate (i.e., the encoded video bitrate during normal * playback) via {@link MediaRecorder#setVideoEncodingBitRate}. For example, if {@link * CamcorderProfile#QUALITY_HIGH_SPEED_720P} advertises 240fps {@link #getFrameRate} and * 64Mbps {@link #getBitrate} in the high speed VideoProfile, 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 #getBitrate} * 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 VideoProfile. * </p> * * @see #getFrameRate * @see MediaRecorder * @see MediaCodec * @see MediaFormat */ public int getBitrate() { return bitrate; } /** * 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 CamcorderProfile#QUALITY_HIGH_SPEED_LOW} to {@link * CamcorderProfile#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 * CamcorderProfile#QUALITY_HIGH_SPEED_720P} advertises 240fps {@link #getFrameRate} * in the VideoProfile, 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 VideoProfile. * </p> * * @see #getBitrate * @see MediaRecorder * @see MediaCodec * @see MediaFormat */ public int getFrameRate() { return frameRate; } /** * The target video frame width in pixels */ public int getWidth() { return width; } /** * The target video frame height in pixels */ public int getHeight() { return height; } /** * The video encoder profile being used for the video track. * <p> * This value is 0 if there is no profile defined for the video codec. * * @see MediaRecorder#setVideoEncodingProfileLevel * @see MediaFormat#KEY_PROFILE */ public int getProfile() { return profile; } // Constructor called by JNI and CamcorderProfile /* package private */ VideoProfile(int codec, int width, int height, int frameRate, int bitrate, int profile) { this.codec = codec; this.width = width; this.height = height; this.frameRate = frameRate; this.bitrate = bitrate; this.profile = profile; } private int codec; private int width; private int height; private int frameRate; private int bitrate; private int profile; } /** * Returns the defined audio encoder profiles. * <p> * The list may be empty. This means there are no audio encoder * profiles defined. Otherwise, the first profile is the default * audio profile. */ public @NonNull List<AudioProfile> getAudioProfiles() { return audioProfiles; } /** * Returns the defined video encoder profiles. * <p> * The list may be empty. This means there are no video encoder * profiles defined. Otherwise, the first profile is the default * video profile. */ public @NonNull List<VideoProfile> getVideoProfiles() { return videoProfiles; } /** * Configuration for an audio encoder. */ public static class AudioProfile { /** * The audio encoder being used for the audio track. * @see android.media.MediaRecorder.AudioEncoder */ public int getCodec() { return codec; } /** * The media type of the audio encoder being used for the video track * @see android.media.MediaFormat#KEY_MIME */ public @NonNull String getMediaType() { if (codec == MediaRecorder.AudioEncoder.AMR_NB) { return MediaFormat.MIMETYPE_AUDIO_AMR_NB; } else if (codec == MediaRecorder.AudioEncoder.AMR_WB) { return MediaFormat.MIMETYPE_AUDIO_AMR_WB; } else if (codec == MediaRecorder.AudioEncoder.AAC || codec == MediaRecorder.AudioEncoder.HE_AAC || codec == MediaRecorder.AudioEncoder.AAC_ELD) { return MediaFormat.MIMETYPE_AUDIO_AAC; } else if (codec == MediaRecorder.AudioEncoder.VORBIS) { return MediaFormat.MIMETYPE_AUDIO_VORBIS; } else if (codec == MediaRecorder.AudioEncoder.OPUS) { return MediaFormat.MIMETYPE_AUDIO_OPUS; } // we should never be here throw new RuntimeException("Unknown codec"); } /** * The target audio output bitrate in bits per second */ public int getBitrate() { return bitrate; } /** * The audio sampling rate used for the audio track */ public int getSampleRate() { return sampleRate; } /** * The number of audio channels used for the audio track */ public int getChannels() { return channels; } /** * The audio encoder profile being used for the audio track * <p> * This value is 0 if there is no profile defined for the audio codec. * @see MediaFormat#KEY_PROFILE */ public int getProfile() { if (codec == MediaRecorder.AudioEncoder.AAC) { return MediaCodecInfo.CodecProfileLevel.AACObjectMain; } else if (codec == MediaRecorder.AudioEncoder.HE_AAC) { return MediaCodecInfo.CodecProfileLevel.AACObjectHE; } else if (codec == MediaRecorder.AudioEncoder.AAC_ELD) { return MediaCodecInfo.CodecProfileLevel.AACObjectELD; } return 0; } // Constructor called by JNI and CamcorderProfile /* package private */ AudioProfile( int codec, int channels, int sampleRate, int bitrate) { this.codec = codec; this.channels = channels; this.sampleRate = sampleRate; this.bitrate = bitrate; } private int codec; private int channels; private int sampleRate; private int bitrate; } //static { // System.loadLibrary("media_jni"); //native_init(); //} private int durationSecs; private int fileFormat; // non-modifiable lists private @NonNull List<AudioProfile> audioProfiles; private @NonNull List<VideoProfile> videoProfiles; // Constructor called by JNI and CamcorderProfile /* package private */ EncoderProfiles( int duration, int fileFormat, VideoProfile[] videoProfiles, AudioProfile[] audioProfiles) { this.durationSecs = duration; this.fileFormat = fileFormat; this.videoProfiles = Collections.unmodifiableList(Arrays.asList(videoProfiles)); this.audioProfiles = Collections.unmodifiableList(Arrays.asList(audioProfiles)); } } media/java/android/media/MediaRecorder.java +41 −1 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
core/api/current.txt +29 −0 Original line number Diff line number Diff line Loading @@ -20898,6 +20898,7 @@ package android.media { public class CamcorderProfile { method public static android.media.CamcorderProfile get(int); method public static android.media.CamcorderProfile get(int, int); method @Nullable public static android.media.EncoderProfiles getAll(@NonNull String, int); method public static boolean hasProfile(int); method public static boolean hasProfile(int, int); field public static final int QUALITY_1080P = 6; // 0x6 Loading Loading @@ -20978,6 +20979,32 @@ package android.media { field @NonNull public final java.util.UUID uuid; } public class EncoderProfiles { method @NonNull public java.util.List<android.media.EncoderProfiles.AudioProfile> getAudioProfiles(); method public int getDurationSeconds(); method public int getFileFormat(); method @NonNull public java.util.List<android.media.EncoderProfiles.VideoProfile> getVideoProfiles(); } public static class EncoderProfiles.AudioProfile { method public int getBitrate(); method public int getChannels(); method public int getCodec(); method @NonNull public String getMediaType(); method public int getProfile(); method public int getSampleRate(); } public static class EncoderProfiles.VideoProfile { method public int getBitrate(); method public int getCodec(); method public int getFrameRate(); method public int getHeight(); method @NonNull public String getMediaType(); method public int getProfile(); method public int getWidth(); } public class ExifInterface { ctor public ExifInterface(@NonNull java.io.File) throws java.io.IOException; ctor public ExifInterface(@NonNull String) throws java.io.IOException; Loading Loading @@ -22904,6 +22931,7 @@ package android.media { method public void setAudioChannels(int); method public void setAudioEncoder(int) throws java.lang.IllegalStateException; method public void setAudioEncodingBitRate(int); method public void setAudioProfile(@NonNull android.media.EncoderProfiles.AudioProfile); method public void setAudioSamplingRate(int); method public void setAudioSource(int) throws java.lang.IllegalStateException; method @Deprecated public void setCamera(android.hardware.Camera); Loading Loading @@ -22932,6 +22960,7 @@ package android.media { method public void setVideoEncodingBitRate(int); method public void setVideoEncodingProfileLevel(int, int); method public void setVideoFrameRate(int) throws java.lang.IllegalStateException; method public void setVideoProfile(@NonNull android.media.EncoderProfiles.VideoProfile); method public void setVideoSize(int, int) throws java.lang.IllegalStateException; method public void setVideoSource(int) throws java.lang.IllegalStateException; method public void start() throws java.lang.IllegalStateException;
media/java/android/media/CamcorderProfile.java +171 −7 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.hardware.Camera; import android.hardware.Camera.CameraInfo; Loading @@ -23,6 +26,9 @@ import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraMetadata; import android.os.Build; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Retrieves the * predefined camcorder profile settings for camcorder applications. Loading Loading @@ -275,6 +281,53 @@ public class CamcorderProfile 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; /** * @hide */ @IntDef({ QUALITY_LOW, QUALITY_HIGH, QUALITY_QCIF, QUALITY_CIF, QUALITY_480P, QUALITY_720P, QUALITY_1080P, QUALITY_QVGA, QUALITY_2160P, QUALITY_VGA, QUALITY_4KDCI, QUALITY_QHD, QUALITY_2K, QUALITY_8KUHD, QUALITY_TIME_LAPSE_LOW , QUALITY_TIME_LAPSE_HIGH, QUALITY_TIME_LAPSE_QCIF, QUALITY_TIME_LAPSE_CIF, QUALITY_TIME_LAPSE_480P, QUALITY_TIME_LAPSE_720P, QUALITY_TIME_LAPSE_1080P, QUALITY_TIME_LAPSE_QVGA, QUALITY_TIME_LAPSE_2160P, QUALITY_TIME_LAPSE_VGA, QUALITY_TIME_LAPSE_4KDCI, QUALITY_TIME_LAPSE_QHD, QUALITY_TIME_LAPSE_2K, QUALITY_TIME_LAPSE_8KUHD, QUALITY_HIGH_SPEED_LOW, QUALITY_HIGH_SPEED_HIGH, QUALITY_HIGH_SPEED_480P, QUALITY_HIGH_SPEED_720P, QUALITY_HIGH_SPEED_1080P, QUALITY_HIGH_SPEED_2160P, QUALITY_HIGH_SPEED_CIF, QUALITY_HIGH_SPEED_VGA, QUALITY_HIGH_SPEED_4KDCI, }) @Retention(RetentionPolicy.SOURCE) public @interface Quality {} /** * Default recording duration in seconds before the session is terminated. * This is useful for applications like MMS has limited file size requirement. Loading Loading @@ -385,9 +438,8 @@ public class CamcorderProfile 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. * Returns the default camcorder profile at the given quality level for the first back-facing * camera on the device. 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) */ Loading @@ -404,8 +456,7 @@ public class CamcorderProfile } /** * Returns the camcorder profile for the given camera at the given * quality level. * Returns the default 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 Loading Loading @@ -457,6 +508,7 @@ public class CamcorderProfile * @see #QUALITY_HIGH_SPEED_720P * @see #QUALITY_HIGH_SPEED_1080P * @see #QUALITY_HIGH_SPEED_2160P * @throws IllegalArgumentException if quality is not one of the defined QUALITY_ values. */ public static CamcorderProfile get(int cameraId, int quality) { if (!((quality >= QUALITY_LIST_START && Loading @@ -472,7 +524,119 @@ public class CamcorderProfile } /** * Returns true if camcorder profile exists for the first back-facing * Returns all encoder profiles of a 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. Numeric camera ids parsed from the list received by * invoking {@link CameraManager#getCameraIdList} can be used as long as they * are {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE} * and not * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL EXTERNAL}. * @param quality the target quality level for the camcorder profile. * @return null if there are no encoder profiles defined for the quality level for the * given camera. * @throws IllegalArgumentException if quality is not one of the defined QUALITY_ values. * @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 */ @Nullable public static EncoderProfiles getAll( @NonNull String cameraId, @Quality 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); } // TODO: get all profiles int id; try { id = Integer.valueOf(cameraId); } catch (NumberFormatException e) { return null; } CamcorderProfile cp = native_get_camcorder_profile(id, quality); if (cp == null) { return null; }; EncoderProfiles.AudioProfile[] audioProfiles; // timelapse profiles do not list audio profiles if (cp.quality >= QUALITY_TIME_LAPSE_LIST_START && cp.quality <= QUALITY_TIME_LAPSE_LIST_END) { audioProfiles = new EncoderProfiles.AudioProfile[] { }; } else { audioProfiles = new EncoderProfiles.AudioProfile[] { new EncoderProfiles.AudioProfile( cp.audioCodec, cp.audioChannels, cp.audioSampleRate, cp.audioBitRate) }; } return new EncoderProfiles( cp.duration, cp.fileFormat, new EncoderProfiles.VideoProfile[] { new EncoderProfiles.VideoProfile( cp.videoCodec, cp.videoFrameWidth, cp.videoFrameHeight, cp.videoFrameRate, cp.videoBitRate, 0 /* TODO: get profile */) }, audioProfiles); } /** * Returns true if a camcorder profile exists for the first back-facing * camera at the given quality level. * * <p> Loading Loading @@ -507,7 +671,7 @@ public class CamcorderProfile } /** * Returns true if camcorder profile exists for the given camera at * Returns true if a camcorder profile exists for the given camera at * the given quality level. * * <p> Loading
media/java/android/media/EncoderProfiles.java 0 → 100644 +351 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.NonNull; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * Describes a set of encoding profiles for a given media (audio and/or video) profile. * These settings are read-only. * * <p>Currently, this is used to describe camera recording profile with more detail than {@link * CamcorderProfile}, by providing encoding parameters for more than just the default audio * and/or video codec. * * <p>The compressed output from a camera recording session contains two tracks: * one for audio and one for video. * <p>In the future audio-only recording profiles may be defined. * * <p>Each media profile specifies a set of audio and a set of video specific settings. * <ul> * <li> The file output format * <li> Default file duration * <p>Video-specific settings are: * <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> Video encoder profile. * <p>Audio-specific settings are: * <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 EncoderProfiles { /** * Default recording duration in seconds before the session is terminated. * This is useful for applications like MMS has limited file size requirement. * This could be 0 if there is no default recording duration. */ public int getDurationSeconds() { return durationSecs; } /** * Recommended output file format * @see android.media.MediaRecorder.OutputFormat */ public int getFileFormat() { return fileFormat; } /** * Configuration for a video encoder. */ public static class VideoProfile { /** * The video encoder being used for the video track * @see android.media.MediaRecorder.VideoEncoder */ public int getCodec() { return codec; } /** * The media type of the video encoder being used for the video track * @see android.media.MediaFormat#KEY_MIME */ public @NonNull String getMediaType() { if (codec == MediaRecorder.VideoEncoder.H263) { return MediaFormat.MIMETYPE_VIDEO_H263; } else if (codec == MediaRecorder.VideoEncoder.H264) { return MediaFormat.MIMETYPE_VIDEO_AVC; } else if (codec == MediaRecorder.VideoEncoder.MPEG_4_SP) { return MediaFormat.MIMETYPE_VIDEO_MPEG4; } else if (codec == MediaRecorder.VideoEncoder.VP8) { return MediaFormat.MIMETYPE_VIDEO_VP8; } else if (codec == MediaRecorder.VideoEncoder.HEVC) { return MediaFormat.MIMETYPE_VIDEO_HEVC; } // we should never be here throw new RuntimeException("Unknown codec"); } /** * The target video output bitrate in bits per second * <p> * This is the target recorded video output bitrate 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 CamcorderProfile#QUALITY_HIGH_SPEED_LOW} to {@link * CamcorderProfile#QUALITY_HIGH_SPEED_2160P}), this is the bitrate 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 bitrate that is corresponding to * the desired recording output bit rate (i.e., the encoded video bitrate during normal * playback) via {@link MediaRecorder#setVideoEncodingBitRate}. For example, if {@link * CamcorderProfile#QUALITY_HIGH_SPEED_720P} advertises 240fps {@link #getFrameRate} and * 64Mbps {@link #getBitrate} in the high speed VideoProfile, 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 #getBitrate} * 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 VideoProfile. * </p> * * @see #getFrameRate * @see MediaRecorder * @see MediaCodec * @see MediaFormat */ public int getBitrate() { return bitrate; } /** * 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 CamcorderProfile#QUALITY_HIGH_SPEED_LOW} to {@link * CamcorderProfile#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 * CamcorderProfile#QUALITY_HIGH_SPEED_720P} advertises 240fps {@link #getFrameRate} * in the VideoProfile, 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 VideoProfile. * </p> * * @see #getBitrate * @see MediaRecorder * @see MediaCodec * @see MediaFormat */ public int getFrameRate() { return frameRate; } /** * The target video frame width in pixels */ public int getWidth() { return width; } /** * The target video frame height in pixels */ public int getHeight() { return height; } /** * The video encoder profile being used for the video track. * <p> * This value is 0 if there is no profile defined for the video codec. * * @see MediaRecorder#setVideoEncodingProfileLevel * @see MediaFormat#KEY_PROFILE */ public int getProfile() { return profile; } // Constructor called by JNI and CamcorderProfile /* package private */ VideoProfile(int codec, int width, int height, int frameRate, int bitrate, int profile) { this.codec = codec; this.width = width; this.height = height; this.frameRate = frameRate; this.bitrate = bitrate; this.profile = profile; } private int codec; private int width; private int height; private int frameRate; private int bitrate; private int profile; } /** * Returns the defined audio encoder profiles. * <p> * The list may be empty. This means there are no audio encoder * profiles defined. Otherwise, the first profile is the default * audio profile. */ public @NonNull List<AudioProfile> getAudioProfiles() { return audioProfiles; } /** * Returns the defined video encoder profiles. * <p> * The list may be empty. This means there are no video encoder * profiles defined. Otherwise, the first profile is the default * video profile. */ public @NonNull List<VideoProfile> getVideoProfiles() { return videoProfiles; } /** * Configuration for an audio encoder. */ public static class AudioProfile { /** * The audio encoder being used for the audio track. * @see android.media.MediaRecorder.AudioEncoder */ public int getCodec() { return codec; } /** * The media type of the audio encoder being used for the video track * @see android.media.MediaFormat#KEY_MIME */ public @NonNull String getMediaType() { if (codec == MediaRecorder.AudioEncoder.AMR_NB) { return MediaFormat.MIMETYPE_AUDIO_AMR_NB; } else if (codec == MediaRecorder.AudioEncoder.AMR_WB) { return MediaFormat.MIMETYPE_AUDIO_AMR_WB; } else if (codec == MediaRecorder.AudioEncoder.AAC || codec == MediaRecorder.AudioEncoder.HE_AAC || codec == MediaRecorder.AudioEncoder.AAC_ELD) { return MediaFormat.MIMETYPE_AUDIO_AAC; } else if (codec == MediaRecorder.AudioEncoder.VORBIS) { return MediaFormat.MIMETYPE_AUDIO_VORBIS; } else if (codec == MediaRecorder.AudioEncoder.OPUS) { return MediaFormat.MIMETYPE_AUDIO_OPUS; } // we should never be here throw new RuntimeException("Unknown codec"); } /** * The target audio output bitrate in bits per second */ public int getBitrate() { return bitrate; } /** * The audio sampling rate used for the audio track */ public int getSampleRate() { return sampleRate; } /** * The number of audio channels used for the audio track */ public int getChannels() { return channels; } /** * The audio encoder profile being used for the audio track * <p> * This value is 0 if there is no profile defined for the audio codec. * @see MediaFormat#KEY_PROFILE */ public int getProfile() { if (codec == MediaRecorder.AudioEncoder.AAC) { return MediaCodecInfo.CodecProfileLevel.AACObjectMain; } else if (codec == MediaRecorder.AudioEncoder.HE_AAC) { return MediaCodecInfo.CodecProfileLevel.AACObjectHE; } else if (codec == MediaRecorder.AudioEncoder.AAC_ELD) { return MediaCodecInfo.CodecProfileLevel.AACObjectELD; } return 0; } // Constructor called by JNI and CamcorderProfile /* package private */ AudioProfile( int codec, int channels, int sampleRate, int bitrate) { this.codec = codec; this.channels = channels; this.sampleRate = sampleRate; this.bitrate = bitrate; } private int codec; private int channels; private int sampleRate; private int bitrate; } //static { // System.loadLibrary("media_jni"); //native_init(); //} private int durationSecs; private int fileFormat; // non-modifiable lists private @NonNull List<AudioProfile> audioProfiles; private @NonNull List<VideoProfile> videoProfiles; // Constructor called by JNI and CamcorderProfile /* package private */ EncoderProfiles( int duration, int fileFormat, VideoProfile[] videoProfiles, AudioProfile[] audioProfiles) { this.durationSecs = duration; this.fileFormat = fileFormat; this.videoProfiles = Collections.unmodifiableList(Arrays.asList(videoProfiles)); this.audioProfiles = Collections.unmodifiableList(Arrays.asList(audioProfiles)); } }
media/java/android/media/MediaRecorder.java +41 −1 File changed.Preview size limit exceeded, changes collapsed. Show changes