• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 android.media;
18 
19 import android.annotation.NonNull;
20 import android.content.ContentResolver;
21 import android.net.Uri;
22 import android.os.Build;
23 import android.os.Bundle;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 import android.util.Log;
27 
28 import com.android.modules.annotation.MinSdk;
29 
30 import org.xmlpull.v1.XmlPullParser;
31 import org.xmlpull.v1.XmlPullParserException;
32 
33 import java.util.ArrayList;
34 import java.util.HashMap;
35 import java.util.HashSet;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Set;
39 
40 /**
41  ApplicationMediaCapabilities is an immutable class that encapsulates an application's capabilities
42  for handling newer video codec format and media features.
43 
44  <p>
45  Android 12 introduces Compatible media transcoding feature.  See
46  <a href="https://developer.android.com/about/versions/12/features#compatible_media_transcoding">
47  Compatible media transcoding</a>. By default, Android assumes apps can support playback of all
48  media formats. Apps that would like to request that media be transcoded into a more compatible
49  format should declare their media capabilities in a media_capabilities.xml resource file and add it
50  as a property tag in the AndroidManifest.xml file. Here is a example:
51  <pre>
52  {@code
53  <media-capabilities xmlns:android="http://schemas.android.com/apk/res/android">
54      <format android:name="HEVC" supported="true"/>
55      <format android:name="HDR10" supported="false"/>
56      <format android:name="HDR10Plus" supported="false"/>
57  </media-capabilities>
58  }
59  </pre>
60  The ApplicationMediaCapabilities class is generated from this xml and used by the platform to
61  represent an application's media capabilities in order to determine whether modern media files need
62  to be transcoded for that application.
63  </p>
64 
65  <p>
66  ApplicationMediaCapabilities objects can also be built by applications at runtime for use with
67  {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)} to provide more
68  control over the transcoding that is built into the platform. ApplicationMediaCapabilities
69  provided by applications at runtime like this override the default manifest capabilities for that
70  media access.The object could be build either through {@link #createFromXml(XmlPullParser)} or
71  through the builder class {@link ApplicationMediaCapabilities.Builder}
72 
73  <h3> Video Codec Support</h3>
74  <p>
75  Newer video codes include HEVC, VP9 and AV1. Application only needs to indicate their support
76  for newer format with this class as they are assumed to support older format like h.264.
77 
78  <h3>Capability of handling HDR(high dynamic range) video</h3>
79  <p>
80  There are four types of HDR video(Dolby-Vision, HDR10, HDR10+, HLG) supported by the platform,
81  application will only need to specify individual types they supported.
82  */
83 @MinSdk(Build.VERSION_CODES.S)
84 public final class ApplicationMediaCapabilities implements Parcelable {
85     private static final String TAG = "ApplicationMediaCapabilities";
86 
87     /** List of supported video codec mime types. */
88     private Set<String> mSupportedVideoMimeTypes = new HashSet<>();
89 
90     /** List of unsupported video codec mime types. */
91     private Set<String> mUnsupportedVideoMimeTypes = new HashSet<>();
92 
93     /** List of supported hdr types. */
94     private Set<String> mSupportedHdrTypes = new HashSet<>();
95 
96     /** List of unsupported hdr types. */
97     private Set<String> mUnsupportedHdrTypes = new HashSet<>();
98 
99     private boolean mIsSlowMotionSupported = false;
100 
ApplicationMediaCapabilities(Builder b)101     private ApplicationMediaCapabilities(Builder b) {
102         mSupportedVideoMimeTypes.addAll(b.getSupportedVideoMimeTypes());
103         mUnsupportedVideoMimeTypes.addAll(b.getUnsupportedVideoMimeTypes());
104         mSupportedHdrTypes.addAll(b.getSupportedHdrTypes());
105         mUnsupportedHdrTypes.addAll(b.getUnsupportedHdrTypes());
106         mIsSlowMotionSupported = b.mIsSlowMotionSupported;
107     }
108 
109     /**
110      * Query if a video codec format is supported by the application.
111      * <p>
112      * If the application has not specified supporting the format or not, this will return false.
113      * Use {@link #isFormatSpecified(String)} to query if a format is specified or not.
114      *
115      * @param videoMime The mime type of the video codec format. Must be the one used in
116      * {@link MediaFormat#KEY_MIME}.
117      * @return true if application supports the video codec format, false otherwise.
118      */
isVideoMimeTypeSupported( @onNull String videoMime)119     public boolean isVideoMimeTypeSupported(
120             @NonNull String videoMime) {
121         if (mSupportedVideoMimeTypes.contains(videoMime.toLowerCase())) {
122             return true;
123         }
124         return false;
125     }
126 
127     /**
128      * Query if a HDR type is supported by the application.
129      * <p>
130      * If the application has not specified supporting the format or not, this will return false.
131      * Use {@link #isFormatSpecified(String)} to query if a format is specified or not.
132      *
133      * @param hdrType The type of the HDR format.
134      * @return true if application supports the HDR format, false otherwise.
135      */
isHdrTypeSupported( @onNull @ediaFeature.MediaHdrType String hdrType)136     public boolean isHdrTypeSupported(
137             @NonNull @MediaFeature.MediaHdrType String hdrType) {
138         if (mSupportedHdrTypes.contains(hdrType)) {
139             return true;
140         }
141         return false;
142     }
143 
144     /**
145      * Query if a format is specified by the application.
146      * <p>
147      * The format could be either the video format or the hdr format.
148      *
149      * @param format The name of the format.
150      * @return true if application specifies the format, false otherwise.
151      */
isFormatSpecified(@onNull String format)152     public boolean isFormatSpecified(@NonNull String format) {
153         if (mSupportedVideoMimeTypes.contains(format) || mUnsupportedVideoMimeTypes.contains(format)
154                 || mSupportedHdrTypes.contains(format) || mUnsupportedHdrTypes.contains(format)) {
155             return true;
156 
157         }
158         return false;
159     }
160 
161     @Override
describeContents()162     public int describeContents() {
163         return 0;
164     }
165 
166     @Override
writeToParcel(@onNull Parcel dest, int flags)167     public void writeToParcel(@NonNull Parcel dest, int flags) {
168         // Write out the supported video mime types.
169         dest.writeInt(mSupportedVideoMimeTypes.size());
170         for (String cap : mSupportedVideoMimeTypes) {
171             dest.writeString(cap);
172         }
173         // Write out the unsupported video mime types.
174         dest.writeInt(mUnsupportedVideoMimeTypes.size());
175         for (String cap : mUnsupportedVideoMimeTypes) {
176             dest.writeString(cap);
177         }
178         // Write out the supported hdr types.
179         dest.writeInt(mSupportedHdrTypes.size());
180         for (String cap : mSupportedHdrTypes) {
181             dest.writeString(cap);
182         }
183         // Write out the unsupported hdr types.
184         dest.writeInt(mUnsupportedHdrTypes.size());
185         for (String cap : mUnsupportedHdrTypes) {
186             dest.writeString(cap);
187         }
188         // Write out the supported slow motion.
189         dest.writeBoolean(mIsSlowMotionSupported);
190     }
191 
192     @Override
toString()193     public String toString() {
194         String caps = new String(
195                 "Supported Video MimeTypes: " + mSupportedVideoMimeTypes.toString());
196         caps += "Unsupported Video MimeTypes: " + mUnsupportedVideoMimeTypes.toString();
197         caps += "Supported HDR types: " + mSupportedHdrTypes.toString();
198         caps += "Unsupported HDR types: " + mUnsupportedHdrTypes.toString();
199         caps += "Supported slow motion: " + mIsSlowMotionSupported;
200         return caps;
201     }
202 
203     @NonNull
204     public static final Creator<ApplicationMediaCapabilities> CREATOR =
205             new Creator<ApplicationMediaCapabilities>() {
206                 public ApplicationMediaCapabilities createFromParcel(Parcel in) {
207                     ApplicationMediaCapabilities.Builder builder =
208                             new ApplicationMediaCapabilities.Builder();
209 
210                     // Parse supported video codec mime types.
211                     int count = in.readInt();
212                     for (int readCount = 0; readCount < count; ++readCount) {
213                         builder.addSupportedVideoMimeType(in.readString());
214                     }
215 
216                     // Parse unsupported video codec mime types.
217                     count = in.readInt();
218                     for (int readCount = 0; readCount < count; ++readCount) {
219                         builder.addUnsupportedVideoMimeType(in.readString());
220                     }
221 
222                     // Parse supported hdr types.
223                     count = in.readInt();
224                     for (int readCount = 0; readCount < count; ++readCount) {
225                         builder.addSupportedHdrType(in.readString());
226                     }
227 
228                     // Parse unsupported hdr types.
229                     count = in.readInt();
230                     for (int readCount = 0; readCount < count; ++readCount) {
231                         builder.addUnsupportedHdrType(in.readString());
232                     }
233 
234                     boolean supported = in.readBoolean();
235                     builder.setSlowMotionSupported(supported);
236 
237                     return builder.build();
238                 }
239 
240                 public ApplicationMediaCapabilities[] newArray(int size) {
241                     return new ApplicationMediaCapabilities[size];
242                 }
243             };
244 
245     /**
246      * Query the video codec mime types supported by the application.
247      * @return List of supported video codec mime types. The list will be empty if there are none.
248      */
249     @NonNull
getSupportedVideoMimeTypes()250     public List<String> getSupportedVideoMimeTypes() {
251         return new ArrayList<>(mSupportedVideoMimeTypes);
252     }
253 
254     /**
255      * Query the video codec mime types that are not supported by the application.
256      * @return List of unsupported video codec mime types. The list will be empty if there are none.
257      */
258     @NonNull
getUnsupportedVideoMimeTypes()259     public List<String> getUnsupportedVideoMimeTypes() {
260         return new ArrayList<>(mUnsupportedVideoMimeTypes);
261     }
262 
263     /**
264      * Query all hdr types that are supported by the application.
265      * @return List of supported hdr types. The list will be empty if there are none.
266      */
267     @NonNull
getSupportedHdrTypes()268     public List<String> getSupportedHdrTypes() {
269         return new ArrayList<>(mSupportedHdrTypes);
270     }
271 
272     /**
273      * Query all hdr types that are not supported by the application.
274      * @return List of unsupported hdr types. The list will be empty if there are none.
275      */
276     @NonNull
getUnsupportedHdrTypes()277     public List<String> getUnsupportedHdrTypes()  {
278         return new ArrayList<>(mUnsupportedHdrTypes);
279     }
280 
281     /**
282      * Whether handling of slow-motion video is supported
283      * @hide
284      */
isSlowMotionSupported()285     public boolean isSlowMotionSupported() {
286         return mIsSlowMotionSupported;
287     }
288 
289     /**
290      * Creates {@link ApplicationMediaCapabilities} from an xml.
291      *
292      * The xml's syntax is the same as the media_capabilities.xml used by the AndroidManifest.xml.
293      * <p> Here is an example:
294      *
295      * <pre>
296      * {@code
297      * <media-capabilities xmlns:android="http://schemas.android.com/apk/res/android">
298      *     <format android:name="HEVC" supported="true"/>
299      *     <format android:name="HDR10" supported="false"/>
300      *     <format android:name="HDR10Plus" supported="false"/>
301      * </media-capabilities>
302      * }
303      * </pre>
304      * <p>
305      *
306      * @param xmlParser The underlying {@link XmlPullParser} that will read the xml.
307      * @return An ApplicationMediaCapabilities object.
308      * @throws UnsupportedOperationException if the capabilities in xml config are invalid or
309      * incompatible.
310      */
311     // TODO: Add developer.android.com link for the format of the xml.
312     @NonNull
createFromXml(@onNull XmlPullParser xmlParser)313     public static ApplicationMediaCapabilities createFromXml(@NonNull XmlPullParser xmlParser) {
314         ApplicationMediaCapabilities.Builder builder = new ApplicationMediaCapabilities.Builder();
315         builder.parseXml(xmlParser);
316         return builder.build();
317     }
318 
319     /**
320      * Builder class for {@link ApplicationMediaCapabilities} objects.
321      * Use this class to configure and create an ApplicationMediaCapabilities instance. Builder
322      * could be created from an existing ApplicationMediaCapabilities object, from a xml file or
323      * MediaCodecList.
324      * //TODO(hkuang): Add xml parsing support to the builder.
325      */
326     public final static class Builder {
327         /** List of supported video codec mime types. */
328         private Set<String> mSupportedVideoMimeTypes = new HashSet<>();
329 
330         /** List of supported hdr types. */
331         private Set<String> mSupportedHdrTypes = new HashSet<>();
332 
333         /** List of unsupported video codec mime types. */
334         private Set<String> mUnsupportedVideoMimeTypes = new HashSet<>();
335 
336         /** List of unsupported hdr types. */
337         private Set<String> mUnsupportedHdrTypes = new HashSet<>();
338 
339         private boolean mIsSlowMotionSupported = false;
340 
341         /* Map to save the format read from the xml. */
342         private Map<String, Boolean> mFormatSupportedMap =  new HashMap<String, Boolean>();
343 
344         /**
345          * Constructs a new Builder with all the supports default to false.
346          */
Builder()347         public Builder() {
348         }
349 
parseXml(@onNull XmlPullParser xmlParser)350         private void parseXml(@NonNull XmlPullParser xmlParser)
351                 throws UnsupportedOperationException {
352             if (xmlParser == null) {
353                 throw new IllegalArgumentException("XmlParser must not be null");
354             }
355 
356             try {
357                 while (xmlParser.next() != XmlPullParser.START_TAG) {
358                     continue;
359                 }
360 
361                 // Validates the tag is "media-capabilities".
362                 if (!xmlParser.getName().equals("media-capabilities")) {
363                     throw new UnsupportedOperationException("Invalid tag");
364                 }
365 
366                 xmlParser.next();
367                 while (xmlParser.getEventType() != XmlPullParser.END_TAG) {
368                     while (xmlParser.getEventType() != XmlPullParser.START_TAG) {
369                         if (xmlParser.getEventType() == XmlPullParser.END_DOCUMENT) {
370                             return;
371                         }
372                         xmlParser.next();
373                     }
374 
375                     // Validates the tag is "format".
376                     if (xmlParser.getName().equals("format")) {
377                         parseFormatTag(xmlParser);
378                     } else {
379                         throw new UnsupportedOperationException("Invalid tag");
380                     }
381                     while (xmlParser.getEventType() != XmlPullParser.END_TAG) {
382                         xmlParser.next();
383                     }
384                     xmlParser.next();
385                 }
386             } catch (XmlPullParserException xppe) {
387                 throw new UnsupportedOperationException("Ill-formatted xml file");
388             } catch (java.io.IOException ioe) {
389                 throw new UnsupportedOperationException("Unable to read xml file");
390             }
391         }
392 
parseFormatTag(XmlPullParser xmlParser)393         private void parseFormatTag(XmlPullParser xmlParser) {
394             String name = null;
395             String supported = null;
396             for (int i = 0; i < xmlParser.getAttributeCount(); i++) {
397                 String attrName = xmlParser.getAttributeName(i);
398                 if (attrName.equals("name")) {
399                     name = xmlParser.getAttributeValue(i);
400                 } else if (attrName.equals("supported")) {
401                     supported = xmlParser.getAttributeValue(i);
402                 } else {
403                     throw new UnsupportedOperationException("Invalid attribute name " + attrName);
404                 }
405             }
406 
407             if (name != null && supported != null) {
408                 if (!supported.equals("true") && !supported.equals("false")) {
409                     throw new UnsupportedOperationException(
410                             ("Supported value must be either true or false"));
411                 }
412                 boolean isSupported = Boolean.parseBoolean(supported);
413 
414                 // Check if the format is already found before.
415                 if (mFormatSupportedMap.get(name) != null && mFormatSupportedMap.get(name)
416                         != isSupported) {
417                     throw new UnsupportedOperationException(
418                             "Format: " + name + " has conflict supported value");
419                 }
420 
421                 switch (name) {
422                     case "HEVC":
423                         if (isSupported) {
424                             mSupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
425                         } else {
426                             mUnsupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
427                         }
428                         break;
429                     case "VP9":
430                         if (isSupported) {
431                             mSupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_VP9);
432                         } else {
433                             mUnsupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_VP9);
434                         }
435                         break;
436                     case "AV1":
437                         if (isSupported) {
438                             mSupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_AV1);
439                         } else {
440                             mUnsupportedVideoMimeTypes.add(MediaFormat.MIMETYPE_VIDEO_AV1);
441                         }
442                         break;
443                     case "HDR10":
444                         if (isSupported) {
445                             mSupportedHdrTypes.add(MediaFeature.HdrType.HDR10);
446                         } else {
447                             mUnsupportedHdrTypes.add(MediaFeature.HdrType.HDR10);
448                         }
449                         break;
450                     case "HDR10Plus":
451                         if (isSupported) {
452                             mSupportedHdrTypes.add(MediaFeature.HdrType.HDR10_PLUS);
453                         } else {
454                             mUnsupportedHdrTypes.add(MediaFeature.HdrType.HDR10_PLUS);
455                         }
456                         break;
457                     case "Dolby-Vision":
458                         if (isSupported) {
459                             mSupportedHdrTypes.add(MediaFeature.HdrType.DOLBY_VISION);
460                         } else {
461                             mUnsupportedHdrTypes.add(MediaFeature.HdrType.DOLBY_VISION);
462                         }
463                         break;
464                     case "HLG":
465                         if (isSupported) {
466                             mSupportedHdrTypes.add(MediaFeature.HdrType.HLG);
467                         } else {
468                             mUnsupportedHdrTypes.add(MediaFeature.HdrType.HLG);
469                         }
470                         break;
471                     case "SlowMotion":
472                         mIsSlowMotionSupported = isSupported;
473                         break;
474                     default:
475                         Log.w(TAG, "Invalid format name " + name);
476                 }
477                 // Save the name and isSupported into the map for validate later.
478                 mFormatSupportedMap.put(name, isSupported);
479             } else {
480                 throw new UnsupportedOperationException(
481                         "Format name and supported must both be specified");
482             }
483         }
484 
485         /**
486          * Builds a {@link ApplicationMediaCapabilities} object.
487          *
488          * @return a new {@link ApplicationMediaCapabilities} instance successfully initialized
489          * with all the parameters set on this <code>Builder</code>.
490          * @throws UnsupportedOperationException if the parameters set on the
491          *                                       <code>Builder</code> were incompatible, or if they
492          *                                       are not supported by the
493          *                                       device.
494          */
495         @NonNull
build()496         public ApplicationMediaCapabilities build() {
497             Log.d(TAG,
498                     "Building ApplicationMediaCapabilities with: (Supported HDR: "
499                             + mSupportedHdrTypes.toString() + " Unsupported HDR: "
500                             + mUnsupportedHdrTypes.toString() + ") (Supported Codec: "
501                             + " " + mSupportedVideoMimeTypes.toString() + " Unsupported Codec:"
502                             + mUnsupportedVideoMimeTypes.toString() + ") "
503                             + mIsSlowMotionSupported);
504 
505             // If hdr is supported, application must also support hevc.
506             if (!mSupportedHdrTypes.isEmpty() && !mSupportedVideoMimeTypes.contains(
507                     MediaFormat.MIMETYPE_VIDEO_HEVC)) {
508                 throw new UnsupportedOperationException("Only support HEVC mime type");
509             }
510             return new ApplicationMediaCapabilities(this);
511         }
512 
513         /**
514          * Adds a supported video codec mime type.
515          *
516          * @param codecMime Supported codec mime types. Must be one of the mime type defined
517          *                  in {@link MediaFormat}.
518          * @throws IllegalArgumentException if mime type is not valid.
519          */
520         @NonNull
addSupportedVideoMimeType( @onNull String codecMime)521         public Builder addSupportedVideoMimeType(
522                 @NonNull String codecMime) {
523             mSupportedVideoMimeTypes.add(codecMime);
524             return this;
525         }
526 
getSupportedVideoMimeTypes()527         private List<String> getSupportedVideoMimeTypes() {
528             return new ArrayList<>(mSupportedVideoMimeTypes);
529         }
530 
isValidVideoCodecMimeType(@onNull String codecMime)531         private boolean isValidVideoCodecMimeType(@NonNull String codecMime) {
532             if (!codecMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)
533                     && !codecMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)
534                     && !codecMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AV1)) {
535                 return false;
536             }
537             return true;
538         }
539 
540         /**
541          * Adds an unsupported video codec mime type.
542          *
543          * @param codecMime Unsupported codec mime type. Must be one of the mime type defined
544          *                  in {@link MediaFormat}.
545          * @throws IllegalArgumentException if mime type is not valid.
546          */
547         @NonNull
addUnsupportedVideoMimeType( @onNull String codecMime)548         public Builder addUnsupportedVideoMimeType(
549                 @NonNull String codecMime) {
550             if (!isValidVideoCodecMimeType(codecMime)) {
551                 throw new IllegalArgumentException("Invalid codec mime type: " + codecMime);
552             }
553             mUnsupportedVideoMimeTypes.add(codecMime);
554             return this;
555         }
556 
getUnsupportedVideoMimeTypes()557         private List<String> getUnsupportedVideoMimeTypes() {
558             return new ArrayList<>(mUnsupportedVideoMimeTypes);
559         }
560 
561         /**
562          * Adds a supported hdr type.
563          *
564          * @param hdrType Supported hdr type. Must be one of the String defined in
565          *                {@link MediaFeature.HdrType}.
566          * @throws IllegalArgumentException if hdrType is not valid.
567          */
568         @NonNull
addSupportedHdrType( @onNull @ediaFeature.MediaHdrType String hdrType)569         public Builder addSupportedHdrType(
570                 @NonNull @MediaFeature.MediaHdrType String hdrType) {
571             if (!isValidVideoCodecHdrType(hdrType)) {
572                 throw new IllegalArgumentException("Invalid hdr type: " + hdrType);
573             }
574             mSupportedHdrTypes.add(hdrType);
575             return this;
576         }
577 
getSupportedHdrTypes()578         private List<String> getSupportedHdrTypes() {
579             return new ArrayList<>(mSupportedHdrTypes);
580         }
581 
isValidVideoCodecHdrType(@onNull String hdrType)582         private boolean isValidVideoCodecHdrType(@NonNull String hdrType) {
583             if (!hdrType.equals(MediaFeature.HdrType.DOLBY_VISION)
584                     && !hdrType.equals(MediaFeature.HdrType.HDR10)
585                     && !hdrType.equals(MediaFeature.HdrType.HDR10_PLUS)
586                     && !hdrType.equals(MediaFeature.HdrType.HLG)) {
587                 return false;
588             }
589             return true;
590         }
591 
592         /**
593          * Adds an unsupported hdr type.
594          *
595          * @param hdrType Unsupported hdr type. Must be one of the String defined in
596          *                {@link MediaFeature.HdrType}.
597          * @throws IllegalArgumentException if hdrType is not valid.
598          */
599         @NonNull
addUnsupportedHdrType( @onNull @ediaFeature.MediaHdrType String hdrType)600         public Builder addUnsupportedHdrType(
601                 @NonNull @MediaFeature.MediaHdrType String hdrType) {
602             if (!isValidVideoCodecHdrType(hdrType)) {
603                 throw new IllegalArgumentException("Invalid hdr type: " + hdrType);
604             }
605             mUnsupportedHdrTypes.add(hdrType);
606             return this;
607         }
608 
getUnsupportedHdrTypes()609         private List<String> getUnsupportedHdrTypes() {
610             return new ArrayList<>(mUnsupportedHdrTypes);
611         }
612 
613         /**
614          * Sets whether slow-motion video is supported.
615          * If an application indicates support for slow-motion, it is application's responsibility
616          * to parse the slow-motion videos using their own parser or using support library.
617          * @see android.media.MediaFormat#KEY_SLOW_MOTION_MARKERS
618          * @hide
619          */
620         @NonNull
setSlowMotionSupported(boolean slowMotionSupported)621         public Builder setSlowMotionSupported(boolean slowMotionSupported) {
622             mIsSlowMotionSupported = slowMotionSupported;
623             return this;
624         }
625     }
626 }
627