/* * 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.IntDef; import android.annotation.NonNull; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; 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. * *

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. * *

The compressed output from a camera recording session contains two tracks: * one for audio and one for video. *

In the future audio-only recording profiles may be defined. * *

Each media profile specifies a set of audio and a set of video specific settings. *

*/ public final class EncoderProfiles { /** * Default recording duration in seconds before the session is terminated. * This is useful for applications like MMS that have a limited file size requirement. * This could be 0 if there is no default recording duration. */ public int getDefaultDurationSeconds() { return durationSecs; } /** * Recommended output file format * @see android.media.MediaRecorder.OutputFormat */ public @MediaRecorder.OutputFormatValues int getRecommendedFileFormat() { return fileFormat; } /** * Configuration for a video encoder. */ public final static class VideoProfile { /** * The video encoder being used for the video track * @see android.media.MediaRecorder.VideoEncoder */ public @MediaRecorder.VideoEncoderValues 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; } else if (codec == MediaRecorder.VideoEncoder.VP9) { return MediaFormat.MIMETYPE_VIDEO_VP9; } else if (codec == MediaRecorder.VideoEncoder.DOLBY_VISION) { return MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION; } else if (codec == MediaRecorder.VideoEncoder.AV1) { return MediaFormat.MIMETYPE_VIDEO_AV1; } // we should never be here throw new RuntimeException("Unknown codec"); } /** * The target video output bitrate in bits per second *

* 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. *

* * @see #getFrameRate * @see MediaRecorder * @see MediaCodec * @see MediaFormat */ public int getBitrate() { return bitrate; } /** * The target video frame rate in frames per second. *

* 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. *

* * @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. *

* This value is negative if there is no profile defined for the video codec. * * @see MediaRecorder#setVideoEncodingProfileLevel * @see MediaFormat#KEY_PROFILE */ public int getProfile() { return profile; } /** * The bit depth of the encoded video. *

* This value is effectively 8 or 10, but some devices may * support additional values. */ public int getBitDepth() { return bitDepth; } /** * The chroma subsampling of the encoded video. *

* For most devices this is always YUV_420 but some devices may * support additional values. * * @see #YUV_420 * @see #YUV_422 * @see #YUV_444 */ public @ChromaSubsampling int getChromaSubsampling() { return chromaSubsampling; } /** * The HDR format of the encoded video. *

* This is one of the HDR_ values. * @see #HDR_NONE * @see #HDR_HLG * @see #HDR_HDR10 * @see #HDR_HDR10PLUS * @see #HDR_DOLBY_VISION */ public @HdrFormat int getHdrFormat() { return hdrFormat; } // Constructor called by JNI and CamcorderProfile /* package private */ VideoProfile(int codec, int width, int height, int frameRate, int bitrate, int profile, int chromaSubsampling, int bitDepth, int hdrFormat) { this.codec = codec; this.width = width; this.height = height; this.frameRate = frameRate; this.bitrate = bitrate; this.profile = profile; this.chromaSubsampling = chromaSubsampling; this.bitDepth = bitDepth; this.hdrFormat = hdrFormat; } /* package private */ VideoProfile(int codec, int width, int height, int frameRate, int bitrate, int profile) { this(codec, width, height, frameRate, bitrate, profile, YUV_420, 8 /* bitDepth */, HDR_NONE); } private int codec; private int width; private int height; private int frameRate; private int bitrate; private int profile; private int chromaSubsampling; private int bitDepth; private int hdrFormat; /** @hide */ @IntDef({ HDR_NONE, HDR_HLG, HDR_HDR10, HDR_HDR10PLUS, HDR_DOLBY_VISION, }) @Retention(RetentionPolicy.SOURCE) public @interface HdrFormat {} /** Not HDR (SDR). *

* An HDR format specifying SDR (Standard Dynamic * Range) recording. */ public static final int HDR_NONE = 0; /** HLG (Hybrid-Log Gamma). *

* An HDR format specifying HLG. */ public static final int HDR_HLG = 1; /** HDR10. *

* An HDR format specifying HDR10. */ public static final int HDR_HDR10 = 2; /** HDR10+. *

* An HDR format specifying HDR10+. */ public static final int HDR_HDR10PLUS = 3; /** * Dolby Vision *

* An HDR format specifying Dolby Vision. For this format * the codec is always a Dolby Vision encoder. The encoder * profile specifies which Dolby Vision version is being * used. * * @see #getProfile */ public static final int HDR_DOLBY_VISION = 4; /** @hide */ @IntDef({ YUV_420, YUV_422, YUV_444, }) @Retention(RetentionPolicy.SOURCE) public @interface ChromaSubsampling {} /** YUV 4:2:0. *

* A chroma subsampling where the U and V planes are subsampled * by 2 both horizontally and vertically. */ public static final int YUV_420 = 0; /** YUV 4:2:2. *

* A chroma subsampling where the U and V planes are subsampled * by 2 horizontally alone. */ public static final int YUV_422 = 1; /** YUV 4:4:4. *

* A chroma subsampling where the U and V planes are not * subsampled. */ public static final int YUV_444 = 2; } /** * Returns the defined audio encoder profiles. *

* 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 getAudioProfiles() { return audioProfiles; } /** * Returns the defined video encoder profiles. *

* 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 getVideoProfiles() { return videoProfiles; } /** * Configuration for an audio encoder. */ public final static class AudioProfile { /** * The audio encoder being used for the audio track. * @see android.media.MediaRecorder.AudioEncoder */ public @MediaRecorder.AudioEncoderValues 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 *

* This value is negative 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 profile; } // Constructor called by JNI and CamcorderProfile /* package private */ AudioProfile( int codec, int channels, int sampleRate, int bitrate, int profile) { this.codec = codec; this.channels = channels; this.sampleRate = sampleRate; this.bitrate = bitrate; this.profile = profile; } private int codec; private int channels; private int sampleRate; private int bitrate; private int profile; // this contains the profile if codec itself does not } private int durationSecs; private int fileFormat; // non-modifiable lists private @NonNull List audioProfiles; private @NonNull List 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)); } }