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