1 /* 2 * Copyright 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.camera.core.impl; 18 19 import static android.media.MediaRecorder.AudioEncoder.AAC; 20 import static android.media.MediaRecorder.AudioEncoder.AAC_ELD; 21 import static android.media.MediaRecorder.AudioEncoder.AMR_NB; 22 import static android.media.MediaRecorder.AudioEncoder.AMR_WB; 23 import static android.media.MediaRecorder.AudioEncoder.HE_AAC; 24 import static android.media.MediaRecorder.AudioEncoder.OPUS; 25 import static android.media.MediaRecorder.AudioEncoder.VORBIS; 26 import static android.media.MediaRecorder.VideoEncoder.AV1; 27 import static android.media.MediaRecorder.VideoEncoder.DOLBY_VISION; 28 import static android.media.MediaRecorder.VideoEncoder.H263; 29 import static android.media.MediaRecorder.VideoEncoder.H264; 30 import static android.media.MediaRecorder.VideoEncoder.HEVC; 31 import static android.media.MediaRecorder.VideoEncoder.MPEG_4_SP; 32 import static android.media.MediaRecorder.VideoEncoder.VP8; 33 import static android.media.MediaRecorder.VideoEncoder.VP9; 34 35 import static java.util.Collections.unmodifiableList; 36 37 import android.media.EncoderProfiles; 38 import android.media.MediaCodecInfo; 39 import android.media.MediaFormat; 40 import android.media.MediaRecorder; 41 import android.util.Size; 42 43 import androidx.annotation.IntDef; 44 45 import com.google.auto.value.AutoValue; 46 47 import org.jspecify.annotations.NonNull; 48 49 import java.lang.annotation.Retention; 50 import java.lang.annotation.RetentionPolicy; 51 import java.util.ArrayList; 52 import java.util.List; 53 54 /** 55 * EncoderProfilesProxy defines the get methods that is mapping to the fields of 56 * {@link EncoderProfiles}. 57 */ 58 public interface EncoderProfilesProxy { 59 60 /** Constant representing no codec profile. */ 61 int CODEC_PROFILE_NONE = -1; 62 63 /** @see EncoderProfiles#getDefaultDurationSeconds() */ getDefaultDurationSeconds()64 int getDefaultDurationSeconds(); 65 66 /** @see EncoderProfiles#getRecommendedFileFormat() */ getRecommendedFileFormat()67 int getRecommendedFileFormat(); 68 69 /** @see EncoderProfiles#getAudioProfiles() */ getAudioProfiles()70 @NonNull List<AudioProfileProxy> getAudioProfiles(); 71 72 /** @see EncoderProfiles#getVideoProfiles() */ getVideoProfiles()73 @NonNull List<VideoProfileProxy> getVideoProfiles(); 74 75 /** 76 * VideoProfileProxy defines the get methods that is mapping to the fields of 77 * {@link EncoderProfiles.VideoProfile}. 78 */ 79 @AutoValue 80 abstract class VideoProfileProxy { 81 82 /** Constant representing no media type. */ 83 public static final String MEDIA_TYPE_NONE = "video/none"; 84 85 /** Constant representing bit depth 8. */ 86 public static final int BIT_DEPTH_8 = 8; 87 88 /** Constant representing bit depth 10. */ 89 public static final int BIT_DEPTH_10 = 10; 90 91 @Retention(RetentionPolicy.SOURCE) 92 @IntDef({H263, H264, HEVC, VP8, MPEG_4_SP, VP9, DOLBY_VISION, AV1, 93 MediaRecorder.VideoEncoder.DEFAULT}) 94 public @interface VideoEncoder { 95 } 96 97 /** Creates a VideoProfileProxy instance. */ create( @ideoEncoder int codec, @NonNull String mediaType, int bitrate, int frameRate, int width, int height, int profile, int bitDepth, int chromaSubsampling, int hdrFormat)98 public static @NonNull VideoProfileProxy create( 99 @VideoEncoder int codec, 100 @NonNull String mediaType, 101 int bitrate, 102 int frameRate, 103 int width, 104 int height, 105 int profile, 106 int bitDepth, 107 int chromaSubsampling, 108 int hdrFormat) { 109 return new AutoValue_EncoderProfilesProxy_VideoProfileProxy( 110 codec, 111 mediaType, 112 bitrate, 113 frameRate, 114 width, 115 height, 116 profile, 117 bitDepth, 118 chromaSubsampling, 119 hdrFormat 120 ); 121 } 122 123 /** @see EncoderProfiles.VideoProfile#getCodec() */ 124 @VideoEncoder getCodec()125 public abstract int getCodec(); 126 127 /** @see EncoderProfiles.VideoProfile#getMediaType() */ getMediaType()128 public abstract @NonNull String getMediaType(); 129 130 /** @see EncoderProfiles.VideoProfile#getBitrate() */ getBitrate()131 public abstract int getBitrate(); 132 133 /** @see EncoderProfiles.VideoProfile#getFrameRate() */ getFrameRate()134 public abstract int getFrameRate(); 135 136 /** @see EncoderProfiles.VideoProfile#getWidth() */ getWidth()137 public abstract int getWidth(); 138 139 /** @see EncoderProfiles.VideoProfile#getHeight() */ getHeight()140 public abstract int getHeight(); 141 142 /** @see EncoderProfiles.VideoProfile#getProfile() */ getProfile()143 public abstract int getProfile(); 144 145 /** @see EncoderProfiles.VideoProfile#getBitDepth() */ getBitDepth()146 public abstract int getBitDepth(); 147 148 /** @see EncoderProfiles.VideoProfile#getChromaSubsampling() */ getChromaSubsampling()149 public abstract int getChromaSubsampling(); 150 151 /** @see EncoderProfiles.VideoProfile#getHdrFormat() */ getHdrFormat()152 public abstract int getHdrFormat(); 153 154 /** Returns video resolution equivalent to {@code new Size(getWidth(), getHeight())}. */ 155 @NonNull getResolution()156 public Size getResolution() { 157 return new Size(getWidth(), getHeight()); 158 } 159 } 160 161 /** 162 * AudioProfileProxy defines the get methods that is mapping to the fields of 163 * {@link EncoderProfiles.AudioProfile}. 164 */ 165 @AutoValue 166 abstract class AudioProfileProxy { 167 168 /** Constant representing no media type. */ 169 public static final String MEDIA_TYPE_NONE = "audio/none"; 170 171 @Retention(RetentionPolicy.SOURCE) 172 @IntDef({AAC, AAC_ELD, AMR_NB, AMR_WB, HE_AAC, OPUS, VORBIS, 173 MediaRecorder.AudioEncoder.DEFAULT}) 174 public @interface AudioEncoder { 175 } 176 177 /** Creates an AudioProfileProxy instance. */ create( @udioEncoder int codec, @NonNull String mediaType, int bitRate, int sampleRate, int channels, int profile)178 public static @NonNull AudioProfileProxy create( 179 @AudioEncoder int codec, 180 @NonNull String mediaType, 181 int bitRate, 182 int sampleRate, 183 int channels, 184 int profile) { 185 return new AutoValue_EncoderProfilesProxy_AudioProfileProxy( 186 codec, 187 mediaType, 188 bitRate, 189 sampleRate, 190 channels, 191 profile 192 ); 193 } 194 195 /** @see EncoderProfiles.AudioProfile#getCodec() */ 196 @AudioEncoder getCodec()197 public abstract int getCodec(); 198 199 /** @see EncoderProfiles.AudioProfile#getMediaType() */ getMediaType()200 public abstract @NonNull String getMediaType(); 201 202 /** @see EncoderProfiles.AudioProfile#getBitrate() */ getBitrate()203 public abstract int getBitrate(); 204 205 /** @see EncoderProfiles.AudioProfile#getSampleRate() */ getSampleRate()206 public abstract int getSampleRate(); 207 208 /** @see EncoderProfiles.AudioProfile#getChannels() */ getChannels()209 public abstract int getChannels(); 210 211 /** @see EncoderProfiles.AudioProfile#getProfile() */ getProfile()212 public abstract int getProfile(); 213 } 214 215 /** 216 * An implementation of {@link EncoderProfilesProxy} that is immutable. 217 */ 218 @AutoValue 219 abstract class ImmutableEncoderProfilesProxy implements EncoderProfilesProxy { 220 221 /** Creates an EncoderProfilesProxy instance. */ create( int defaultDurationSeconds, int recommendedFileFormat, @NonNull List<AudioProfileProxy> audioProfiles, @NonNull List<VideoProfileProxy> videoProfiles)222 public static @NonNull ImmutableEncoderProfilesProxy create( 223 int defaultDurationSeconds, 224 int recommendedFileFormat, 225 @NonNull List<AudioProfileProxy> audioProfiles, 226 @NonNull List<VideoProfileProxy> videoProfiles) { 227 return new AutoValue_EncoderProfilesProxy_ImmutableEncoderProfilesProxy( 228 defaultDurationSeconds, 229 recommendedFileFormat, 230 unmodifiableList(new ArrayList<>(audioProfiles)), 231 unmodifiableList(new ArrayList<>(videoProfiles)) 232 ); 233 } 234 } 235 236 /** 237 * Returns a mime-type string for the given video codec type. 238 * 239 * @return A mime-type string or {@link VideoProfileProxy#MEDIA_TYPE_NONE} if the codec type is 240 * {@link MediaRecorder.VideoEncoder#DEFAULT}, as this type is under-defined and cannot be 241 * resolved to a specific mime type without more information. 242 */ getVideoCodecMimeType( @ideoProfileProxy.VideoEncoder int codec)243 static @NonNull String getVideoCodecMimeType( 244 @VideoProfileProxy.VideoEncoder int codec) { 245 switch (codec) { 246 // Mime-type definitions taken from 247 // frameworks/av/media/libstagefright/foundation/MediaDefs.cpp 248 case H263: 249 return MediaFormat.MIMETYPE_VIDEO_H263; 250 case H264: 251 return MediaFormat.MIMETYPE_VIDEO_AVC; 252 case HEVC: 253 return MediaFormat.MIMETYPE_VIDEO_HEVC; 254 case VP8: 255 return MediaFormat.MIMETYPE_VIDEO_VP8; 256 case MPEG_4_SP: 257 return MediaFormat.MIMETYPE_VIDEO_MPEG4; 258 case VP9: 259 return MediaFormat.MIMETYPE_VIDEO_VP9; 260 case DOLBY_VISION: 261 return MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION; 262 case AV1: 263 return MediaFormat.MIMETYPE_VIDEO_AV1; 264 case MediaRecorder.VideoEncoder.DEFAULT: 265 break; 266 } 267 268 return VideoProfileProxy.MEDIA_TYPE_NONE; 269 } 270 271 /** 272 * Returns a mime-type string for the given audio codec type. 273 * 274 * @return A mime-type string or {@link AudioProfileProxy#MEDIA_TYPE_NONE} if the codec type is 275 * {@link android.media.MediaRecorder.AudioEncoder#DEFAULT}, as this type is under-defined 276 * and cannot be resolved to a specific mime type without more information. 277 */ getAudioCodecMimeType(@udioProfileProxy.AudioEncoder int codec)278 static @NonNull String getAudioCodecMimeType(@AudioProfileProxy.AudioEncoder int codec) { 279 // Mime-type definitions taken from 280 // frameworks/av/media/libstagefright/foundation/MediaDefs.cpp 281 switch (codec) { 282 case AAC: // Should use aac-profile LC 283 case HE_AAC: // Should use aac-profile HE 284 case AAC_ELD: // Should use aac-profile ELD 285 return MediaFormat.MIMETYPE_AUDIO_AAC; 286 case AMR_NB: 287 return MediaFormat.MIMETYPE_AUDIO_AMR_NB; 288 case AMR_WB: 289 return MediaFormat.MIMETYPE_AUDIO_AMR_WB; 290 case OPUS: 291 return MediaFormat.MIMETYPE_AUDIO_OPUS; 292 case VORBIS: 293 return MediaFormat.MIMETYPE_AUDIO_VORBIS; 294 case MediaRecorder.AudioEncoder.DEFAULT: 295 break; 296 } 297 298 return AudioProfileProxy.MEDIA_TYPE_NONE; 299 } 300 301 /** 302 * Returns the required audio profile for the given audio encoder. 303 * 304 * <p>For example, this can be used to differentiate between AAC encoders 305 * {@link android.media.MediaRecorder.AudioEncoder#AAC}, 306 * {@link android.media.MediaRecorder.AudioEncoder#AAC_ELD}, 307 * and {@link android.media.MediaRecorder.AudioEncoder#HE_AAC}. 308 * Should be used with the {@link MediaCodecInfo.CodecProfileLevel#profile} field. 309 * 310 * @return The profile required by the audio codec. If no profile is required, returns 311 * {@link EncoderProfilesProxy#CODEC_PROFILE_NONE}. 312 */ getRequiredAudioProfile(@udioProfileProxy.AudioEncoder int codec)313 static int getRequiredAudioProfile(@AudioProfileProxy.AudioEncoder int codec) { 314 switch (codec) { 315 case AAC: 316 return MediaCodecInfo.CodecProfileLevel.AACObjectLC; 317 case AAC_ELD: 318 return MediaCodecInfo.CodecProfileLevel.AACObjectELD; 319 case HE_AAC: 320 return MediaCodecInfo.CodecProfileLevel.AACObjectHE; 321 default: 322 return EncoderProfilesProxy.CODEC_PROFILE_NONE; 323 } 324 } 325 } 326