1 /*
2  * Copyright (C) 2008 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 static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
20 
21 import android.annotation.IntDef;
22 import android.annotation.IntRange;
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.annotation.SystemApi;
26 import android.compat.annotation.UnsupportedAppUsage;
27 import android.content.ContentResolver;
28 import android.content.Context;
29 import android.content.res.AssetFileDescriptor;
30 import android.graphics.Bitmap;
31 import android.net.Uri;
32 import android.os.Build;
33 import android.os.Bundle;
34 import android.os.FileUtils;
35 import android.os.IBinder;
36 import android.os.ParcelFileDescriptor;
37 import android.os.SystemProperties;
38 import android.text.TextUtils;
39 import android.util.Log;
40 
41 import java.io.FileDescriptor;
42 import java.io.FileInputStream;
43 import java.io.FileNotFoundException;
44 import java.io.IOException;
45 import java.lang.annotation.Retention;
46 import java.lang.annotation.RetentionPolicy;
47 import java.util.HashMap;
48 import java.util.List;
49 import java.util.Map;
50 
51 /**
52  * MediaMetadataRetriever class provides a unified interface for retrieving
53  * frame and meta data from an input media file.
54  */
55 public class MediaMetadataRetriever implements AutoCloseable {
56     private static final String TAG = "MediaMetadataRetriever";
57 
58     // borrowed from ExoPlayer
59     private static final String[] STANDARD_GENRES = new String[] {
60             // These are the official ID3v1 genres.
61             "Blues",
62             "Classic Rock",
63             "Country",
64             "Dance",
65             "Disco",
66             "Funk",
67             "Grunge",
68             "Hip-Hop",
69             "Jazz",
70             "Metal",
71             "New Age",
72             "Oldies",
73             "Other",
74             "Pop",
75             "R&B",
76             "Rap",
77             "Reggae",
78             "Rock",
79             "Techno",
80             "Industrial",
81             "Alternative",
82             "Ska",
83             "Death Metal",
84             "Pranks",
85             "Soundtrack",
86             "Euro-Techno",
87             "Ambient",
88             "Trip-Hop",
89             "Vocal",
90             "Jazz+Funk",
91             "Fusion",
92             "Trance",
93             "Classical",
94             "Instrumental",
95             "Acid",
96             "House",
97             "Game",
98             "Sound Clip",
99             "Gospel",
100             "Noise",
101             "AlternRock",
102             "Bass",
103             "Soul",
104             "Punk",
105             "Space",
106             "Meditative",
107             "Instrumental Pop",
108             "Instrumental Rock",
109             "Ethnic",
110             "Gothic",
111             "Darkwave",
112             "Techno-Industrial",
113             "Electronic",
114             "Pop-Folk",
115             "Eurodance",
116             "Dream",
117             "Southern Rock",
118             "Comedy",
119             "Cult",
120             "Gangsta",
121             "Top 40",
122             "Christian Rap",
123             "Pop/Funk",
124             "Jungle",
125             "Native American",
126             "Cabaret",
127             "New Wave",
128             "Psychadelic",
129             "Rave",
130             "Showtunes",
131             "Trailer",
132             "Lo-Fi",
133             "Tribal",
134             "Acid Punk",
135             "Acid Jazz",
136             "Polka",
137             "Retro",
138             "Musical",
139             "Rock & Roll",
140             "Hard Rock",
141             // These were made up by the authors of Winamp and later added to the ID3 spec.
142             "Folk",
143             "Folk-Rock",
144             "National Folk",
145             "Swing",
146             "Fast Fusion",
147             "Bebob",
148             "Latin",
149             "Revival",
150             "Celtic",
151             "Bluegrass",
152             "Avantgarde",
153             "Gothic Rock",
154             "Progressive Rock",
155             "Psychedelic Rock",
156             "Symphonic Rock",
157             "Slow Rock",
158             "Big Band",
159             "Chorus",
160             "Easy Listening",
161             "Acoustic",
162             "Humour",
163             "Speech",
164             "Chanson",
165             "Opera",
166             "Chamber Music",
167             "Sonata",
168             "Symphony",
169             "Booty Bass",
170             "Primus",
171             "Porn Groove",
172             "Satire",
173             "Slow Jam",
174             "Club",
175             "Tango",
176             "Samba",
177             "Folklore",
178             "Ballad",
179             "Power Ballad",
180             "Rhythmic Soul",
181             "Freestyle",
182             "Duet",
183             "Punk Rock",
184             "Drum Solo",
185             "A capella",
186             "Euro-House",
187             "Dance Hall",
188             // These were made up by the authors of Winamp but have not been added to the ID3 spec.
189             "Goa",
190             "Drum & Bass",
191             "Club-House",
192             "Hardcore",
193             "Terror",
194             "Indie",
195             "BritPop",
196             "Afro-Punk",
197             "Polsk Punk",
198             "Beat",
199             "Christian Gangsta Rap",
200             "Heavy Metal",
201             "Black Metal",
202             "Crossover",
203             "Contemporary Christian",
204             "Christian Rock",
205             "Merengue",
206             "Salsa",
207             "Thrash Metal",
208             "Anime",
209             "Jpop",
210             "Synthpop"
211     };
212 
213     static {
214         System.loadLibrary("media_jni");
native_init()215         native_init();
216     }
217 
218     // The field below is accessed by native methods
219     @SuppressWarnings("unused")
220     private long mNativeContext;
221 
222     private static final int EMBEDDED_PICTURE_TYPE_ANY = 0xFFFF;
223 
MediaMetadataRetriever()224     public MediaMetadataRetriever() {
225         native_setup();
226     }
227 
228     /**
229      * Sets the data source (file pathname) to use. Call this
230      * method before the rest of the methods in this class. This method may be
231      * time-consuming.
232      *
233      * @param path The path, or the URI (doesn't support streaming source currently)
234      * of the input media file.
235      * @throws IllegalArgumentException If the path is invalid.
236      */
setDataSource(String path)237     public void setDataSource(String path) throws IllegalArgumentException {
238         if (path == null) {
239             throw new IllegalArgumentException("null path");
240         }
241 
242         final Uri uri = Uri.parse(path);
243         final String scheme = uri.getScheme();
244         if ("file".equals(scheme)) {
245             path = uri.getPath();
246         } else if (scheme != null) {
247             setDataSource(path, new HashMap<String, String>());
248             return;
249         }
250 
251         try (FileInputStream is = new FileInputStream(path)) {
252             FileDescriptor fd = is.getFD();
253             setDataSource(fd, 0, 0x7ffffffffffffffL);
254         } catch (FileNotFoundException fileEx) {
255             throw new IllegalArgumentException(path + " does not exist");
256         } catch (IOException ioEx) {
257             throw new IllegalArgumentException("couldn't open " + path);
258         }
259     }
260 
261     /**
262      * Sets the data source (URI) to use. Call this
263      * method before the rest of the methods in this class. This method may be
264      * time-consuming.
265      *
266      * @param uri The URI of the input media.
267      * @param headers the headers to be sent together with the request for the data
268      * @throws IllegalArgumentException If the URI is invalid.
269      */
setDataSource(String uri, Map<String, String> headers)270     public void setDataSource(String uri,  Map<String, String> headers)
271             throws IllegalArgumentException {
272         int i = 0;
273         String[] keys = new String[headers.size()];
274         String[] values = new String[headers.size()];
275         for (Map.Entry<String, String> entry: headers.entrySet()) {
276             keys[i] = entry.getKey();
277             values[i] = entry.getValue();
278             ++i;
279         }
280 
281         _setDataSource(
282                 MediaHTTPService.createHttpServiceBinderIfNecessary(uri),
283                 uri,
284                 keys,
285                 values);
286     }
287 
_setDataSource( IBinder httpServiceBinder, String uri, String[] keys, String[] values)288     private native void _setDataSource(
289         IBinder httpServiceBinder, String uri, String[] keys, String[] values)
290         throws IllegalArgumentException;
291 
292     /**
293      * Sets the data source (FileDescriptor) to use.  It is the caller's
294      * responsibility to close the file descriptor. It is safe to do so as soon
295      * as this call returns. Call this method before the rest of the methods in
296      * this class. This method may be time-consuming.
297      *
298      * @param fd the FileDescriptor for the file you want to play
299      * @param offset the offset into the file where the data to be played starts,
300      * in bytes. It must be non-negative
301      * @param length the length in bytes of the data to be played. It must be
302      * non-negative.
303      * @throws IllegalArgumentException if the arguments are invalid
304      */
setDataSource(FileDescriptor fd, long offset, long length)305     public void setDataSource(FileDescriptor fd, long offset, long length)
306             throws IllegalArgumentException  {
307 
308         try (ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fd)) {
309             if (modernFd == null) {
310                 _setDataSource(fd, offset, length);
311             } else {
312                 _setDataSource(modernFd.getFileDescriptor(), offset, length);
313             }
314         } catch (IOException e) {
315             Log.w(TAG, "Ignoring IO error while setting data source", e);
316         }
317     }
318 
_setDataSource(FileDescriptor fd, long offset, long length)319     private native void _setDataSource(FileDescriptor fd, long offset, long length)
320             throws IllegalArgumentException;
321 
322     /**
323      * Sets the data source (FileDescriptor) to use. It is the caller's
324      * responsibility to close the file descriptor. It is safe to do so as soon
325      * as this call returns. Call this method before the rest of the methods in
326      * this class. This method may be time-consuming.
327      *
328      * @param fd the FileDescriptor for the file you want to play
329      * @throws IllegalArgumentException if the FileDescriptor is invalid
330      */
setDataSource(FileDescriptor fd)331     public void setDataSource(FileDescriptor fd)
332             throws IllegalArgumentException {
333         // intentionally less than LONG_MAX
334         setDataSource(fd, 0, 0x7ffffffffffffffL);
335     }
336 
337     /**
338      * Sets the data source as a content Uri. Call this method before
339      * the rest of the methods in this class. This method may be time-consuming.
340      *
341      * @param context the Context to use when resolving the Uri
342      * @param uri the Content URI of the data you want to play
343      * @throws IllegalArgumentException if the Uri is invalid
344      * @throws SecurityException if the Uri cannot be used due to lack of
345      * permission.
346      */
setDataSource(Context context, Uri uri)347     public void setDataSource(Context context, Uri uri)
348         throws IllegalArgumentException, SecurityException {
349         if (uri == null) {
350             throw new IllegalArgumentException("null uri");
351         }
352 
353         String scheme = uri.getScheme();
354         if(scheme == null || scheme.equals("file")) {
355             setDataSource(uri.getPath());
356             return;
357         }
358 
359         AssetFileDescriptor fd = null;
360         try {
361             ContentResolver resolver = context.getContentResolver();
362             try {
363                 boolean optimize =
364                         SystemProperties.getBoolean("fuse.sys.transcode_retriever_optimize", false);
365                 Bundle opts = new Bundle();
366                 opts.putBoolean("android.provider.extra.ACCEPT_ORIGINAL_MEDIA_FORMAT", true);
367                 fd = optimize ? resolver.openTypedAssetFileDescriptor(uri, "*/*", opts)
368                         : resolver.openAssetFileDescriptor(uri, "r");
369             } catch(FileNotFoundException e) {
370                 throw new IllegalArgumentException("could not access " + uri);
371             }
372             if (fd == null) {
373                 throw new IllegalArgumentException("got null FileDescriptor for " + uri);
374             }
375             FileDescriptor descriptor = fd.getFileDescriptor();
376             if (!descriptor.valid()) {
377                 throw new IllegalArgumentException("got invalid FileDescriptor for " + uri);
378             }
379             // Note: using getDeclaredLength so that our behavior is the same
380             // as previous versions when the content provider is returning
381             // a full file.
382             if (fd.getDeclaredLength() < 0) {
383                 setDataSource(descriptor);
384             } else {
385                 setDataSource(descriptor, fd.getStartOffset(), fd.getDeclaredLength());
386             }
387             return;
388         } catch (SecurityException ex) {
389         } finally {
390             try {
391                 if (fd != null) {
392                     fd.close();
393                 }
394             } catch(IOException ioEx) {
395             }
396         }
397         setDataSource(uri.toString());
398     }
399 
400     /**
401      * Sets the data source (MediaDataSource) to use.
402      *
403      * @param dataSource the MediaDataSource for the media you want to play
404      */
setDataSource(MediaDataSource dataSource)405     public void setDataSource(MediaDataSource dataSource)
406             throws IllegalArgumentException {
407         _setDataSource(dataSource);
408     }
409 
_setDataSource(MediaDataSource dataSource)410     private native void _setDataSource(MediaDataSource dataSource)
411           throws IllegalArgumentException;
412 
nativeExtractMetadata(int keyCode)413     private native @Nullable String nativeExtractMetadata(int keyCode);
414 
415     /**
416      * Call this method after setDataSource(). This method retrieves the
417      * meta data value associated with the keyCode.
418      *
419      * The keyCode currently supported is listed below as METADATA_XXX
420      * constants. With any other value, it returns a null pointer.
421      *
422      * @param keyCode One of the constants listed below at the end of the class.
423      * @return The meta data value associate with the given keyCode on success;
424      * null on failure.
425      */
extractMetadata(int keyCode)426     public @Nullable String extractMetadata(int keyCode) {
427         String meta = nativeExtractMetadata(keyCode);
428         if (keyCode == METADATA_KEY_GENRE) {
429             // translate numeric genre code(s) to human readable
430             meta = convertGenreTag(meta);
431         }
432         return meta;
433     }
434 
435     /*
436      * The id3v2 spec doesn't specify the syntax of the genre tag very precisely, so
437      * some assumptions are made. Using one possible interpretation of the id3v2
438      * spec, this method converts an id3 genre tag string to a human readable string,
439      * as follows:
440      * - if the first character of the tag is a digit, the entire tag is assumed to
441      *   be an id3v1 numeric genre code. If the tag does not parse to a number, or
442      *   the number is outside the range of defined standard genres, it is ignored.
443      * - if the tag does not start with a digit, it is assumed to be an id3v2 style
444      *   tag consisting of one or more genres, with each genre being either a parenthesized
445      *   integer referring to an id3v1 numeric genre code, the special indicators "(CR)" or
446      *   "(RX)" (for "Cover" or "Remix", respectively), or a custom genre string. When
447      *   a custom genre string is encountered, it is assumed to continue until the end
448      *   of the tag, unless it starts with "((" in which case it is assumed to continue
449      *   until the next close-parenthesis or the end of the tag. Any parse error in the tag
450      *   causes it to be ignored.
451      * The human-readable genre string is not localized, and uses the English genre names
452      * from the spec.
453      */
convertGenreTag(String meta)454     private String convertGenreTag(String meta) {
455         if (TextUtils.isEmpty(meta)) {
456             return null;
457         }
458 
459         if (Character.isDigit(meta.charAt(0))) {
460             // assume a single id3v1-style bare number without any extra characters
461             try {
462                 int genreIndex = Integer.parseInt(meta);
463                 if (genreIndex >= 0 && genreIndex < STANDARD_GENRES.length) {
464                     return STANDARD_GENRES[genreIndex];
465                 }
466             } catch (NumberFormatException e) {
467                 // ignore and fall through
468             }
469             return null;
470         } else {
471             // assume id3v2-style genre tag, with parenthesized numeric genres
472             // and/or literal genre strings, possibly more than one per tag.
473             StringBuilder genres = null;
474             String nextGenre = null;
475             while (true) {
476                 if (!TextUtils.isEmpty(nextGenre)) {
477                     if (genres == null) {
478                         genres = new StringBuilder();
479                     }
480                     if (genres.length() != 0) {
481                         genres.append(", ");
482                     }
483                     genres.append(nextGenre);
484                     nextGenre = null;
485                 }
486                 if (TextUtils.isEmpty(meta)) {
487                     // entire tag has been processed.
488                     break;
489                 }
490                 if (meta.startsWith("(RX)")) {
491                     nextGenre = "Remix";
492                     meta = meta.substring(4);
493                 } else if (meta.startsWith("(CR)")) {
494                     nextGenre = "Cover";
495                     meta = meta.substring(4);
496                 } else if (meta.startsWith("((")) {
497                     // the id3v2 spec says that custom genres that start with a parenthesis
498                     // should be "escaped" with another parenthesis, however the spec doesn't
499                     // specify escaping parentheses inside the custom string. We'll parse any
500                     // such strings until a closing parenthesis is found, or the end of
501                     // the tag is reached.
502                     int closeParenOffset = meta.indexOf(')');
503                     if (closeParenOffset == -1) {
504                         // string continues to end of tag
505                         nextGenre = meta.substring(1);
506                         meta = "";
507                     } else {
508                         nextGenre = meta.substring(1, closeParenOffset + 1);
509                         meta = meta.substring(closeParenOffset + 1);
510                     }
511                 } else if (meta.startsWith("(")) {
512                     // should be a parenthesized numeric genre
513                     int closeParenOffset = meta.indexOf(')');
514                     if (closeParenOffset == -1) {
515                         return null;
516                     }
517                     String genreNumString = meta.substring(1, closeParenOffset);
518                     try {
519                         int genreIndex = Integer.parseInt(genreNumString.toString());
520                         if (genreIndex >= 0 && genreIndex < STANDARD_GENRES.length) {
521                             nextGenre = STANDARD_GENRES[genreIndex];
522                         } else {
523                             return null;
524                         }
525                     } catch (NumberFormatException e) {
526                         return null;
527                     }
528                     meta = meta.substring(closeParenOffset + 1);
529                 } else {
530                     // custom genre
531                     nextGenre = meta;
532                     meta = "";
533                 }
534             }
535             return genres == null || genres.length() == 0 ? null : genres.toString();
536         }
537     }
538 
539     /**
540      * This method is similar to {@link #getFrameAtTime(long, int, BitmapParams)}
541      * except that the device will choose the actual {@link Bitmap.Config} to use.
542      *
543      * @param timeUs The time position where the frame will be retrieved.
544      * When retrieving the frame at the given time position, there is no
545      * guarantee that the data source has a frame located at the position.
546      * When this happens, a frame nearby will be returned. If timeUs is
547      * negative, time position and option will ignored, and any frame
548      * that the implementation considers as representative may be returned.
549      *
550      * @param option a hint on how the frame is found. Use
551      * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame
552      * that has a timestamp earlier than or the same as timeUs. Use
553      * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame
554      * that has a timestamp later than or the same as timeUs. Use
555      * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame
556      * that has a timestamp closest to or the same as timeUs. Use
557      * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may
558      * or may not be a sync frame but is closest to or the same as timeUs.
559      * {@link #OPTION_CLOSEST} often has larger performance overhead compared
560      * to the other options if there is no sync frame located at timeUs.
561      *
562      * @return A Bitmap containing a representative video frame, which can be null,
563      *         if such a frame cannot be retrieved. {@link Bitmap#getConfig()} can
564      *         be used to query the actual {@link Bitmap.Config}.
565      *
566      * @see #getFrameAtTime(long, int, BitmapParams)
567      */
getFrameAtTime(long timeUs, @Option int option)568     public @Nullable Bitmap getFrameAtTime(long timeUs, @Option int option) {
569         if (option < OPTION_PREVIOUS_SYNC ||
570             option > OPTION_CLOSEST) {
571             throw new IllegalArgumentException("Unsupported option: " + option);
572         }
573 
574         return _getFrameAtTime(timeUs, option, -1 /*dst_width*/, -1 /*dst_height*/, null);
575     }
576 
577     /**
578      * Call this method after setDataSource(). This method finds a
579      * representative frame close to the given time position by considering
580      * the given option if possible, and returns it as a bitmap.
581      *
582      * <p>If you don't need a full-resolution
583      * frame (for example, because you need a thumbnail image), use
584      * {@link #getScaledFrameAtTime getScaledFrameAtTime()} instead of this
585      * method.</p>
586      *
587      * @param timeUs The time position where the frame will be retrieved.
588      * When retrieving the frame at the given time position, there is no
589      * guarantee that the data source has a frame located at the position.
590      * When this happens, a frame nearby will be returned. If timeUs is
591      * negative, time position and option will ignored, and any frame
592      * that the implementation considers as representative may be returned.
593      *
594      * @param option a hint on how the frame is found. Use
595      * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame
596      * that has a timestamp earlier than or the same as timeUs. Use
597      * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame
598      * that has a timestamp later than or the same as timeUs. Use
599      * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame
600      * that has a timestamp closest to or the same as timeUs. Use
601      * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may
602      * or may not be a sync frame but is closest to or the same as timeUs.
603      * {@link #OPTION_CLOSEST} often has larger performance overhead compared
604      * to the other options if there is no sync frame located at timeUs.
605      *
606      * @param params BitmapParams that controls the returned bitmap config
607      *        (such as pixel formats).
608      *
609      * @return A Bitmap containing a representative video frame, which
610      *         can be null, if such a frame cannot be retrieved.
611      *
612      * @see #getFrameAtTime(long, int)
613      */
getFrameAtTime( long timeUs, @Option int option, @NonNull BitmapParams params)614     public @Nullable Bitmap getFrameAtTime(
615             long timeUs, @Option int option, @NonNull BitmapParams params) {
616         if (option < OPTION_PREVIOUS_SYNC ||
617             option > OPTION_CLOSEST) {
618             throw new IllegalArgumentException("Unsupported option: " + option);
619         }
620 
621         return _getFrameAtTime(timeUs, option, -1 /*dst_width*/, -1 /*dst_height*/, params);
622     }
623 
624     /**
625      * This method is similar to {@link #getScaledFrameAtTime(long, int, int, int, BitmapParams)}
626      * except that the device will choose the actual {@link Bitmap.Config} to use.
627      *
628      * @param timeUs The time position in microseconds where the frame will be retrieved.
629      * When retrieving the frame at the given time position, there is no
630      * guarantee that the data source has a frame located at the position.
631      * When this happens, a frame nearby will be returned. If timeUs is
632      * negative, time position and option will ignored, and any frame
633      * that the implementation considers as representative may be returned.
634      *
635      * @param option a hint on how the frame is found. Use
636      * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame
637      * that has a timestamp earlier than or the same as timeUs. Use
638      * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame
639      * that has a timestamp later than or the same as timeUs. Use
640      * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame
641      * that has a timestamp closest to or the same as timeUs. Use
642      * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may
643      * or may not be a sync frame but is closest to or the same as timeUs.
644      * {@link #OPTION_CLOSEST} often has larger performance overhead compared
645      * to the other options if there is no sync frame located at timeUs.
646      *
647      * @param dstWidth expected output bitmap width
648      * @param dstHeight expected output bitmap height
649      * @return A Bitmap containing a representative video frame, which can be null,
650      *         if such a frame cannot be retrieved. {@link Bitmap#getConfig()} can
651      *         be used to query the actual {@link Bitmap.Config}.
652      * @throws IllegalArgumentException if passed in invalid option or width by height
653      *         is less than or equal to 0.
654      * @see #getScaledFrameAtTime(long, int, int, int, BitmapParams)
655      */
getScaledFrameAtTime(long timeUs, @Option int option, @IntRange(from=1) int dstWidth, @IntRange(from=1) int dstHeight)656     public @Nullable Bitmap getScaledFrameAtTime(long timeUs, @Option int option,
657             @IntRange(from=1) int dstWidth, @IntRange(from=1) int dstHeight) {
658         validate(option, dstWidth, dstHeight);
659         return _getFrameAtTime(timeUs, option, dstWidth, dstHeight, null);
660     }
661 
662     /**
663      * Retrieve a video frame near a given timestamp scaled to a desired size.
664      * Call this method after setDataSource(). This method finds a representative
665      * frame close to the given time position by considering the given option
666      * if possible, and returns it as a bitmap with same aspect ratio as the source
667      * while scaling it so that it fits into the desired size of dst_width by dst_height.
668      * This is useful for generating a thumbnail for an input data source or just to
669      * obtain a scaled frame at the given time position.
670      *
671      * @param timeUs The time position in microseconds where the frame will be retrieved.
672      * When retrieving the frame at the given time position, there is no
673      * guarantee that the data source has a frame located at the position.
674      * When this happens, a frame nearby will be returned. If timeUs is
675      * negative, time position and option will ignored, and any frame
676      * that the implementation considers as representative may be returned.
677      *
678      * @param option a hint on how the frame is found. Use
679      * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame
680      * that has a timestamp earlier than or the same as timeUs. Use
681      * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame
682      * that has a timestamp later than or the same as timeUs. Use
683      * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame
684      * that has a timestamp closest to or the same as timeUs. Use
685      * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may
686      * or may not be a sync frame but is closest to or the same as timeUs.
687      * {@link #OPTION_CLOSEST} often has larger performance overhead compared
688      * to the other options if there is no sync frame located at timeUs.
689      *
690      * @param dstWidth expected output bitmap width
691      * @param dstHeight expected output bitmap height
692      * @param params BitmapParams that controls the returned bitmap config
693      *        (such as pixel formats).
694      *
695      * @return A Bitmap of size not larger than dstWidth by dstHeight containing a
696      *         scaled video frame, which can be null, if such a frame cannot be retrieved.
697      * @throws IllegalArgumentException if passed in invalid option or width by height
698      *         is less than or equal to 0.
699      * @see #getScaledFrameAtTime(long, int, int, int)
700      */
getScaledFrameAtTime(long timeUs, @Option int option, @IntRange(from=1) int dstWidth, @IntRange(from=1) int dstHeight, @NonNull BitmapParams params)701     public @Nullable Bitmap getScaledFrameAtTime(long timeUs, @Option int option,
702             @IntRange(from=1) int dstWidth, @IntRange(from=1) int dstHeight,
703             @NonNull BitmapParams params) {
704         validate(option, dstWidth, dstHeight);
705         return _getFrameAtTime(timeUs, option, dstWidth, dstHeight, params);
706     }
707 
validate(@ption int option, int dstWidth, int dstHeight)708     private void validate(@Option int option, int dstWidth, int dstHeight) {
709         if (option < OPTION_PREVIOUS_SYNC || option > OPTION_CLOSEST) {
710             throw new IllegalArgumentException("Unsupported option: " + option);
711         }
712         if (dstWidth <= 0) {
713             throw new IllegalArgumentException("Invalid width: " + dstWidth);
714         }
715         if (dstHeight <= 0) {
716             throw new IllegalArgumentException("Invalid height: " + dstHeight);
717         }
718     }
719 
720     /**
721      * Call this method after setDataSource(). This method finds a
722      * representative frame close to the given time position if possible,
723      * and returns it as a bitmap. Call this method if one does not care
724      * how the frame is found as long as it is close to the given time;
725      * otherwise, please call {@link #getFrameAtTime(long, int)}.
726      *
727      * <p>If you don't need a full-resolution
728      * frame (for example, because you need a thumbnail image), use
729      * {@link #getScaledFrameAtTime getScaledFrameAtTime()} instead of this
730      * method.</p>
731      *
732      * @param timeUs The time position where the frame will be retrieved.
733      * When retrieving the frame at the given time position, there is no
734      * guarentee that the data source has a frame located at the position.
735      * When this happens, a frame nearby will be returned. If timeUs is
736      * negative, time position and option will ignored, and any frame
737      * that the implementation considers as representative may be returned.
738      *
739      * @return A Bitmap of size dst_widthxdst_height containing a representative
740      *         video frame, which can be null, if such a frame cannot be retrieved.
741      *
742      * @see #getFrameAtTime(long, int)
743      */
getFrameAtTime(long timeUs)744     public @Nullable Bitmap getFrameAtTime(long timeUs) {
745         return getFrameAtTime(timeUs, OPTION_CLOSEST_SYNC);
746     }
747 
748     /**
749      * Call this method after setDataSource(). This method finds a
750      * representative frame at any time position if possible,
751      * and returns it as a bitmap. Call this method if one does not
752      * care about where the frame is located; otherwise, please call
753      * {@link #getFrameAtTime(long)} or {@link #getFrameAtTime(long, int)}
754      *
755      * <p>If you don't need a full-resolution
756      * frame (for example, because you need a thumbnail image), use
757      * {@link #getScaledFrameAtTime getScaledFrameAtTime()} instead of this
758      * method.</p>
759      *
760      * @return A Bitmap containing a representative video frame, which
761      *         can be null, if such a frame cannot be retrieved.
762      *
763      * @see #getFrameAtTime(long)
764      * @see #getFrameAtTime(long, int)
765      */
getFrameAtTime()766     public @Nullable Bitmap getFrameAtTime() {
767         return _getFrameAtTime(
768                 -1, OPTION_CLOSEST_SYNC, -1 /*dst_width*/, -1 /*dst_height*/, null);
769     }
770 
_getFrameAtTime( long timeUs, int option, int width, int height, @Nullable BitmapParams params)771     private native Bitmap _getFrameAtTime(
772             long timeUs, int option, int width, int height, @Nullable BitmapParams params);
773 
774     public static final class BitmapParams {
775         private Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;
776         private Bitmap.Config outActualConfig = Bitmap.Config.ARGB_8888;
777 
778         /**
779          * Create a default BitmapParams object. By default, it uses {@link Bitmap.Config#ARGB_8888}
780          * as the preferred bitmap config.
781          */
BitmapParams()782         public BitmapParams() {}
783 
784         /**
785          * Set the preferred bitmap config for the decoder to decode into.
786          *
787          * If not set, or the request cannot be met, the decoder will output
788          * in {@link Bitmap.Config#ARGB_8888} config by default.
789          *
790          * After decode, the actual config used can be retrieved by {@link #getActualConfig()}.
791          *
792          * @param config the preferred bitmap config to use.
793          */
setPreferredConfig(@onNull Bitmap.Config config)794         public void setPreferredConfig(@NonNull Bitmap.Config config) {
795             if (config == null) {
796                 throw new IllegalArgumentException("preferred config can't be null");
797             }
798             inPreferredConfig = config;
799         }
800 
801         /**
802          * Retrieve the preferred bitmap config in the params.
803          *
804          * @return the preferred bitmap config.
805          */
getPreferredConfig()806         public @NonNull Bitmap.Config getPreferredConfig() {
807             return inPreferredConfig;
808         }
809 
810         /**
811          * Get the actual bitmap config used to decode the bitmap after the decoding.
812          *
813          * @return the actual bitmap config used.
814          */
getActualConfig()815         public @NonNull Bitmap.Config getActualConfig() {
816             return outActualConfig;
817         }
818     }
819 
820     /**
821      * This method retrieves a video frame by its index. It should only be called
822      * after {@link #setDataSource}.
823      *
824      * After the bitmap is returned, you can query the actual parameters that were
825      * used to create the bitmap from the {@code BitmapParams} argument, for instance
826      * to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}.
827      *
828      * @param frameIndex 0-based index of the video frame. The frame index must be that of
829      *        a valid frame. The total number of frames available for retrieval can be queried
830      *        via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key.
831      * @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
832      *
833      * @throws IllegalStateException if the container doesn't contain video or image sequences.
834      * @throws IllegalArgumentException if the requested frame index does not exist.
835      *
836      * @return A Bitmap containing the requested video frame, or null if the retrieval fails.
837      *
838      * @see #getFrameAtIndex(int)
839      * @see #getFramesAtIndex(int, int, BitmapParams)
840      * @see #getFramesAtIndex(int, int)
841      */
getFrameAtIndex(int frameIndex, @NonNull BitmapParams params)842     public @Nullable Bitmap getFrameAtIndex(int frameIndex, @NonNull BitmapParams params) {
843         List<Bitmap> bitmaps = getFramesAtIndex(frameIndex, 1, params);
844         return bitmaps.get(0);
845     }
846 
847     /**
848      * This method is similar to {@link #getFrameAtIndex(int, BitmapParams)} except that
849      * the default for {@link BitmapParams} will be used.
850      *
851      * @param frameIndex 0-based index of the video frame. The frame index must be that of
852      *        a valid frame. The total number of frames available for retrieval can be queried
853      *        via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key.
854      *
855      * @throws IllegalStateException if the container doesn't contain video or image sequences.
856      * @throws IllegalArgumentException if the requested frame index does not exist.
857      *
858      * @return A Bitmap containing the requested video frame, or null if the retrieval fails.
859      *
860      * @see #getFrameAtIndex(int, BitmapParams)
861      * @see #getFramesAtIndex(int, int, BitmapParams)
862      * @see #getFramesAtIndex(int, int)
863      */
getFrameAtIndex(int frameIndex)864     public @Nullable Bitmap getFrameAtIndex(int frameIndex) {
865         List<Bitmap> bitmaps = getFramesAtIndex(frameIndex, 1);
866         return bitmaps.get(0);
867     }
868 
869     /**
870      * This method retrieves a consecutive set of video frames starting at the
871      * specified index. It should only be called after {@link #setDataSource}.
872      *
873      * If the caller intends to retrieve more than one consecutive video frames,
874      * this method is preferred over {@link #getFrameAtIndex(int, BitmapParams)} for efficiency.
875      *
876      * After the bitmaps are returned, you can query the actual parameters that were
877      * used to create the bitmaps from the {@code BitmapParams} argument, for instance
878      * to query the bitmap config used for the bitmaps with {@link BitmapParams#getActualConfig}.
879      *
880      * @param frameIndex 0-based index of the first video frame to retrieve. The frame index
881      *        must be that of a valid frame. The total number of frames available for retrieval
882      *        can be queried via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key.
883      * @param numFrames number of consecutive video frames to retrieve. Must be a positive
884      *        value. The stream must contain at least numFrames frames starting at frameIndex.
885      * @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
886      *
887      * @throws IllegalStateException if the container doesn't contain video or image sequences.
888      * @throws IllegalArgumentException if the frameIndex or numFrames is invalid, or the
889      *         stream doesn't contain at least numFrames starting at frameIndex.
890 
891      * @return An list of Bitmaps containing the requested video frames. The returned
892      *         array could contain less frames than requested if the retrieval fails.
893      *
894      * @see #getFrameAtIndex(int, BitmapParams)
895      * @see #getFrameAtIndex(int)
896      * @see #getFramesAtIndex(int, int)
897      */
getFramesAtIndex( int frameIndex, int numFrames, @NonNull BitmapParams params)898     public @NonNull List<Bitmap> getFramesAtIndex(
899             int frameIndex, int numFrames, @NonNull BitmapParams params) {
900         return getFramesAtIndexInternal(frameIndex, numFrames, params);
901     }
902 
903     /**
904      * This method is similar to {@link #getFramesAtIndex(int, int, BitmapParams)} except that
905      * the default for {@link BitmapParams} will be used.
906      *
907      * @param frameIndex 0-based index of the first video frame to retrieve. The frame index
908      *        must be that of a valid frame. The total number of frames available for retrieval
909      *        can be queried via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key.
910      * @param numFrames number of consecutive video frames to retrieve. Must be a positive
911      *        value. The stream must contain at least numFrames frames starting at frameIndex.
912      *
913      * @throws IllegalStateException if the container doesn't contain video or image sequences.
914      * @throws IllegalArgumentException if the frameIndex or numFrames is invalid, or the
915      *         stream doesn't contain at least numFrames starting at frameIndex.
916 
917      * @return An list of Bitmaps containing the requested video frames. The returned
918      *         array could contain less frames than requested if the retrieval fails.
919      *
920      * @see #getFrameAtIndex(int, BitmapParams)
921      * @see #getFrameAtIndex(int)
922      * @see #getFramesAtIndex(int, int, BitmapParams)
923      */
getFramesAtIndex(int frameIndex, int numFrames)924     public @NonNull List<Bitmap> getFramesAtIndex(int frameIndex, int numFrames) {
925         return getFramesAtIndexInternal(frameIndex, numFrames, null);
926     }
927 
getFramesAtIndexInternal( int frameIndex, int numFrames, @Nullable BitmapParams params)928     private @NonNull List<Bitmap> getFramesAtIndexInternal(
929             int frameIndex, int numFrames, @Nullable BitmapParams params) {
930         if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO))) {
931             throw new IllegalStateException("Does not contain video or image sequences");
932         }
933         int frameCount = Integer.parseInt(
934                 extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_FRAME_COUNT));
935         if (frameIndex < 0 || numFrames < 1
936                 || frameIndex >= frameCount
937                 || frameIndex > frameCount - numFrames) {
938             throw new IllegalArgumentException("Invalid frameIndex or numFrames: "
939                 + frameIndex + ", " + numFrames);
940         }
941         return _getFrameAtIndex(frameIndex, numFrames, params);
942     }
943 
_getFrameAtIndex( int frameIndex, int numFrames, @Nullable BitmapParams params)944     private native @NonNull List<Bitmap> _getFrameAtIndex(
945             int frameIndex, int numFrames, @Nullable BitmapParams params);
946 
947     /**
948      * This method retrieves a still image by its index. It should only be called
949      * after {@link #setDataSource}.
950      *
951      * After the bitmap is returned, you can query the actual parameters that were
952      * used to create the bitmap from the {@code BitmapParams} argument, for instance
953      * to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}.
954      *
955      * @param imageIndex 0-based index of the image.
956      * @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
957      *
958      * @throws IllegalStateException if the container doesn't contain still images.
959      * @throws IllegalArgumentException if the requested image does not exist.
960      *
961      * @return the requested still image, or null if the image cannot be retrieved.
962      *
963      * @see #getImageAtIndex(int)
964      * @see #getPrimaryImage(BitmapParams)
965      * @see #getPrimaryImage()
966      */
getImageAtIndex(int imageIndex, @NonNull BitmapParams params)967     public @Nullable Bitmap getImageAtIndex(int imageIndex, @NonNull BitmapParams params) {
968         return getImageAtIndexInternal(imageIndex, params);
969     }
970 
971     /**
972      * @hide
973      *
974      * This method retrieves the thumbnail image for a still image if it's available.
975      * It should only be called after {@link #setDataSource}.
976      *
977      * @param imageIndex 0-based index of the image, negative value indicates primary image.
978      * @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
979      * @param targetSize intended size of one edge (wdith or height) of the thumbnail,
980      *                   this is a heuristic for the framework to decide whether the embedded
981      *                   thumbnail should be used.
982      * @param maxPixels maximum pixels of thumbnail, this is a heuristic for the frameowrk to
983      *                  decide whehther the embedded thumnbail (or a downscaled version of it)
984      *                  should be used.
985      * @return the retrieved thumbnail, or null if no suitable thumbnail is available.
986      */
getThumbnailImageAtIndex( int imageIndex, @NonNull BitmapParams params, int targetSize, int maxPixels)987     public native @Nullable Bitmap getThumbnailImageAtIndex(
988             int imageIndex, @NonNull BitmapParams params, int targetSize, int maxPixels);
989 
990     /**
991      * This method is similar to {@link #getImageAtIndex(int, BitmapParams)} except that
992      * the default for {@link BitmapParams} will be used.
993      *
994      * @param imageIndex 0-based index of the image.
995      *
996      * @throws IllegalStateException if the container doesn't contain still images.
997      * @throws IllegalArgumentException if the requested image does not exist.
998      *
999      * @return the requested still image, or null if the image cannot be retrieved.
1000      *
1001      * @see #getImageAtIndex(int, BitmapParams)
1002      * @see #getPrimaryImage(BitmapParams)
1003      * @see #getPrimaryImage()
1004      */
getImageAtIndex(int imageIndex)1005     public @Nullable Bitmap getImageAtIndex(int imageIndex) {
1006         return getImageAtIndexInternal(imageIndex, null);
1007     }
1008 
1009     /**
1010      * This method retrieves the primary image of the media content. It should only
1011      * be called after {@link #setDataSource}.
1012      *
1013      * After the bitmap is returned, you can query the actual parameters that were
1014      * used to create the bitmap from the {@code BitmapParams} argument, for instance
1015      * to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}.
1016      *
1017      * @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
1018      *
1019      * @return the primary image, or null if it cannot be retrieved.
1020      *
1021      * @throws IllegalStateException if the container doesn't contain still images.
1022      *
1023      * @see #getImageAtIndex(int, BitmapParams)
1024      * @see #getImageAtIndex(int)
1025      * @see #getPrimaryImage()
1026      */
getPrimaryImage(@onNull BitmapParams params)1027     public @Nullable Bitmap getPrimaryImage(@NonNull BitmapParams params) {
1028         return getImageAtIndexInternal(-1, params);
1029     }
1030 
1031     /**
1032      * This method is similar to {@link #getPrimaryImage(BitmapParams)} except that
1033      * the default for {@link BitmapParams} will be used.
1034      *
1035      * @return the primary image, or null if it cannot be retrieved.
1036      *
1037      * @throws IllegalStateException if the container doesn't contain still images.
1038      *
1039      * @see #getImageAtIndex(int, BitmapParams)
1040      * @see #getImageAtIndex(int)
1041      * @see #getPrimaryImage(BitmapParams)
1042      */
getPrimaryImage()1043     public @Nullable Bitmap getPrimaryImage() {
1044         return getImageAtIndexInternal(-1, null);
1045     }
1046 
getImageAtIndexInternal(int imageIndex, @Nullable BitmapParams params)1047     private Bitmap getImageAtIndexInternal(int imageIndex, @Nullable BitmapParams params) {
1048         if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE))) {
1049             throw new IllegalStateException("Does not contain still images");
1050         }
1051 
1052         String imageCount = extractMetadata(MediaMetadataRetriever.METADATA_KEY_IMAGE_COUNT);
1053         if (imageIndex >= Integer.parseInt(imageCount)) {
1054             throw new IllegalArgumentException("Invalid image index: " + imageCount);
1055         }
1056 
1057         return _getImageAtIndex(imageIndex, params);
1058     }
1059 
_getImageAtIndex(int imageIndex, @Nullable BitmapParams params)1060     private native Bitmap _getImageAtIndex(int imageIndex, @Nullable BitmapParams params);
1061 
1062     /**
1063      * Call this method after setDataSource(). This method finds the optional
1064      * graphic or album/cover art associated associated with the data source. If
1065      * there are more than one pictures, (any) one of them is returned.
1066      *
1067      * @return null if no such graphic is found.
1068      */
getEmbeddedPicture()1069     public @Nullable byte[] getEmbeddedPicture() {
1070         return getEmbeddedPicture(EMBEDDED_PICTURE_TYPE_ANY);
1071     }
1072 
1073     @UnsupportedAppUsage
getEmbeddedPicture(int pictureType)1074     private native byte[] getEmbeddedPicture(int pictureType);
1075 
1076     /**
1077      * Releases any acquired resources. Call it when done with the object.
1078      *
1079      * @throws IOException When an {@link IOException} is thrown while closing a {@link
1080      * MediaDataSource} passed to {@link #setDataSource(MediaDataSource)}. This throws clause exists
1081      * since API {@link android.os.Build.VERSION_CODES#TIRAMISU}, but this method can throw in
1082      * earlier API versions where the exception is not declared.
1083      */
1084     @Override
close()1085     public void close() throws IOException {
1086         release();
1087     }
1088 
1089     /**
1090      * Releases any acquired resources. Call it when done with the object.
1091      *
1092      * @throws IOException When an {@link IOException} is thrown while closing a {@link
1093      * MediaDataSource} passed to {@link #setDataSource(MediaDataSource)}. This throws clause exists
1094      * since API {@link android.os.Build.VERSION_CODES#TIRAMISU}, but this method can throw in
1095      * earlier API versions where the exception is not declared.
1096      */
release()1097     public native void release() throws IOException;
1098     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
native_setup()1099     private native void native_setup();
1100     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
native_init()1101     private static native void native_init();
1102 
1103     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
native_finalize()1104     private native final void native_finalize();
1105 
1106     @Override
finalize()1107     protected void finalize() throws Throwable {
1108         try {
1109             native_finalize();
1110         } finally {
1111             super.finalize();
1112         }
1113     }
1114 
1115     /**
1116      * Option used in method {@link #getFrameAtTime(long, int)} to get a
1117      * frame at a specified location.
1118      *
1119      * @see #getFrameAtTime(long, int)
1120      */
1121     /* Do not change these option values without updating their counterparts
1122      * in include/media/MediaSource.h!
1123      */
1124     /**
1125      * This option is used with {@link #getFrameAtTime(long, int)} to retrieve
1126      * a sync (or key) frame associated with a data source that is located
1127      * right before or at the given time.
1128      *
1129      * @see #getFrameAtTime(long, int)
1130      */
1131     public static final int OPTION_PREVIOUS_SYNC    = 0x00;
1132     /**
1133      * This option is used with {@link #getFrameAtTime(long, int)} to retrieve
1134      * a sync (or key) frame associated with a data source that is located
1135      * right after or at the given time.
1136      *
1137      * @see #getFrameAtTime(long, int)
1138      */
1139     public static final int OPTION_NEXT_SYNC        = 0x01;
1140     /**
1141      * This option is used with {@link #getFrameAtTime(long, int)} to retrieve
1142      * a sync (or key) frame associated with a data source that is located
1143      * closest to (in time) or at the given time.
1144      *
1145      * @see #getFrameAtTime(long, int)
1146      */
1147     public static final int OPTION_CLOSEST_SYNC     = 0x02;
1148     /**
1149      * This option is used with {@link #getFrameAtTime(long, int)} to retrieve
1150      * a frame (not necessarily a key frame) associated with a data source that
1151      * is located closest to or at the given time.
1152      *
1153      * @see #getFrameAtTime(long, int)
1154      */
1155     public static final int OPTION_CLOSEST          = 0x03;
1156 
1157     /** @hide */
1158     @IntDef(flag = false, prefix = { "OPTION_" }, value = {
1159             OPTION_PREVIOUS_SYNC,
1160             OPTION_NEXT_SYNC,
1161             OPTION_CLOSEST_SYNC,
1162             OPTION_CLOSEST,
1163     })
1164     @Retention(RetentionPolicy.SOURCE)
1165     public @interface Option {}
1166 
1167     /*
1168      * Do not change these metadata key values without updating their
1169      * counterparts in include/media/mediametadataretriever.h!
1170      */
1171     /**
1172      * The metadata key to retrieve the numeric string describing the
1173      * order of the audio data source on its original recording.
1174      */
1175     public static final int METADATA_KEY_CD_TRACK_NUMBER = 0;
1176     /**
1177      * The metadata key to retrieve the information about the album title
1178      * of the data source.
1179      */
1180     public static final int METADATA_KEY_ALBUM           = 1;
1181     /**
1182      * The metadata key to retrieve the information about the artist of
1183      * the data source.
1184      */
1185     public static final int METADATA_KEY_ARTIST          = 2;
1186     /**
1187      * The metadata key to retrieve the information about the author of
1188      * the data source.
1189      */
1190     public static final int METADATA_KEY_AUTHOR          = 3;
1191     /**
1192      * The metadata key to retrieve the information about the composer of
1193      * the data source.
1194      */
1195     public static final int METADATA_KEY_COMPOSER        = 4;
1196     /**
1197      * The metadata key to retrieve the date when the data source was created
1198      * or modified.
1199      */
1200     public static final int METADATA_KEY_DATE            = 5;
1201     /**
1202      * The metadata key to retrieve the content type or genre of the data
1203      * source.
1204      */
1205     public static final int METADATA_KEY_GENRE           = 6;
1206     /**
1207      * The metadata key to retrieve the data source title.
1208      */
1209     public static final int METADATA_KEY_TITLE           = 7;
1210     /**
1211      * The metadata key to retrieve the year when the data source was created
1212      * or modified.
1213      */
1214     public static final int METADATA_KEY_YEAR            = 8;
1215     /**
1216      * The metadata key to retrieve the playback duration (in ms) of the data source.
1217      */
1218     public static final int METADATA_KEY_DURATION        = 9;
1219     /**
1220      * The metadata key to retrieve the number of tracks, such as audio, video,
1221      * text, in the data source, such as a mp4 or 3gpp file.
1222      */
1223     public static final int METADATA_KEY_NUM_TRACKS      = 10;
1224     /**
1225      * The metadata key to retrieve the information of the writer (such as
1226      * lyricist) of the data source.
1227      */
1228     public static final int METADATA_KEY_WRITER          = 11;
1229     /**
1230      * The metadata key to retrieve the mime type of the data source. Some
1231      * example mime types include: "video/mp4", "audio/mp4", "audio/amr-wb",
1232      * etc.
1233      */
1234     public static final int METADATA_KEY_MIMETYPE        = 12;
1235     /**
1236      * The metadata key to retrieve the information about the performers or
1237      * artist associated with the data source.
1238      */
1239     public static final int METADATA_KEY_ALBUMARTIST     = 13;
1240     /**
1241      * The metadata key to retrieve the numberic string that describes which
1242      * part of a set the audio data source comes from.
1243      */
1244     public static final int METADATA_KEY_DISC_NUMBER     = 14;
1245     /**
1246      * The metadata key to retrieve the music album compilation status.
1247      */
1248     public static final int METADATA_KEY_COMPILATION     = 15;
1249     /**
1250      * If this key exists the media contains audio content.
1251      */
1252     public static final int METADATA_KEY_HAS_AUDIO       = 16;
1253     /**
1254      * If this key exists the media contains video content.
1255      */
1256     public static final int METADATA_KEY_HAS_VIDEO       = 17;
1257     /**
1258      * If the media contains video, this key retrieves its width.
1259      */
1260     public static final int METADATA_KEY_VIDEO_WIDTH     = 18;
1261     /**
1262      * If the media contains video, this key retrieves its height.
1263      */
1264     public static final int METADATA_KEY_VIDEO_HEIGHT    = 19;
1265     /**
1266      * This key retrieves the average bitrate (in bits/sec), if available.
1267      */
1268     public static final int METADATA_KEY_BITRATE         = 20;
1269     /**
1270      * This key retrieves the language code of text tracks, if available.
1271      * If multiple text tracks present, the return value will look like:
1272      * "eng:chi"
1273      * @hide
1274      */
1275     public static final int METADATA_KEY_TIMED_TEXT_LANGUAGES      = 21;
1276     /**
1277      * If this key exists the media is drm-protected.
1278      * @hide
1279      */
1280     public static final int METADATA_KEY_IS_DRM          = 22;
1281     /**
1282      * This key retrieves the location information, if available.
1283      * The location should be specified according to ISO-6709 standard, under
1284      * a mp4/3gp box "@xyz". Location with longitude of -90 degrees and latitude
1285      * of 180 degrees will be retrieved as "+180.0000-90.0000/", for instance.
1286      */
1287     public static final int METADATA_KEY_LOCATION        = 23;
1288     /**
1289      * This key retrieves the video rotation angle in degrees, if available.
1290      * The video rotation angle may be 0, 90, 180, or 270 degrees.
1291      */
1292     public static final int METADATA_KEY_VIDEO_ROTATION = 24;
1293     /**
1294      * This key retrieves the original capture framerate, if it's
1295      * available. The capture framerate will be a floating point
1296      * number.
1297      */
1298     public static final int METADATA_KEY_CAPTURE_FRAMERATE = 25;
1299     /**
1300      * If this key exists the media contains still image content.
1301      */
1302     public static final int METADATA_KEY_HAS_IMAGE       = 26;
1303     /**
1304      * If the media contains still images, this key retrieves the number
1305      * of still images.
1306      */
1307     public static final int METADATA_KEY_IMAGE_COUNT     = 27;
1308     /**
1309      * If the media contains still images, this key retrieves the image
1310      * index of the primary image.
1311      */
1312     public static final int METADATA_KEY_IMAGE_PRIMARY   = 28;
1313     /**
1314      * If the media contains still images, this key retrieves the width
1315      * of the primary image.
1316      */
1317     public static final int METADATA_KEY_IMAGE_WIDTH     = 29;
1318     /**
1319      * If the media contains still images, this key retrieves the height
1320      * of the primary image.
1321      */
1322     public static final int METADATA_KEY_IMAGE_HEIGHT    = 30;
1323     /**
1324      * If the media contains still images, this key retrieves the rotation
1325      * angle (in degrees clockwise) of the primary image. The image rotation
1326      * angle must be one of 0, 90, 180, or 270 degrees.
1327      */
1328     public static final int METADATA_KEY_IMAGE_ROTATION  = 31;
1329     /**
1330      * If the media contains video and this key exists, it retrieves the
1331      * total number of frames in the video sequence.
1332      */
1333     public static final int METADATA_KEY_VIDEO_FRAME_COUNT = 32;
1334 
1335     /**
1336      * If the media contains EXIF data, this key retrieves the offset (in bytes)
1337      * of the data.
1338      */
1339     public static final int METADATA_KEY_EXIF_OFFSET = 33;
1340 
1341     /**
1342      * If the media contains EXIF data, this key retrieves the length (in bytes)
1343      * of the data.
1344      */
1345     public static final int METADATA_KEY_EXIF_LENGTH = 34;
1346 
1347     /**
1348      * This key retrieves the color standard, if available.
1349      *
1350      * @see MediaFormat#COLOR_STANDARD_BT709
1351      * @see MediaFormat#COLOR_STANDARD_BT601_PAL
1352      * @see MediaFormat#COLOR_STANDARD_BT601_NTSC
1353      * @see MediaFormat#COLOR_STANDARD_BT2020
1354      */
1355     public static final int METADATA_KEY_COLOR_STANDARD = 35;
1356 
1357     /**
1358      * This key retrieves the color transfer, if available.
1359      *
1360      * @see MediaFormat#COLOR_TRANSFER_LINEAR
1361      * @see MediaFormat#COLOR_TRANSFER_SDR_VIDEO
1362      * @see MediaFormat#COLOR_TRANSFER_ST2084
1363      * @see MediaFormat#COLOR_TRANSFER_HLG
1364      */
1365     public static final int METADATA_KEY_COLOR_TRANSFER = 36;
1366 
1367     /**
1368      * This key retrieves the color range, if available.
1369      *
1370      * @see MediaFormat#COLOR_RANGE_LIMITED
1371      * @see MediaFormat#COLOR_RANGE_FULL
1372      */
1373     public static final int METADATA_KEY_COLOR_RANGE    = 37;
1374 
1375     /**
1376      * This key retrieves the sample rate in Hz, if available.
1377      * This is a signed 32-bit integer formatted as a string in base 10.
1378      */
1379     public static final int METADATA_KEY_SAMPLERATE      = 38;
1380 
1381     /**
1382      * This key retrieves the bits per sample in numbers of bits, if available.
1383      * This is a signed 32-bit integer formatted as a string in base 10.
1384      */
1385     public static final int METADATA_KEY_BITS_PER_SAMPLE = 39;
1386 
1387     /**
1388      * This key retrieves the video codec mimetype if available.
1389      * @hide
1390      */
1391     @SystemApi(client = MODULE_LIBRARIES)
1392     public static final int METADATA_KEY_VIDEO_CODEC_MIME_TYPE = 40;
1393 
1394     /**
1395      * If the media contains XMP data, this key retrieves the offset (in bytes)
1396      * of the data.
1397      */
1398     public static final int METADATA_KEY_XMP_OFFSET = 41;
1399 
1400     /**
1401      * If the media contains XMP data, this key retrieves the length (in bytes)
1402      * of the data.
1403      */
1404     public static final int METADATA_KEY_XMP_LENGTH = 42;
1405 
1406     // Add more here...
1407 }
1408