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